From nobody Fri Sep 25 23:51:08 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 829A945C718; Mon, 7 Sep 2026 10:00:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775205; cv=none; b=hWc4NbQpAEm69rq/gI6nWNIig2C2rfcf0wY2+y6Qf50uoXSEGG/t5VEfTGDnnu4DJ3LBa3DKkTkfCJsCMsUNve25sVE9alhApNZfiSKmMMYCc6q4rW2XbG5Cp7JebXiTZpsghFbX3LVIXyzdlc2dgxlnlsAIbK1VF+obYX7sFQY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775205; c=relaxed/simple; bh=tuAFupYWCi/JFuVDRYTyDnJkPl9ERItmrGX6MZpEGXo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JCNgIl7Xc2Q0A+Xf65Z/lPBOtNf48J33zo49DjsDiIjfvNTJbvke58sZfOMzoLuO9yD/7097dq13/aEiFSbidb08dBuGLXROeZjeaynhg9ZletoAVMPiUo99RnkST4cb5h6kR+B87vO55tXeiKQmJatpoEDCGzHoLlQQNhWjbFQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=uq06EAQi; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="uq06EAQi" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 2E6871477; Mon, 7 Sep 2026 02:59:58 -0700 (PDT) Received: from ewhatever.cambridge.arm.com (ewhatever.cambridge.arm.com [10.2.197.99]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 1CAD53F7B4; Mon, 7 Sep 2026 02:59:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1788775201; bh=tuAFupYWCi/JFuVDRYTyDnJkPl9ERItmrGX6MZpEGXo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uq06EAQiF5fnTU8E3hvtIxvSjbO9yhQCRYFdVawFbi5hA1Jgeu7tJXoIep/XnfYxU 86QT98EqSi1jGxiJZl9d31WRnBKLBUwJwHfROEUT6CrT1+OqJ4tvn8HZ1Ja6uXs7Ov IIklcZecR+Ilb1GYVBVDzyq544cfi5oR5HDfiwzc= From: Suzuki K Poulose To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: maz@kernel.org, will@kernel.org, catalin.marinas@arm.com, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, steven.price@arm.com, aneesh.kumar@kernel.org, oupton@kernel.org, gshan@redhat.com, joey.gouly@arm.com, tabba@google.com, yuzenghui@huawei.com, linux-coco@lists.linux.dev, gankulkarni@os.amperecomputing.com, sdonthineni@nvidia.com, alpergun@google.com, fj0570is@fujitsu.com, WeiLin.Chang@arm.com, lpieralisi@kernel.org, enju.kohei@fujitsu.com, Suzuki K Poulose Subject: [PATCH v17 1/7] firmware: arm_rmm: Add SMC definitions for calling the RMM Date: Mon, 7 Sep 2026 10:59:35 +0100 Message-ID: <20260907095942.1140734-2-suzuki.poulose@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260907095942.1140734-1-suzuki.poulose@arm.com> References: <20260907095942.1140734-1-suzuki.poulose@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Steven Price The RMM (Realm Management Monitor) provides functionality that can be accessed by SMC calls from the host. The SMC definitions are based on DEN0137[1] version 2.0-bet3 [1] https://developer.arm.com/documentation/den0137/2-0bet3/ Signed-off-by: Steven Price Signed-off-by: Suzuki K Poulose --- Changes since v16: * Updated definitions to RMM specification v2.0-bet3. Changes since v15: * Dropped unused symbols REC_MAX_GIC_NUM_LRS and RMI_PERMITTED_GICV3_HCR_= BITS. * Output is now (partially) generated from the spec source. Changes since v14: * Updated to RMM spec v2.0-bet2 but without the changes to move metadata out of individual address range descriptors as this is expected to be reverted in a future spec release. Changes since v13: * Updated to RMM spec v2.0-bet1 Changes since v12: * Updated to RMM spec v2.0-bet0 Changes since v9: * Corrected size of 'ripas_value' in struct rec_exit. The spec states this is an 8-bit type with padding afterwards (rather than a u64). Changes since v8: * Added RMI_PERMITTED_GICV3_HCR_BITS to define which bits the RMM permits to be modified. Changes since v6: * Renamed REC_ENTER_xxx defines to include 'FLAG' to make it obvious these are flag values. Changes since v5: * Sorted the SMC #defines by value. * Renamed SMI_RxI_CALL to SMI_RMI_CALL since the macro is only used for RMI calls. * Renamed REC_GIC_NUM_LRS to REC_MAX_GIC_NUM_LRS since the actual number of available list registers could be lower. * Provided a define for the reserved fields of FeatureRegister0. * Fix inconsistent names for padding fields. Changes since v4: * Update to point to final released RMM spec. * Minor rearrangements. Changes since v3: * Update to match RMM spec v1.0-rel0-rc1. Changes since v2: * Fix specification link. * Rename rec_entry->rec_enter to match spec. * Fix size of pmu_ovf_status to match spec. --- include/linux/arm-smccc-rmi.h | 494 ++++++++++++++++++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 include/linux/arm-smccc-rmi.h diff --git a/include/linux/arm-smccc-rmi.h b/include/linux/arm-smccc-rmi.h new file mode 100644 index 0000000000000..3eb88caf40964 --- /dev/null +++ b/include/linux/arm-smccc-rmi.h @@ -0,0 +1,494 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023-2026 ARM Ltd. + * + * The values and structures in this file are from the Realm Management Mo= nitor + * specification (DEN0137) version 2.0-bet3: + * https://developer.arm.com/documentation/den0137/2-0bet3/ + */ + +#ifndef __LINUX_ARM_SMCCC_RMI_H_ +#define __LINUX_ARM_SMCCC_RMI_H_ + +#include +#include +#include +#include +#include + +#include + +#define SMC_RMI_CALL(func) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_STANDARD, \ + (func)) + +#define SMC_RMI_VERSION SMC_RMI_CALL(0x0150) + +#define SMC_RMI_RTT_DATA_MAP_INIT SMC_RMI_CALL(0x0153) + +#define SMC_RMI_REALM_ACTIVATE SMC_RMI_CALL(0x0157) +#define SMC_RMI_REALM_CREATE SMC_RMI_CALL(0x0158) +#define SMC_RMI_REALM_DESTROY SMC_RMI_CALL(0x0159) +#define SMC_RMI_REC_CREATE SMC_RMI_CALL(0x015a) +#define SMC_RMI_REC_DESTROY SMC_RMI_CALL(0x015b) +#define SMC_RMI_REC_ENTER SMC_RMI_CALL(0x015c) +#define SMC_RMI_RTT_CREATE SMC_RMI_CALL(0x015d) +#define SMC_RMI_RTT_DESTROY SMC_RMI_CALL(0x015e) + +#define SMC_RMI_RTT_READ_ENTRY SMC_RMI_CALL(0x0161) + +#define SMC_RMI_RTT_DEV_VALIDATE SMC_RMI_CALL(0x0163) +#define SMC_RMI_PSCI_COMPLETE SMC_RMI_CALL(0x0164) +#define SMC_RMI_FEATURES SMC_RMI_CALL(0x0165) +#define SMC_RMI_RTT_FOLD SMC_RMI_CALL(0x0166) + +#define SMC_RMI_RTT_INIT_RIPAS SMC_RMI_CALL(0x0168) +#define SMC_RMI_RTT_SET_RIPAS SMC_RMI_CALL(0x0169) +#define SMC_RMI_VSMMU_CREATE SMC_RMI_CALL(0x016a) +#define SMC_RMI_VSMMU_DESTROY SMC_RMI_CALL(0x016b) + +#define SMC_RMI_RMM_CONFIG_SET SMC_RMI_CALL(0x016e) +#define SMC_RMI_PSMMU_IRQ_NOTIFY SMC_RMI_CALL(0x016f) +#define SMC_RMI_ATTEST_PLAT_TOKEN_REFRESH SMC_RMI_CALL(0x0170) + +#define SMC_RMI_PDEV_ABORT SMC_RMI_CALL(0x0174) +#define SMC_RMI_PDEV_COMMUNICATE SMC_RMI_CALL(0x0175) +#define SMC_RMI_PDEV_CREATE SMC_RMI_CALL(0x0176) +#define SMC_RMI_PDEV_DESTROY SMC_RMI_CALL(0x0177) +#define SMC_RMI_PDEV_GET_STATE SMC_RMI_CALL(0x0178) + +#define SMC_RMI_PDEV_STREAM_KEY_REFRESH SMC_RMI_CALL(0x017a) +#define SMC_RMI_PDEV_SET_PUBKEY SMC_RMI_CALL(0x017b) +#define SMC_RMI_PDEV_STOP SMC_RMI_CALL(0x017c) +#define SMC_RMI_RTT_AUX_CREATE SMC_RMI_CALL(0x017d) +#define SMC_RMI_RTT_AUX_DESTROY SMC_RMI_CALL(0x017e) +#define SMC_RMI_RTT_AUX_FOLD SMC_RMI_CALL(0x017f) + +#define SMC_RMI_VDEV_ABORT SMC_RMI_CALL(0x0185) +#define SMC_RMI_VDEV_COMMUNICATE SMC_RMI_CALL(0x0186) +#define SMC_RMI_VDEV_CREATE SMC_RMI_CALL(0x0187) +#define SMC_RMI_VDEV_DESTROY SMC_RMI_CALL(0x0188) +#define SMC_RMI_VDEV_GET_STATE SMC_RMI_CALL(0x0189) +#define SMC_RMI_VDEV_UNLOCK SMC_RMI_CALL(0x018a) +#define SMC_RMI_RTT_SET_S2AP SMC_RMI_CALL(0x018b) + +#define SMC_RMI_VDEV_GET_INTERFACE_REPORT SMC_RMI_CALL(0x01d0) +#define SMC_RMI_VDEV_GET_MEASUREMENTS SMC_RMI_CALL(0x01d1) +#define SMC_RMI_VDEV_LOCK SMC_RMI_CALL(0x01d2) +#define SMC_RMI_VDEV_START SMC_RMI_CALL(0x01d3) + +#define SMC_RMI_VSMMU_EVENT_HANDLE SMC_RMI_CALL(0x01d6) +#define SMC_RMI_PSMMU_ACTIVATE SMC_RMI_CALL(0x01d7) +#define SMC_RMI_PSMMU_DEACTIVATE SMC_RMI_CALL(0x01d8) + +#define SMC_RMI_PSMMU_ST_L2_CREATE SMC_RMI_CALL(0x01db) +#define SMC_RMI_PSMMU_ST_L2_DESTROY SMC_RMI_CALL(0x01dc) +#define SMC_RMI_DPT_L0_CREATE SMC_RMI_CALL(0x01dd) +#define SMC_RMI_DPT_L0_DESTROY SMC_RMI_CALL(0x01de) +#define SMC_RMI_DPT_L1_CREATE SMC_RMI_CALL(0x01df) +#define SMC_RMI_DPT_L1_DESTROY SMC_RMI_CALL(0x01e0) +#define SMC_RMI_GRANULE_TRACKING_GET SMC_RMI_CALL(0x01e1) + +#define SMC_RMI_GRANULE_TRACKING_SET SMC_RMI_CALL(0x01e3) + +#define SMC_RMI_RMM_CONFIG_GET SMC_RMI_CALL(0x01ec) + +#define SMC_RMI_RMM_STATE_GET SMC_RMI_CALL(0x01ee) + +#define SMC_RMI_PSMMU_EVENT_CONSUME SMC_RMI_CALL(0x01f0) +#define SMC_RMI_GRANULE_RANGE_DELEGATE SMC_RMI_CALL(0x01f1) +#define SMC_RMI_GRANULE_RANGE_UNDELEGATE SMC_RMI_CALL(0x01f2) +#define SMC_RMI_GPT_L1_CREATE SMC_RMI_CALL(0x01f3) +#define SMC_RMI_GPT_L1_DESTROY SMC_RMI_CALL(0x01f4) +#define SMC_RMI_RTT_DATA_MAP SMC_RMI_CALL(0x01f5) +#define SMC_RMI_RTT_DATA_UNMAP SMC_RMI_CALL(0x01f6) +#define SMC_RMI_RTT_DEV_MAP SMC_RMI_CALL(0x01f7) +#define SMC_RMI_RTT_DEV_UNMAP SMC_RMI_CALL(0x01f8) +#define SMC_RMI_RTT_ARCH_DEV_MAP SMC_RMI_CALL(0x01f9) +#define SMC_RMI_RTT_ARCH_DEV_UNMAP SMC_RMI_CALL(0x01fa) +#define SMC_RMI_RTT_UNPROT_MAP SMC_RMI_CALL(0x01fb) +#define SMC_RMI_RTT_UNPROT_UNMAP SMC_RMI_CALL(0x01fc) +#define SMC_RMI_RTT_AUX_PROT_MAP SMC_RMI_CALL(0x01fd) +#define SMC_RMI_RTT_AUX_PROT_UNMAP SMC_RMI_CALL(0x01fe) +#define SMC_RMI_RTT_AUX_UNPROT_MAP SMC_RMI_CALL(0x01ff) +#define SMC_RMI_RTT_AUX_UNPROT_UNMAP SMC_RMI_CALL(0x0200) +#define SMC_RMI_REALM_TERMINATE SMC_RMI_CALL(0x0201) +#define SMC_RMI_RMM_ACTIVATE SMC_RMI_CALL(0x0202) +#define SMC_RMI_OP_CONTINUE SMC_RMI_CALL(0x0203) +#define SMC_RMI_PDEV_STREAM_CONNECT SMC_RMI_CALL(0x0204) +#define SMC_RMI_PDEV_STREAM_DISCONNECT SMC_RMI_CALL(0x0205) +#define SMC_RMI_PDEV_STREAM_COMPLETE SMC_RMI_CALL(0x0206) +#define SMC_RMI_PDEV_STREAM_KEY_PURGE SMC_RMI_CALL(0x0207) +#define SMC_RMI_OP_MEM_DONATE SMC_RMI_CALL(0x0208) +#define SMC_RMI_OP_MEM_RECLAIM SMC_RMI_CALL(0x0209) +#define SMC_RMI_OP_CANCEL SMC_RMI_CALL(0x020a) +#define SMC_RMI_VSMMU_FEATURES SMC_RMI_CALL(0x020b) +#define SMC_RMI_VSMMU_CMD_GET SMC_RMI_CALL(0x020c) +#define SMC_RMI_VSMMU_CMD_COMPLETE SMC_RMI_CALL(0x020d) +#define SMC_RMI_PSMMU_INFO SMC_RMI_CALL(0x020e) +#define SMC_RMI_RMM_DEACTIVATE SMC_RMI_CALL(0x020f) +#define SMC_RMI_PDEV_STREAM_INFO SMC_RMI_CALL(0x0210) +#define SMC_RMI_GPT_INFO SMC_RMI_CALL(0x0211) + +#define RMI_ABI_MAJOR_VERSION 2 +#define RMI_ABI_MINOR_VERSION 0 + +#define RMI_ABI_VERSION_GET_MAJOR(version) ((version) >> 16) +#define RMI_ABI_VERSION_GET_MINOR(version) ((version) & 0xFFFF) +#define RMI_ABI_VERSION(major, minor) (((major) << 16) | (minor)) + +#define RMI_RETURN_STATUS_MASK (0xFFUL) +#define RMI_RETURN_INDEX_MASK (0xFFUL << 8) +#define RMI_RETURN_MEMREQ_MASK (0x3UL << 8) +#define RMI_RETURN_CAN_CANCEL_MASK (0x1UL << 10) + +#define RMI_RETURN_STATUS(ret) FIELD_GET(RMI_RETURN_STATUS_MASK, ret) +#define RMI_RETURN_INDEX(ret) FIELD_GET(RMI_RETURN_INDEX_MASK, ret) +#define RMI_RETURN_MEMREQ(ret) FIELD_GET(RMI_RETURN_MEMREQ_MASK, ret) +#define RMI_RETURN_CAN_CANCEL(ret) FIELD_GET(RMI_RETURN_CAN_CANCEL_MASK, r= et) + +#define RMI_SUCCESS 0 +#define RMI_ERROR_INPUT 1 +#define RMI_ERROR_REALM 2 +#define RMI_ERROR_REC 3 +#define RMI_ERROR_RTT 4 +#define RMI_ERROR_NOT_SUPPORTED 5 +#define RMI_ERROR_DEVICE 6 +#define RMI_ERROR_RTT_AUX 7 +#define RMI_ERROR_PSMMU_ST 8 +#define RMI_ERROR_DPT 9 +#define RMI_BUSY 10 +#define RMI_ERROR_GLOBAL 11 +#define RMI_ERROR_TRACKING 12 +#define RMI_INCOMPLETE 13 +#define RMI_BLOCKED 14 +#define RMI_ERROR_GPT 15 +#define RMI_ERROR_GRANULE 16 + +#define RMI_CONTINUE_KEEP_GOING 0 +#define RMI_CONTINUE_STOP 1 + +#define RMI_OP_MEM_REQ_NONE 0 +#define RMI_OP_MEM_REQ_DONATE 1 +#define RMI_OP_MEM_REQ_RECLAIM 2 + +#define RMI_DONATE_SIZE_MASK 3UL +#define RMI_DONATE_COUNT_MASK GENMASK(15, 2) +#define RMI_DONATE_CONTIG_MASK BIT(16) +#define RMI_DONATE_STATE_MASK GENMASK(18, 17) + +#define RMI_DONATE_SIZE(req) FIELD_GET(RMI_DONATE_SIZE_MASK, req) +#define RMI_DONATE_COUNT(req) FIELD_GET(RMI_DONATE_COUNT_MASK, req) +#define RMI_DONATE_CONTIG(req) FIELD_GET(RMI_DONATE_CONTIG_MASK, req) +#define RMI_DONATE_STATE(req) FIELD_GET(RMI_DONATE_STATE_MASK, req) + +#define RMI_OP_MEM_DELEGATED 0 +#define RMI_OP_MEM_UNDELEGATED 1 +#define RMI_OP_MEM_CONDITIONAL 2 + +#define RMI_ADDR_TYPE_NONE 0 +#define RMI_ADDR_TYPE_SINGLE 1 +#define RMI_ADDR_TYPE_LIST 2 + +#define RMI_ADDR_RANGE_SIZE_MASK GENMASK(1, 0) +#define RMI_ADDR_RANGE_COUNT_MASK GENMASK(PAGE_SHIFT - 1, 2) +#define RMI_ADDR_RANGE_ADDR_MASK (PAGE_MASK & GENMASK(51, 0)) +#define RMI_ADDR_RANGE_STATE_MASK GENMASK(63, 62) + +#define RMI_ADDR_RANGE_SIZE(ar) (FIELD_GET(RMI_ADDR_RANGE_SIZE_MASK, \ + (ar))) +#define RMI_ADDR_RANGE_COUNT(ar) (FIELD_GET(RMI_ADDR_RANGE_COUNT_MASK, \ + (ar))) +#define RMI_ADDR_RANGE_ADDR(ar) ((ar) & RMI_ADDR_RANGE_ADDR_MASK) +#define RMI_ADDR_RANGE_STATE(ar) (FIELD_GET(RMI_ADDR_RANGE_STATE_MASK, \ + (ar))) + +enum rmi_ripas { + RMI_EMPTY =3D 0, + RMI_RAM =3D 1, + RMI_DESTROYED =3D 2, + RMI_DEV =3D 3, +}; + +#define RMI_NO_MEASURE_CONTENT 0 +#define RMI_MEASURE_CONTENT 1 + +#define RMI_FEATURE_REGISTER_0_S2SZ GENMASK(7, 0) +#define RMI_FEATURE_REGISTER_0_LPA2 BIT(8) +#define RMI_FEATURE_REGISTER_0_SVE BIT(9) +#define RMI_FEATURE_REGISTER_0_SVE_VL GENMASK(13, 10) +#define RMI_FEATURE_REGISTER_0_NUM_BPS GENMASK(19, 14) +#define RMI_FEATURE_REGISTER_0_NUM_WPS GENMASK(25, 20) +#define RMI_FEATURE_REGISTER_0_PMU BIT(26) +#define RMI_FEATURE_REGISTER_0_PMU_NUM_CTRS GENMASK(31, 27) +#define RMI_FEATURE_REGISTER_0_L0GPT_BLOCK_DELEGATE BIT(32) +#define RMI_FEATURE_REGISTER_0_S2OASZ GENMASK(40, 33) + +#define RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_4KB BIT(0) +#define RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_16KB BIT(1) +#define RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_64KB BIT(2) +#define RMI_FEATURE_REGISTER_1_HASH_SHA_256 BIT(3) +#define RMI_FEATURE_REGISTER_1_HASH_SHA_384 BIT(4) +#define RMI_FEATURE_REGISTER_1_HASH_SHA_512 BIT(5) +#define RMI_FEATURE_REGISTER_1_MAX_RECS_ORDER GENMASK(9, 6) +#define RMI_FEATURE_REGISTER_1_L0GPTSZ GENMASK(13, 10) +#define RMI_FEATURE_REGISTER_1_PPS GENMASK(16, 14) + +#define RMI_FEATURE_REGISTER_2_DA BIT(0) +#define RMI_FEATURE_REGISTER_2_DA_COH BIT(1) +#define RMI_FEATURE_REGISTER_2_VSMMU BIT(2) +#define RMI_FEATURE_REGISTER_2_ATS BIT(3) +#define RMI_FEATURE_REGISTER_2_PDEV_MAX_VDEVS_ORDER GENMASK(7, 4) +#define RMI_FEATURE_REGISTER_2_VDEV_KROU BIT(8) +#define RMI_FEATURE_REGISTER_2_NON_TEE_STREAM BIT(9) +#define RMI_FEATURE_REGISTER_2_REALM_MAX_VDEVS_ORDER GENMASK(14, 10) + +#define RMI_FEATURE_REGISTER_3_MAX_NUM_AUX_PLANES GENMASK(3, 0) +#define RMI_FEATURE_REGISTER_3_RTT_PLANE GENMASK(5, 4) +#define RMI_FEATURE_REGISTER_3_RTT_S2AP_INDIRECT BIT(6) + +#define RMI_FEATURE_REGISTER_4_MEC_COUNT GENMASK(63, 0) + +#define RMI_MEM_CATEGORY_CONVENTIONAL 0 +#define RMI_MEM_CATEGORY_DEV_NCOH 1 +#define RMI_MEM_CATEGORY_DEV_COH 2 +#define RMI_MEM_CATEGORY_NONE 3 + +#define RMI_TRACKING_RESERVED 0 +#define RMI_TRACKING_NONE 1 +#define RMI_TRACKING_FINE 2 +#define RMI_TRACKING_COARSE 3 +#define RMI_TRACKING_INTERMEDIATE 4 + +#define RMI_GRANULE_SIZE_4KB 0 +#define RMI_GRANULE_SIZE_16KB 1 +#define RMI_GRANULE_SIZE_64KB 2 + +#define RMI_GPT_PAR_RESERVED 0U +#define RMI_GPT_PAR_PLAT 1U +#define RMI_GPT_PAR_HOST_NOT_CREATED 2U +#define RMI_GPT_PAR_HOST_CREATED 3U + +/* + * Note many of these fields are smaller than u64 but all fields have u64 + * alignment, so use u64 to ensure correct alignment. + */ +struct rmm_config { + union { /* 0x0 */ + struct { + u64 tracking_region_size; + u64 rmi_granule_size; + }; + u8 sizer[SZ_4K]; + }; +}; + +static_assert(sizeof(struct rmm_config) =3D=3D SZ_4K); + +#define RMI_REALM_PARAM_FLAG_SVE BIT(1) +#define RMI_REALM_PARAM_FLAG_PMU BIT(2) +#define RMI_REALM_PARAM_FLAG_DA BIT(3) +#define RMI_REALM_PARAM_FLAG_LFA_POLICY GENMASK(6, 5) +#define RMI_REALM_PARAM_FLAG_MEC_POLICY GENMASK(8, 7) + +#define RMI_HASH_SHA_256 0 +#define RMI_HASH_SHA_512 1 +#define RMI_HASH_SHA_384 2 + +struct realm_params { + union { /* 0x0 */ + struct { + u64 flags0; + u64 s2sz; + u64 sve_vl; + u64 num_bps; + u64 num_wps; + u64 pmu_num_ctrs; + u64 hash_algo; + u64 num_aux_planes; + }; + u8 padding0[0x400]; + }; + union { /* 0x400 */ + struct { + u8 rpv[64]; + u64 ats_plane; + }; + u8 padding1[0x400]; + }; + union { /* 0x800 */ + struct { + u64 padding2; + u64 rtt_base; + s64 rtt_level_start; + u64 rtt_num_start; + u64 flags1; + u64 max_num_vdevs; + }; + u8 padding3[0x700]; + }; + union { /* 0xf00 */ + struct { + u8 padding4[0x80]; + u64 aux_rtt_base[3]; + }; + u8 padding5[0x100]; + }; +}; + +static_assert(sizeof(struct realm_params) =3D=3D SZ_4K); + +/* + * The number of GPRs (starting from X0) that are + * configured by the host when a REC is created. + */ +#define REC_CREATE_NR_GPRS 8 + +#define REC_PARAMS_FLAG_RUNNABLE BIT(0) + +struct rec_params { + union { /* 0x0 */ + u64 flags; + u8 padding0[0x100]; + }; + union { /* 0x100 */ + u64 mpidr; + u8 padding1[0x100]; + }; + union { /* 0x200 */ + u64 pc; + u8 padding2[0x100]; + }; + union { /* 0x300 */ + u64 gprs[REC_CREATE_NR_GPRS]; + u8 padding3[0xd00]; + }; +}; + +static_assert(sizeof(struct rec_params) =3D=3D SZ_4K); + +#define REC_ENTER_FLAG_EMULATED_MMIO BIT(0) +#define REC_ENTER_FLAG_INJECT_SEA BIT(1) +#define REC_ENTER_FLAG_TRAP_WFI BIT(2) +#define REC_ENTER_FLAG_TRAP_WFE BIT(3) +#define REC_ENTER_FLAG_RIPAS_RESPONSE BIT(4) +#define REC_ENTER_FLAG_S2AP_RESPONSE BIT(5) +#define REC_ENTER_FLAG_DEV_MEM_RESPONSE BIT(6) +#define REC_ENTER_FLAG_FORCE_P0 BIT(7) + +#define REC_RUN_GPRS 31 + +struct rec_enter { + union { /* 0x000 */ + u64 flags; + u8 padding0[0x200]; + }; + union { /* 0x200 */ + u64 gprs[REC_RUN_GPRS]; + u8 padding1[0x600]; + }; +}; + +static_assert(sizeof(struct rec_enter) =3D=3D SZ_2K); + +#define RMI_EXIT_SYNC 0x00 +#define RMI_EXIT_IRQ 0x01 +#define RMI_EXIT_FIQ 0x02 +#define RMI_EXIT_PSCI 0x03 +#define RMI_EXIT_RIPAS_CHANGE 0x04 +#define RMI_EXIT_HOST_CALL 0x05 +#define RMI_EXIT_SERROR 0x06 +#define RMI_EXIT_S2AP_CHANGE 0x07 +#define RMI_EXIT_VDEV_VALIDATE_MAPPING 0x08 +#define RMI_EXIT_VSMMU_COMMAND 0x0a + +struct rec_exit { + union { /* 0x000 */ + u8 exit_reason; + u8 padding0[0x100]; + }; + union { /* 0x100 */ + struct { + u64 esr; + u64 far; + u64 hpfar; + u64 rtt_tree; + }; + u8 padding1[0x100]; + }; + union { /* 0x200 */ + u64 gprs[REC_RUN_GPRS]; + u8 padding2[0x100]; + }; + union { /* 0x300 */ + u8 padding3[0x100]; + }; + union { /* 0x400 */ + struct { + u64 cntp_ctl; + u64 cntp_cval; + u64 cntv_ctl; + u64 cntv_cval; + }; + u8 padding4[0x100]; + }; + union { /* 0x500 */ + struct { + u64 ripas_base; + u64 ripas_top; + u8 ripas_value; + u8 padding5[0xf]; + u64 s2ap_base; + u64 s2ap_top; + u64 vdev_id_1; + u64 vdev_id_2; + u64 dev_mem_base; + u64 dev_mem_top; + u64 dev_mem_pa; + }; + u8 padding6[0x100]; + }; + union { /* 0x600 */ + struct { + u16 imm; + u8 padding7[0x6]; + u64 plane; + }; + u8 padding8[0x100]; + }; + union { /* 0x700 */ + struct { + u8 pmu_ovf_status; + u8 padding9[0xf]; + u64 vsmmu; + }; + u8 padding10[0x100]; + }; +}; + +static_assert(sizeof(struct rec_exit) =3D=3D SZ_2K); + +struct rec_run { + struct rec_enter enter; + struct rec_exit exit; +}; + +static_assert(sizeof(struct rec_run) =3D=3D SZ_4K); + +/* RMI_RTT_UNPROT_MAP_FLAGS definitions */ +#define RMI_RTT_UNPROT_MAP_FLAGS_OADDR_TYPE GENMASK(1, 0) +#define RMI_RTT_UNPROT_MAP_FLAGS_LIST_COUNT GENMASK(15, 2) +#define RMI_RTT_UNPROT_MAP_FLAGS_MEMATTR GENMASK(18, 16) +#define RMI_RTT_UNPROT_MAP_FLAGS_S2AP GENMASK(22, 19) + +/* RMI_RTT_PROT_MAP_FLAGS definitions */ +#define RMI_RTT_PROT_MAP_FLAGS_OADDR_TYPE GENMASK(1, 0) +#define RMI_RTT_PROT_MAP_FLAGS_LIST_COUNT GENMASK(15, 2) + +/* S2AP Direct Encodings, used in RMI_RTT_UNPROT_MAP_FLAGS_S2AP */ +#define RMI_S2AP_DIRECT_WRITE BIT(0) +#define RMI_S2AP_DIRECT_READ BIT(1) + +#endif /* __LINUX_ARM_SMCCC_RMI_H_ */ --=20 2.43.0 From nobody Fri Sep 25 23:51:08 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 909F745FFAC; Mon, 7 Sep 2026 10:00:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775207; cv=none; b=NA4FKoUttgRFn2DVeVbTq9JfOcUq40+nCH37LcM+fK/iwTt6974tjeaYvubt0G7r9jEpTv8jUdJDbcS2poVGsj/sUo11nnRVcT0QY6B1dBDYumtNp3V2s+2fWhHuZ1FnxfDz/3Ml87BI66GH1DEq6113zX4nb8HE9efKkJNZx3E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775207; c=relaxed/simple; bh=nFw/45d3GjvrrFy9+7hw6bjxDSm8+zdi5kCZcXAlpwc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=M8D7ASbEZK5pE9hSZ56uz0+18HrUeDAi6GUhAfnaNQurIQ7yaj1OjYoQ4bUGnNAX8aPeRiWzA1gjjVL301nk3Yg1IwoOl0FLK/tfi/8/7ISsWkF2slgdmqiZdgdBGXYeSOXgetebCCPHM8IzNUm0qkqYgLn6l8WwwoDXBMUO6V4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=JsjF03FN; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="JsjF03FN" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4273E1A32; Mon, 7 Sep 2026 03:00:01 -0700 (PDT) Received: from ewhatever.cambridge.arm.com (ewhatever.cambridge.arm.com [10.2.197.99]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 2E9513F7B4; Mon, 7 Sep 2026 03:00:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1788775204; bh=nFw/45d3GjvrrFy9+7hw6bjxDSm8+zdi5kCZcXAlpwc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JsjF03FN8hexrMFnkujlmg6ePWHQyZXPz8vaVZKBYRa1aoC5FHgmCLblEz/o7Misj n3vXF8KwzsEkJPYqUVGDTUMRViE0pVbIpiA1iNNYQYISadjsepFvJeMdIzFgVlo/9/ MqsfdWQhSfpZv26ensJlZer+hrHUO6ohq4geBw5U= From: Suzuki K Poulose To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: maz@kernel.org, will@kernel.org, catalin.marinas@arm.com, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, steven.price@arm.com, aneesh.kumar@kernel.org, oupton@kernel.org, gshan@redhat.com, joey.gouly@arm.com, tabba@google.com, yuzenghui@huawei.com, linux-coco@lists.linux.dev, gankulkarni@os.amperecomputing.com, sdonthineni@nvidia.com, alpergun@google.com, fj0570is@fujitsu.com, WeiLin.Chang@arm.com, lpieralisi@kernel.org, enju.kohei@fujitsu.com, Suzuki K Poulose Subject: [PATCH v17 2/7] firmware: arm_rmm: Check for RMI support at init Date: Mon, 7 Sep 2026 10:59:36 +0100 Message-ID: <20260907095942.1140734-3-suzuki.poulose@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260907095942.1140734-1-suzuki.poulose@arm.com> References: <20260907095942.1140734-1-suzuki.poulose@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Steven Price Query the RMI version number and check if it is a compatible version. The first two feature registers are read and exposed for future code to use. Signed-off-by: Steven Price Signed-off-by: Suzuki K Poulose --- v17: * Rename ARM_RMM to ARM_RMM_RMI to make it easier to add Guest facing RSI support, which is also in progress v16: * Update Kconfig text to include PCIe TDISP. * Export rmi_feat_reg() here rather than in a later commit. v15: * The code is moved again, this time into the 'firmware' directory. v14: * This moves the basic RMI setup into the 'kernel' directory. This is because RMI will be used for some features outside of KVM so should be available even if KVM isn't compiled in. --- arch/arm64/Kconfig | 1 + arch/arm64/kernel/cpufeature.c | 1 + drivers/firmware/Kconfig | 1 + drivers/firmware/Makefile | 1 + drivers/firmware/arm_rmm/Kconfig | 26 ++++++++ drivers/firmware/arm_rmm/Makefile | 2 + drivers/firmware/arm_rmm/rmi.c | 101 ++++++++++++++++++++++++++++++ include/linux/arm-rmi-cmds.h | 34 ++++++++++ 8 files changed, 167 insertions(+) create mode 100644 drivers/firmware/arm_rmm/Kconfig create mode 100644 drivers/firmware/arm_rmm/Makefile create mode 100644 drivers/firmware/arm_rmm/rmi.c create mode 100644 include/linux/arm-rmi-cmds.h diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b5a51b0ef9440..ff9565d3ffa59 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -38,6 +38,7 @@ config ARM64 select ARCH_HAS_MEMBARRIER_SYNC_CORE select ARCH_HAS_MEM_ENCRYPT select ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS + select ARCH_SUPPORTS_RMM select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_NONLEAF_PMD_YOUNG if ARM64_HAFT diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 17b83a2518a8f..db26f6b0eaf5e 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -293,6 +293,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar3[] = =3D { static const struct arm64_ftr_bits ftr_id_aa64pfr0[] =3D { ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1= _CSV3_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1= _CSV2_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1= _RME_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_D= IT_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1= _AMU_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_MP= AM_SHIFT, 4, 0), diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index b7cc11e4fbfa6..62660bf520a8d 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -310,5 +310,6 @@ source "drivers/firmware/samsung/Kconfig" source "drivers/firmware/smccc/Kconfig" source "drivers/firmware/tegra/Kconfig" source "drivers/firmware/xilinx/Kconfig" +source "drivers/firmware/arm_rmm/Kconfig" =20 endmenu diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index be46f1e1dc77f..196a650ccf025 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -39,3 +39,4 @@ obj-y +=3D samsung/ obj-y +=3D smccc/ obj-y +=3D tegra/ obj-y +=3D xilinx/ +obj-y +=3D arm_rmm/ diff --git a/drivers/firmware/arm_rmm/Kconfig b/drivers/firmware/arm_rmm/Kc= onfig new file mode 100644 index 0000000000000..82724ee23186d --- /dev/null +++ b/drivers/firmware/arm_rmm/Kconfig @@ -0,0 +1,26 @@ + +config ARCH_SUPPORTS_RMM + bool + +config ARM_RMM_RMI + bool "Realm Management Interface (RMI) Support" + depends on ARCH_SUPPORTS_RMM + default y + help + Support the Realm Management Monitor (RMM) on Arm systems that + implement the Realm Management Extension (RME), as defined by the + Arm Confidential Compute Architecture. + + The RMM runs at EL2 in the Realm world and provides the Realm + Management Interface (RMI) used by a Normal World host to create, + manage and run protected virtual machines called Realms. The RMM can + also act as a TSM, as defined by the PCIe TDISP and can manage the + PCI IDE setup for securing the PCIe links. + + This option builds the host-side RMI support used by KVM to detect a + compatible RMM, configure it, manage delegated memory and enable + Realm guests. + + Selecting this option does not by itself make Realm guests available: + the system must also provide RME-capable hardware and firmware with a + compatible RMM implementation. diff --git a/drivers/firmware/arm_rmm/Makefile b/drivers/firmware/arm_rmm/M= akefile new file mode 100644 index 0000000000000..65171988fdcae --- /dev/null +++ b/drivers/firmware/arm_rmm/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_ARM_RMM_RMI) =3D rmi.o diff --git a/drivers/firmware/arm_rmm/rmi.c b/drivers/firmware/arm_rmm/rmi.c new file mode 100644 index 0000000000000..008a783407b4e --- /dev/null +++ b/drivers/firmware/arm_rmm/rmi.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023-2026 ARM Ltd. + */ + +#include +#include +#include +#include + +#include +#include + +/* Currently only the first 2 registers are used by Linux */ +#define RMI_FEAT_REG_COUNT 2 +static __ro_after_init unsigned long rmi_feat_reg_cache[RMI_FEAT_REG_COUNT= ]; + +unsigned long rmi_feat_reg(unsigned long id) +{ + if (WARN_ON(id >=3D RMI_FEAT_REG_COUNT)) + return 0; + + return rmi_feat_reg_cache[id]; +} +EXPORT_SYMBOL_GPL(rmi_feat_reg); + +static int rmi_check_version(void) +{ + struct arm_smccc_res res; + unsigned short version_major, version_minor; + unsigned long host_version =3D RMI_ABI_VERSION(RMI_ABI_MAJOR_VERSION, + RMI_ABI_MINOR_VERSION); + unsigned long aa64pfr0 =3D read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); + + /* If RME isn't supported, then RMI can't be */ + if (cpuid_feature_extract_unsigned_field(aa64pfr0, ID_AA64PFR0_EL1_RME_SH= IFT) =3D=3D 0) + return -ENXIO; + + arm_smccc_1_1_invoke(SMC_RMI_VERSION, host_version, &res); + + if (res.a0 =3D=3D SMCCC_RET_NOT_SUPPORTED) + return -ENXIO; + + version_major =3D RMI_ABI_VERSION_GET_MAJOR(res.a1); + version_minor =3D RMI_ABI_VERSION_GET_MINOR(res.a1); + + if (res.a0 !=3D RMI_SUCCESS) { + unsigned short high_version_major, high_version_minor; + + high_version_major =3D RMI_ABI_VERSION_GET_MAJOR(res.a2); + high_version_minor =3D RMI_ABI_VERSION_GET_MINOR(res.a2); + + pr_err("Unsupported RMI ABI (v%d.%d - v%d.%d) we want v%d.%d\n", + version_major, version_minor, + high_version_major, high_version_minor, + RMI_ABI_MAJOR_VERSION, + RMI_ABI_MINOR_VERSION); + return -ENXIO; + } + + pr_info("RMI ABI version %d.%d\n", version_major, version_minor); + + return 0; +} + +static int rmi_read_features(void) +{ + /* + * Since we've negotiated a compatible version these feature registers + * should always be available + */ + for (int i =3D 0; i < RMI_FEAT_REG_COUNT; i++) { + if (WARN_ON(rmi_features(i, &rmi_feat_reg_cache[i]))) + return -EINVAL; + } + + return 0; +} + +static int __init arm64_init_rmi(void) +{ + int ret; + + /* Continue without realm support if we can't agree on a version */ + ret =3D rmi_check_version(); + if (ret) + return ret; + + ret =3D rmi_read_features(); + if (ret) + return ret; + + return 0; +} + +/* + * Note arm64_init_rmi() must be called before kvm_init_rmi() otherwise KVM + * will not support realm guests. subsys_initcall() is called before + * module_init() (used for KVM) so this is OK. + */ +subsys_initcall(arm64_init_rmi); diff --git a/include/linux/arm-rmi-cmds.h b/include/linux/arm-rmi-cmds.h new file mode 100644 index 0000000000000..2fb1f7f86d71e --- /dev/null +++ b/include/linux/arm-rmi-cmds.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 ARM Ltd. + */ + +#ifndef __LINUX_ARM_RMI_CMDS_H_ +#define __LINUX_ARM_RMI_CMDS_H_ + +#include +#include +#include + +unsigned long rmi_feat_reg(unsigned long id); + +/** + * rmi_features() - Read feature register + * @index: Feature register index + * @out: Feature register value is written to this pointer + * + * Return: RMI return code + */ +static inline int rmi_features(unsigned long index, unsigned long *out) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(SMC_RMI_FEATURES, index, &res); + + if (res.a0 =3D=3D RMI_SUCCESS && out) + *out =3D res.a1; + + return res.a0; +} + +#endif --=20 2.43.0 From nobody Fri Sep 25 23:51:08 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id DD2404503EB; Mon, 7 Sep 2026 10:00:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775210; cv=none; b=RwwcqTfvPs4I7s4O2OmfjpCYYgyJtxO3B0ZSxbSKw4IVJPvvVxU/Z7vt6oeO9mfLsqYfDBfjD0UpZCTomwlLgtSOjSZKbK9Is4qPpxTUpwkb18wnKh+VnE9g9/Ydly51MSOhOd2uFP4S1goiamLh9EbRnvK0aNiYkRSZl1lZluQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775210; c=relaxed/simple; bh=+Wef5eEgQduEiDa1tV8XW5jWMF2Z9IL+jMT+GW+PGLA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lVUiECWh+7RemtGVzJ530fIJvhgiaWZ/0Ood+YzyXkhu06vTt3ONxOeYq99J8k1KIrYn3uOu/r75DqkVn4CYBVtrJmUUH11k9lGW5IeUuhTc0/XgKZRy7ub4KBIAzUXOWE8aIoc/EujYJqFQvNeNF3pHWJ2PCpaZY5FZ1V0jUww= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=jQpfArcJ; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="jQpfArcJ" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 549641476; Mon, 7 Sep 2026 03:00:04 -0700 (PDT) Received: from ewhatever.cambridge.arm.com (ewhatever.cambridge.arm.com [10.2.197.99]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 410193F7B4; Mon, 7 Sep 2026 03:00:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1788775208; bh=+Wef5eEgQduEiDa1tV8XW5jWMF2Z9IL+jMT+GW+PGLA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jQpfArcJNK14BqrE92Ldp01QPPFr6TyiIvwNP777zdWog7UVwfxqzWITJ+l/tW7eE rLkG1biGLRUcNJLia/dMMEpIGEkCRvie29sxlD2TzB5kKL+QkSJVoJcTbqE4AOcli3 E4SZrAHma4XIdc+dJikuynjKrqTlHOs53UDoQyQg= From: Suzuki K Poulose To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: maz@kernel.org, will@kernel.org, catalin.marinas@arm.com, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, steven.price@arm.com, aneesh.kumar@kernel.org, oupton@kernel.org, gshan@redhat.com, joey.gouly@arm.com, tabba@google.com, yuzenghui@huawei.com, linux-coco@lists.linux.dev, gankulkarni@os.amperecomputing.com, sdonthineni@nvidia.com, alpergun@google.com, fj0570is@fujitsu.com, WeiLin.Chang@arm.com, lpieralisi@kernel.org, enju.kohei@fujitsu.com, Suzuki K Poulose Subject: [PATCH v17 3/7] firmware: arm_rmm: Configure the RMM with the host's page size Date: Mon, 7 Sep 2026 10:59:37 +0100 Message-ID: <20260907095942.1140734-4-suzuki.poulose@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260907095942.1140734-1-suzuki.poulose@arm.com> References: <20260907095942.1140734-1-suzuki.poulose@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Steven Price RMM v2.0 brings the ability to set the RMM's granule size. Check the feature registers and configure the RMM so that it matches the host's page size. This means that operations can be done with a granularity equal to PAGE_SIZE. Signed-off-by: Steven Price Signed-off-by: Suzuki K Poulose --- Changes since v15: * Actually check the feature register for the host's page-size support. Changes since v14: * Move the implementation into drivers/firmware/arm_rmm. Changes since v13: * Moved out of KVM. --- drivers/firmware/arm_rmm/rmi.c | 58 ++++++++++++++++++++++++++++++++++ include/linux/arm-rmi-cmds.h | 17 ++++++++++ 2 files changed, 75 insertions(+) diff --git a/drivers/firmware/arm_rmm/rmi.c b/drivers/firmware/arm_rmm/rmi.c index 008a783407b4e..76f91c145e1fd 100644 --- a/drivers/firmware/arm_rmm/rmi.c +++ b/drivers/firmware/arm_rmm/rmi.c @@ -77,6 +77,60 @@ static int rmi_read_features(void) return 0; } =20 +static int rmi_configure(void) +{ + unsigned long granule_feature; + unsigned long granule_size; + int ret =3D 0; + struct rmm_config *config; + + switch (PAGE_SIZE) { + case SZ_4K: + granule_size =3D RMI_GRANULE_SIZE_4KB; + granule_feature =3D RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_4KB; + break; + case SZ_16K: + granule_size =3D RMI_GRANULE_SIZE_16KB; + granule_feature =3D RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_16KB; + break; + case SZ_64K: + granule_size =3D RMI_GRANULE_SIZE_64KB; + granule_feature =3D RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_64KB; + break; + default: + BUILD_BUG(); + } + + if (!(rmi_feat_reg(1) & granule_feature)) { + pr_err("RMM does not support %luKB granules\n", + PAGE_SIZE >> 10); + return -ENXIO; + } + + config =3D (struct rmm_config *)get_zeroed_page(GFP_KERNEL); + if (!config) + return -ENOMEM; + + config->rmi_granule_size =3D granule_size; + + /* + * For now we set the tracking_region_size to 0 which is the only option + * for 4KB PAGE_SIZE (1GB for 4KB PAGE_SIZE, 32MB/512MB for 16KB/64KB). + * TODO: Support other tracking sizes via Kconfig option for other + * PAGE_SIZES + */ + config->tracking_region_size =3D 0; + + ret =3D rmi_rmm_config_set(virt_to_phys(config)); + if (ret) { + pr_err("RMM config set failed\n"); + ret =3D -EINVAL; + } + + free_page((unsigned long)config); + return ret; +} + static int __init arm64_init_rmi(void) { int ret; @@ -90,6 +144,10 @@ static int __init arm64_init_rmi(void) if (ret) return ret; =20 + ret =3D rmi_configure(); + if (ret) + return ret; + return 0; } =20 diff --git a/include/linux/arm-rmi-cmds.h b/include/linux/arm-rmi-cmds.h index 2fb1f7f86d71e..9aa27697e2377 100644 --- a/include/linux/arm-rmi-cmds.h +++ b/include/linux/arm-rmi-cmds.h @@ -12,6 +12,23 @@ =20 unsigned long rmi_feat_reg(unsigned long id); =20 +/** + * rmi_rmm_config_set() - Configure the RMM + * @cfg_ptr: PA of a struct rmm_config + * + * Sets configuration options on the RMM. + * + * Return: RMI return code + */ +static inline int rmi_rmm_config_set(unsigned long cfg_ptr) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(SMC_RMI_RMM_CONFIG_SET, cfg_ptr, &res); + + return res.a0; +} + /** * rmi_features() - Read feature register * @index: Feature register index --=20 2.43.0 From nobody Fri Sep 25 23:51:08 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id A2EA930675F; Mon, 7 Sep 2026 10:00:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775214; cv=none; b=grZC8jTROnCg0D7jk2Vj5eE2vSyaCPIRMutwjK9CktP660XKPUD8s6l6j7zCn1xnL2o0zJKCbWNzQRDgtw+m/JcYsXK4f7lh2P88I9OD6L/8615GyiWeuH6Z4r1KhouywPTAGKjXuQ9xvXN8Z7DE1O9S5ADgmSmFb9C01p0T29c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775214; c=relaxed/simple; bh=3BjSs7IhO3CkbsnIt5UUNVXIqKtZ0i/eG3y9UTd6ACY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JPr+tsJRxoxEIA1Ncl89vQLyYR9xjs+gXS1QYezn2pPnCwhdvN5Aj3+cKUycpVEP7W6ilPNJKx/Dq+ToqL59poeyFxtwJDuqGX5/tEWRypFVtnwJz2DXIiLOCiGrcmKjjUvCuEdSbxTukQPRv2dKsJ0+oWFHwK8O5f2MqDZyRHI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=Jszne0ZL; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="Jszne0ZL" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 819791477; Mon, 7 Sep 2026 03:00:07 -0700 (PDT) Received: from ewhatever.cambridge.arm.com (ewhatever.cambridge.arm.com [10.2.197.99]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 537823F7B4; Mon, 7 Sep 2026 03:00:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1788775211; bh=3BjSs7IhO3CkbsnIt5UUNVXIqKtZ0i/eG3y9UTd6ACY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Jszne0ZLWBbsAPt7J1tyEC/JAURqnHnu0ZtQj31sWzARPrh4f+kdP7XFv2sb50zrf ckiO9TOsQdsZs92IiKhxaIh7JkrAVi7E7nxTW2cCGrA+6YRYOTexH3MsFM7CWk7wru siuZu2K8ZyOkxUKIIRJmtesWZvO5JsWuoj9SYh10= From: Suzuki K Poulose To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: maz@kernel.org, will@kernel.org, catalin.marinas@arm.com, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, steven.price@arm.com, aneesh.kumar@kernel.org, oupton@kernel.org, gshan@redhat.com, joey.gouly@arm.com, tabba@google.com, yuzenghui@huawei.com, linux-coco@lists.linux.dev, gankulkarni@os.amperecomputing.com, sdonthineni@nvidia.com, alpergun@google.com, fj0570is@fujitsu.com, WeiLin.Chang@arm.com, lpieralisi@kernel.org, enju.kohei@fujitsu.com, Suzuki K Poulose Subject: [PATCH v17 4/7] firmware: arm_rmm: Add support for SRO Date: Mon, 7 Sep 2026 10:59:38 +0100 Message-ID: <20260907095942.1140734-5-suzuki.poulose@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260907095942.1140734-1-suzuki.poulose@arm.com> References: <20260907095942.1140734-1-suzuki.poulose@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Steven Price RMM v2.0 introduces the concept of "Stateful RMI Operations" (SRO). This means that an SMC can return with an operation still in progress. The host is expected to continue the operation until it reaches a conclusion (either success or failure). During this process the RMM can request additional memory ('donate') or hand memory back to the host ('reclaim'). The host can request an in progress operation is cancelled, but still continue the operation until it has completed (otherwise the incomplete operation may cause future RMM operations to fail). The SRO is tracked using a struct rmi_sro_state object which keeps track of any memory which has been allocated but not yet consumed by the RMM or reclaimed from the RMM. This allows the memory to be reused in a future request within the same operation. It will also permit an operation to be done in a context where memory allocation may be difficult (e.g. atomic context) with the option to abort the operation and retry the memory allocation outside of the atomic context. The memory stored in the struct rmi_sro_state object can then be reused on the subsequent attempt. Wrappers for SRO RMI commands are also provided here because they depend on the rmi_sro_execute() implementation added by this patch. Delegate/undelegate handles are also added here because they now use the SRO/stateful command infrastructure. Signed-off-by: Steven Price Signed-off-by: Suzuki K Poulose --- v17: * Handle buggy RMM firmware to avoid looping forever for non-cancellable = SROs. * Add comment (for the AI agents) to clarify that all memory donating SRO= s are cancellable. v16: * Wrappers for realm guests split into a separate patch. * Better support for cancellation - previously a cancelled operation could be treated as successful. * Consistently use a signed type for wrapper return values so that Linux error codes can be returned as well as RMI return values. v15: * Wrappers for SRO RMI functions are provided in this patch due to their dependency on the SRO infrastructure. * Fold the range delegate/undelegate wrappers into this patch because they depend on the stateful command infrastructure. * Add cpu_relax() calls when RMI_BUSY/RMI_BLOCKED is returned. * Various fixes. v14: * SRO support has improved although is still not fully complete. The infrastructure has been moved out of KVM. --- drivers/firmware/arm_rmm/rmi.c | 508 +++++++++++++++++++++++++++++++++ include/linux/arm-rmi-cmds.h | 88 ++++++ 2 files changed, 596 insertions(+) diff --git a/drivers/firmware/arm_rmm/rmi.c b/drivers/firmware/arm_rmm/rmi.c index 76f91c145e1fd..42c973c3a98bb 100644 --- a/drivers/firmware/arm_rmm/rmi.c +++ b/drivers/firmware/arm_rmm/rmi.c @@ -6,6 +6,7 @@ #include #include #include +#include #include =20 #include @@ -24,6 +25,513 @@ unsigned long rmi_feat_reg(unsigned long id) } EXPORT_SYMBOL_GPL(rmi_feat_reg); =20 +int rmi_delegate_range(phys_addr_t phys, + unsigned long size, + phys_addr_t *out_phys) +{ + long ret =3D 0; + unsigned long top =3D phys + size; + unsigned long out_top; + + while (phys < top) { + ret =3D rmi_granule_range_delegate(phys, top, &out_top); + if (ret =3D=3D RMI_SUCCESS) + phys =3D out_top; + else if (ret =3D=3D RMI_BUSY || ret =3D=3D RMI_BLOCKED) + cpu_relax(); + else + break; + } + + if (out_phys) + *out_phys =3D phys; + + return ret; +} +EXPORT_SYMBOL_GPL(rmi_delegate_range); + +int rmi_undelegate_range(phys_addr_t phys, + unsigned long size) +{ + long ret =3D 0; + unsigned long top =3D phys + size; + unsigned long out_top; + + while (phys < top) { + ret =3D rmi_granule_range_undelegate(phys, top, &out_top); + if (ret =3D=3D RMI_SUCCESS) + phys =3D out_top; + else if (ret =3D=3D RMI_BUSY || ret =3D=3D RMI_BLOCKED) + cpu_relax(); + else + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(rmi_undelegate_range); + +static unsigned long donate_req_to_size(unsigned long donatereq) +{ + unsigned long unit_size =3D RMI_DONATE_SIZE(donatereq); + + return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(3 - unit_size)); +} + +static void rmi_smccc_invoke(struct arm_smccc_1_2_regs *regs_in, + struct arm_smccc_1_2_regs *regs_out) +{ + struct arm_smccc_1_2_regs regs =3D *regs_in; + unsigned long status; + + while (1) { + arm_smccc_1_2_invoke(®s, regs_out); + status =3D RMI_RETURN_STATUS(regs_out->a0); + if (status !=3D RMI_BUSY && status !=3D RMI_BLOCKED) + break; + cpu_relax(); + } +} + +static void rmi_op_continue(unsigned long sro_handle, unsigned long flags, + struct arm_smccc_1_2_regs *out_regs) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_OP_CONTINUE, sro_handle, flags + }; + + rmi_smccc_invoke(®s, out_regs); +} + +static void rmi_op_cancel(unsigned long sro_handle, + struct arm_smccc_1_2_regs *out_regs) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_OP_CANCEL, sro_handle + }; + + rmi_smccc_invoke(®s, out_regs); +} + +static void rmi_op_mem_donate(unsigned long sro_handle, unsigned long list= _addr, + unsigned long list_count, unsigned long flags, + struct arm_smccc_1_2_regs *out_regs) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_OP_MEM_DONATE, sro_handle, list_addr, list_count, flags + }; + + /* + * The output donated count (a1) is always valid, irrespective + * of the return result. i.e., 0 if there was an error + */ + rmi_smccc_invoke(®s, out_regs); +} + +static void rmi_op_mem_reclaim(unsigned long sro_handle, + unsigned long list_addr, + unsigned long list_count, + struct arm_smccc_1_2_regs *out_regs) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_OP_MEM_RECLAIM, sro_handle, list_addr, list_count + }; + + rmi_smccc_invoke(®s, out_regs); +} + +int free_delegated_page(phys_addr_t phys) +{ + if (WARN_ON_ONCE(rmi_undelegate_page(phys))) { + /* Undelegate failed: leak the page */ + return -EBUSY; + } + + free_page((unsigned long)phys_to_virt(phys)); + + return 0; +} +EXPORT_SYMBOL_GPL(free_delegated_page); + +static int rmi_sro_ensure_capacity(struct rmi_sro_state *sro, + unsigned long count) +{ + if (WARN_ON_ONCE(sro->addr_count > RMI_MAX_ADDR_LIST)) + return -EOVERFLOW; + + if (count > RMI_MAX_ADDR_LIST - sro->addr_count) + return -ENOSPC; + + return 0; +} + +static int rmi_sro_donate_contig(struct rmi_sro_state *sro, + unsigned long sro_handle, + unsigned long donatereq, + struct arm_smccc_1_2_regs *out_regs, + gfp_t gfp) +{ + unsigned long unit_size =3D RMI_DONATE_SIZE(donatereq); + unsigned long unit_size_bytes =3D donate_req_to_size(donatereq); + unsigned long count =3D RMI_DONATE_COUNT(donatereq); + unsigned long state =3D RMI_DONATE_STATE(donatereq); + unsigned long size =3D unit_size_bytes * count; + unsigned long addr_range; + int ret; + void *virt; + phys_addr_t phys; + + /* + * The RMM specification requires contiguous allocations are always a + * power of 2 + */ + if (WARN_ON_ONCE(!is_power_of_2(size))) + return -EINVAL; + + for (int i =3D 0; i < sro->addr_count; i++) { + unsigned long entry =3D sro->addr_list[i]; + + if (RMI_ADDR_RANGE_SIZE(entry) =3D=3D unit_size && + RMI_ADDR_RANGE_COUNT(entry) =3D=3D count && + RMI_ADDR_RANGE_STATE(entry) =3D=3D state && + IS_ALIGNED(RMI_ADDR_RANGE_ADDR(entry), size)) { + sro->addr_count--; + swap(sro->addr_list[sro->addr_count], + sro->addr_list[i]); + + goto out; + } + } + + ret =3D rmi_sro_ensure_capacity(sro, 1); + if (ret) + return ret; + + virt =3D alloc_pages_exact(size, gfp); + if (!virt) + return -ENOMEM; + phys =3D virt_to_phys(virt); + + if (state =3D=3D RMI_OP_MEM_DELEGATED) { + phys_addr_t delegated_phys; + + if (rmi_delegate_range(phys, size, &delegated_phys)) { + if (!rmi_undelegate_range(phys, delegated_phys - phys)) + free_pages_exact(virt, size); + return -ENXIO; + } + } + + addr_range =3D phys & RMI_ADDR_RANGE_ADDR_MASK; + FIELD_MODIFY(RMI_ADDR_RANGE_SIZE_MASK, &addr_range, unit_size); + FIELD_MODIFY(RMI_ADDR_RANGE_COUNT_MASK, &addr_range, count); + FIELD_MODIFY(RMI_ADDR_RANGE_STATE_MASK, &addr_range, state); + + sro->addr_list[sro->addr_count] =3D addr_range; + +out: + rmi_op_mem_donate(sro_handle, + virt_to_phys(&sro->addr_list[sro->addr_count]), 1, + 0, out_regs); + + unsigned long donated_granules =3D out_regs->a1; + unsigned long donated_size =3D donated_granules << PAGE_SHIFT; + + if (donated_granules =3D=3D 0) { + /* No pages used by the RMM */ + sro->addr_count++; + } else if (donated_size < size) { + phys =3D sro->addr_list[sro->addr_count] & RMI_ADDR_RANGE_ADDR_MASK; + + /* Not all granules used by the RMM, free the remaining pages */ + for (long i =3D donated_size; i < size; i +=3D PAGE_SIZE) { + if (state =3D=3D RMI_OP_MEM_DELEGATED) + free_delegated_page(phys + i); + else + __free_page(phys_to_page(phys + i)); + } + } + + return 0; +} + +static int rmi_sro_donate_noncontig(struct rmi_sro_state *sro, + unsigned long sro_handle, + unsigned long donatereq, + struct arm_smccc_1_2_regs *out_regs, + gfp_t gfp) +{ + unsigned long unit_size =3D RMI_DONATE_SIZE(donatereq); + unsigned long unit_size_bytes =3D donate_req_to_size(donatereq); + unsigned long count =3D RMI_DONATE_COUNT(donatereq); + unsigned long state =3D RMI_DONATE_STATE(donatereq); + unsigned long found =3D 0; + unsigned long addr_list_start =3D sro->addr_count; + int ret; + + for (int i =3D 0; i < addr_list_start && found < count; i++) { + unsigned long entry =3D sro->addr_list[i]; + + if (RMI_ADDR_RANGE_SIZE(entry) =3D=3D unit_size && + RMI_ADDR_RANGE_COUNT(entry) =3D=3D 1 && + RMI_ADDR_RANGE_STATE(entry) =3D=3D state) { + addr_list_start--; + swap(sro->addr_list[addr_list_start], + sro->addr_list[i]); + found++; + i--; + } + } + + ret =3D rmi_sro_ensure_capacity(sro, count - found); + if (ret) + return ret; + + while (found < count) { + unsigned long addr_range; + void *virt =3D alloc_pages_exact(unit_size_bytes, gfp); + phys_addr_t phys; + + if (!virt) + return -ENOMEM; + + phys =3D virt_to_phys(virt); + + if (state =3D=3D RMI_OP_MEM_DELEGATED) { + phys_addr_t delegated_phys; + + if (rmi_delegate_range(phys, unit_size_bytes, + &delegated_phys)) { + if (!rmi_undelegate_range(phys, delegated_phys - phys)) + free_pages_exact(virt, unit_size_bytes); + return -ENXIO; + } + } + + addr_range =3D phys & RMI_ADDR_RANGE_ADDR_MASK; + FIELD_MODIFY(RMI_ADDR_RANGE_SIZE_MASK, &addr_range, unit_size); + FIELD_MODIFY(RMI_ADDR_RANGE_COUNT_MASK, &addr_range, 1); + FIELD_MODIFY(RMI_ADDR_RANGE_STATE_MASK, &addr_range, state); + + sro->addr_list[sro->addr_count++] =3D addr_range; + found++; + } + + rmi_op_mem_donate(sro_handle, + virt_to_phys(&sro->addr_list[addr_list_start]), + found, 0, out_regs); + + unsigned long donated_granules =3D out_regs->a1; + unsigned long granules_per_unit =3D unit_size_bytes >> PAGE_SHIFT; + unsigned long consumed_units; + + /* + * The RMM shouldn't report more granules than we provided, but clamp + * just in case. + */ + if (WARN_ON_ONCE(donated_granules > found * granules_per_unit)) + donated_granules =3D found * granules_per_unit; + + /* + * The RMM reports the consumed memory in terms of granules, but we + * track in the address lists in unit-sized ranges. So divide to get + * the number of (complete) consumed units. + */ + consumed_units =3D donated_granules / granules_per_unit; + if (donated_granules % granules_per_unit) { + /* + * A unit has been partially consumed, the start is owned by + * the RMM, the tail is owned by the host + */ + unsigned long entry =3D + sro->addr_list[addr_list_start + consumed_units]; + phys_addr_t phys =3D RMI_ADDR_RANGE_ADDR(entry); + unsigned long donated_size =3D + (donated_granules % granules_per_unit) << PAGE_SHIFT; + + /* Free the tail back */ + for (unsigned long i =3D donated_size; i < unit_size_bytes; + i +=3D PAGE_SIZE) { + if (state =3D=3D RMI_OP_MEM_DELEGATED) + free_delegated_page(phys + i); + else + __free_page(phys_to_page(phys + i)); + } + + /* + * This unit is now fully 'consumed' (either held by the RMM or + * freed) + */ + consumed_units++; + } + + /* Keep just the units the RMM didn't use in addr_list */ + for (unsigned long i =3D consumed_units; i < found; i++) + sro->addr_list[addr_list_start + i - consumed_units] =3D + sro->addr_list[addr_list_start + i]; + + sro->addr_count -=3D consumed_units; + + return 0; +} + +static int rmi_sro_donate(struct rmi_sro_state *sro, + unsigned long sro_handle, + unsigned long donatereq, + struct arm_smccc_1_2_regs *regs, + gfp_t gfp) +{ + if (WARN_ON_ONCE(!RMI_DONATE_COUNT(donatereq))) + return -EINVAL; + + if (RMI_DONATE_CONTIG(donatereq)) { + return rmi_sro_donate_contig(sro, sro_handle, donatereq, + regs, gfp); + } else { + return rmi_sro_donate_noncontig(sro, sro_handle, donatereq, + regs, gfp); + } +} + +static int rmi_sro_reclaim(struct rmi_sro_state *sro, + unsigned long sro_handle, + struct arm_smccc_1_2_regs *out_regs) +{ + unsigned long capacity; + int ret; + + ret =3D rmi_sro_ensure_capacity(sro, 1); + if (ret) + rmi_sro_free(sro); + + capacity =3D RMI_MAX_ADDR_LIST - sro->addr_count; + + rmi_op_mem_reclaim(sro_handle, + virt_to_phys(&sro->addr_list[sro->addr_count]), + capacity, out_regs); + + if (WARN_ON_ONCE(out_regs->a1 > capacity)) + out_regs->a1 =3D capacity; + + sro->addr_count +=3D out_regs->a1; + + return 0; +} + +void rmi_sro_free(struct rmi_sro_state *sro) +{ + for (int i =3D 0; i < sro->addr_count; i++) { + unsigned long entry =3D sro->addr_list[i]; + unsigned long addr =3D RMI_ADDR_RANGE_ADDR(entry); + unsigned long unit_size =3D RMI_ADDR_RANGE_SIZE(entry); + unsigned long count =3D RMI_ADDR_RANGE_COUNT(entry); + unsigned long state =3D RMI_ADDR_RANGE_STATE(entry); + unsigned long size =3D donate_req_to_size(unit_size) * count; + + if (state =3D=3D RMI_OP_MEM_DELEGATED) { + if (WARN_ON_ONCE(rmi_undelegate_range(addr, size))) { + /* Leak the pages */ + continue; + } + } + free_pages_exact(phys_to_virt(addr), size); + } + + sro->addr_count =3D 0; +} +EXPORT_SYMBOL_GPL(rmi_sro_free); + +long rmi_sro_memxfer_execute(struct rmi_sro_state *sro, gfp_t gfp) +{ + unsigned long sro_handle; + struct arm_smccc_1_2_regs *regs =3D &sro->regs; + bool cancelled =3D false; + + rmi_smccc_invoke(regs, regs); + + sro_handle =3D regs->a1; + + while (RMI_RETURN_STATUS(regs->a0) =3D=3D RMI_INCOMPLETE) { + bool can_cancel =3D RMI_RETURN_CAN_CANCEL(regs->a0); + int ret =3D 0; + + switch (RMI_RETURN_MEMREQ(regs->a0)) { + case RMI_OP_MEM_REQ_NONE: + rmi_op_continue(sro_handle, RMI_CONTINUE_KEEP_GOING, + regs); + break; + case RMI_OP_MEM_REQ_DONATE: + ret =3D rmi_sro_donate(sro, sro_handle, regs->a2, regs, + gfp); + break; + case RMI_OP_MEM_REQ_RECLAIM: + ret =3D rmi_sro_reclaim(sro, sro_handle, regs); + break; + default: + ret =3D WARN_ON_ONCE(1); + break; + } + + if (ret) { + /* + * All memory donating SROs must be cancellable. So a + * failure in memory allocation shouldn't be an issue. + * However, if we encounter a random failure (e.g., + * buggy RMM), don't loop forever, just give up. + */ + if (WARN_ON_ONCE(!can_cancel)) + return ret; + + rmi_op_cancel(sro_handle, regs); + cancelled =3D true; + + if (WARN_ON_ONCE(RMI_RETURN_STATUS(regs->a0) !=3D RMI_INCOMPLETE)) + return ret; + } + } + + if (cancelled) + return -ECANCELED; + + return regs->a0; +} +EXPORT_SYMBOL_GPL(rmi_sro_memxfer_execute); + +/* For RMI commands that are stateful but not memory-transferring */ +long rmi_sro_execute(struct arm_smccc_1_2_regs *regs) +{ + unsigned long sro_handle; + bool cancelled =3D false; + + rmi_smccc_invoke(regs, regs); + + sro_handle =3D regs->a1; + + while (RMI_RETURN_STATUS(regs->a0) =3D=3D RMI_INCOMPLETE) { + bool can_cancel =3D RMI_RETURN_CAN_CANCEL(regs->a0); + + switch (RMI_RETURN_MEMREQ(regs->a0)) { + case RMI_OP_MEM_REQ_NONE: + rmi_op_continue(sro_handle, RMI_CONTINUE_KEEP_GOING, + regs); + break; + default: + WARN_ON_ONCE(1); + if (!can_cancel) + return regs->a0; + + cancelled =3D true; + rmi_op_cancel(sro_handle, regs); + } + } + + if (cancelled) + return -ECANCELED; + + return regs->a0; +} +EXPORT_SYMBOL_GPL(rmi_sro_execute); + static int rmi_check_version(void) { struct arm_smccc_res res; diff --git a/include/linux/arm-rmi-cmds.h b/include/linux/arm-rmi-cmds.h index 9aa27697e2377..fed0f3421895d 100644 --- a/include/linux/arm-rmi-cmds.h +++ b/include/linux/arm-rmi-cmds.h @@ -10,8 +10,43 @@ #include #include =20 +#define RMI_MAX_ADDR_LIST 256 + +struct rmi_sro_state { + struct arm_smccc_1_2_regs regs; + unsigned long addr_count; + unsigned long addr_list[RMI_MAX_ADDR_LIST]; +}; + unsigned long rmi_feat_reg(unsigned long id); =20 +int rmi_delegate_range(phys_addr_t phys, unsigned long size, + phys_addr_t *out_phys); +int rmi_undelegate_range(phys_addr_t phys, unsigned long size); +int free_delegated_page(phys_addr_t phys); + +static inline int rmi_delegate_page(phys_addr_t phys) +{ + return rmi_delegate_range(phys, PAGE_SIZE, NULL); +} + +static inline int rmi_undelegate_page(phys_addr_t phys) +{ + return rmi_undelegate_range(phys, PAGE_SIZE); +} + +long rmi_sro_memxfer_execute(struct rmi_sro_state *sro, gfp_t gfp); +void rmi_sro_free(struct rmi_sro_state *sro); +long rmi_sro_execute(struct arm_smccc_1_2_regs *regs); + +#define rmi_sro_memxfer_cmd(sro, gfp, ...) ({ \ + struct rmi_sro_state *__sro =3D (sro); \ + *__sro =3D (struct rmi_sro_state){ .regs =3D {__VA_ARGS__} }; \ + long __ret =3D rmi_sro_memxfer_execute(__sro, gfp); \ + rmi_sro_free(__sro); \ + __ret; \ +}) + /** * rmi_rmm_config_set() - Configure the RMM * @cfg_ptr: PA of a struct rmm_config @@ -48,4 +83,57 @@ static inline int rmi_features(unsigned long index, unsi= gned long *out) return res.a0; } =20 +/** + * rmi_granule_range_delegate() - Delegate granules + * @base: PA of the first granule of the range + * @top: PA of the first granule after the range + * @out_top: PA of the first granule not delegated + * + * Delegate a range of granule for use by the realm world. If the entire r= ange + * was delegated then @out_top =3D=3D @top, otherwise the function should = be called + * again with @base =3D=3D @out_top. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_granule_range_delegate(unsigned long base, + unsigned long top, + unsigned long *out_top) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_GRANULE_RANGE_DELEGATE, base, top + }; + long ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS && out_top) + *out_top =3D regs.a1; + + return ret; +} + +/** + * rmi_granule_range_undelegate() - Undelegate a range of granules + * @base: Base PA of the target range + * @top: Top PA of the target range + * @out_top: Returns the top PA of range whose state is undelegated + * + * Undelegate a range of granules to allow use by the normal world. Will f= ail if + * the granules are in use. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_granule_range_undelegate(unsigned long base, + unsigned long top, + unsigned long *out_top) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_GRANULE_RANGE_UNDELEGATE, base, top + }; + long ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS && out_top) + *out_top =3D regs.a1; + + return ret; +} + #endif --=20 2.43.0 From nobody Fri Sep 25 23:51:08 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E21D046A604; Mon, 7 Sep 2026 10:00:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775216; cv=none; b=oQ05wn4yBSS7P4IbrruVsMxUHxp3hDyueXQNyrfvcmbpUJSqpZ41KJ9fCvO57i2Hj8qihBv7UmfQstnEUA97R/fEnC8kEhkGTO0a1lzkHRzdckgroUEg2zP+zW06EvXRYHKMM9Hgz9T1MaxGrKjbcGiCWwE2S7X9eWR4PqRbavc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775216; c=relaxed/simple; bh=3REQ5jWF12CkaqiVLtnquClwniilkFTh6i4V9X/W8Gs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NSgfLDrPxR9LeECGIBhISVbLRBwCv+a6jf7juqlBqO9F9uTZ1ImwlgDKAwA4TK3HQqcBljFhN2W+v3KTdDEpkDw+TWq5pOD8CovISBvPZXx1t7aBTDDOyIT6gmz1WIA/VFN7PZsaW+1M+und84pq7paFAUkx3HdFLsRypM7ewKQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=o0NNnupV; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="o0NNnupV" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 915ED1476; Mon, 7 Sep 2026 03:00:10 -0700 (PDT) Received: from ewhatever.cambridge.arm.com (ewhatever.cambridge.arm.com [10.2.197.99]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 805B03F7B4; Mon, 7 Sep 2026 03:00:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1788775214; bh=3REQ5jWF12CkaqiVLtnquClwniilkFTh6i4V9X/W8Gs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=o0NNnupVWVetQC/vx9RJ9UwpkUGwpzRnsMh/ZRIvgHt+mOk9nl819dKIE+ZvGQhUy BQply/fsvQkQWNz+OxKAzFYILQkAcFFFc62hn3afjNrGmhfiyPdqPrmw4a1knt1Oo8 +EeUQ0bCZdi67lxEO0ZhxGXTqxCelNU1w59Qv6Js= From: Suzuki K Poulose To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: maz@kernel.org, will@kernel.org, catalin.marinas@arm.com, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, steven.price@arm.com, aneesh.kumar@kernel.org, oupton@kernel.org, gshan@redhat.com, joey.gouly@arm.com, tabba@google.com, yuzenghui@huawei.com, linux-coco@lists.linux.dev, gankulkarni@os.amperecomputing.com, sdonthineni@nvidia.com, alpergun@google.com, fj0570is@fujitsu.com, WeiLin.Chang@arm.com, lpieralisi@kernel.org, enju.kohei@fujitsu.com, Suzuki K Poulose Subject: [PATCH v17 5/7] firmware: arm_rmm: Activate the RMM Date: Mon, 7 Sep 2026 10:59:39 +0100 Message-ID: <20260907095942.1140734-6-suzuki.poulose@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260907095942.1140734-1-suzuki.poulose@arm.com> References: <20260907095942.1140734-1-suzuki.poulose@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Steven Price Activate the RMM after the basic configuration. This is a memory transferri= ng, stateful operation. Signed-off-by: Steven Price Signed-off-by: Suzuki K Poulose --- Changes since v16: * Split into a new patch --- drivers/firmware/arm_rmm/rmi.c | 17 +++++++++++++++-- include/linux/arm-rmi-cmds.h | 11 +++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/arm_rmm/rmi.c b/drivers/firmware/arm_rmm/rmi.c index 42c973c3a98bb..d969c8738efde 100644 --- a/drivers/firmware/arm_rmm/rmi.c +++ b/drivers/firmware/arm_rmm/rmi.c @@ -641,7 +641,8 @@ static int rmi_configure(void) =20 static int __init arm64_init_rmi(void) { - int ret; + int ret =3D 0; + struct rmi_sro_state *sro =3D NULL; =20 /* Continue without realm support if we can't agree on a version */ ret =3D rmi_check_version(); @@ -656,7 +657,19 @@ static int __init arm64_init_rmi(void) if (ret) return ret; =20 - return 0; + /* Activate the RMM */ + sro =3D kmalloc_obj(*sro); + if (!sro) + return -ENOMEM; + + ret =3D rmi_rmm_activate(sro); + if (ret) { + pr_err("RMM activate failed\n"); + ret =3D ret < 0 ? ret : -ENXIO; + } + + kfree(sro); + return ret; } =20 /* diff --git a/include/linux/arm-rmi-cmds.h b/include/linux/arm-rmi-cmds.h index fed0f3421895d..dea7c7004d35f 100644 --- a/include/linux/arm-rmi-cmds.h +++ b/include/linux/arm-rmi-cmds.h @@ -64,6 +64,17 @@ static inline int rmi_rmm_config_set(unsigned long cfg_p= tr) return res.a0; } =20 +/** + * rmi_rmm_activate() - Activate the RMM + * @sro: Preallocated SRO context to be used + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rmm_activate(struct rmi_sro_state *sro) +{ + return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, SMC_RMI_RMM_ACTIVATE); +} + /** * rmi_features() - Read feature register * @index: Feature register index --=20 2.43.0 From nobody Fri Sep 25 23:51:08 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 109B1459AE0; Mon, 7 Sep 2026 10:00:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775220; cv=none; b=IBFDjsHNlwkyLEt6X93QmfwME/KHdUxohDfZcDY1vtvbv0ShAU8yCksleHCNpTcgNQp+xKD2gdZYm3D1w2Fa+o0nl0jzLb6or8oiMfT3+EOhHuZ42QRMGORNJ6FMLSOZ0SSs2/dgbHABeQNcz3+gRr0gOnunYtRMaGOmHN7pmxE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775220; c=relaxed/simple; bh=OUCQPMUJW7TTVGc7oNgwJqrfut6BVN3OsAInh6zFCiM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TbgkEFMA6fnlVPMsi4TYPjbdt7cGdIPfUg1qWrMjXwjoG386oTNYnWiC+mie3IxS3D1i+jvo7vwtJ3WjLnI00MCBGLoiRBDMZAFch6CGc0Zo6nWXXOcAGBhT7+DSy1AI2g4+8rCUvEeJ5A6MlQTdY/hsKw+GXnLJq5O/7IzsfPs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=f3TBSzIh; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="f3TBSzIh" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A32C21477; Mon, 7 Sep 2026 03:00:13 -0700 (PDT) Received: from ewhatever.cambridge.arm.com (ewhatever.cambridge.arm.com [10.2.197.99]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 923163F7B4; Mon, 7 Sep 2026 03:00:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1788775217; bh=OUCQPMUJW7TTVGc7oNgwJqrfut6BVN3OsAInh6zFCiM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=f3TBSzIhoKYuzOfTmmv5k7h07N7/pP7rqN+M027hcqlR8QjPvMdDnXVuZfAs9LjpF OV92sUGUmAMPlZisdW09YBIhLu9oGsksDOdSq0m0aAH2zU43SuA6xkPOm4r09w0q6b vhspVXMia33PeRUSnU57NxnHeaArjU7tZWS7mgn8= From: Suzuki K Poulose To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: maz@kernel.org, will@kernel.org, catalin.marinas@arm.com, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, steven.price@arm.com, aneesh.kumar@kernel.org, oupton@kernel.org, gshan@redhat.com, joey.gouly@arm.com, tabba@google.com, yuzenghui@huawei.com, linux-coco@lists.linux.dev, gankulkarni@os.amperecomputing.com, sdonthineni@nvidia.com, alpergun@google.com, fj0570is@fujitsu.com, WeiLin.Chang@arm.com, lpieralisi@kernel.org, enju.kohei@fujitsu.com, Suzuki K Poulose Subject: [PATCH v17 6/7] firmware: arm_rmm: Ensure the RMM has GPT entries for memory Date: Mon, 7 Sep 2026 10:59:40 +0100 Message-ID: <20260907095942.1140734-7-suzuki.poulose@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260907095942.1140734-1-suzuki.poulose@arm.com> References: <20260907095942.1140734-1-suzuki.poulose@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Steven Price The RMM maintains the state of all the granules in the system to make sure that the host is abiding by the rules. This state can be maintained at different granularity, per page (TRACKING_FINE) or per region (TRACKING_COARSE or TRACKING_INTERMEDIATE). The region size depends on the underlying "RMI_GRANULE_SIZE". For a "coarse"/"intermediate" region, all pa= ges in the region must be of the same state, this implies we need to have "fine" tracking for DRAM, so that we can delegate individual pages. For now we only support a statically carved out memory for tracking granules for the "fine" regions. This can be extended in the future to allow modifying the tracking granularity and remove the need for a static allocation by the firmware. Similarly, the firmware may create L0 GPT entries describing the total address space. But if we change the "PAS" (Physical Address Space) of a granule, then the firmware may need to create L1 tables to track the PAS at a finer granularity. Linux therefore checks if the platform firmware man= ages the PAR region. i.e., the firmware is in charge of managing the L1 GPTs (creation and the required memory for the GPT tables - via static carveouts) without host intervention. Support for dynamic GPT creation by the host wil= l be added later. If the firmware requires us to manage the tracking or GPT memory, Deactivate the RMM and reclaim any memory donated at RMM activation. Apply the same checks when hotplugged memory is brought online. Signed-off-by: Steven Price [ Switch to RMI_GPT_L1_INFO for checking GPTs and deactivate RMM ] Co-Developed-by: Suzuki K Poulose Signed-off-by: Suzuki K Poulose --- Changes since v16: * Check fine tracking and create L1 GPTs for hotplug-added memory. * Clarify the L1 GPT setup and move the explanatory comment. * Switch to using RMI_GPT_INFO command for checking the GPTs. * Deactivate the RMM and reclaim the memory if we can't proceed. Changes since v15: * Skip firmware-reserved NOMAP memory in rmi_init_metadata() * Handle negative error codes from wrappers. Changes since v14: * Move the implementation into drivers/firmware/arm_rmm. Changes since v13: * Moved out of KVM --- drivers/firmware/arm_rmm/rmi.c | 139 +++++++++++++++++++++++++++++++++ include/linux/arm-rmi-cmds.h | 75 ++++++++++++++++++ 2 files changed, 214 insertions(+) diff --git a/drivers/firmware/arm_rmm/rmi.c b/drivers/firmware/arm_rmm/rmi.c index d969c8738efde..34058e34188d3 100644 --- a/drivers/firmware/arm_rmm/rmi.c +++ b/drivers/firmware/arm_rmm/rmi.c @@ -5,6 +5,7 @@ =20 #include #include +#include #include #include #include @@ -12,6 +13,8 @@ #include #include =20 +static bool arm64_rmi_is_available; + /* Currently only the first 2 registers are used by Linux */ #define RMI_FEAT_REG_COUNT 2 static __ro_after_init unsigned long rmi_feat_reg_cache[RMI_FEAT_REG_COUNT= ]; @@ -639,6 +642,124 @@ static int rmi_configure(void) return ret; } =20 +/* + * Make sure the area is tracked by RMM at FINE granularity. + * We do not support changing the tracking yet. + */ +static int rmi_verify_memory_tracking(phys_addr_t start, phys_addr_t end) +{ + while (start < end) { + unsigned long ret, category, state, next; + + ret =3D rmi_granule_tracking_get(start, end, &category, &state, &next); + if (ret !=3D RMI_SUCCESS) + return -ENOMEM; + + if (state !=3D RMI_TRACKING_FINE || + category !=3D RMI_MEM_CATEGORY_CONVENTIONAL) { + /* TODO: Set granule tracking in this case */ + pr_err("Granule tracking for region isn't fine/conventional: %llx-%lx\n= ", + start, next); + return -ENODEV; + } + start =3D next; + } + + return 0; +} + +/* + * We do not support creating L1 GPTs yet. So, make sure that + * all the regions are managed by the firmware. + */ +static int rmi_verify_gpt_firmware_managed(phys_addr_t start, phys_addr_t = end) +{ + unsigned long l0gpt_sz; + unsigned long next, par_state; + + l0gpt_sz =3D 1UL << (30 + FIELD_GET(RMI_FEATURE_REGISTER_1_L0GPTSZ, + rmi_feat_reg(1))); + start =3D ALIGN_DOWN(start, l0gpt_sz); + end =3D ALIGN(end, l0gpt_sz); + + while (start < end) { + long ret =3D rmi_gpt_info(start, end, &next, &par_state); + + if (ret !=3D RMI_SUCCESS) + return -ENOMEM; + + if (par_state !=3D RMI_GPT_PAR_PLAT) { + pr_err("GPT for the region is not managed by firmware %llx-%lx\n", + start, next); + return -ENOMEM; + } + start =3D next; + } + + return 0; +} + +static int rmi_prepare_memory(phys_addr_t start, phys_addr_t end) +{ + int ret; + + ret =3D rmi_verify_memory_tracking(start, end); + if (ret) + return ret; + + return rmi_verify_gpt_firmware_managed(start, end); +} + +static int rmi_init_metadata(void) +{ + phys_addr_t start, end; + struct memblock_region *r; + + for_each_mem_region(r) { + int ret; + + /* Firmware-reserved NOMAP regions are not usable system RAM */ + if (memblock_is_nomap(r)) + continue; + + start =3D memblock_region_memory_base_pfn(r) << PAGE_SHIFT; + end =3D memblock_region_memory_end_pfn(r) << PAGE_SHIFT; + + ret =3D rmi_prepare_memory(start, end); + if (ret) + return ret; + } + + return 0; +} + +static int rmi_memory_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct memory_notify *arg =3D data; + phys_addr_t start, end; + int ret; + + if (action !=3D MEM_GOING_ONLINE) + return NOTIFY_DONE; + + start =3D PFN_PHYS(arg->start_pfn); + end =3D PFN_PHYS(arg->start_pfn + arg->nr_pages); + ret =3D rmi_prepare_memory(start, end); + + return notifier_from_errno(ret); +} + +static struct notifier_block rmi_memory_nb =3D { + .notifier_call =3D rmi_memory_notifier, +}; + +bool is_rmi_available(void) +{ + return arm64_rmi_is_available; +} +EXPORT_SYMBOL_GPL(is_rmi_available); + static int __init arm64_init_rmi(void) { int ret =3D 0; @@ -666,8 +787,26 @@ static int __init arm64_init_rmi(void) if (ret) { pr_err("RMM activate failed\n"); ret =3D ret < 0 ? ret : -ENXIO; + goto out_free_sro; } =20 + ret =3D rmi_init_metadata(); + if (ret) + goto out_deactivate; + + ret =3D register_memory_notifier(&rmi_memory_nb); + if (ret) + goto out_deactivate; + + arm64_rmi_is_available =3D true; + pr_info("RMI configured\n"); + kfree(sro); + + return 0; + +out_deactivate: + rmi_rmm_deactivate(sro); +out_free_sro: kfree(sro); return ret; } diff --git a/include/linux/arm-rmi-cmds.h b/include/linux/arm-rmi-cmds.h index dea7c7004d35f..79e2c1f165112 100644 --- a/include/linux/arm-rmi-cmds.h +++ b/include/linux/arm-rmi-cmds.h @@ -35,6 +35,8 @@ static inline int rmi_undelegate_page(phys_addr_t phys) return rmi_undelegate_range(phys, PAGE_SIZE); } =20 +bool is_rmi_available(void); + long rmi_sro_memxfer_execute(struct rmi_sro_state *sro, gfp_t gfp); void rmi_sro_free(struct rmi_sro_state *sro); long rmi_sro_execute(struct arm_smccc_1_2_regs *regs); @@ -64,6 +66,19 @@ static inline int rmi_rmm_config_set(unsigned long cfg_p= tr) return res.a0; } =20 +/** + * rmi_rmm_deactivate() - Deactivate the RMM and reclaim any memory donate= d at + * rmi_rmm_activate() + * + * @sro: Preallocated SRO context to be used + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rmm_deactivate(struct rmi_sro_state *sro) +{ + return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, SMC_RMI_RMM_DEACTIVATE); +} + /** * rmi_rmm_activate() - Activate the RMM * @sro: Preallocated SRO context to be used @@ -75,6 +90,66 @@ static inline long rmi_rmm_activate(struct rmi_sro_state= *sro) return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, SMC_RMI_RMM_ACTIVATE); } =20 +/** + * rmi_granule_tracking_get() - Get configuration of a Granule tracking re= gion + * @start: Base PA of the tracking region + * @end: End of the PA region + * @out_category: Memory category + * @out_state: Tracking region state + * @out_top: Top of the memory region + * + * Return: RMI return code + */ +static inline int rmi_granule_tracking_get(unsigned long start, + unsigned long end, + unsigned long *out_category, + unsigned long *out_state, + unsigned long *out_top) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(SMC_RMI_GRANULE_TRACKING_GET, start, end, &res); + + if (res.a0 =3D=3D RMI_SUCCESS) { + if (out_category) + *out_category =3D res.a1; + if (out_state) + *out_state =3D res.a2; + if (out_top) + *out_top =3D res.a3; + } + + return res.a0; +} + +/* + * rmi_gpt_info - Query the GPT info for the given PAR. + * @base: Base of the physical address region + * @top: Top of the physical address region + * @out_top: Top of the phyiscal address region for which + * the GPT @out_gpt_par_state is valid + * @out_gpt_par_state: State of the GPT covered by [base, out_top) + */ +static inline long rmi_gpt_info(unsigned long base, unsigned long end, + unsigned long *out_top, + unsigned long *out_gpt_par_state) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_GPT_INFO, base, end, + }; + + long ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS) { + if (out_top) + *out_top =3D regs.a1; + if (out_gpt_par_state) + *out_gpt_par_state =3D regs.a2; + } + + return ret; +} + /** * rmi_features() - Read feature register * @index: Feature register index --=20 2.43.0 From nobody Fri Sep 25 23:51:08 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 33DC946D0AC; Mon, 7 Sep 2026 10:00:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775223; cv=none; b=JB+baecRrDhhwHgLVEPzEtMeyNzap0Rgwfo0TCnsaF3mO69HykeVsQtstWYsVkXk9934TJZW5jvTUM7cI3BEZ3LPy5dP5Sc1+sEDwRVCEewgNO9wjmRifZA7xw0ax15yIXUC728777xN0wUpE1QVt8kqN9Gw+CeHeMLS4zCGWtU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788775223; c=relaxed/simple; bh=Y4QX89Kcn05W76GumGdqUmJ8ztUjeh8UKnCPUSoyg34=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dPbdkf4MKz5AQXzYVn1aEUqBoYJTcOWEvuivxjgGXVvtOElo+4VTRX7suh/Usca/PoLzoK4mDAfjmNZaRcAlBt51WmDUA5T5+08YELL5hxUZdAtrDWU+jnSRoV1mA51IeIMjpeSqC7s/tPPuq5qwNZdQc/sP3efCz0DAbGM5crY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=tPr7Nd7z; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="tPr7Nd7z" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id B93B81476; Mon, 7 Sep 2026 03:00:16 -0700 (PDT) Received: from ewhatever.cambridge.arm.com (ewhatever.cambridge.arm.com [10.2.197.99]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id A44453F7B4; Mon, 7 Sep 2026 03:00:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1788775220; bh=Y4QX89Kcn05W76GumGdqUmJ8ztUjeh8UKnCPUSoyg34=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tPr7Nd7z9xlbACYVkZVCyxPzXPXsX8Rle+EXAwSj1ooluqtYkHGQCij1f4EFVTCg/ U6vbOqDgR3treYX/g6St7kDb/kYEwjr1zFLjh7HnUqK+FWVR/wi5Q0l05uWOD0YjA3 BSFYS4//g+TbiR3rLvlYE56C2uKBJpf6fNasn0TU= From: Suzuki K Poulose To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: maz@kernel.org, will@kernel.org, catalin.marinas@arm.com, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, steven.price@arm.com, aneesh.kumar@kernel.org, oupton@kernel.org, gshan@redhat.com, joey.gouly@arm.com, tabba@google.com, yuzenghui@huawei.com, linux-coco@lists.linux.dev, gankulkarni@os.amperecomputing.com, sdonthineni@nvidia.com, alpergun@google.com, fj0570is@fujitsu.com, WeiLin.Chang@arm.com, lpieralisi@kernel.org, enju.kohei@fujitsu.com, Suzuki K Poulose Subject: [PATCH v17 7/7] firmware: arm_rmm: Add wrappers for Realm related RMI commands Date: Mon, 7 Sep 2026 10:59:41 +0100 Message-ID: <20260907095942.1140734-8-suzuki.poulose@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260907095942.1140734-1-suzuki.poulose@arm.com> References: <20260907095942.1140734-1-suzuki.poulose@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Steven Price Introduce wrappers for the RMI functions needed for creating and managing realm guests. This will be used by the KVM to manage the Realms Signed-off-by: Steven Price Signed-off-by: Suzuki K Poulose --- Changes since v16: * Split into a separate patch and move away from arch/arm64 to include/linux/. * Also moved into the firmware_rmm series from the KVM CCA support. This is done in a hope to reduce the merge conflicts and make the KVM CCA upstreaming in independent parallel chunks --- include/linux/arm-rmi-cmds.h | 453 +++++++++++++++++++++++++++++++++++ 1 file changed, 453 insertions(+) diff --git a/include/linux/arm-rmi-cmds.h b/include/linux/arm-rmi-cmds.h index 79e2c1f165112..746257d77dd61 100644 --- a/include/linux/arm-rmi-cmds.h +++ b/include/linux/arm-rmi-cmds.h @@ -222,4 +222,457 @@ static inline long rmi_granule_range_undelegate(unsig= ned long base, return ret; } =20 +/** + * rmi_rtt_data_map_init() - Create a protected mapping with data contents + * @rd: PA of the RD + * @data: PA of the target granule + * @ipa: IPA at which the granule will be mapped in the guest + * @src: PA of the source granule + * @flags: RMI_MEASURE_CONTENT if the contents should be measured + * + * Create a mapping from Protected IPA space to conventional memory, copyi= ng + * contents from a Non-secure Granule provided by the caller. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rtt_data_map_init(unsigned long rd, unsigned long d= ata, + unsigned long ipa, unsigned long src, + unsigned long flags) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_RTT_DATA_MAP_INIT, rd, data, ipa, src, flags + }; + + return rmi_sro_execute(®s); +} + +/** + * rmi_rtt_data_map() - Create mappings in protected IPA with unknown cont= ents + * @rd: PA of the RD + * @base: Base of the target IPA range + * @top: Top of the target IPA range + * @flags: Flags + * @oaddr: Output address set descriptor + * @out_top: Top address of range which was processed. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rtt_data_map(unsigned long rd, + unsigned long base, + unsigned long top, + unsigned long flags, + unsigned long oaddr, + unsigned long *out_top) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_RTT_DATA_MAP, rd, base, top, flags, oaddr + }; + long ret; + + ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS && out_top) + *out_top =3D regs.a1; + + return ret; +} + +/** + * rmi_rtt_data_unmap() - Remove mappings to conventional memory + * @rd: PA of the RD for the target Realm + * @base: Base of the target IPA range + * @top: Top of the target IPA range + * @flags: Flags + * @oaddr: Output address set descriptor + * @out_top: Returns top IPA of range which has been unmapped + * @out_range: Output address range + * @out_count: Number of entries in output address list + * + * Removes mappings to convention memory with a target Protected IPA range. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rtt_data_unmap(unsigned long rd, + unsigned long base, + unsigned long top, + unsigned long flags, + unsigned long oaddr, + unsigned long *out_top, + unsigned long *out_range, + unsigned long *out_count) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_RTT_DATA_UNMAP, rd, base, top, flags, oaddr + }; + long ret; + + ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS) { + if (out_top) + *out_top =3D regs.a1; + if (out_range) + *out_range =3D regs.a2; + if (out_count) + *out_count =3D regs.a3; + } + + return ret; +} + +/** + * rmi_psci_complete() - Complete pending PSCI command + * @calling_rec: PA of the calling REC + * @status: Status of the PSCI request + * + * Completes a pending PSCI command. + * + * Return: RMI return code + */ +static inline long rmi_psci_complete(unsigned long calling_rec, + unsigned long status) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(SMC_RMI_PSCI_COMPLETE, calling_rec, status, &res); + + return res.a0; +} + +/** + * rmi_realm_activate() - Active a realm + * @rd: PA of the RD + * + * Mark a realm as Active signalling that creation is complete and allowing + * execution of the realm. + * + * Return: RMI return code + */ +static inline long rmi_realm_activate(unsigned long rd) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(SMC_RMI_REALM_ACTIVATE, rd, &res); + + return res.a0; +} + +/** + * rmi_realm_create() - Create a realm + * @rd: PA of the RD + * @params: PA of realm parameters + * @sro: Preallocated SRO context to be used + * + * Create a new realm using the given parameters. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_realm_create(unsigned long rd, unsigned long params, + struct rmi_sro_state *sro) +{ + return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, + SMC_RMI_REALM_CREATE, rd, params); +} + +/** + * rmi_realm_terminate() - Terminate a realm + * @rd: PA of the RD + * @sro: Preallocated SRO context to be used + * + * Terminates a realm, moving it into a ZOMBIE state + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_realm_terminate(unsigned long rd, + struct rmi_sro_state *sro) +{ + return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, + SMC_RMI_REALM_TERMINATE, rd); +} + +/** + * rmi_realm_destroy() - Destroy a realm + * @rd: PA of the RD + * @sro: Preallocated SRO context to be used + * + * Destroys a realm, all objects belonging to the realm must be destroyed = first. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_realm_destroy(unsigned long rd, + struct rmi_sro_state *sro) +{ + return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, + SMC_RMI_REALM_DESTROY, rd); +} + +/** + * rmi_rec_create() - Create a REC + * @rd: PA of the RD + * @rec: PA of the target REC + * @params: PA of REC parameters + * @sro: Allocated SRO context to be used + * + * Create a REC using the parameters specified in the struct rec_params po= inted + * to by @params. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rec_create(unsigned long rd, + unsigned long rec, + unsigned long params, + struct rmi_sro_state *sro) +{ + long ret; + + *sro =3D (struct rmi_sro_state){.regs =3D { + SMC_RMI_REC_CREATE, rd, rec, params + }}; + ret =3D rmi_sro_memxfer_execute(sro, GFP_KERNEL); + rmi_sro_free(sro); + + return ret; +} + +/** + * rmi_rec_destroy() - Destroy a REC + * @rec: PA of the target REC + * @sro: Allocated SRO context to be used + * + * Destroys a REC. The REC must not be running. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rec_destroy(unsigned long rec, + struct rmi_sro_state *sro) +{ + return rmi_sro_memxfer_cmd(sro, GFP_KERNEL, SMC_RMI_REC_DESTROY, rec); +} + +/** + * rmi_rec_enter() - Enter a REC + * @rec: PA of the target REC + * @run_ptr: PA of RecRun structure + * + * Starts (or continues) execution within a REC. + * + * Return: RMI return code + */ +static inline long rmi_rec_enter(unsigned long rec, unsigned long run_ptr) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(SMC_RMI_REC_ENTER, rec, run_ptr, &res); + + return res.a0; +} + +/** + * rmi_rtt_create() - Creates an RTT + * @rd: PA of the RD + * @rtt: PA of the target RTT + * @ipa: Base of the IPA range described by the RTT + * @level: Depth of the RTT within the tree + * + * Creates an RTT (Realm Translation Table) at the specified level for the + * translation of the specified address within the realm. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rtt_create(unsigned long rd, unsigned long rtt, + unsigned long ipa, long level) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_RTT_CREATE, rd, rtt, ipa, level + }; + + return rmi_sro_execute(®s); +} + +/** + * rmi_rtt_destroy() - Destroy an RTT + * @rd: PA of the RD for the target realm + * @ipa: Base of the IPA range described by the RTT + * @level: RTT level + * @out_rtt: Pointer to write the PA of the RTT which was destroyed + * @out_top: Pointer to write the top IPA of non-live RTT entries, from en= try + * at which the RTT walk terminated. + * + * Destroys an RTT. The RTT must be non-live, i.e. none of the entries in = the + * table are in ASSIGNED or TABLE state. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code. + */ +static inline long rmi_rtt_destroy(unsigned long rd, + unsigned long ipa, + long level, + unsigned long *out_rtt, + unsigned long *out_top) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_RTT_DESTROY, rd, ipa, level + }; + long ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS) { + if (out_rtt) + *out_rtt =3D regs.a1; + if (out_top) + *out_top =3D regs.a2; + } + + return ret; +} + +/** + * rmi_rtt_fold() - Fold an RTT + * @rd: PA of the RD + * @ipa: Base of the IPA range described by the RTT + * @level: Depth of the RTT within the tree + * @out_rtt: Pointer to write the PA of the RTT which was destroyed + * + * Folds an RTT. If all entries with the RTT are 'homogeneous' the RTT can= be + * folded into the parent and the RTT destroyed. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rtt_fold(unsigned long rd, unsigned long ipa, + long level, unsigned long *out_rtt) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_RTT_FOLD, rd, ipa, level + }; + long ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS && out_rtt) + *out_rtt =3D regs.a1; + + return ret; +} + +/** + * rmi_rtt_init_ripas() - Set RIPAS for new realm + * @rd: PA of the RD + * @base: Base of target IPA region + * @top: Top of target IPA region + * @out_top: Top IPA of range whose RIPAS was modified + * + * Sets the RIPAS of a target IPA range to RAM, for a realm in the NEW sta= te. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rtt_init_ripas(unsigned long rd, unsigned long base, + unsigned long top, unsigned long *out_top) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_RTT_INIT_RIPAS, rd, base, top + }; + long ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS && out_top) + *out_top =3D regs.a1; + + return ret; +} + +/** + * rmi_rtt_unprot_map() - Map unprotected granules into a realm + * @rd: PA of the RD + * @base: Base IPA of the mapping + * @top: Top of the target IPA range + * @flags: Flags + * @oaddr: Output address set descriptor + * @out_top: Top IPA of range which has been mapped + * + * Create mappings to memory within a target unprotected IPA range. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rtt_unprot_map(unsigned long rd, + unsigned long base, + unsigned long top, + unsigned long flags, + unsigned long oaddr, + unsigned long *out_top) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_RTT_UNPROT_MAP, rd, base, top, flags, oaddr + }; + long ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS && out_top) + *out_top =3D regs.a1; + + return ret; +} + +/** + * rmi_rtt_set_ripas() - Set RIPAS for an running realm + * @rd: PA of the RD + * @rec: PA of the REC making the request + * @base: Base of target IPA region + * @top: Top of target IPA region + * @out_top: Pointer to write top IPA of range whose RIPAS was modified + * + * Completes a request made by the realm to change the RIPAS of a target I= PA + * range. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rtt_set_ripas(unsigned long rd, unsigned long rec, + unsigned long base, unsigned long top, + unsigned long *out_top) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_RTT_SET_RIPAS, rd, rec, base, top + }; + long ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS && out_top) + *out_top =3D regs.a1; + + return ret; +} + +/** + * rmi_rtt_unprot_unmap() - Remove mappings within an unprotected IPA range + * @rd: PA of the RD + * @base: Base IPA of the mapping + * @top: Top of the target IPA range + * @flags: Flags + * @oaddr: Output address set descriptor + * @out_top: Top IPA which has been unmapped + * @out_range: Output address range + * @out_count: Number of entries in output address list + * + * Removes mappings to memory within a target unprotected IPA range. + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_rtt_unprot_unmap(unsigned long rd, + unsigned long base, + unsigned long top, + unsigned long flags, + unsigned long oaddr, + unsigned long *out_top, + unsigned long *out_range, + unsigned long *out_count) +{ + struct arm_smccc_1_2_regs regs =3D { + SMC_RMI_RTT_UNPROT_UNMAP, rd, base, top, flags, oaddr + }; + long ret =3D rmi_sro_execute(®s); + + if (ret =3D=3D RMI_SUCCESS) { + if (out_top) + *out_top =3D regs.a1; + if (out_range) + *out_range =3D regs.a2; + if (out_count) + *out_count =3D regs.a3; + } + + return ret; +} + #endif --=20 2.43.0