From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6AF2740EB89; Mon, 3 Aug 2026 13:44:24 +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=1785764666; cv=none; b=ExMlGkGnW6J+GRMYNMyFnuEpx4uSR5mVAIWKKTJ00rjrKe6HbUlnhrhfqwRURzSpHESs5kMJTBCixrw0SaXQyqDZMQSotZlNjsz+7EkXYMt8zHDlSPRacnBIujcSAf5UbAstFjppVs62SgZzuts5jDWd2ficbrK1C4H4TOyHT0Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764666; c=relaxed/simple; bh=9QMo47r6s9gLWBU6WhnPd1uuUOh3zK4SrXC9g2fL1bA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TyXbLIpsdfsWiXFAKyp+icjhDVFQkd54+Fk+cIAvHX21wde/LvojZc5M5GA6LyaS3cb8pdqZ+U1WTWcwiDLpYDOzyaO5KYshhpc8quzuZe8MePUKxt4e4UVEqtJXPFPURG34WbzCKAMguqtS1JZb4YxzZ2A75q/mnE7omfe3mNg= 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=mb7YCoAS; 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="mb7YCoAS" 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 A39751476; Mon, 3 Aug 2026 06:44:19 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9013D3F66F; Mon, 3 Aug 2026 06:44:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764663; bh=9QMo47r6s9gLWBU6WhnPd1uuUOh3zK4SrXC9g2fL1bA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mb7YCoASLbbwlZtLGg+BPlEh+dnDuHEE+GFJCO1Z3mgfM4szv8nBMIpE45XN7OHyQ 1s55AJNqEMfvA5Vukm8w4BbRTuiblbWUCS0ezzDVkE4ShUFeGHLEO6ws9AbiNuS4Ig wbYKtk3IvO0aS/kU6GzLsT72QxiAN3kXBxzytPNc= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 01/45] firmware: arm_rmm: Add SMC definitions for calling the RMM Date: Mon, 3 Aug 2026 14:43:17 +0100 Message-ID: <20260803134403.80630-2-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" 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-bet2 [1] https://developer.arm.com/documentation/den0137/2-0bet2/ Signed-off-by: Steven Price --- Changes since v15: * Dropped unused symbols REC_MAX_GIC_NUM_LRS and RMI_PERMITTED_GICV3_HCR_B= ITS. * 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 | 493 ++++++++++++++++++++++++++++++++++ 1 file changed, 493 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 000000000000..3dad7bb62ba1 --- /dev/null +++ b/include/linux/arm-smccc-rmi.h @@ -0,0 +1,493 @@ +/* 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-bet2: + * https://developer.arm.com/documentation/den0137/2-0bet2/ + */ + +#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_VDEV_P2P_BIND SMC_RMI_CALL(0x01d4) +#define SMC_RMI_VDEV_P2P_UNBIND SMC_RMI_CALL(0x01d5) +#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_CMEM_ADD_PDEV SMC_RMI_CALL(0x01e4) +#define SMC_RMI_CMEM_CREATE SMC_RMI_CALL(0x01e5) +#define SMC_RMI_CMEM_DESTROY SMC_RMI_CALL(0x01e6) +#define SMC_RMI_CMEM_POPULATE SMC_RMI_CALL(0x01e7) +#define SMC_RMI_CMEM_REMOVE_PDEV SMC_RMI_CALL(0x01e8) +#define SMC_RMI_CMEM_START SMC_RMI_CALL(0x01e9) +#define SMC_RMI_CMEM_STOP SMC_RMI_CALL(0x01ea) +#define SMC_RMI_CMEM_UNPOPULATE SMC_RMI_CALL(0x01eb) +#define SMC_RMI_RMM_CONFIG_GET SMC_RMI_CALL(0x01ec) +#define SMC_RMI_PDEV_MEC_REFRESH SMC_RMI_CALL(0x01ed) +#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 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 BIT(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_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 BIT(63) + +#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_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_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_P2P BIT(10) +#define RMI_FEATURE_REGISTER_2_CMEM_CXL BIT(11) +#define RMI_FEATURE_REGISTER_2_MAX_CMEM GENMASK(19, 12) +#define RMI_FEATURE_REGISTER_2_CMEM_TSE_REQ BIT(20) + +#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_TRACKING_RESERVED 0 +#define RMI_TRACKING_NONE 1 +#define RMI_TRACKING_FINE 2 +#define RMI_TRACKING_COARSE 3 + +#define RMI_GRANULE_SIZE_4KB 0 +#define RMI_GRANULE_SIZE_16KB 1 +#define RMI_GRANULE_SIZE_64KB 2 + +/* + * 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_LPA2 BIT(0) +#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; + }; + 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 +#define RMI_EXIT_VDEV_P2P_BINDING 0x0b + +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 Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8E30F4137A0; Mon, 3 Aug 2026 13:44:28 +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=1785764670; cv=none; b=Ss6FC9HH39WBFUyWwTyiCkdNiveT2SiVVOKzHhakoQfypfaFIg3aqq99A2pKTk89BweZ2+yLbfCMG7iMMd4GoGBhv1STQjMj2D6mHD+bPgErx/cgEDQfXSJzUGfusr3kx/PwbRfSpeQ/FBX1/vjjRJBohaCxtA5EbLtaFrGbJAQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764670; c=relaxed/simple; bh=tlsaj4m26Ey7o2A3mqrYe7pOBLDgXjDPJ5uCPqwZu6o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AeIfV8WV+Jr0pN85rGiYUOny2C4w8XEX1sHfAabOFOienUWv7gf6xe5J926xzPmYPrQRuS10tuYFhY/t6ytuIC5r5m9dxS8RwXPM4Spbb0umh61Qb1xIWpIUQeVd/WWnTxuBWjYd1fCJnQmS7DZdp0E7ZDMVnqnP3nf+Tkcy7v4= 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=bfwe9ljp; 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="bfwe9ljp" 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 DF7BA1595; Mon, 3 Aug 2026 06:44:23 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 1D43D3F66F; Mon, 3 Aug 2026 06:44:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764667; bh=tlsaj4m26Ey7o2A3mqrYe7pOBLDgXjDPJ5uCPqwZu6o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bfwe9ljphKHnk02i2bUdQNUSpa2cKpcBdHPsSm41T1SgYcGZl5gWJDf56A4T70vTx EjzpIsRCe1Yh4BZ6usPyGGOjKvwuzw4aVTweIk5KwWN4O6U5Fw5PD9h8JCYHvra8Be jy8oHnoSsJ+WNNB9DnDJoo9uZ3Qd1Z9c1vYM5DT4= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 02/45] firmware: arm_rmm: Add wrappers for direct RMI calls Date: Mon, 3 Aug 2026 14:43:18 +0100 Message-ID: <20260803134403.80630-3-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" The wrappers make the call sites easier to read and deal with the boilerplate of handling the error codes from the RMM. Signed-off-by: Steven Price --- Changes from v15: * Split out wrappers for realms to a separate commit. * Wrappers that have output arguments now only write the output when the command completes successfully. Changes from v14: * Update to RMM v2.0-bet2 spec. * Move SRO related wrappers to a later patch due to dependencies. * Common wrappers are split into include/linux/arm-rmi-cmds.h. Changes from v13: * Update to RMM v2.0-bet1 spec including some SRO support (there still some FIXMEs where SRO support is incomplete). Changes from v12: * Update to RMM v2.0 specification Changes from v8: * Switch from arm_smccc_1_2_smc() to arm_smccc_1_2_invoke() in rmi_rtt_read_entry() for consistency. Changes from v7: * Minor renaming of parameters and updated comments Changes from v5: * Further improve comments Changes from v4: * Improve comments Changes from v2: * Make output arguments optional. * Mask RIPAS value rmi_rtt_read_entry() * Drop unused rmi_rtt_get_phys() --- include/linux/arm-rmi-cmds.h | 83 ++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 include/linux/arm-rmi-cmds.h diff --git a/include/linux/arm-rmi-cmds.h b/include/linux/arm-rmi-cmds.h new file mode 100644 index 000000000000..5ee94da96e4a --- /dev/null +++ b/include/linux/arm-rmi-cmds.h @@ -0,0 +1,83 @@ +/* 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 + +#include + +/** + * 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_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_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 Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id EFFD141684D; Mon, 3 Aug 2026 13:44:32 +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=1785764674; cv=none; b=JKnjjrpbfaQHPxynXhTHYlezxDrwKXz64pSh7d03FJ7dHZUlCXTpd2P6Cg/2NWIn7MSqtn29eDPJn3WH/3VoA+LcqOvjpz+uJsFxVUJzMjcwtzBGb2qFaltnjErpwyedioEMwb5/4Zepm1L7YMaYYzfbQZRankQuu6dck7sE+cs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764674; c=relaxed/simple; bh=+YieMOk7OvKlR73r97xaxKE5U8IgmhAkbUHPiPHHxs8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EzdZCrVHYxGHW2FBk7CeDKFyb+mJtIPGt5FCEHaggyLojRxHhP2rpZPhsTgn53WvQzj+BEJMjH/22NIs+h5MfmA2KdbxVw5Dktp1zr9GKa9HWr+fA7iOhWRtUcedYP8vc37D75NZ9XWWUbj0WFFShwx5HVGXd7qyfw66wfm2Pyo= 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=rrQKJhF+; 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="rrQKJhF+" 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 3C83015A1; Mon, 3 Aug 2026 06:44:28 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 537423F66F; Mon, 3 Aug 2026 06:44:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764672; bh=+YieMOk7OvKlR73r97xaxKE5U8IgmhAkbUHPiPHHxs8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rrQKJhF+qvHYd7u4WVhFEIcs8ycvTdfz+xkIOa1wxL8mJ33hztGR7mWZi0hFTBcVp iSVK3VRV5oIADwlRJTBdd4q3ATBYjH8OsDl5adIqjL+2U2fVcg26obueNxBWPRiRe3 meZlnK2Bc3v8IXT3R3kD4OyKdOvH77JrW06UMPZs= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 03/45] firmware: arm_rmm: Check for RMI support at init Date: Mon, 3 Aug 2026 14:43:19 +0100 Message-ID: <20260803134403.80630-4-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" 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 --- 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 | 2 + 8 files changed, 135 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 diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b3afe0688919..0f1956edf130 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 9a22df0c5120..4ae63c89cda9 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 12dc70254842..55542879fbb8 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -301,5 +301,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 4ddec2820c96..07e8ca1789b4 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -38,3 +38,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 000000000000..6f154f7d55dc --- /dev/null +++ b/drivers/firmware/arm_rmm/Kconfig @@ -0,0 +1,26 @@ + +config ARCH_SUPPORTS_RMM + bool + +config ARM_RMM + bool "Realm Management Monitor (RMM) 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 000000000000..51aef5cc04b0 --- /dev/null +++ b/drivers/firmware/arm_rmm/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_ARM_RMM) =3D rmi.o diff --git a/drivers/firmware/arm_rmm/rmi.c b/drivers/firmware/arm_rmm/rmi.c new file mode 100644 index 000000000000..008a783407b4 --- /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 index 5ee94da96e4a..c97a70e771a6 100644 --- a/include/linux/arm-rmi-cmds.h +++ b/include/linux/arm-rmi-cmds.h @@ -12,6 +12,8 @@ =20 #include =20 +unsigned long rmi_feat_reg(unsigned long id); + /** * rmi_rmm_config_set() - Configure the RMM * @cfg_ptr: PA of a struct rmm_config --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 62C4F418A49; Mon, 3 Aug 2026 13:44:37 +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=1785764679; cv=none; b=S0LfkxkkwIdpVop/s43xosPBsKJ2VQroo4kLgHXqrdya1o3A5PtwrFUGX4hpb5UEMmqEAb3YIbpxX3DfBwJGqP2fwYiXKkSx6rDI2XxelrGmlQleieKOLHovdGT2aTYt+vIcVAnw83oXH3nxgnKFhBUQZCltMTJfVOFvNzzpH4U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764679; c=relaxed/simple; bh=a87dBoIo+abuHgtTSNKpMeJOicdZeUlF8rukrl520eU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ebpvBRB2sY5DuGATwF3gisW591U4QRHlU1222x9INk8R86FInYsBfHd8Qv3Tm5Jc6M1tXxEytyNdHpkKF7AptNF/VZ4SvWqu0533T7lbrg6yPY1l2MnhQFz5SpqX5ciSYefD09YECvx0wLzW+3dKEGNa4o6De3LVXM3hmMdsYsk= 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=pMyjQBeB; 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="pMyjQBeB" 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 BE762143D; Mon, 3 Aug 2026 06:44:32 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9965A3F66F; Mon, 3 Aug 2026 06:44:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764676; bh=a87dBoIo+abuHgtTSNKpMeJOicdZeUlF8rukrl520eU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pMyjQBeBYwoZSI0DbSR2aZTg1nQpOqpGBko74lcraMj2do/JBVxlHmi9zICxzM7de iZEcEpqEky0c+AANwK9eXvydVOl2QjP1Ndgt52P0yU90vYc0XiNtTXKBLkf/sijbYw qQ/ALa0hCmvxwZtXPBgCjnL7vQDdrWON0zgltEN8= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 04/45] firmware: arm_rmm: Configure the RMM with the host's page size Date: Mon, 3 Aug 2026 14:43:20 +0100 Message-ID: <20260803134403.80630-5-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" 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. Reviewed-by: Suzuki K Poulose Signed-off-by: Steven Price --- 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 | 61 ++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/firmware/arm_rmm/rmi.c b/drivers/firmware/arm_rmm/rmi.c index 008a783407b4..ff9f76cc199a 100644 --- a/drivers/firmware/arm_rmm/rmi.c +++ b/drivers/firmware/arm_rmm/rmi.c @@ -77,6 +77,63 @@ static int rmi_read_features(void) return 0; } =20 +static int rmi_configure(void) +{ + unsigned long granule_feature; + unsigned long granule_size; + long rmi_ret; + 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; + + rmi_ret =3D rmi_rmm_config_set(virt_to_phys(config)); + if (rmi_ret) { + pr_err("RMM config set failed\n"); + ret =3D -EINVAL; + goto out_free_config; + } + +out_free_config: + free_page((unsigned long)config); + return ret; +} + static int __init arm64_init_rmi(void) { int ret; @@ -90,6 +147,10 @@ static int __init arm64_init_rmi(void) if (ret) return ret; =20 + ret =3D rmi_configure(); + if (ret) + return ret; + return 0; } =20 --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BBCEC41A4E7; Mon, 3 Aug 2026 13:44:41 +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=1785764684; cv=none; b=SFroupC+t0mgauRuX5QqTvt0yZfsJLJvpMycOAPmNLybS4GoZ99Zx4vx+ak/sV2fMn7cDwEh9tOiVYBpzwtxHzOfIUBCOucLb41IUryvABuvMxTDuJb1nhLTNa1cDQHrMpKL5urV4DHmEhjlqhhWpPmGABjb/O5wgGnOtfhYrbg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764684; c=relaxed/simple; bh=Xvsfw9CIsFVjF4QcUEu5fS0HzgbbreGRSC+lOucrneY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=A3mNk0WxfvGNs3nkIXYxMYDP/5wud2r/4nitUVcI3xk1+92JpY7pnstRph98l4ph5K0FFX70mrUYNdx3O+mxtOfmNxq1dHg0Kt7KWyKm2qXKyEjZYDP1jiUuGKxL1Orsp6TNR7SDQd7ptaClCbTMoxa34587kIa1boxz+c5bUJs= 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=Srti61Lv; 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="Srti61Lv" 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 2EFD91596; Mon, 3 Aug 2026 06:44:37 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 36FFC3F66F; Mon, 3 Aug 2026 06:44:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764681; bh=Xvsfw9CIsFVjF4QcUEu5fS0HzgbbreGRSC+lOucrneY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Srti61LvdAFc+PtBeuLNfPoEKZIRW2w6iut8yhXNTqdrdn5RWz/gYN9rLrvo1sNpq 1pQSt5DXC+ZrqqI79B5aZPY6urp6UZzn1egQrJVodEiej6wSC2+w/Iyvjsjf5Y0zz7 jl2tsUVlbN/P69ZExBxscIZTlyhjrGnEQ8IyPpBA= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 05/45] firmware: arm_rmm: Add support for SRO Date: Mon, 3 Aug 2026 14:43:21 +0100 Message-ID: <20260803134403.80630-6-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" 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 --- 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 | 515 ++++++++++++++++++++++++++++++++- include/linux/arm-rmi-cmds.h | 114 ++++++++ 2 files changed, 628 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/arm_rmm/rmi.c b/drivers/firmware/arm_rmm/rmi.c index ff9f76cc199a..51ea661cecf9 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,502 @@ 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 + }; + + 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) { + if (can_cancel) { + 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; @@ -84,6 +581,7 @@ static int rmi_configure(void) long rmi_ret; int ret =3D 0; struct rmm_config *config; + struct rmi_sro_state *sro; =20 switch (PAGE_SIZE) { case SZ_4K: @@ -112,6 +610,12 @@ static int rmi_configure(void) if (!config) return -ENOMEM; =20 + sro =3D kmalloc_obj(*sro); + if (!sro) { + ret =3D -ENOMEM; + goto out_free_config; + } + config->rmi_granule_size =3D granule_size; =20 /* @@ -126,9 +630,18 @@ static int rmi_configure(void) if (rmi_ret) { pr_err("RMM config set failed\n"); ret =3D -EINVAL; - goto out_free_config; + goto out_free_sro; + } + + rmi_ret =3D rmi_rmm_activate(sro); + if (rmi_ret) { + pr_err("RMM activate failed\n"); + ret =3D rmi_ret < 0 ? rmi_ret : -ENXIO; + goto out_free_sro; } =20 +out_free_sro: + kfree(sro); out_free_config: free_page((unsigned long)config); return ret; diff --git a/include/linux/arm-rmi-cmds.h b/include/linux/arm-rmi-cmds.h index c97a70e771a6..8814708536d6 100644 --- a/include/linux/arm-rmi-cmds.h +++ b/include/linux/arm-rmi-cmds.h @@ -12,8 +12,43 @@ =20 #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 @@ -31,6 +66,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_granule_tracking_get() - Get configuration of a Granule tracking re= gion * @start: Base PA of the tracking region @@ -63,6 +109,21 @@ static inline int rmi_granule_tracking_get(unsigned lon= g start, return res.a0; } =20 +/** + * rmi_gpt_l1_create() - Create a Level 1 GPT + * @addr: Base of physical address region described by the L1GPT + * @sro: Preallocated SRO context to be used + * @gfp: Allocation flags for SRO memory donation requests + * + * Return: 0 on success, positive RMI result code or negative Linux error = code + */ +static inline long rmi_gpt_l1_create(unsigned long addr, + struct rmi_sro_state *sro, + gfp_t gfp) +{ + return rmi_sro_memxfer_cmd(sro, gfp, SMC_RMI_GPT_L1_CREATE, addr); +} + /** * rmi_features() - Read feature register * @index: Feature register index @@ -82,4 +143,57 @@ static inline int rmi_features(unsigned long index, uns= igned 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 Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 06C5E41A506; Mon, 3 Aug 2026 13:44:46 +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=1785764687; cv=none; b=l6RChCX2Ufp8Dr6yM8kkvgZKhqPnmgQCOCP8OXebtNukmXJ0oEwKHogtlMxbPjUh8FkdKEH7DKPmCGKLq8ADFNaySaguN0C5XIFSe9MAXumSlynwMQd0tModjaypnZ5uhvZBTmkm4guGPLPgnc7XIMcydIh7oCuMqqQQ4Jx4b/g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764687; c=relaxed/simple; bh=nPF/ZhgiMk9bT/ySrNjtkfhDkfa90yGsUJUy9W38zhU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=j5W84WHSxCEB/GWA39rm+Fx8O6gE6Rt5qeipApD3ptl2wtoCGKs3w7zSXmu1zel0/Uuj9X+htd11Rp0oUzTl3ATrDryHO9hgctyXkqOAe724YWWxdsT7QRfo4tG8BTV5kC3mKbmenIvqK91cBVJvHRVvxCBVm3QLOqp6xtjluys= 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=kR91DteK; 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="kR91DteK" 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 868881655; Mon, 3 Aug 2026 06:44:41 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 8BACD3F66F; Mon, 3 Aug 2026 06:44:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764685; bh=nPF/ZhgiMk9bT/ySrNjtkfhDkfa90yGsUJUy9W38zhU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kR91DteKvJS1LNtN2AMmFtMDm+A51cVL/ppCZeYK7/mdjFJv2m+5TobVw1Z9yXwjQ GZbo8CsDIXv7d6zikoia3JH8GOdV3eD+jeGocm1BEBBxQ8GMqv4TMo4qPFprunnUzT yPZK6e1y1RSQnmYc4y8JDF4fo/Oam5hPmpNn9X9Y= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 06/45] firmware: arm_rmm: Ensure the RMM has GPT entries for memory Date: Mon, 3 Aug 2026 14:43:22 +0100 Message-ID: <20260803134403.80630-7-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" 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). The region size depends on the underlying "RMI_GRANULE_SIZE". For a "coarse" region all pages 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. 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. Signed-off-by: Steven Price --- 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 | 101 +++++++++++++++++++++++++++++++++ include/linux/arm-rmi-cmds.h | 2 + 2 files changed, 103 insertions(+) diff --git a/drivers/firmware/arm_rmm/rmi.c b/drivers/firmware/arm_rmm/rmi.c index 51ea661cecf9..bce3304bbc1a 100644 --- a/drivers/firmware/arm_rmm/rmi.c +++ b/drivers/firmware/arm_rmm/rmi.c @@ -12,6 +12,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= ]; @@ -647,6 +649,98 @@ 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 || + 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\n", + start); + return -ENODEV; + } + start =3D next; + } + + return 0; +} + +static int rmi_create_gpts(phys_addr_t start, phys_addr_t end) +{ + struct rmi_sro_state *sro; + unsigned long l0gpt_sz; + + sro =3D kmalloc_obj(*sro, GFP_KERNEL); + if (!sro) + return -ENOMEM; + + 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_l1_create(start, sro, GFP_KERNEL); + + /* + * Make sure the L1 GPT tables are created for the region. + * RMI_ERROR_GPT indicates the L1 table already exists. + */ + if (ret < 0) { + kfree(sro); + return ret; + } + + if (ret !=3D RMI_SUCCESS && RMI_RETURN_STATUS(ret) !=3D RMI_ERROR_GPT) { + pr_err("GPT Level1 table missing for %llx\n", start); + kfree(sro); + return -ENOMEM; + } + start +=3D l0gpt_sz; + } + + kfree(sro); + return 0; +} + +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_verify_memory_tracking(start, end); + if (ret) + return ret; + ret =3D rmi_create_gpts(start, end); + if (ret) + return ret; + } + + return 0; +} + +bool is_rmi_available(void) +{ + return arm64_rmi_is_available; +} + static int __init arm64_init_rmi(void) { int ret; @@ -664,6 +758,13 @@ static int __init arm64_init_rmi(void) if (ret) return ret; =20 + ret =3D rmi_init_metadata(); + if (ret) + return ret; + + arm64_rmi_is_available =3D true; + pr_info("RMI configured\n"); + return 0; } =20 diff --git a/include/linux/arm-rmi-cmds.h b/include/linux/arm-rmi-cmds.h index 8814708536d6..805a7ed9fc00 100644 --- a/include/linux/arm-rmi-cmds.h +++ b/include/linux/arm-rmi-cmds.h @@ -37,6 +37,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); --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3570341A506; Mon, 3 Aug 2026 13:44:51 +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=1785764693; cv=none; b=j6Ftru5E2nRY98H8Ev8Vshv6lhUvyyvDaZjG12IvW9C/qTZtW3Bq947ySNhqWynwb8qPMnsIBwSBI+B2etaZkDM2+nFFhZsYYI/Fo8+t5SvubSF6YwyFcZnssimc8vOYUh61DUIxgpDX7OgCbl8MZd9+B0Gu2O1tRKQdCga5UCE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764693; c=relaxed/simple; bh=atB3+AUi+d6UB2ANLJFnJ3D22hkMovBf+VHS20wL0+U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lNl5Pys9DeX3Gm24EQDv7GSMKvJ1hI3iZHKs9Tfs2gt+eD0e6W1yIEAOrqVxNrATQrQ/JhYIPDCtyWIOiiWIUSO6Eu9OuFnbgqYcYWCK8TDMF9PDC9xAQZMYsCvwW4YxKsLQ03r2c/Y0XxQlWDwzJHCZ23tvcJGu6Ds962smPSo= 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=h3PkWGNX; 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="h3PkWGNX" 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 8F759165C; Mon, 3 Aug 2026 06:44:46 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id ECAA43F66F; Mon, 3 Aug 2026 06:44:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764690; bh=atB3+AUi+d6UB2ANLJFnJ3D22hkMovBf+VHS20wL0+U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=h3PkWGNXVDNuddBOjUSAnEFkpuP/5w/cj7Cibu6fl/arIuAfR43QNFsFCpB1sQlwV Lsaf3cs1Q19MTkWdimIrgDHbOqRxtPSyR6jeH0ZdY7jlDB4FHia6jAitCYOKyPN4C0 U2F8bzY7FmqvpRK1amSD620+Wb717jd6pV29T3lc= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 07/45] arm64: mm: Handle Granule Protection Faults (GPFs) Date: Mon, 3 Aug 2026 14:43:23 +0100 Message-ID: <20260803134403.80630-8-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" If the host attempts to access granules that have been delegated for use in a realm these accesses will be caught and will trigger a Granule Protection Fault (GPF). A fault during a page walk signals a bug in the kernel and is handled by oopsing the kernel. A non-page walk fault could be caused by user space having access to a page which has been delegated to the kernel and will trigger a SIGBUS to allow debugging why user space is trying to access a delegated page. Reviewed-by: Suzuki K Poulose Reviewed-by: Gavin Shan Signed-off-by: Steven Price --- Changes since v10: * Don't call arm64_notify_die() in do_gpf() but simply return 1. Changes since v2: * Include missing "Granule Protection Fault at level -1" --- arch/arm64/mm/fault.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 85e23388f9bb..ea3ae0ca7dba 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -909,6 +909,22 @@ static int do_tag_check_fault(unsigned long far, unsig= ned long esr, return 0; } =20 +static int do_gpf_ptw(unsigned long far, unsigned long esr, struct pt_regs= *regs) +{ + const struct fault_info *inf =3D esr_to_fault_info(esr); + + die_kernel_fault(inf->name, far, esr, regs); + return 0; +} + +static int do_gpf(unsigned long far, unsigned long esr, struct pt_regs *re= gs) +{ + if (!is_el1_instruction_abort(esr) && fixup_exception(regs, esr)) + return 0; + + return 1; +} + static const struct fault_info fault_info[] =3D { { do_bad, SIGKILL, SI_KERNEL, "ttbr address size fault" }, { do_bad, SIGKILL, SI_KERNEL, "level 1 address size fault" }, @@ -945,12 +961,12 @@ static const struct fault_info fault_info[] =3D { { do_bad, SIGKILL, SI_KERNEL, "unknown 32" }, { do_alignment_fault, SIGBUS, BUS_ADRALN, "alignment fault" }, { do_bad, SIGKILL, SI_KERNEL, "unknown 34" }, - { do_bad, SIGKILL, SI_KERNEL, "unknown 35" }, - { do_bad, SIGKILL, SI_KERNEL, "unknown 36" }, - { do_bad, SIGKILL, SI_KERNEL, "unknown 37" }, - { do_bad, SIGKILL, SI_KERNEL, "unknown 38" }, - { do_bad, SIGKILL, SI_KERNEL, "unknown 39" }, - { do_bad, SIGKILL, SI_KERNEL, "unknown 40" }, + { do_gpf_ptw, SIGKILL, SI_KERNEL, "level -1 granule protection fault (tr= anslation table walk)" }, + { do_gpf_ptw, SIGKILL, SI_KERNEL, "level 0 granule protection fault (tra= nslation table walk)" }, + { do_gpf_ptw, SIGKILL, SI_KERNEL, "level 1 granule protection fault (tra= nslation table walk)" }, + { do_gpf_ptw, SIGKILL, SI_KERNEL, "level 2 granule protection fault (tra= nslation table walk)" }, + { do_gpf_ptw, SIGKILL, SI_KERNEL, "level 3 granule protection fault (tra= nslation table walk)" }, + { do_gpf, SIGBUS, SI_KERNEL, "granule protection fault" }, { do_bad, SIGKILL, SI_KERNEL, "level -1 address size fault" }, { do_bad, SIGKILL, SI_KERNEL, "unknown 42" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level -1 translation fault= " }, --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id B6A1941D12B; Mon, 3 Aug 2026 13:44:55 +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=1785764697; cv=none; b=e8MHE/knO+rzXnG8Fyx9mNmBjE2k3nKfNchLumS+1o0TBn8L1+/s5GsYuYuyxQY5eH5MrF8+1zR8mMR7uHddct8jgbIndKx+poZzkP8U9GQ9trgLAJ8WIrCXxtr4At9zb2OJdZM4mf9kmJGTfo4PXUn1lV/NYURUjOHE1S7609c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764697; c=relaxed/simple; bh=4Tj9S5AJyJlT1xaoyFWjtSoFJSn54sEDNzeHR7ufHFU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=o8wTZarlOdgkgZdSgt6x7JP4NhqgtZuVXUjuQuEhWwpKZ2ehYHnpeUKzo2Q0X6pkcLnGECLN+xhCBdnkk1/fkZuP+/xzVa2CVqu5ebJb5E2w9jtGBWk1ETKUnGLrBbgwlIVgVZI8LKz9IR0q4TXvMGbJ8gtXbv7kDry8/0i1twQ= 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=b461bBK5; 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="b461bBK5" 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 4071E143D; Mon, 3 Aug 2026 06:44:51 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 019643F66F; Mon, 3 Aug 2026 06:44:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764695; bh=4Tj9S5AJyJlT1xaoyFWjtSoFJSn54sEDNzeHR7ufHFU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=b461bBK5C0pTSb+cljqPR6GfT0hAizswP5puVbbTpFEFko10BID/4ir000LibaYUb UMOlON3yVshFON8DcBNzD+/BnEYhre/b0skaVVg6f13tYDEYimZNasZHMTd6qcmrXc lweXz0pfPMliptcHso+MyTkGk6EwoI1fDXRYz3s4= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Suzuki K Poulose , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 08/45] KVM: arm64: Include kvm_emulate.h in kvm/arm_psci.h Date: Mon, 3 Aug 2026 14:43:24 +0100 Message-ID: <20260803134403.80630-9-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Suzuki K Poulose Fix a potential build error (like below, when asm/kvm_emulate.h gets included after the kvm/arm_psci.h) by including the missing header file in kvm/arm_psci.h: ./include/kvm/arm_psci.h: In function =E2=80=98kvm_psci_version=E2=80=99: ./include/kvm/arm_psci.h:29:13: error: implicit declaration of function =E2=80=98vcpu_has_feature=E2=80=99; did you mean =E2=80=98cpu_have_featu= re=E2=80=99? [-Werror=3Dimplicit-function-declaration] 29 | if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_PSCI_0_2)) { | ^~~~~~~~~~~~~~~~ | cpu_have_feature Reviewed-by: Gavin Shan Signed-off-by: Suzuki K Poulose Signed-off-by: Steven Price --- include/kvm/arm_psci.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h index cbaec804eb83..38dab7add79b 100644 --- a/include/kvm/arm_psci.h +++ b/include/kvm/arm_psci.h @@ -10,6 +10,8 @@ #include #include =20 +#include + #define KVM_ARM_PSCI_0_1 PSCI_VERSION(0, 1) #define KVM_ARM_PSCI_0_2 PSCI_VERSION(0, 2) #define KVM_ARM_PSCI_1_0 PSCI_VERSION(1, 0) --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D0E5D411FB8; Mon, 3 Aug 2026 13:45:00 +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=1785764702; cv=none; b=D3XsAMiKvFuJDlctZqINaO4k23XnbENOiSZPC4rI3sIZ4Aypwm9d58tc6vsJkCpp3/2kr7I49CQ48pex2yHEe36wgTXf9VJ2bERMTVvZN5qBHqzOwFBTGTI92iVzSafeKTOkt5IT3t5TNnnzzLQfblsoHSJN9pa4SZMhAI9KHTc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764702; c=relaxed/simple; bh=LXyCzvFruOCuPoP9WYAH053wu6GqC2lVthabhKFJsbs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lUQ1EncDGTr+nMoOliLskR+BaIgJKjE7+jhDyzdNTJsrSa2EU2zVNwslKaZqvvnEQqocSN0ifhc2I5MQzOo1SY+thwtwbAMt9+q7fm803K0UbFFimEU4qraEFeIgzHp71mvH/5jtW+iPi2RevqH706whRc5aaMTGMXCPOBmjakU= 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=vYl0ASJ9; 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="vYl0ASJ9" 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 0D447143D; Mon, 3 Aug 2026 06:44:56 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B9F383F66F; Mon, 3 Aug 2026 06:44:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764700; bh=LXyCzvFruOCuPoP9WYAH053wu6GqC2lVthabhKFJsbs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vYl0ASJ9r+3uuN/SPpZC3hvV+z30+bHDb08xp8msAw9hzsFAwBMB7Sjq+CXfCH3Gb IbNW+k4z87Lkpuz3F+mvJDPmsIyRSyB99sessXNzfvtYE/V1VQEj6umgyORO5GakWF 8yPQDDZiqq6zvGrdPAQQbo9qNtJHIU+15DQYY11w= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 09/45] KVM: arm64: Avoid including linux/kvm_host.h in kvm_pgtable.h Date: Mon, 3 Aug 2026 14:43:25 +0100 Message-ID: <20260803134403.80630-10-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" To avoid future include cycles, drop the linux/kvm_host.h include in kvm_pgtable.h and include the lightweight headers required for the types and inline helpers used there. Additionally provide a forward declaration for struct kvm_s2_mmu as it's only used as a pointer in this file. Both pgtable.c and kvm_pkvm.h relied on the indirect inclusion of kvm_host.h, so make that explicit. Signed-off-by: Steven Price --- New patch in v13 --- arch/arm64/include/asm/kvm_pgtable.h | 6 +++++- arch/arm64/include/asm/kvm_pkvm.h | 2 +- arch/arm64/kvm/hyp/pgtable.c | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/= kvm_pgtable.h index 41a8687938eb..c2e4b29e605f 100644 --- a/arch/arm64/include/asm/kvm_pgtable.h +++ b/arch/arm64/include/asm/kvm_pgtable.h @@ -8,9 +8,13 @@ #define __ARM64_KVM_PGTABLE_H__ =20 #include -#include +#include +#include +#include #include =20 +struct kvm_s2_mmu; + #define KVM_PGTABLE_FIRST_LEVEL -1 #define KVM_PGTABLE_LAST_LEVEL 3 =20 diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm= _pkvm.h index 74fedd9c5ff0..0afe742d1f3f 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -7,9 +7,9 @@ #define __ARM64_KVM_PKVM_H__ =20 #include +#include #include #include -#include #include =20 /* Maximum number of VMs that can co-exist under pKVM. */ diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index 91a7dfad6686..3d608b7e0cf0 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -8,6 +8,7 @@ */ =20 #include +#include #include #include =20 --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 295C941E6A7; Mon, 3 Aug 2026 13:45: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=1785764707; cv=none; b=YLSyhH5ir+0obfN4Sb0AC0ZsGyVMIjrWRXREibD84ffb/fvx7ql7n0qucNCBeV4lJZa4+PkUQRiJYYn/bKMPaBIBJMhn32nbIrJijY9A+VymmsApWce0U9CvbZYjiMnaA0x0kFfNxhUP/ot7OUw6LZfNzd6mmXNsVIiz/NPRasA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764707; c=relaxed/simple; bh=0z7OwJOTdAOu3wdJf6+hKVpLSJT5pZGMhsWkA4wfIm0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rjbyFA5XYxu1N+vSTgWpEkMjuP2+7j9BEYK8N9OAeVRzeRgR8CNHYl1cmIqDNXgi6OlROaBWWP8dgpavTRNtpV93u2Zk0YfZrpcPyIeCDwXai2RrzmRSXkMoHwss5lPx/rQmneqcCo2VnVtE/tkmFE5VG4I4qVp3kqdqPCvxrtI= 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=TBXJo1uI; 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="TBXJo1uI" 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 ADB2B1476; Mon, 3 Aug 2026 06:45:00 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 72FB63F66F; Mon, 3 Aug 2026 06:45:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764704; bh=0z7OwJOTdAOu3wdJf6+hKVpLSJT5pZGMhsWkA4wfIm0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TBXJo1uIu15P6Tn6BpY0WllpFEdIqEYM3ulr8OYJ+D4CSxC+Gn0iwRX+fHFwNWHQp Pe2YG/T6KzPHTPKtI0aVjccRonWDcjpmBFWUOFAelXTW9Ai4khk9YX+05uGJl3c+NE SVi6gR0oajN7KYw1KAiySSDZCCiUVx3A9Tvn7vXY= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 10/45] KVM: arm64: CCA: Add wrappers for realm related RMIs Date: Mon, 3 Aug 2026 14:43:26 +0100 Message-ID: <20260803134403.80630-11-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" Introduce wrappers for the RMI functions needed for creating and managing realm guests. Signed-off-by: Steven Price --- v16: Split into new patch --- arch/arm64/include/asm/rmi_cmds.h | 465 ++++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 arch/arm64/include/asm/rmi_cmds.h diff --git a/arch/arm64/include/asm/rmi_cmds.h b/arch/arm64/include/asm/rmi= _cmds.h new file mode 100644 index 000000000000..25185935bf3c --- /dev/null +++ b/arch/arm64/include/asm/rmi_cmds.h @@ -0,0 +1,465 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023-2026 ARM Ltd. + */ + +#ifndef __ASM_RMI_CMDS_H +#define __ASM_RMI_CMDS_H + +#include +#include + +/** + * 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 /* __ASM_RMI_CMDS_H */ --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id C9F403BBFDA; Mon, 3 Aug 2026 13:45:09 +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=1785764712; cv=none; b=u/8WGBY381zsUAaOtKwK7bwUwksxEC2tWH06+TIfgdcZBuDIvVK85WGy75tfXGZG1j7Spp57MAVeIq7zX5DcR6TeqqHtQ3CMT1Mln82nWxOfwjx5k/PWm/vMcj4W28onUFA7dayQdWQEaJH3kx+GrVLTMlvDISQfXdd2HcYA4Ww= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764712; c=relaxed/simple; bh=YLMzS57B0Blt2+xGLVJcY5KsMCzwEAb8VT/RdBje/y4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VotkYug5+pB2+78EyzkXuMYb0AVvWDEkCSlea9V1La3/ie34Co7+4nl1lMOznIcwThNjipVWBq4G1owVZNAuJx5mz8LMPR6iggnkHBArqelcX5cGoWVDN7wee+AgCrZ1wjp8fFSxNBMiFaLxP+94JffF7u9bpJcX/h8kJtxNpwA= 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=mnBB10PY; 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="mnBB10PY" 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 548D1143D; Mon, 3 Aug 2026 06:45:05 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 1D1033F66F; Mon, 3 Aug 2026 06:45:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764709; bh=YLMzS57B0Blt2+xGLVJcY5KsMCzwEAb8VT/RdBje/y4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mnBB10PYXt0wMv0qsGnPZYXiSsv0pxi0j3Mjma4uUeMcqS84WE4KGuon2AuO/f7Vo HgzRHGl2kcN6V0LSlqjaBkVNyDLBSCS2eNXZwlDDWI4a7LqcY++bzm1H9e4PnC5/Lj VpMGSU1hfn3SFINbVa4szKaui/Bo5r4HZxGQpDQw= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 11/45] KVM: arm64: CCA: Check for RMI support at KVM init Date: Mon, 3 Aug 2026 14:43:27 +0100 Message-ID: <20260803134403.80630-12-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" Check if the RMI support is sufficient for using in KVM. Specifically, we currently only support creating realm VMs when KVM is running in VHE mode. Signed-off-by: Steven Price --- Changes since v13: * Most of the init has been moved out of the 'kvm' directory so this is much more basic now. Changes since v12: * Drop check for 4k page size. Changes since v11: * Reword slightly the comments on the realm states. Changes since v10: * kvm_is_realm() no longer has a NULL check. * Rename from "rme" to "rmi" when referring to the RMM interface. * Check for RME (hardware) support before probing for RMI support. Changes since v8: * No need to guard kvm_init_rme() behind 'in_hyp_mode'. Changes since v6: * Improved message for an unsupported RMI ABI version. Changes since v5: * Reword "unsupported" message from "host supports" to "we want" to clarify that 'we' are the 'host'. Changes since v2: * Drop return value from kvm_init_rme(), it was always 0. * Rely on the RMM return value to identify whether the RSI ABI is compatible. --- arch/arm64/include/asm/kvm_host.h | 4 ++++ arch/arm64/include/asm/kvm_rmi.h | 17 +++++++++++++++++ arch/arm64/include/asm/virt.h | 1 + arch/arm64/kvm/Kconfig | 1 + arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/arm.c | 5 +++++ arch/arm64/kvm/rmi.c | 24 ++++++++++++++++++++++++ 7 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/include/asm/kvm_rmi.h create mode 100644 arch/arm64/kvm/rmi.c diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm= _host.h index bae2c4f92ef5..1a5e15040111 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -27,6 +27,7 @@ #include #include #include +#include #include =20 #define __KVM_HAVE_ARCH_INTC_INITIALIZED @@ -424,6 +425,9 @@ struct kvm_arch { /* Nested virtualization info */ struct dentry *debugfs_nv_dentry; #endif + + bool is_realm; + struct realm realm; }; =20 struct kvm_vcpu_fault_info { diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h new file mode 100644 index 000000000000..57d24b244c95 --- /dev/null +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023-2026 ARM Ltd. + */ + +#ifndef __ASM_KVM_RMI_H +#define __ASM_KVM_RMI_H + +/** + * struct realm - Additional per VM data for a Realm + */ +struct realm { +}; + +void kvm_init_rmi(void); + +#endif /* __ASM_KVM_RMI_H */ diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h index b546703c3ab9..92cec42952f4 100644 --- a/arch/arm64/include/asm/virt.h +++ b/arch/arm64/include/asm/virt.h @@ -87,6 +87,7 @@ void __hyp_reset_vectors(void); bool is_kvm_arm_initialised(void); =20 DECLARE_STATIC_KEY_FALSE(kvm_protected_mode_initialized); +DECLARE_STATIC_KEY_FALSE(kvm_rmi_is_available); =20 static inline bool is_pkvm_initialized(void) { diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 449154f9a485..189e8ad78b22 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -37,6 +37,7 @@ menuconfig KVM select SCHED_INFO select GUEST_PERF_EVENTS if PERF_EVENTS select KVM_GUEST_MEMFD + select ARM_RMM help Support hosting virtualized guest machines. =20 diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index 59612d2f277c..ed3cf30eb06e 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -16,7 +16,7 @@ CFLAGS_handle_exit.o +=3D -Wno-override-init kvm-y +=3D arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \ inject_fault.o va_layout.o handle_exit.o config.o \ guest.o debug.o reset.o sys_regs.o stacktrace.o \ - vgic-sys-reg-v3.o fpsimd.o pkvm.o \ + vgic-sys-reg-v3.o fpsimd.o pkvm.o rmi.o \ arch_timer.o trng.o vmid.o emulate-nested.o nested.o at.o \ vgic/vgic.o vgic/vgic-init.o \ vgic/vgic-irqfd.o vgic/vgic-v2.o \ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 50adfff75be8..b961c22fce3d 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include =20 @@ -111,6 +112,8 @@ long kvm_get_cap_for_kvm_ioctl(unsigned int ioctl, long= *ext) return -EINVAL; } =20 +DEFINE_STATIC_KEY_FALSE(kvm_rmi_is_available); + DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector); =20 DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_base); @@ -3019,6 +3022,8 @@ static __init int kvm_arm_init(void) =20 in_hyp_mode =3D is_kernel_in_hyp_mode(); =20 + kvm_init_rmi(); + if (cpus_have_final_cap(ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) || cpus_have_final_cap(ARM64_WORKAROUND_1508412)) kvm_info("Guests without required CPU erratum workarounds can deadlock s= ystem!\n" \ diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c new file mode 100644 index 000000000000..384991d69f78 --- /dev/null +++ b/arch/arm64/kvm/rmi.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023-2026 ARM Ltd. + */ + +#include + +#include +#include + +void kvm_init_rmi(void) +{ + /* + * TODO: Support Realm guests in nVHE mode, this will require adding + * EL2 stub(s) for REC entry and possibly other things. + */ + if (!is_kernel_in_hyp_mode()) + return; + + if (!is_rmi_available()) + return; + + /* Future patch will enable static branch kvm_rmi_is_available */ +} --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9E5582AD2E; Mon, 3 Aug 2026 13:45: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=1785764715; cv=none; b=Noh34+dPiR1NjUjzUuAMPdM5YUjFIPIey1oALltjdA09FERoYIG5BiQdk/bKbvaVDKiG3OwQXkP2iVWirCCsBMEixJQueWrSJA0hUbkPuaa5upx8ru8zlfJ6jkoV13TPPkMGKdKZgQFXwquMf/RnMPj4dpccAdyU3906Vd25P38= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764715; c=relaxed/simple; bh=A5swwuKF1sO6Ks2eU21cOmS2+QgmSfc5adtL4WsCNVs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FlbZSkOX3foT86lMUAQakgO45Nci/q9HGN7T037LF4nPR1XRgXK/K1Azktcrsdv50Rf0CbajOzohMt0hvsVX0a9jlyKEnt+Y0vVCNRNTyThNam2oBszG2GHHfZGw67q5x7RUmsFgP6SxLQR4YyKKz60uKGaZS0ZxqbBAsqvjPGM= 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=Cz+udvNR; 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="Cz+udvNR" 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 03344143D; Mon, 3 Aug 2026 06:45:10 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B7D033F66F; Mon, 3 Aug 2026 06:45:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764714; bh=A5swwuKF1sO6Ks2eU21cOmS2+QgmSfc5adtL4WsCNVs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Cz+udvNRcM1Tk4J/RUkbxEBfr01o+wyepwZMwkWNP6dPU53LYHVSaSaRSIAwEbG8P PD8KzhfmpLeMgjyAuA1bJBBn8kBae7e+GGTDKJMXmkyek873FlOBbB7jF/isgOtgW/ wiG9rwtlgwMcOX07xk3G1Ao0AERzyMQR9/Tpsx9U= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 12/45] KVM: arm64: CCA: Check for LPA2 support Date: Mon, 3 Aug 2026 14:43:28 +0100 Message-ID: <20260803134403.80630-13-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" If KVM has enabled LPA2 support then check that the RMM also supports it. If there is a mismatch then disable support for realm guests as the VMM may attempt to create a guest which is incompatible with the RMM. Reviewed-by: Suzuki K Poulose Signed-off-by: Steven Price --- v15: * Extend rmi_has_feature() to take the register number and check the presence of SHA-256 support which is default. v13: * New patch --- arch/arm64/kvm/rmi.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 384991d69f78..247c4f033945 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -5,9 +5,31 @@ =20 #include =20 +#include #include #include =20 +static bool rmi_has_feature(int reg, unsigned long feature) +{ + return !!u64_get_bits(rmi_feat_reg(reg), feature); +} + +static int rmm_check_features(void) +{ + if (kvm_lpa2_is_enabled() && + !rmi_has_feature(0, RMI_FEATURE_REGISTER_0_LPA2)) { + kvm_err("RMM doesn't support LPA2\n"); + return -ENXIO; + } + + if (!rmi_has_feature(1, RMI_FEATURE_REGISTER_1_HASH_SHA_256)) { + kvm_err("RMM doesn't support SHA-256 measurements\n"); + return -ENXIO; + } + + return 0; +} + void kvm_init_rmi(void) { /* @@ -20,5 +42,8 @@ void kvm_init_rmi(void) if (!is_rmi_available()) return; =20 + if (rmm_check_features()) + return; + /* Future patch will enable static branch kvm_rmi_is_available */ } --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id EE6A84137BD; Mon, 3 Aug 2026 13:45:18 +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=1785764720; cv=none; b=PPXagnY1mzKJPQO02lWVpzYpEMqcB75LxTatQTKXU70BKh3xazYFOHUmljiSwe8JbIy/Vb2psxoCzYnBW6FJqMn/xxfIIwIqEoe4+hs4tE34QXG1d41x7QjT44d/g+VeB/0GZ3IAXUi1/l4QedCjMPBqnWXv95RYbiqDs2TatWY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764720; c=relaxed/simple; bh=W+mj+aqPxD9OUiQlGZIDCnrFnQ+H1UYPLtwRXKLa5sU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ie30Ywp2+0FlM007LWiAFupBND5LZZfIj+bcsTHIPFrQy4HSA7690CI1hLqsk8fOlF0zauCuXOv13UxLay8S+v4jQNAK64DlAnoBSHkM+q/EU2zy3fHYvZ2InIReBUVoRuPqvGUwd7UpiWTqAwLD9pR4yCKMCu6QgR8OEfqYbTk= 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=YvuycBeb; 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="YvuycBeb" 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 7E04E143D; Mon, 3 Aug 2026 06:45:14 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 7A31F3F66F; Mon, 3 Aug 2026 06:45:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764718; bh=W+mj+aqPxD9OUiQlGZIDCnrFnQ+H1UYPLtwRXKLa5sU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YvuycBeb1X/WazYVlz1m2L9thez4M3rMZVzDqDbLfY278Cz6/+TbaTmglWNDDfXHC 1lH3jHSV8Ca4WpPjhI88b9w6t3/59d0oSTPzD1TCDPzWYXvoSqFFegaLwniGmW9mml 8EEvf7kRoHMvoUHEe0vl4a/wN/xewJPb4+a0qfIg= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 13/45] KVM: arm64: CCA: Define the user ABI Date: Mon, 3 Aug 2026 14:43:29 +0100 Message-ID: <20260803134403.80630-14-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" There is one CAP (KVM_CAP_ARM_RMI) which identifies the presence of CCA, and one ioctl. The ioctl (KVM_ARM_RMI_POPULATE) is used to populate memory during creation of the realm as this requires the RMM to copy data from an unprotected address to the protected memory - CCA does not support shared <-> private memory conversion where the memory contents is preserved as this is incompatible with memory encryption. Signed-off-by: Steven Price --- Changes since v15: * Expand KVM_ARM_RMI_POPULATE documentation to be explicit that in-place shared-to-private conversion isn't supported. Changes since v13: * KVM_ARM_VCPU_RMI_PSCI_COMPLETE removed. * KVM_ARM_RMI_POPULATE documentation updated to reflect that the structure is written by the kernel. * CAP number bumped. Changes since v12: * Change KVM_ARM_RMI_POPULATE to update the structure with the amount that has been progressed rather than return the number of bytes populated. * Describe the flag KVM_ARM_RMI_POPULATE_FLAGS_MEASURE. * CAP number is bumped. * NOTE: The PSCI ioctl may be removed in a future spec release. Changes since v11: * Completely reworked to be more implicit. Rather than having explicit CAP operations to progress the realm construction these operations are done when needed (on populating and on first vCPU run). * Populate and PSCI complete are promoted to proper ioctls. Changes since v10: * Rename symbols from RME to RMI. Changes since v9: * Improvements to documentation. * Bump the magic number for KVM_CAP_ARM_RME to avoid conflicts. Changes since v8: * Minor improvements to documentation following review. * Bump the magic numbers to avoid conflicts. Changes since v7: * Add documentation of new ioctls * Bump the magic numbers to avoid conflicts Changes since v6: * Rename some of the symbols to make their usage clearer and avoid repetition. Changes from v5: * Actually expose the new VCPU capability (KVM_ARM_VCPU_REC) by bumping KVM_VCPU_MAX_FEATURES - note this also exposes KVM_ARM_VCPU_HAS_EL2! --- Documentation/virt/kvm/api.rst | 47 ++++++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 13 ++++++++++ 2 files changed, 60 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 1de6fd5fc88c..ce588c05b26a 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6642,6 +6642,44 @@ if the guest_memfd memory was pinned in IOMMU page t= ables. =20 See also: :ref: `KVM_SET_MEMORY_ATTRIBUTES`. =20 +4.146 KVM_ARM_RMI_POPULATE +-------------------------- + +:Capability: KVM_CAP_ARM_RMI +:Architectures: arm64 +:Type: vm ioctl +:Parameters: struct kvm_arm_rmi_populate (in/out) +:Returns: 0 on success, < 0 on error + +:: + + struct kvm_arm_rmi_populate { + __u64 base; + __u64 size; + __u64 source_uaddr; + __u32 flags; + __u32 reserved; + }; + +Populate the guest address range described by `base` and `size` with data = from +the userspace buffer at `source_uaddr`. The guest_memfd range backing the +memory must have `KVM_MEMORY_ATTRIBUTE_PRIVATE` set. + +Arm CCA cannot perform an in-place shared-to-private conversion while +preserving memory contents. Therefore, `source_uaddr` must be a valid, +page-aligned userspace pointer. The operation uses `RMI_RTT_DATA_MAP_INIT`, +which also sets the region to `RIPAS_RAM`. + +This is only valid before any VCPUs have been run. The ioctl might not pop= ulate +the entire region and in this case the kernel updates the fields `base`, `= size` +and `source_uaddr`. User space may have to repeatedly call it until `size`= is 0 +to populate the entire region. + +`flags` can be set to `KVM_ARM_RMI_POPULATE_FLAGS_MEASURE` to request that= the +populated data is hashed and added to the guest's Realm Initial Measurement +(RIM) stored by the RMM. This can then be retrieved by the guest (using th= e RSI +interface) to present to an attestation server. + .. _kvm_run: =20 5. The kvm_run structure @@ -9025,6 +9063,15 @@ enabled, cmma can't be enabled anymore and pfmfi and= the storage key interpretation are disabled. If cmma has already been enabled or the hpage_2g module parameter is not set to 1, -EINVAL is returned. =20 +7.48 KVM_CAP_ARM_RMI +-------------------- + +:Architectures: arm64 +:Target: VM +:Parameters: None + +This capability indicates that support for CCA realms is available. + 8. Other capabilities. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 129d6f630325..0231ff174a50 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -998,6 +998,7 @@ struct kvm_enable_cap { #define KVM_CAP_S390_VSIE_ESAMODE 248 #define KVM_CAP_S390_HPAGE_2G 249 #define KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES 250 +#define KVM_CAP_ARM_RMI 251 =20 struct kvm_irq_routing_irqchip { __u32 irqchip; @@ -1686,4 +1687,16 @@ struct kvm_pre_fault_memory { __u64 padding[5]; }; =20 +/* Available with KVM_CAP_ARM_RMI, only for VMs with KVM_VM_TYPE_ARM_REALM= */ +#define KVM_ARM_RMI_POPULATE _IOWR(KVMIO, 0xd7, struct kvm_arm_rmi_populat= e) +#define KVM_ARM_RMI_POPULATE_FLAGS_MEASURE (1 << 0) + +struct kvm_arm_rmi_populate { + __u64 base; + __u64 size; + __u64 source_uaddr; + __u32 flags; + __u32 reserved; +}; + #endif /* __LINUX_KVM_H */ --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 16199414DF4; Mon, 3 Aug 2026 13:45:24 +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=1785764726; cv=none; b=oebrnqA5FK6wR59XoXsQk62xe4Kyw9ZLshVo2PyVMmMu2Noz0byikUvSyvgHbZfUR4wIR2v0lkva/Whhwur4H7pdZbg1tMHuCZtm2fGBSHsr41Y92jcrZbrWjncCBtQYnwXwtL2DQlffHiRqXLsBwojisfnJ1F2zxDOESkrF0gU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764726; c=relaxed/simple; bh=RIL7oE0ereG/ijnO1qlh3vLGborUE/e/mQqj+8n28ow=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=s+V6q3bV2fuGlupF0/T1L0Cemtd0oSIiJZgj0coh39KyfLZJRY/OnBvE9q19vVTMwEDb7CYeWCywLdYwt1jw3DAwlXAwAXWmIZB7df/oSCnO2aWIUprfRYNZ+2v/HGCj4Mtz2yxoZ6sanHI1Y1y28dNeqC4MbCfyhntQdR3iDGs= 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=E1flnbaT; 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="E1flnbaT" 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 8DF2C1596; Mon, 3 Aug 2026 06:45:19 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id E53543F66F; Mon, 3 Aug 2026 06:45:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764723; bh=RIL7oE0ereG/ijnO1qlh3vLGborUE/e/mQqj+8n28ow=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=E1flnbaTU10dNTMlHlP8atUzPqGKrWFfsJu17NHHVHjllmF1uhH5v2l4FsY8bhMRy MufHKdsuM4Kv0d+8miOT519XjVSRBjLIdkiGpyKb9+fZsvE5wEvXk+PPGBTX3aioMj 549iiMShhWl0aSsxYKAcOCFmZ21mQGtD7AtyNyGU= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 14/45] KVM: arm64: CCA: Add basic infrastructure for creating a realm Date: Mon, 3 Aug 2026 14:43:30 +0100 Message-ID: <20260803134403.80630-15-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" Introduce the skeleton functions for creating and destroying a realm. The IPA size requested is checked against what the RMM supports. The actual work of constructing the realm will be added in future patches. Signed-off-by: Steven Price --- Changes since v15: * Remove realm->params and only temporarily allocate the page when the realm is being created. Changes since v14: * Adapt to the RMM v2.0-bet2 realm parameter layout and SRO-based realm creation. Changes since v13: * Rebased and updated to RMM-v2.0-bet1. * Auxiliary granules have been removed in RMM-v2.0-bet1 Changes since v12: * Drop the RMM_PAGE_{SHIFT,SIZE} defines - the RMM is now configured to be the same as the host's page size. * Rework delegate/undelegate functions to use the new RMI range based operations. Changes since v11: * Major rework to drop the realm configuration and make the construction of realms implicit rather than driven by the VMM directly. * The code to create RDs, handle VMIDs etc is moved to later patches. Changes since v10: * Rename from RME to RMI. * Move the stage2 cleanup to a later patch. Changes since v9: * Avoid walking the stage 2 page tables when destroying the realm - the real ones are not accessible to the non-secure world, and the RMM may leave junk in the physical pages when returning them. * Fix an error path in realm_create_rd() to actually return an error value. Changes since v8: * Fix free_delegated_granule() to not call kvm_account_pgtable_pages(); a separate wrapper will be introduced in a later patch to deal with RTTs. * Minor code cleanups following review. Changes since v7: * Minor code cleanup following Gavin's review. Changes since v6: * Separate RMM RTT calculations from host PAGE_SIZE. This allows the host page size to be larger than 4k while still communicating with an RMM which uses 4k granules. Changes since v5: * Introduce free_delegated_granule() to replace many undelegate/free_page() instances and centralise the comment on leaking when the undelegate fails. * Several other minor improvements suggested by reviews - thanks for the feedback! Changes since v2: * Improved commit description. * Improved return failures for rmi_check_version(). * Clear contents of PGD after it has been undelegated in case the RMM left stale data. * Minor changes to reflect changes in previous patches. --- arch/arm64/include/asm/kvm_emulate.h | 24 +++++++++++ arch/arm64/include/asm/kvm_rmi.h | 63 ++++++++++++++++++++++++++++ arch/arm64/kvm/arm.c | 12 ++++++ arch/arm64/kvm/mmu.c | 18 +++++++- arch/arm64/kvm/rmi.c | 56 +++++++++++++++++++++++++ 5 files changed, 171 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/= kvm_emulate.h index 5bf3d7e1d92c..e26d6755279f 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -688,4 +688,28 @@ static inline void vcpu_set_hcrx(struct kvm_vcpu *vcpu) vcpu->arch.hcrx_el2 |=3D HCRX_EL2_EnASR; } } + +static inline bool kvm_is_realm(struct kvm *kvm) +{ + if (static_branch_unlikely(&kvm_rmi_is_available)) + return kvm->arch.is_realm; + return false; +} + +static inline enum realm_state kvm_realm_state(struct kvm *kvm) +{ + return READ_ONCE(kvm->arch.realm.state); +} + +static inline void kvm_set_realm_state(struct kvm *kvm, + enum realm_state new_state) +{ + WRITE_ONCE(kvm->arch.realm.state, new_state); +} + +static inline bool kvm_realm_is_created(struct kvm *kvm) +{ + return kvm_is_realm(kvm) && kvm_realm_state(kvm) !=3D REALM_STATE_NONE; +} + #endif /* __ARM64_KVM_EMULATE_H__ */ diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 57d24b244c95..cefd00b76806 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -6,12 +6,75 @@ #ifndef __ASM_KVM_RMI_H #define __ASM_KVM_RMI_H =20 +#include + +/** + * enum realm_state - State of a Realm + * + * Mirrors the RMM's Realm lifecycle states where they are meaningful to K= VM, + * with REALM_STATE_DYING being a KVM-internal state used to prevent furth= er + * requests while teardown is in progress. KVM does not track REALM_SYSTEM= _OFF + * or REALM_ZOMBIE separately as they naturally lead to teardown. + */ +enum realm_state { + /** + * @REALM_STATE_NONE: + * Realm has not yet been created. rmi_realm_create() has not + * yet been called. + */ + REALM_STATE_NONE, + /** + * @REALM_STATE_NEW: + * Realm is under construction, rmi_realm_create() has been + * called, but it is not yet activated. Pages may be populated. + */ + REALM_STATE_NEW, + /** + * @REALM_STATE_ACTIVE: + * Realm has been created and is eligible for execution with + * rmi_rec_enter(). Pages may no longer be populated with + * rmi_data_create(). + */ + REALM_STATE_ACTIVE, + /** + * @REALM_STATE_DYING: + * Realm is in the process of being destroyed or has already been + * destroyed. + */ + REALM_STATE_DYING, + /** + * @REALM_STATE_DEAD: + * Realm has been destroyed. + */ + REALM_STATE_DEAD +}; + /** * struct realm - Additional per VM data for a Realm + * + * @rd: Kernel mapping of the RMM-managed Realm Descriptor (RD) granule + * @sro: Preallocated SRO state context for Realm MMU operations + * @state: The lifetime state machine for the realm + * @ia_bits: Number of valid Input Address bits in the IPA */ struct realm { + void *rd; + /* + * Reused by RTT map/unmap SRO commands. Those commands are only + * issued from Realm stage-2 map/unmap paths while kvm->mmu_lock is + * held for write, including Realm fault handling where + * kvm_fault_lock() takes the write side, so concurrent use is + * serialized. + */ + struct rmi_sro_state *sro; + enum realm_state state; + unsigned int ia_bits; }; =20 void kvm_init_rmi(void); +u32 kvm_rmm_ipa_limit(void); + +int kvm_init_realm(struct kvm *kvm); +void kvm_destroy_realm(struct kvm *kvm); =20 #endif /* __ASM_KVM_RMI_H */ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index b961c22fce3d..c4d906861736 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -266,6 +266,13 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long ty= pe) =20 bitmap_zero(kvm->arch.vcpu_features, KVM_VCPU_MAX_FEATURES); =20 + /* Initialise the realm bits after the generic bits are enabled */ + if (kvm_is_realm(kvm)) { + ret =3D kvm_init_realm(kvm); + if (ret) + goto err_uninit_mmu; + } + return 0; =20 err_uninit_mmu: @@ -328,6 +335,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kvm_unshare_hyp(kvm, kvm + 1); =20 kvm_arm_teardown_hypercalls(kvm); + if (kvm_is_realm(kvm)) + kvm_destroy_realm(kvm); } =20 static bool kvm_has_full_ptr_auth(void) @@ -488,6 +497,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long = ext) else r =3D kvm_supports_cacheable_pfnmap(); break; + case KVM_CAP_ARM_RMI: + r =3D static_key_enabled(&kvm_rmi_is_available); + break; =20 default: r =3D 0; diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 6c941aaa10c6..8b9efa8a3539 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -904,10 +904,14 @@ static struct kvm_pgtable_mm_ops kvm_s2_mm_ops =3D { =20 static int kvm_init_ipa_range(struct kvm_s2_mmu *mmu, unsigned long type) { + struct kvm *kvm =3D kvm_s2_mmu_to_kvm(mmu); u32 kvm_ipa_limit =3D get_kvm_ipa_limit(); u64 mmfr0, mmfr1; u32 phys_shift; =20 + if (kvm_is_realm(kvm)) + kvm_ipa_limit =3D kvm_rmm_ipa_limit(); + phys_shift =3D KVM_VM_TYPE_ARM_IPA_SIZE(type); if (is_protected_kvm_enabled()) { phys_shift =3D kvm_ipa_limit; @@ -957,9 +961,18 @@ static void stage2_destroy_range(struct kvm_pgtable *p= gt, phys_addr_t addr, =20 static void kvm_stage2_destroy(struct kvm_pgtable *pgt) { + struct kvm *kvm =3D kvm_s2_mmu_to_kvm(pgt->mmu); unsigned int ia_bits =3D VTCR_EL2_IPA(pgt->mmu->vtcr); =20 - stage2_destroy_range(pgt, 0, BIT(ia_bits)); + /* + * Realm RTTs are inaccessible to the host and may contain stale data + * after the RMM has released them. The non-root RTTs are explicitly + * destroyed through RMI before the RD is destroyed; only the root PGD + * pages remain to be freed here. + */ + if (!kvm_is_realm(kvm)) + stage2_destroy_range(pgt, 0, BIT(ia_bits)); + KVM_PGT_FN(kvm_pgtable_stage2_destroy_pgd)(pgt); } =20 @@ -1001,6 +1014,8 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s= 2_mmu *mmu, unsigned long t return -EINVAL; } =20 + mmu->arch =3D &kvm->arch; + err =3D kvm_init_ipa_range(mmu, type); if (err) return err; @@ -1009,7 +1024,6 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s= 2_mmu *mmu, unsigned long t if (!pgt) return -ENOMEM; =20 - mmu->arch =3D &kvm->arch; err =3D KVM_PGT_FN(kvm_pgtable_stage2_init)(pgt, mmu, &kvm_s2_mm_ops); if (err) goto out_free_pgtable; diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 247c4f033945..528b01d5d71d 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -5,6 +5,8 @@ =20 #include =20 +#include +#include #include #include #include @@ -14,6 +16,60 @@ static bool rmi_has_feature(int reg, unsigned long featu= re) return !!u64_get_bits(rmi_feat_reg(reg), feature); } =20 +u32 kvm_rmm_ipa_limit(void) +{ + return u64_get_bits(rmi_feat_reg(0), RMI_FEATURE_REGISTER_0_S2SZ); +} + +void kvm_destroy_realm(struct kvm *kvm) +{ + struct realm *realm =3D &kvm->arch.realm; + size_t pgd_size =3D kvm_pgtable_stage2_pgd_size(kvm->arch.mmu.vtcr); + + if (!kvm_realm_is_created(kvm)) { + kfree(realm->sro); + realm->sro =3D NULL; + return; + } + + kvm_set_realm_state(kvm, REALM_STATE_DYING); + + if (realm->rd) { + phys_addr_t rd_phys =3D virt_to_phys(realm->rd); + + if (WARN_ON(rmi_realm_terminate(rd_phys, realm->sro))) + return; + + if (WARN_ON(rmi_realm_destroy(rd_phys, realm->sro))) + return; + free_delegated_page(rd_phys); + realm->rd =3D NULL; + } + + if (WARN_ON(rmi_undelegate_range(kvm->arch.mmu.pgd_phys, + pgd_size))) + return; + + kvm_set_realm_state(kvm, REALM_STATE_DEAD); + + /* Now that the realm is destroyed, free the entry-level RTTs. */ + kvm_free_stage2_pgd(&kvm->arch.mmu); + + kfree(realm->sro); + realm->sro =3D NULL; +} + +int kvm_init_realm(struct kvm *kvm) +{ + struct realm *realm =3D &kvm->arch.realm; + + realm->sro =3D kmalloc_obj(*realm->sro); + if (!realm->sro) + return -ENOMEM; + + return 0; +} + static int rmm_check_features(void) { if (kvm_lpa2_is_enabled() && --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8C2CD423EAE; Mon, 3 Aug 2026 13:45:28 +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=1785764730; cv=none; b=bx2aaqXkn0YnbEN3ojA1EyTjSXe7JJM2uIH+ePAQtfQahO6+art6ST9ekLMPNLHc6vuLv14rumRr/rxvXjUDcAKF/gteRg2BqzZ0wXN9JRVnN79Zo7WYxcKDBImP2p9bknJRiOxl6WWZPSmvuCMZSn6pT7Z18C2LLgu6dJDkTws= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764730; c=relaxed/simple; bh=RQcKO9nHmQHlEm5pEoraUvIMCuQ6ccv5B7RjBEVRDt8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qFhv1KqMHXAj05HOZwt6jUYb3SZSe4qRJXLuj5YAVixcjGBxk7S6MyPx20KN/pAEgRcW4N/b00HBY4xA9mBqNMTsdvVDkavhJcvuYJp6MeQ4WCN+09hOKjpniEb/j8j2/OaOS6voI8HJI16tLOOoaaYbqnJjBrS05v3xA6A6ClQ= 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=Z/xBRPct; 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="Z/xBRPct" 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 CCC3F1476; Mon, 3 Aug 2026 06:45:23 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 0B70F3F66F; Mon, 3 Aug 2026 06:45:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764727; bh=RQcKO9nHmQHlEm5pEoraUvIMCuQ6ccv5B7RjBEVRDt8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Z/xBRPctLTMKWaTVAvfkpxNPzBsCqVFd51g2KTiht797VzLSEOwObRgKNyWn4/vMO RKZQQhVJKuRJ3OPFq+sxR2yY8uoWrgI/PwhrJYTdmQpDe1PVmK+AWasr1UM2Yysn7x BWrTYJio4Y51DkYPjcYfW9kClUiIvu9jkng/4Yvk= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Suzuki K Poulose , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 15/45] KVM: arm64: CCA: Don't expose unsupported capabilities for realm guests Date: Mon, 3 Aug 2026 14:43:31 +0100 Message-ID: <20260803134403.80630-16-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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: Suzuki K Poulose RMM v2.0 provides no mechanism for the host to perform debug operations on the guest. So limit the extensions that are visible to an allowlist so that only those capabilities we can support are advertised. Signed-off-by: Suzuki K Poulose Signed-off-by: Steven Price --- Changes since v13: * Add missing check in kvm_vm_ioctl_enable_cap(). Changes since v10: * Add a kvm_realm_ext_allowed() function which limits which extensions are exposed to an allowlist. This removes the need for special casing various extensions. Changes since v7: * Remove the helper functions and inline the kvm_is_realm() check with a ternary operator. * Rewrite the commit message to explain this patch. --- arch/arm64/kvm/arm.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index c4d906861736..6f39831dcf5d 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -135,6 +135,26 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) return kvm_vcpu_exiting_guest_mode(vcpu) =3D=3D IN_GUEST_MODE; } =20 +static bool kvm_realm_ext_allowed(long ext) +{ + switch (ext) { + case KVM_CAP_IRQCHIP: + case KVM_CAP_ARM_PSCI: + case KVM_CAP_ARM_PSCI_0_2: + case KVM_CAP_NR_VCPUS: + case KVM_CAP_MAX_VCPUS: + case KVM_CAP_MAX_VCPU_ID: + case KVM_CAP_MSI_DEVID: + case KVM_CAP_ARM_VM_IPA_SIZE: + case KVM_CAP_ARM_PTRAUTH_ADDRESS: + case KVM_CAP_ARM_PTRAUTH_GENERIC: + case KVM_CAP_ARM_RMI: + case KVM_CAP_SYNC_MMU: + return true; + } + return false; +} + int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) { @@ -146,6 +166,9 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, if (is_protected_kvm_enabled() && !kvm_pkvm_ext_allowed(kvm, cap->cap)) return -EINVAL; =20 + if (kvm && kvm_is_realm(kvm) && !kvm_realm_ext_allowed(cap->cap)) + return -EINVAL; + switch (cap->cap) { case KVM_CAP_ARM_NISV_TO_USER: r =3D 0; @@ -380,6 +403,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long = ext) if (is_protected_kvm_enabled() && !kvm_pkvm_ext_allowed(kvm, ext)) return 0; =20 + if (kvm && kvm_is_realm(kvm) && !kvm_realm_ext_allowed(ext)) + return 0; + switch (ext) { case KVM_CAP_IRQCHIP: r =3D vgic_present; --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 774E8415F1B; Mon, 3 Aug 2026 13:45:32 +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=1785764734; cv=none; b=cgxMIYxxUMVVl5ljCJ0SzFkE4gOpsNpkLRecsI3+E7E4wncu3QoLLjrOfLFHlv/RsqFoprqnfmgfS4QROmYrip0YhIRrQi0lcyrkbO8p+3X74kONiR+eEBqbz7cI9ytJ8KDYwtaV4SA22QJKSncGiglpAATwSIPOwb06u3Yx37Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764734; c=relaxed/simple; bh=fpzfERsy2u8KGN3uMqoxXEuQcKvM63ltT7aRUzheLWo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fd13jaRJegbKuqCsBTXpuXO9GoqERRHmPxD5Dx/SH0t4ZDflKGz9BRY+8AWJ5MtEg9KAnlD59GjVxl+ED+LzvLGBFJGEOVeP00/9+/hxFeR5O4cZYR471lXOJOm2vOhz2c58t+EA/+sVmJ6KRTUOlwhCOnm1pQQ5W0bw5j3tysU= 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=qcqA/Zcc; 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="qcqA/Zcc" 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 E76081655; Mon, 3 Aug 2026 06:45:27 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 350B63F66F; Mon, 3 Aug 2026 06:45:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764732; bh=fpzfERsy2u8KGN3uMqoxXEuQcKvM63ltT7aRUzheLWo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qcqA/ZcchKrTFecaMxjpxFmLhay53GZrGNTiFNQWtOwL5hixC3vRsRJuPWlpYu+97 wqDq5GaOrJCQLRpj6RKMZtSyLJ8lG+R4C8dYurJhYT8ug4/lLd/tYk8arS0cQ1V+vA AH6fcpOOsnBuS/pa9TGm9/KOlB94E8nPtDFRrygI= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 16/45] KVM: arm64: CCA: Allow passing the machine type in KVM creation Date: Mon, 3 Aug 2026 14:43:32 +0100 Message-ID: <20260803134403.80630-17-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" Previously machine type was used purely for specifying the physical address size of the guest. Reserve the higher bits to specify an ARM specific machine type and declare a new type 'KVM_VM_TYPE_ARM_REALM' used to create a realm guest. Signed-off-by: Steven Price --- Changes since v15: * Specify the encoding for each VM type in the documentation. Changes since v13: * Rework to use the two top bits for the machine type now that pKVM has merged and used the top bit for KVM_VM_TYPE_ARM_PROTECTED. * Update the documentation to include KVM_VM_TYPE_ARM_PROTECTED as well. Changes since v9: * Explictly set realm.state to REALM_STATE_NONE rather than rely on the zeroing of the structure. Changes since v7: * Add some documentation explaining the new machine type. Changes since v6: * Make the check for kvm_rme_is_available more visible and report an error code of -EPERM (instead of -EINVAL) to make it explicit that the kernel supports RME, but the platform doesn't. --- Documentation/virt/kvm/api.rst | 21 +++++++++++++++++++-- arch/arm64/kvm/arm.c | 11 +++++++++++ include/uapi/linux/kvm.h | 7 ++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index ce588c05b26a..802601eaf560 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -181,8 +181,25 @@ flag KVM_VM_MIPS_VZ. ARM64: ^^^^^^ =20 -On arm64, the physical address size for a VM (IPA Size limit) is limited -to 40bits by default. The limit can be configured if the host supports the +On arm64, the machine type identifier is used to encode a type and the +physical address size for the VM. The lower byte (bits[7:0]) encodes the +address size and the upper bits[31:30] encode a machine type. The machine +types that might be available are: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Type [31:30] Description + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + KVM_VM_TYPE_ARM_NORMAL 0b00 A standard VM + KVM_VM_TYPE_ARM_REALM 0b01 A "realm" VM using the Arm Confiden= tial + Compute extensions, the VM's memory= is + protected from the host. + KVM_VM_TYPE_ARM_PROTECTED 0b10 A "protected" VM using pKVM to + isolate the VM from the host. + Reserved 0b11 Reserved for future use + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The physical address size for a VM (IPA Size limit) is limited to 40bits +by default. The limit can be configured if the host supports the extension KVM_CAP_ARM_VM_IPA_SIZE. When supported, use KVM_VM_TYPE_ARM_IPA_SIZE(IPA_Bits) to set the size in the machine type identifier, where IPA_Bits is the maximum width of any physical diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 6f39831dcf5d..9881fd6c511c 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -249,6 +249,17 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long ty= pe) mutex_unlock(&kvm->lock); #endif =20 + if ((type & KVM_VM_TYPE_ARM_PROTECTED) && + (type & KVM_VM_TYPE_ARM_REALM)) + return -EINVAL; + + if (type & KVM_VM_TYPE_ARM_REALM) { + if (!static_branch_unlikely(&kvm_rmi_is_available)) + return -EINVAL; + kvm_set_realm_state(kvm, REALM_STATE_NONE); + kvm->arch.is_realm =3D true; + } + kvm_init_nested(kvm); =20 ret =3D kvm_share_hyp(kvm, kvm + 1); diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 0231ff174a50..adee3936d6ae 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -700,14 +700,19 @@ struct kvm_enable_cap { * address size for the VM. Bits[7-0] are reserved for the guest * PA size shift (i.e, log2(PA_Size)). For backward compatibility, * value 0 implies the default IPA size, 40bits. + * + * Bits[30-31] are reserved for the VM type */ #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL #define KVM_VM_TYPE_ARM_IPA_SIZE(x) \ ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK) =20 +#define KVM_VM_TYPE_ARM_NORMAL 0 +#define KVM_VM_TYPE_ARM_REALM (1UL << 30) #define KVM_VM_TYPE_ARM_PROTECTED (1UL << 31) #define KVM_VM_TYPE_ARM_MASK (KVM_VM_TYPE_ARM_IPA_SIZE_MASK | \ - KVM_VM_TYPE_ARM_PROTECTED) + KVM_VM_TYPE_ARM_PROTECTED | \ + KVM_VM_TYPE_ARM_REALM) =20 /* * ioctls for /dev/kvm fds: --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8A8D2415F33; Mon, 3 Aug 2026 13:45:36 +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=1785764738; cv=none; b=lqUU1tc5XNFGBLNMTO55PX1RH8yzrstyZpdvD4yIjwJsrrdql01IoxaQLXvSkUqmwz2tuw76g6c9Xx77EG+48Xm1SiU+WByedkEMwCMK/vnlZl8qkcHixsQLXsduDxgSPi3jxT0KFf2numNUZDyR4V4NOPgrwiqTpcMti5Iu1qA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764738; c=relaxed/simple; bh=UC0sk15nLkB2x6MbQ+glyWOmG2CuMdXCu9G86EDctoc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Uq9pdGiUbxjOdlFOHY45/WEqLRMmHGE8IIEqUPjDjcUF/Xng45ZLDLXYz6PbBTS0uwq4wwK1+1XkkqDNNoSPcw2h8HYNtM1NWIwuaGumyuRHN1bOE+1V4cEGNBtWgUal1sXA+suMBPfr0JcsfCeaDDh4swkQ6nxVUXrxolpMSzA= 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=GXRV9FFC; 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="GXRV9FFC" 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 0FEBE1476; Mon, 3 Aug 2026 06:45:32 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 528233F66F; Mon, 3 Aug 2026 06:45:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764736; bh=UC0sk15nLkB2x6MbQ+glyWOmG2CuMdXCu9G86EDctoc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GXRV9FFCpHAL/nNWYMR4A0Pifer71//rKndSiLvg8MQ9m41SboPYvR9V9ERMXGUXs AV8/IDzuhLgEunFBHmWtIgWNXjt6ESJ5wGNw6p2bc2nNYN1d+Q7WUTi8DL5t9NlLA5 2q8VqsHnpHUkwfgM9cG+Sn4v2YLwJGEsnW+Juiks= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 17/45] KVM: arm64: CCA: Tear down RTTs Date: Mon, 3 Aug 2026 14:43:33 +0100 Message-ID: <20260803134403.80630-18-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" The RMM owns the stage 2 page tables for a realm, and KVM must request that the RMM creates/destroys entries as necessary. The physical pages to store the page tables are delegated to the realm as required, and can be undelegated when no longer used. Creating new RTTs is the easy part, tearing down is a little more tricky. The result of realm_rtt_destroy() can be used to effectively walk the tree and destroy the entries (undelegating pages that were given to the realm). Signed-off-by: Steven Price --- Changes since v15: * Propagate negative error codes. Changes since v14: * Teardown is now serialized under config_lock and idempotent. Changes since v13: * Avoid the double call of kvm_free_stage2_pgd() by splitting the work across that and a new function kvm_realm_uninit_stage2() which is only called for realm guests. Changes since v12: * Simplify some functions now we know RMM page size is the same as the host's. Changes since v11: * Moved some code from earlier in the series to this one so that it's added when it's first used. Changes since v10: * RME->RMI rename. * Some code to handle freeing stage 2 PGD moved into this patch where it belongs. Changes since v9: * Add a comment clarifying that root level RTTs are not destroyed until after the RD is destroyed. Changes since v8: * Introduce free_rtt() wrapper which calls free_delegated_granule() followed by kvm_account_pgtable_pages(). This makes it clear where an RTT is being freed rather than just a delegated granule. Changes since v6: * Move rme_rtt_level_mapsize() and supporting defines from kvm_rme.h into rme.c as they are only used in that file. Changes since v5: * Rename some RME_xxx defines to do with page sizes as RMM_xxx - they are a property of the RMM specification not the RME architecture. Changes since v2: * Moved {alloc,free}_delegated_page() and ensure_spare_page() to a later patch when they are actually used. * Some simplifications now rmi_xxx() functions allow NULL as an output parameter. * Improved comments and code layout. --- arch/arm64/include/asm/kvm_rmi.h | 11 ++ arch/arm64/kvm/mmu.c | 17 ++- arch/arm64/kvm/rmi.c | 198 +++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index cefd00b76806..339a9f8c4408 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -56,6 +56,8 @@ enum realm_state { * @sro: Preallocated SRO state context for Realm MMU operations * @state: The lifetime state machine for the realm * @ia_bits: Number of valid Input Address bits in the IPA + * @stage2_unmapped: The Realm stage-2 mappings have been removed + * @rtts_destroyed: The non-root RTTs have been torn down */ struct realm { void *rd; @@ -69,6 +71,8 @@ struct realm { struct rmi_sro_state *sro; enum realm_state state; unsigned int ia_bits; + bool stage2_unmapped; + bool rtts_destroyed; }; =20 void kvm_init_rmi(void); @@ -76,5 +80,12 @@ u32 kvm_rmm_ipa_limit(void); =20 int kvm_init_realm(struct kvm *kvm); void kvm_destroy_realm(struct kvm *kvm); +int kvm_realm_teardown_stage2(struct kvm *kvm); + +static inline bool kvm_realm_is_private_address(struct realm *realm, + unsigned long addr) +{ + return !(addr & BIT(realm->ia_bits - 1)); +} =20 #endif /* __ASM_KVM_RMI_H */ diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 8b9efa8a3539..cd06881c1497 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1060,9 +1060,24 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_= s2_mmu *mmu, unsigned long t return err; } =20 +static void kvm_realm_uninit_stage2(struct kvm_s2_mmu *mmu) +{ + struct kvm *kvm =3D kvm_s2_mmu_to_kvm(mmu); + + mutex_lock(&kvm->arch.config_lock); + if (kvm_realm_state(kvm) =3D=3D REALM_STATE_ACTIVE) { + kvm_set_realm_state(kvm, REALM_STATE_DYING); + WARN_ON(kvm_realm_teardown_stage2(kvm)); + } + mutex_unlock(&kvm->arch.config_lock); +} + void kvm_uninit_stage2_mmu(struct kvm *kvm) { - kvm_free_stage2_pgd(&kvm->arch.mmu); + if (kvm_is_realm(kvm)) + kvm_realm_uninit_stage2(&kvm->arch.mmu); + else + kvm_free_stage2_pgd(&kvm->arch.mmu); kvm_mmu_free_memory_cache(&kvm->arch.mmu.split_page_cache); } =20 diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 528b01d5d71d..4154c6cc1112 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -11,6 +11,14 @@ #include #include =20 +static inline unsigned long rmi_rtt_level_mapsize(int level) +{ + if (WARN_ON(level > KVM_PGTABLE_LAST_LEVEL)) + return PAGE_SIZE; + + return (1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(level)); +} + static bool rmi_has_feature(int reg, unsigned long feature) { return !!u64_get_bits(rmi_feat_reg(reg), feature); @@ -21,11 +29,189 @@ u32 kvm_rmm_ipa_limit(void) return u64_get_bits(rmi_feat_reg(0), RMI_FEATURE_REGISTER_0_S2SZ); } =20 +static int get_start_level(struct realm *realm) +{ + return 4 - stage2_pgtable_levels(realm->ia_bits); +} + +static void free_rtt(phys_addr_t phys) +{ + if (free_delegated_page(phys)) + return; + + kvm_account_pgtable_pages(phys_to_virt(phys), -1); +} + +/* + * realm_rtt_destroy - Destroy an RTT at @level for @addr. + * + * Returns - Result of the RMI_RTT_DESTROY call, and: + * @rtt_granule: RTT granule, if the RTT was destroyed. + * @next_addr: IPA corresponding to the next possible valid entry we + * can target + */ +static long realm_rtt_destroy(struct realm *realm, unsigned long addr, + int level, phys_addr_t *rtt_granule, + unsigned long *next_addr) +{ + unsigned long out_rtt; + long ret; + + ret =3D rmi_rtt_destroy(virt_to_phys(realm->rd), addr, level, + &out_rtt, next_addr); + + *rtt_granule =3D out_rtt; + + return ret; +} + +static int realm_tear_down_rtt_level(struct realm *realm, int level, + unsigned long start, unsigned long end) +{ + ssize_t map_size; + unsigned long addr, next_addr; + + if (WARN_ON(level > KVM_PGTABLE_LAST_LEVEL)) + return -EINVAL; + + map_size =3D rmi_rtt_level_mapsize(level - 1); + + for (addr =3D start; addr < end; addr =3D next_addr) { + phys_addr_t rtt_granule; + long ret; + unsigned long align_addr =3D ALIGN(addr, map_size); + + next_addr =3D ALIGN(addr + 1, map_size); + + if (next_addr > end || align_addr !=3D addr) { + /* + * The target range is smaller than what this level + * covers, recurse deeper. + */ + ret =3D realm_tear_down_rtt_level(realm, + level + 1, + addr, + min(next_addr, end)); + if (ret) + return ret; + continue; + } + + ret =3D realm_rtt_destroy(realm, addr, level, + &rtt_granule, &next_addr); + if (ret < 0) + return ret; + + switch (RMI_RETURN_STATUS(ret)) { + case RMI_SUCCESS: + free_rtt(rtt_granule); + break; + case RMI_ERROR_RTT: + if (next_addr > addr) { + /* Missing RTT, skip */ + break; + } + /* + * We tear down the RTT range for the full IPA + * space, after everything is unmapped. Also we + * descend down only if we cannot tear down a + * top level RTT. Thus RMM must be able to walk + * to the requested level. e.g., a block mapping + * exists at L1 or L2. + */ + if (WARN_ON(RMI_RETURN_INDEX(ret) !=3D level)) + return -EBUSY; + if (WARN_ON(level =3D=3D KVM_PGTABLE_LAST_LEVEL)) + return -EBUSY; + + /* + * The table has active entries in it, recurse deeper + * and tear down the RTTs. + */ + next_addr =3D ALIGN(addr + 1, map_size); + ret =3D realm_tear_down_rtt_level(realm, + level + 1, + addr, + next_addr); + if (ret) + return ret; + /* + * Now that the child RTTs are destroyed, + * retry at this level. + */ + next_addr =3D addr; + break; + default: + WARN_ON(1); + return -ENXIO; + } + } + + return 0; +} + +static int realm_tear_down_rtt_range(struct realm *realm, + unsigned long start, unsigned long end) +{ + /* + * Root level RTTs can only be destroyed after the RD is destroyed. So + * tear down everything below the root level + */ + return realm_tear_down_rtt_level(realm, get_start_level(realm) + 1, + start, end); +} + +static int realm_destroy_rtts(struct kvm *kvm) +{ + struct realm *realm =3D &kvm->arch.realm; + unsigned int ia_bits =3D realm->ia_bits; + int ret; + + lockdep_assert_held(&kvm->arch.config_lock); + + if (realm->rtts_destroyed) + return 0; + + ret =3D realm_tear_down_rtt_range(realm, 0, (1UL << ia_bits)); + if (ret) + return ret; + + realm->rtts_destroyed =3D true; + return 0; +} + +static void realm_unmap_stage2(struct kvm *kvm) +{ + struct realm *realm =3D &kvm->arch.realm; + + lockdep_assert_held(&kvm->arch.config_lock); + + if (realm->stage2_unmapped) + return; + + write_lock(&kvm->mmu_lock); + kvm_stage2_unmap_range(&kvm->arch.mmu, 0, + BIT(realm->ia_bits - 1), true); + write_unlock(&kvm->mmu_lock); + + realm->stage2_unmapped =3D true; +} + +int kvm_realm_teardown_stage2(struct kvm *kvm) +{ + lockdep_assert_held(&kvm->arch.config_lock); + + realm_unmap_stage2(kvm); + return realm_destroy_rtts(kvm); +} + void kvm_destroy_realm(struct kvm *kvm) { struct realm *realm =3D &kvm->arch.realm; size_t pgd_size =3D kvm_pgtable_stage2_pgd_size(kvm->arch.mmu.vtcr); =20 + guard(mutex)(&kvm->arch.config_lock); + if (!kvm_realm_is_created(kvm)) { kfree(realm->sro); realm->sro =3D NULL; @@ -34,12 +220,24 @@ void kvm_destroy_realm(struct kvm *kvm) =20 kvm_set_realm_state(kvm, REALM_STATE_DYING); =20 + /* + * REALM_DESTROY requires the realm to be non-live: all RECs must have + * been destroyed and the root RTTs must be empty. Unmap the IPA space + * and destroy any non-root RTTs before tearing down the RD. The root + * RTT pages are still owned by the RMM at this point, so keep the KVM + * pgtable alive until after REALM_DESTROY and undelegation. + */ + realm_unmap_stage2(kvm); + if (realm->rd) { phys_addr_t rd_phys =3D virt_to_phys(realm->rd); =20 if (WARN_ON(rmi_realm_terminate(rd_phys, realm->sro))) return; =20 + if (WARN_ON(realm_destroy_rtts(kvm))) + return; + if (WARN_ON(rmi_realm_destroy(rd_phys, realm->sro))) return; free_delegated_page(rd_phys); --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 881564279F8; Mon, 3 Aug 2026 13:45:41 +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=1785764743; cv=none; b=VGwj+RWMmwkM+GQE58w+ZhZfZ8ExBtXjVKG/4X4rEKqJLHP74f4ucaO1rPjtwWdg6W9K7giTldLI52LFukx9RlSV1GGVwVWoaHuBzGKMesh5t5FuiGFNnIjVyTXbeicbU+KSFUUCDM4jnBNdGauBsk1oSrU45XF2z1sY02qGUcs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764743; c=relaxed/simple; bh=sAsN6eSDXeVqmO6cS4TqVq5CroV3r+4L1qYoCWFOJFY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XD0bmYrx2nIyGDnkn2asrFtJOKbD0L5aGqUzU6wKWmJboIvOPpBIGRECl6UfFKlsYICor7cacNQ4P8YtPh0UIgU2Ogc7Fe1P7gchbo24mlyx9LhiQ3yOQmb0tG6R9tTe/XFxlJ6eFH71Xs2l0f0BegIZcRTLYiLNBP6+rTQS7QQ= 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=fUfh5Igr; 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="fUfh5Igr" 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 13A441476; Mon, 3 Aug 2026 06:45:37 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 7528A3F66F; Mon, 3 Aug 2026 06:45:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764741; bh=sAsN6eSDXeVqmO6cS4TqVq5CroV3r+4L1qYoCWFOJFY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fUfh5IgrUx/qRDkG1GOjP1F0gzbo6mbOkFiti7p0nym7XtX9iDuqXWk2w6EKd9ByC sxvOYNXZQmT6hOMB5iqZ6dW+aBOeAvcd5thiOqctp26Go+j6qDsHE/B8WyIB87Luaj YVjOp/2+n31qThLwxwtnEp4habpou/GlS01eKnzE= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 18/45] KVM: arm64: CCA: Allocate and free RECs to match vCPUs Date: Mon, 3 Aug 2026 14:43:34 +0100 Message-ID: <20260803134403.80630-19-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" The RMM maintains a data structure known as the Realm Execution Context (or REC). It is similar to struct kvm_vcpu and tracks the state of the virtual CPUs. KVM must delegate memory and request the structures are created when vCPUs are created, and suitably tear down on destruction. RECs may require additional pages (e.g. for storing larger register state for SVE). The RMM can request extra pages for this purpose using the Stateful RMI Operations (SRO) functionality to request pages during REC creation. These pages are then passed back to the host from the RMM ('reclaimed') when the REC is destroyed. The kernel tracking object (struct rmi_sro_state) is stored in the realm_rec structure to avoid memory allocation during the destruction path. Note that only some of register state for the REC can be set by KVM, the rest is defined by the RMM (zeroed). The register state then cannot be changed by KVM after the REC is created (except when the guest explicitly requests this e.g. by performing a PSCI call). Note that the function kvm_create_rec() is unused at this point, a future patch will add the call and remove the __maybe_unused attribute. Signed-off-by: Steven Price --- Changes since v15: * Propagate negative error code in kvm_create_rec(). Changes since v14: * Handle partial REC creation better by NULLing rec->run, rec->rec_page and rec->sro when freeing. Changes since v13: * Support SRO for REC creation/destruction instead of auxiliary granules. Changes since v12: * Use the new range-based delegation RMI. Changes since v11: * Remove the KVM_ARM_VCPU_REC feature. User space no longer needs to configure each VCPU separately, RECs are created on the first VCPU run of the guest. Changes since v9: * Size the aux_pages array according to the PAGE_SIZE of the host. Changes since v7: * Add comment explaining the aux_pages array. * Rename "undeleted_failed" variable to "should_free" to avoid a confusing double negative. Changes since v6: * Avoid reporting the KVM_ARM_VCPU_REC feature if the guest isn't a realm guest. * Support host page size being larger than RMM's granule size when allocating/freeing aux granules. Changes since v5: * Separate the concept of vcpu_is_rec() and kvm_arm_vcpu_rec_finalized() by using the KVM_ARM_VCPU_REC feature as the indication that the VCPU is a REC. Changes since v2: * Free rec->run earlier in kvm_destroy_realm() and adapt to previous patch= es. --- arch/arm64/include/asm/kvm_emulate.h | 5 ++ arch/arm64/include/asm/kvm_host.h | 3 + arch/arm64/include/asm/kvm_rmi.h | 20 ++++++ arch/arm64/kvm/arm.c | 6 ++ arch/arm64/kvm/reset.c | 1 + arch/arm64/kvm/rmi.c | 103 +++++++++++++++++++++++++++ 6 files changed, 138 insertions(+) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/= kvm_emulate.h index e26d6755279f..2e69fe494716 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -712,4 +712,9 @@ static inline bool kvm_realm_is_created(struct kvm *kvm) return kvm_is_realm(kvm) && kvm_realm_state(kvm) !=3D REALM_STATE_NONE; } =20 +static inline bool vcpu_is_rec(const struct kvm_vcpu *vcpu) +{ + return kvm_is_realm(vcpu->kvm); +} + #endif /* __ARM64_KVM_EMULATE_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm= _host.h index 1a5e15040111..9b46b39ed11e 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -949,6 +949,9 @@ struct kvm_vcpu_arch { =20 /* Hyp-readable copy of kvm_vcpu::pid */ pid_t pid; + + /* Realm meta data */ + struct realm_rec rec; }; =20 /* diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 339a9f8c4408..3bffd021ca26 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -75,12 +75,32 @@ struct realm { bool rtts_destroyed; }; =20 +/** + * struct realm_rec - Additional per VCPU data for a Realm + * + * @mpidr: MPIDR (Multiprocessor Affinity Register) value to identify this= VCPU + * @rec_page: Kernel VA of the RMM's private page for this REC + * @rec_phys: Physical address of @rec_page + * @run: Kernel VA of the RmiRecRun structure shared with the RMM + * @run_phys: Physical address of @run + * @sro: A preallocated SRO state context + */ +struct realm_rec { + unsigned long mpidr; + void *rec_page; + phys_addr_t rec_phys; + struct rec_run *run; + phys_addr_t run_phys; + struct rmi_sro_state *sro; +}; + void kvm_init_rmi(void); u32 kvm_rmm_ipa_limit(void); =20 int kvm_init_realm(struct kvm *kvm); void kvm_destroy_realm(struct kvm *kvm); int kvm_realm_teardown_stage2(struct kvm *kvm); +void kvm_destroy_rec(struct kvm_vcpu *vcpu); =20 static inline bool kvm_realm_is_private_address(struct realm *realm, unsigned long addr) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 9881fd6c511c..38fac98cd6a4 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -589,6 +589,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) /* Force users to call KVM_ARM_VCPU_INIT */ vcpu_clear_flag(vcpu, VCPU_INITIALIZED); =20 + vcpu->arch.rec.mpidr =3D INVALID_HWID; + vcpu->arch.mmu_page_cache.gfp_zero =3D __GFP_ZERO; =20 /* Set up the timer */ @@ -1668,6 +1670,10 @@ static int kvm_vcpu_init_check_features(struct kvm_v= cpu *vcpu, if (test_bit(KVM_ARM_VCPU_HAS_EL2, &features)) return -EINVAL; =20 + /* Realms are incompatible with AArch32 */ + if (vcpu_is_rec(vcpu)) + return -EINVAL; + return 0; } =20 diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index b963fd975aac..c18cdca7d125 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -161,6 +161,7 @@ void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu) free_page((unsigned long)vcpu->arch.ctxt.vncr_array); kfree(vcpu->arch.vncr_tlb); kfree(vcpu->arch.ccsidr); + kvm_destroy_rec(vcpu); } =20 static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 4154c6cc1112..f6686287119d 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -205,6 +205,109 @@ int kvm_realm_teardown_stage2(struct kvm *kvm) return realm_destroy_rtts(kvm); } =20 +static int __maybe_unused kvm_create_rec(struct kvm_vcpu *vcpu) +{ + struct user_pt_regs *vcpu_regs =3D vcpu_gp_regs(vcpu); + unsigned long mpidr =3D kvm_vcpu_get_mpidr_aff(vcpu); + struct realm *realm =3D &vcpu->kvm->arch.realm; + struct realm_rec *rec =3D &vcpu->arch.rec; + struct rec_params *params; + long rmi_ret; + int r, i; + + if (rec->run) + return -EBUSY; + + /* + * The RMM will report PSCI v1.0 to Realms and the KVM_ARM_VCPU_PSCI_0_2 + * flag covers v0.2 and onwards. + */ + if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_PSCI_0_2)) + return -EINVAL; + + BUILD_BUG_ON(sizeof(*params) > PAGE_SIZE); + BUILD_BUG_ON(sizeof(*rec->run) > PAGE_SIZE); + + params =3D (struct rec_params *)get_zeroed_page(GFP_KERNEL); + rec->rec_page =3D (void *)__get_free_page(GFP_KERNEL); + rec->run =3D (struct rec_run *)get_zeroed_page(GFP_KERNEL); + rec->sro =3D kmalloc_obj(*rec->sro); + if (!params || !rec->rec_page || !rec->run || !rec->sro) { + r =3D -ENOMEM; + goto out_free_pages; + } + + for (i =3D 0; i < ARRAY_SIZE(params->gprs); i++) + params->gprs[i] =3D vcpu_regs->regs[i]; + + params->pc =3D vcpu_regs->pc; + + if (vcpu->vcpu_id =3D=3D 0) + params->flags |=3D REC_PARAMS_FLAG_RUNNABLE; + + rec->rec_phys =3D virt_to_phys(rec->rec_page); + rec->run_phys =3D virt_to_phys(rec->run); + + if (rmi_delegate_page(rec->rec_phys)) { + r =3D -ENXIO; + goto out_free_pages; + } + + params->mpidr =3D mpidr; + + rmi_ret =3D rmi_rec_create(virt_to_phys(realm->rd), rec->rec_phys, + virt_to_phys(params), rec->sro); + if (rmi_ret) { + r =3D rmi_ret < 0 ? rmi_ret : -ENXIO; + goto out_undelegate_rmm_rec; + } + + rec->mpidr =3D mpidr; + + free_page((unsigned long)params); + return 0; + +out_undelegate_rmm_rec: + if (WARN_ON(rmi_undelegate_page(rec->rec_phys))) + rec->rec_page =3D NULL; +out_free_pages: + free_page((unsigned long)rec->run); + free_page((unsigned long)rec->rec_page); + free_page((unsigned long)params); + kfree(rec->sro); + rec->run =3D NULL; + rec->rec_page =3D NULL; + rec->rec_phys =3D 0; + rec->run_phys =3D 0; + rec->sro =3D NULL; + return r; +} + +void kvm_destroy_rec(struct kvm_vcpu *vcpu) +{ + struct realm_rec *rec =3D &vcpu->arch.rec; + + if (!vcpu_is_rec(vcpu)) + return; + + if (!rec->run) { + /* Nothing to do if the VCPU hasn't been finalized */ + return; + } + + if (WARN_ON(rmi_rec_destroy(rec->rec_phys, rec->sro))) + return; + + free_page((unsigned long)rec->run); + kfree(rec->sro); + free_delegated_page(rec->rec_phys); + rec->run =3D NULL; + rec->sro =3D NULL; + rec->rec_page =3D NULL; + rec->rec_phys =3D 0; + rec->run_phys =3D 0; +} + void kvm_destroy_realm(struct kvm *kvm) { struct realm *realm =3D &kvm->arch.realm; --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 10C76429CC2; Mon, 3 Aug 2026 13:45:47 +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=1785764748; cv=none; b=Ks5RJvcbVE9wJ3WYtt6szHna+6Zn+ISg1XLGd66vsTkuF2V6+7uDEcsCd8/MYyy+vF0WRvzwYNln5E340paE+5EJ88hRWBNNXeGHnA+WNoBVhH+sFLjxnmi3uaKGW9zm5sjm36XaJwxCGvSSiqxyx+Hh56TYj2jgh/E1ktfldH8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764748; c=relaxed/simple; bh=ygMs2UwnCR4SgJLKpQ2BcHIDquX9SduxRcKHFIS1oyk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BDQIzLmQJXFbGA1luLzF+UVlHAAZc4INbS7Bjx8q2jG8ss0OsDH0Xxrn2Q9MMzvBza6yGgaTuXLPzDy4ksdDPe3O45gJlK8pw3zV4wMt0VLIjRFj76OHis2bYeCsm17vs6yl/xqY7iZUvYI+91EBxrRv6jEtRnPMJPChc4If4Vg= 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=IFdZVPkQ; 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="IFdZVPkQ" 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 73099165C; Mon, 3 Aug 2026 06:45:42 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 824263F66F; Mon, 3 Aug 2026 06:45:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764746; bh=ygMs2UwnCR4SgJLKpQ2BcHIDquX9SduxRcKHFIS1oyk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IFdZVPkQ9XZly09cJiv5cEFhJmjaW6ajlfUATI2q0NVE48VuyoBhxn7cJ4+gPoPuW cJ4JPm819wSUfmVaNb2fB+8DKtQmyy36L91NevrgU1uOhUozWX0aO5C6N2zSXs5Ofr h56m5TWegwC5X9+GYcfYncyeThv3h2SaV6Q4MuTU= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 19/45] KVM: arm64: CCA: Support the VGIC in realms Date: Mon, 3 Aug 2026 14:43:35 +0100 Message-ID: <20260803134403.80630-20-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" The RMM provides emulation of a VGIC to the realm guest. With RMM v2.0 the registers are passed in the system registers so this works similar to a normal guest, but kvm_arch_vcpu_put() need reordering to early out, and realm guests don't support GICv2 even if the host does. Signed-off-by: Steven Price --- Changes from v12: * GIC registers are now passed in the system registers rather than via rec_entry/rec_exit which removes most of the changes. Changes from v11: * Minor changes to align with the previous patches. Note that the VGIC handling will change with RMM v2.0. Changes from v10: * Make sure we sync the VGIC v4 state, and only populate valid lrs from the list. Changes from v9: * Copy gicv3_vmcr from the RMM at the same time as gicv3_hcr rather than having to handle that as a special case. Changes from v8: * Propagate gicv3_hcr to from the RMM. Changes from v5: * Handle RMM providing fewer GIC LRs than the hardware supports. --- arch/arm64/kvm/arm.c | 11 ++++++++--- arch/arm64/kvm/vgic/vgic-init.c | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 38fac98cd6a4..2959a1451232 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -791,19 +791,24 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_call_hyp_nvhe(__pkvm_vcpu_put); } =20 + kvm_timer_vcpu_put(vcpu); + kvm_vgic_put(vcpu); kvm_vcpu_put_debug(vcpu); + + vcpu->cpu =3D -1; + + if (vcpu_is_rec(vcpu)) + return; + kvm_arch_vcpu_put_fp(vcpu); if (has_vhe()) kvm_vcpu_put_vhe(vcpu); - kvm_timer_vcpu_put(vcpu); - kvm_vgic_put(vcpu); kvm_vcpu_pmu_restore_host(vcpu); if (vcpu_has_nv(vcpu)) kvm_vcpu_put_hw_mmu(vcpu); kvm_arm_vmid_clear_active(); =20 vcpu_clear_on_unsupported_cpu(vcpu); - vcpu->cpu =3D -1; } =20 static void __kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-ini= t.c index 907057881b26..fd77db35ef02 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -81,7 +81,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) * the proper checks already. */ if (type =3D=3D KVM_DEV_TYPE_ARM_VGIC_V2 && - !kvm_vgic_global_state.can_emulate_gicv2) + (!kvm_vgic_global_state.can_emulate_gicv2 || kvm_is_realm(kvm))) return -ENODEV; =20 /* --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 00855429CEB; Mon, 3 Aug 2026 13:45:52 +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=1785764753; cv=none; b=gDUtxZdiYrMMaIZKNv6QEJwkB/wCoYWVQ0m3D9AQS0xSHbd6RVkxAzzecMPoF6knOpusbAZ1td7gwkYfmt27X4iAO7c6PPH7zlVAUo43op66gDyBY4zLs95HJIVSE8PSbTLSgsyJLxASRmCWUxffOWs01gk0k2DXNWCPbh3XQiY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764753; c=relaxed/simple; bh=+to7CADPvNbqpJgbAHoG4amNfn4k084irx3hyn1zoX8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TfmMFq0g1pHUn4gzjxgYq8VNC/RGhn+C3kX+nKphdRw6H9dIyyMYeC2ae8Ca+0l4flUKDxGN4RBfPjfkG1rbLEv///VZtjL115zDUKtq1E90KL4oz0w4uk5IWYEhrYoCk5edX146mwiVwJw3EQbFiwkP7zukhzhmFYYcWW6TtpY= 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=qjpJ8LBk; 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="qjpJ8LBk" 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 625241476; Mon, 3 Aug 2026 06:45:47 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id EACBD3F66F; Mon, 3 Aug 2026 06:45:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764751; bh=+to7CADPvNbqpJgbAHoG4amNfn4k084irx3hyn1zoX8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qjpJ8LBkfQDODk2ibY1YVPZOPNdSLZLrSU45GUaFsaOu+TM1kibD7zJdPPhSXD3a4 VdUElxRYvW7rZH2EO5bOr4vNNpQY38Y24fETfZdZ4ClG0io6GYheVdNAH+BUmD9NdV AVFMc3TwDyy/3pvYge3rYsVad/MGLmBIEie49u2Q= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 20/45] KVM: arm64: CCA: Support timers in realm RECs Date: Mon, 3 Aug 2026 14:43:36 +0100 Message-ID: <20260803134403.80630-21-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" The RMM keeps track of the timer while the realm REC is running, but on exit to the normal world KVM is responsible for handling the timers. A later patch adds the support for propagating the timer values from the exit data structure and calling kvm_realm_timers_update(). Signed-off-by: Steven Price --- Changes since v15: * Major rewrite to make better use of the KVM infrastructure. Changes since v14: * Special case in kvm_timer_vcpu_load()/kvm_timer_vcpu_put() the timer handling. Changes since v12: * Adapt to upstream changes. Changes since v11: * Drop the kvm_is_realm() check from timer_set_offset(). We already ensure that the offset is 0 when calling the function. Changes since v10: * KVM_CAP_COUNTER_OFFSET is now already hidden by a previous patch. Changes since v9: * No need to move the call to kvm_timer_unblocking() in kvm_timer_vcpu_load(). Changes since v7: * Hide KVM_CAP_COUNTER_OFFSET for realm guests. --- arch/arm64/kvm/arch_timer.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 4155fe89b58a..00ff182ae288 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -56,11 +56,22 @@ static unsigned long kvm_arch_timer_get_irq_flags(void) return kvm_vgic_global_state.no_hw_deactivation ? VGIC_IRQ_SW_RESAMPLE : = 0; } =20 +static unsigned long kvm_realm_timer_get_irq_flags(void) +{ + /* RMI_REC_ENTER rejects LRs which have the HW bit set. */ + return VGIC_IRQ_SW_RESAMPLE; +} + static const struct irq_ops arch_timer_irq_ops =3D { .get_flags =3D kvm_arch_timer_get_irq_flags, .get_input_level =3D kvm_arch_timer_get_input_level, }; =20 +static const struct irq_ops realm_timer_irq_ops =3D { + .get_flags =3D kvm_realm_timer_get_irq_flags, + .get_input_level =3D kvm_arch_timer_get_input_level, +}; + static const struct irq_ops arch_timer_irq_ops_vgic_v5 =3D { .get_input_level =3D kvm_arch_timer_get_input_level, .queue_irq_unlock =3D vgic_v5_ppi_queue_irq_unlock, @@ -1073,7 +1084,8 @@ static void timer_context_init(struct kvm_vcpu *vcpu,= int timerid) =20 ctxt->timer_id =3D timerid; =20 - if (!kvm_vm_is_protected(vcpu->kvm)) { + /* The RMM architecture fixes both Realm counter offsets at zero. */ + if (!kvm_vm_is_protected(vcpu->kvm) && !vcpu_is_rec(vcpu)) { if (timerid =3D=3D TIMER_VTIMER) ctxt->offset.vm_offset =3D &kvm->arch.timer_data.voffset; else @@ -1103,8 +1115,11 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) for (int i =3D 0; i < NR_KVM_TIMERS; i++) timer_context_init(vcpu, i); =20 - /* Synchronize offsets across timers of a VM if not already provided */ - if (!vcpu_is_protected(vcpu) && + /* + * Synchronize offsets across timers of a VM if not already provided. + * Realm counter offsets are fixed at zero by the RMM architecture. + */ + if (!vcpu_is_protected(vcpu) && !vcpu_is_rec(vcpu) && !test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &vcpu->kvm->arch.flags)) { timer_set_offset(vcpu_vtimer(vcpu), kvm_phys_timer_read()); timer_set_offset(vcpu_ptimer(vcpu), 0); @@ -1602,8 +1617,15 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu) =20 get_timer_map(vcpu, &map); =20 - ops =3D vgic_is_v5(vcpu->kvm) ? &arch_timer_irq_ops_vgic_v5 : - &arch_timer_irq_ops; + /* + * RMI_REC_ENTER rejects LRs with the HW bit set, so use the existing + * software resampling mechanism for Realm timer interrupts. + */ + if (vcpu_is_rec(vcpu)) + ops =3D &realm_timer_irq_ops; + else + ops =3D vgic_is_v5(vcpu->kvm) ? &arch_timer_irq_ops_vgic_v5 : + &arch_timer_irq_ops; =20 for (int i =3D 0; i < nr_timers(vcpu); i++) kvm_vgic_set_irq_ops(vcpu, timer_irq(vcpu_get_timer(vcpu, i)), ops); @@ -1729,7 +1751,7 @@ int kvm_vm_ioctl_set_counter_offset(struct kvm *kvm, if (offset->reserved) return -EINVAL; =20 - if (kvm_vm_is_protected(kvm)) + if (kvm_vm_is_protected(kvm) || kvm_is_realm(kvm)) return -EINVAL; =20 mutex_lock(&kvm->lock); --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id F2A9741687C; Mon, 3 Aug 2026 13:45:56 +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=1785764759; cv=none; b=Cr/8PoBGZi6aSWB5/AosN653sjQSkc8me1X35ka2/e1PhfNmzQMNsCBpyhSa+P9abHkFvA5Lh05rmucLliBEz5p6bIWF9q5gm3kFsSBuGWTNWRbPrYFIruXyW02GFBrrBuh4TRjrapCNGrKLtERN81EDUtI7tGEEX4tvxIkhiUE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764759; c=relaxed/simple; bh=cqTMhbIa83aTp8kjyG4T8WMTL8yZoAVg00R6YVLJmZI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jco/l9nC927dbD59hbaKC3OK/EtFu7JprAsItVHElBmZHaN4TWwqWvMbNXFlYY7JwwUfWI+nazNicHOYKa3L44wQAeCYKmvumNeiObs+RXsf9mpj492/z7e5YJjXTJUmSQE1SjScrKCakxHXILDVrc05PpyG703U84TEofbN9Xo= 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=i4+tXJAj; 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="i4+tXJAj" 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 3713F1655; Mon, 3 Aug 2026 06:45:52 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id EDACE3F66F; Mon, 3 Aug 2026 06:45:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764756; bh=cqTMhbIa83aTp8kjyG4T8WMTL8yZoAVg00R6YVLJmZI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=i4+tXJAjFHb55f2Gt6txuXNwITpvEw1nXFfpdXjzblsiuZtqAWxbgal+L2hB53gzV rmOcxYWafOItfT6SSWD+7SO7SRIp9PJ8Bl17wTNDn6JBsp7CZ6VaEUc/w0uywWRbZc 8RTy91TMVBPVA9tbPCsINOc9/UXFKdR3p2Mg6B/Q= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 21/45] KVM: arm64: CCA: Handle realm enter/exit Date: Mon, 3 Aug 2026 14:43:37 +0100 Message-ID: <20260803134403.80630-22-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" Entering a realm is done using a SMC call to the RMM. On exit the exit-codes need to be handled slightly differently to the normal KVM path so define our own functions for realm enter/exit and hook them in if the guest is a realm guest. Signed-off-by: Steven Price --- Changes since v15: * Major rewrite to use KVM requests and fit in better with the existing KVM code. Changes since v13: * The RMM is now required to provide an ESR value with the correct information to emulate MMIO, so we no longer need to hardcode 0s in rec_exit_sys_reg(). * The PSCI changes mean that there is a potential race when turning on a VCPU which can cause a RMI_ERROR_REC return. Exit to user space with -EAGAIN in this case. Changes since v12: * Call guest_state_{enter,exit}_irqoff() around rmi_rec_enter(). * Add handling of the IRQ exception case where IRQs need to be briefly enabled before exiting guest timing. Changes since v8: * Introduce kvm_rec_pre_enter() called before entering an atomic section to handle operations that might require memory allocation (specifically completing a RIPAS change introduced in a later patch). * Updates to align with upstream changes to hpfar_el2 which now (ab)uses HPFAR_EL2_NS as a valid flag. * Fix exit reason when racing with PSCI shutdown to return KVM_EXIT_SHUTDOWN rather than KVM_EXIT_UNKNOWN. Changes since v7: * A return of 0 from kvm_handle_sys_reg() doesn't mean the register has been read (although that can never happen in the current code). Tidy up the condition to handle any future refactoring. Changes since v6: * Use vcpu_err() rather than pr_err/kvm_err when there is an associated vcpu to the error. * Return -EFAULT for KVM_EXIT_MEMORY_FAULT as per the documentation for this exit type. * Split code handling a RIPAS change triggered by the guest to the following patch. Changes since v5: * For a RIPAS_CHANGE request from the guest perform the actual RIPAS change on next entry rather than immediately on the exit. This allows the VMM to 'reject' a RIPAS change by refusing to continue scheduling. Changes since v4: * Rename handle_rme_exit() to handle_rec_exit() * Move the loop to copy registers into the REC enter structure from the to rec_exit_handlers callbacks to kvm_rec_enter(). This fixes a bug where the handler exits to user space and user space wants to modify the GPRS. * Some code rearrangement in rec_exit_ripas_change(). Changes since v2: * realm_set_ipa_state() now provides an output parameter for the top_iap that was changed. Use this to signal the VMM with the correct range that has been transitioned. * Adapt to previous patch changes. --- arch/arm64/include/asm/kvm_asm.h | 2 + arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/include/asm/kvm_rmi.h | 5 + arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/arm.c | 18 +++- arch/arm64/kvm/handle_exit.c | 14 +++ arch/arm64/kvm/rmi-exit.c | 167 ++++++++++++++++++++++++++++++ arch/arm64/kvm/rmi.c | 56 ++++++++++ 8 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/kvm/rmi-exit.c diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_= asm.h index 043495f7fc78..0629851e1114 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -21,6 +21,7 @@ #define ARM_EXCEPTION_EL1_SERROR 1 #define ARM_EXCEPTION_TRAP 2 #define ARM_EXCEPTION_IL 3 +#define ARM_EXCEPTION_EXIT 4 /* The hyp-stub will return this for any kvm_call_hyp() call */ #define ARM_EXCEPTION_HYP_GONE HVC_STUB_ERR =20 @@ -28,6 +29,7 @@ {ARM_EXCEPTION_IRQ, "IRQ" }, \ {ARM_EXCEPTION_EL1_SERROR, "SERROR" }, \ {ARM_EXCEPTION_TRAP, "TRAP" }, \ + {ARM_EXCEPTION_EXIT, "EXIT" }, \ {ARM_EXCEPTION_HYP_GONE, "HYP_GONE" } =20 /* diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm= _host.h index 9b46b39ed11e..15d42d1993bb 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -56,6 +56,7 @@ #define KVM_REQ_GUEST_HYP_IRQ_PENDING KVM_ARCH_REQ(9) #define KVM_REQ_MAP_L1_VNCR_EL2 KVM_ARCH_REQ(10) #define KVM_REQ_VGIC_PROCESS_UPDATE KVM_ARCH_REQ(11) +#define KVM_REQ_RMI KVM_ARCH_REQ(12) =20 #define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE |= \ KVM_DIRTY_LOG_INITIALLY_SET) diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 3bffd021ca26..1e5026039458 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -102,6 +102,11 @@ void kvm_destroy_realm(struct kvm *kvm); int kvm_realm_teardown_stage2(struct kvm *kvm); void kvm_destroy_rec(struct kvm_vcpu *vcpu); =20 +int kvm_rec_enter(struct kvm_vcpu *vcpu); +int kvm_rec_exit(struct kvm_vcpu *vcpu, int rec_run_status); +int kvm_rec_handle_request(struct kvm_vcpu *vcpu); +bool kvm_rec_handle_hvc(struct kvm_vcpu *vcpu, int *ret); + static inline bool kvm_realm_is_private_address(struct realm *realm, unsigned long addr) { diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index ed3cf30eb06e..4a2d52fdb6a2 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -16,7 +16,7 @@ CFLAGS_handle_exit.o +=3D -Wno-override-init kvm-y +=3D arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \ inject_fault.o va_layout.o handle_exit.o config.o \ guest.o debug.o reset.o sys_regs.o stacktrace.o \ - vgic-sys-reg-v3.o fpsimd.o pkvm.o rmi.o \ + vgic-sys-reg-v3.o fpsimd.o pkvm.o rmi.o rmi-exit.o \ arch_timer.o trng.o vmid.o emulate-nested.o nested.o at.o \ vgic/vgic.o vgic/vgic-init.o \ vgic/vgic-irqfd.o vgic/vgic-v2.o \ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 2959a1451232..3ad2f1d5b9e2 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1206,6 +1206,13 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu) if (kvm_check_request(KVM_REQ_SUSPEND, vcpu)) return kvm_vcpu_suspend(vcpu); =20 + if (kvm_check_request(KVM_REQ_RMI, vcpu)) { + int ret =3D kvm_rec_handle_request(vcpu); + + if (ret <=3D 0) + return ret; + } + if (kvm_dirty_ring_check_request(vcpu)) return 0; =20 @@ -1291,9 +1298,18 @@ static int noinstr kvm_arm_vcpu_enter_exit(struct kv= m_vcpu *vcpu) int ret; =20 guest_state_enter_irqoff(); - ret =3D kvm_call_hyp_ret(__kvm_vcpu_run, vcpu); + if (vcpu_is_rec(vcpu)) + ret =3D kvm_rec_enter(vcpu); + else + ret =3D kvm_call_hyp_ret(__kvm_vcpu_run, vcpu); guest_state_exit_irqoff(); =20 + if (vcpu_is_rec(vcpu)) { + instrumentation_begin(); + ret =3D kvm_rec_exit(vcpu, ret); + instrumentation_end(); + } + return ret; } =20 diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 54aedf93c78b..6950188efc68 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -37,10 +38,15 @@ static void kvm_handle_guest_serror(struct kvm_vcpu *vc= pu, u64 esr) =20 static int handle_hvc(struct kvm_vcpu *vcpu) { + int ret; + trace_kvm_hvc_arm64(*vcpu_pc(vcpu), vcpu_get_reg(vcpu, 0), kvm_vcpu_hvc_get_imm(vcpu)); vcpu->stat.hvc_exit_stat++; =20 + if (kvm_rec_handle_hvc(vcpu, &ret)) + return ret; + /* Forward hvc instructions to the virtual EL2 if the guest has EL2. */ if (vcpu_has_nv(vcpu)) { if (vcpu_read_sys_reg(vcpu, HCR_EL2) & HCR_HCD) @@ -447,6 +453,9 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_in= dex) { struct kvm_run *run =3D vcpu->run; =20 + if (exception_index < 0) + return exception_index; + if (ARM_SERROR_PENDING(exception_index)) { /* * The SError is handled by handle_exit_early(). If the guest @@ -478,6 +487,8 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_in= dex) */ run->exit_reason =3D KVM_EXIT_FAIL_ENTRY; return -EINVAL; + case ARM_EXCEPTION_EXIT: + return 0; default: kvm_pr_unimpl("Unsupported exception type: %d", exception_index); @@ -489,6 +500,9 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_in= dex) /* For exit types that need handling before we can be preempted */ void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index) { + if (exception_index < 0 || exception_index =3D=3D ARM_EXCEPTION_EXIT) + return; + if (ARM_SERROR_PENDING(exception_index)) { if (this_cpu_has_cap(ARM64_HAS_RAS_EXTN)) { u64 disr =3D kvm_vcpu_get_disr(vcpu); diff --git a/arch/arm64/kvm/rmi-exit.c b/arch/arm64/kvm/rmi-exit.c new file mode 100644 index 000000000000..04e6535552cb --- /dev/null +++ b/arch/arm64/kvm/rmi-exit.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023-2026 ARM Ltd. + */ + +#include + +#include +#include +#include +#include + +static int rec_exit_fatal(struct kvm_vcpu *vcpu, const char *reason, + unsigned long value) +{ + vcpu_err(vcpu, "%s: %#lx\n", reason, value); + vcpu->run->exit_reason =3D KVM_EXIT_INTERNAL_ERROR; + kvm_vm_dead(vcpu->kvm); + return ARM_EXCEPTION_EXIT; +} + +static void rec_exit_sync(struct kvm_vcpu *vcpu) +{ + struct realm_rec *rec =3D &vcpu->arch.rec; + u64 esr =3D rec->run->exit.esr; + u8 ec =3D ESR_ELx_EC(esr); + + switch (ec) { + case ESR_ELx_EC_SYS64: { + int rt =3D ESR_ELx_SYS64_ISS_RT(esr); + bool is_write =3D (esr & ESR_ELx_SYS64_ISS_DIR_MASK) =3D=3D + ESR_ELx_SYS64_ISS_DIR_WRITE; + + if (is_write && rt < REC_RUN_GPRS) + vcpu_set_reg(vcpu, rt, rec->run->exit.gprs[rt]); + else if (!is_write) + kvm_make_request(KVM_REQ_RMI, vcpu); + break; + } + } +} + +static void rec_exit_hvc(struct kvm_vcpu *vcpu) +{ + struct realm_rec *rec =3D &vcpu->arch.rec; + int i; + + for (i =3D 0; i < REC_RUN_GPRS; i++) + vcpu_set_reg(vcpu, i, rec->run->exit.gprs[i]); + + vcpu->arch.fault.esr_el2 =3D (ESR_ELx_EC_HVC64 << ESR_ELx_EC_SHIFT) | + ESR_ELx_IL; +} + +bool kvm_rec_handle_hvc(struct kvm_vcpu *vcpu, int *ret) +{ + struct realm_rec *rec; + struct realm *realm; + unsigned long base; + unsigned long ripas; + unsigned long top; + + if (!vcpu_is_rec(vcpu)) + return false; + + rec =3D &vcpu->arch.rec; + if (rec->run->exit.exit_reason !=3D RMI_EXIT_RIPAS_CHANGE) + return false; + + realm =3D &vcpu->kvm->arch.realm; + base =3D rec->run->exit.ripas_base; + top =3D rec->run->exit.ripas_top; + ripas =3D rec->run->exit.ripas_value; + + if (top <=3D base || + !kvm_realm_is_private_address(realm, base) || + !kvm_realm_is_private_address(realm, top - 1)) { + vcpu_err(vcpu, "Invalid RIPAS_CHANGE for %#lx - %#lx, ripas: %#lx\n", + base, top, ripas); + /* Set RMI_REJECT bit */ + rec->run->enter.flags =3D REC_ENTER_FLAG_RIPAS_RESPONSE; + *ret =3D -EINVAL; + return true; + } + + /* Exit to VMM, the actual RIPAS change is done on next entry */ + kvm_prepare_memory_fault_exit(vcpu, base, top - base, false, false, + ripas =3D=3D RMI_RAM); + kvm_make_request(KVM_REQ_RMI, vcpu); + + /* + * KVM_EXIT_MEMORY_FAULT requires a return code of -EFAULT, see the + * API documentation + */ + *ret =3D -EFAULT; + return true; +} + +int kvm_rec_exit(struct kvm_vcpu *vcpu, int rec_run_ret) +{ + struct realm_rec *rec =3D &vcpu->arch.rec; + unsigned long status; + + if (rec_run_ret < 0) + return rec_exit_fatal(vcpu, "REC_ENTER failed", rec_run_ret); + + status =3D RMI_RETURN_STATUS(rec_run_ret); + + /* + * If a PSCI_SYSTEM_OFF request raced with a vcpu executing, we might + * see the following status code indicating an attempt to run + * a REC when the RD state is SYSTEM_OFF. In this case, we just need to + * return to user space which can deal with the system event or will try + * to run the KVM VCPU again, at which point we will no longer attempt + * to enter the Realm because we will have a sleep request pending on + * the VCPU as a result of KVM's PSCI handling. + */ + if (status =3D=3D RMI_ERROR_REALM) { + vcpu->run->exit_reason =3D KVM_EXIT_SHUTDOWN; + return ARM_EXCEPTION_EXIT; + } + + /* + * If a VCPU has been turned on, but the REC state hasn't been updated + * we may experience RMI_ERROR_REC. Exit to the userspace with -EAGAIN + * for a retry. + */ + if (status =3D=3D RMI_ERROR_REC) + return -EAGAIN; + if (rec_run_ret) + return rec_exit_fatal(vcpu, "Unexpected REC_ENTER status", + rec_run_ret); + + vcpu->arch.fault.esr_el2 =3D rec->run->exit.esr; + vcpu->arch.fault.far_el2 =3D rec->run->exit.far; + /* HPFAR_EL2 is only valid for RMI_EXIT_SYNC */ + vcpu->arch.fault.hpfar_el2 =3D 0; + + /* Reset the emulation flags for the next run of the REC */ + rec->run->enter.flags =3D 0; + + switch (rec->run->exit.exit_reason) { + case RMI_EXIT_SYNC: + /* + * HPFAR_EL2_NS is hijacked to indicate a valid HPFAR value, + * see __get_fault_info() + */ + vcpu->arch.fault.hpfar_el2 =3D rec->run->exit.hpfar | HPFAR_EL2_NS; + rec_exit_sync(vcpu); + return ARM_EXCEPTION_TRAP; + case RMI_EXIT_IRQ: + case RMI_EXIT_FIQ: + return ARM_EXCEPTION_IRQ; + case RMI_EXIT_SERROR: + return ARM_EXCEPTION_EL1_SERROR; + case RMI_EXIT_PSCI: + rec_exit_hvc(vcpu); + kvm_make_request(KVM_REQ_RMI, vcpu); + return ARM_EXCEPTION_TRAP; + case RMI_EXIT_RIPAS_CHANGE: + rec_exit_hvc(vcpu); + return ARM_EXCEPTION_TRAP; + } + + return rec_exit_fatal(vcpu, "Unsupported Realm exit reason", + rec->run->exit.exit_reason); +} diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index f6686287119d..92085b88f427 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -6,6 +6,7 @@ #include =20 #include +#include #include #include #include @@ -205,6 +206,61 @@ int kvm_realm_teardown_stage2(struct kvm *kvm) return realm_destroy_rtts(kvm); } =20 +int kvm_rec_handle_request(struct kvm_vcpu *vcpu) +{ + struct realm_rec *rec =3D &vcpu->arch.rec; + u64 esr; + + switch (rec->run->exit.exit_reason) { + case RMI_EXIT_SYNC: + esr =3D rec->run->exit.esr; + if (ESR_ELx_EC(esr) =3D=3D ESR_ELx_EC_SYS64 && + (esr & ESR_ELx_SYS64_ISS_DIR_MASK) =3D=3D + ESR_ELx_SYS64_ISS_DIR_READ) { + int rt =3D ESR_ELx_SYS64_ISS_RT(esr); + + if (rt < REC_RUN_GPRS) + rec->run->enter.gprs[rt] =3D + vcpu_get_reg(vcpu, rt); + } + break; + default: + KVM_BUG(1, vcpu->kvm, "Unhandled realm exit_reason"); + return -ENXIO; + } + + return 1; +} + +static void noinstr load_realm_timer_state(struct kvm_vcpu *vcpu) +{ + struct rec_exit *rec_exit =3D &vcpu->arch.rec.run->exit; + + /* + * The RMM reports the EL1 timer state on every REC exit. Install that + * state before returning to the generic KVM run loop, which expects + * the loaded vCPU's timers to be live. + */ + write_sysreg_el0(rec_exit->cntv_cval, SYS_CNTV_CVAL); + write_sysreg_el0(rec_exit->cntp_cval, SYS_CNTP_CVAL); + isb(); + + write_sysreg_el0(rec_exit->cntv_ctl, SYS_CNTV_CTL); + write_sysreg_el0(rec_exit->cntp_ctl, SYS_CNTP_CTL); +} + +int noinstr kvm_rec_enter(struct kvm_vcpu *vcpu) +{ + struct realm_rec *rec =3D &vcpu->arch.rec; + int ret; + + ret =3D rmi_rec_enter(rec->rec_phys, rec->run_phys); + if (!ret) + load_realm_timer_state(vcpu); + + return ret; +} + static int __maybe_unused kvm_create_rec(struct kvm_vcpu *vcpu) { struct user_pt_regs *vcpu_regs =3D vcpu_gp_regs(vcpu); --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 89C5442AFB6; Mon, 3 Aug 2026 13:46:01 +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=1785764763; cv=none; b=Rr+jqRumWODdl2eStug8iJaLxadT9V1AXENEi04wjLVD9oGEXNPyTjVFQstO7S8dLlyC4Tu7oULkC31riDQEtsYJ6f6/sVUWpoEdpA3xNtaFpneupvdGhyPhGXJbsTwJ/ecj50V0nHvpO76OzpZhg4VavY7gpIx7e0Ep0mMrr2c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764763; c=relaxed/simple; bh=D3rmKR33hCAfWHrfdoSfi5LciefckTekrl6s2h/SJ3g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AspY0pqQ9rkb1+/b/hXKPbH+zkKFSTARhSRweHx5zv2uhQu9SwhJSZHciGlYO/mRFN7FA/9qNYa0ev4kIv1sH1WbYnHen1jSAKcd6g5eWYXSxGcKTp1hlt/7/OQNzoQUGQKljXbAxJUUq3LtSPcWx17rdASBdFNvKVElx/jpyH8= 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=MMMsavny; 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="MMMsavny" 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 CEBAC1476; Mon, 3 Aug 2026 06:45:56 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id AF5403F66F; Mon, 3 Aug 2026 06:45:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764760; bh=D3rmKR33hCAfWHrfdoSfi5LciefckTekrl6s2h/SJ3g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MMMsavny4J4ESoteQjAOh1WpxAz8t29ZqB7TAHFE9vPROBFXqRrzGFjOAhFaMlBSi fF3zkXofpA5y2mBTrIjTmIjtXAjU983ILUUcUlzpHM5mkKnS+4xN4rdH5XpFJ93jaE inYciD8VY2HyweZan3e9H8iq9hRmxhJ+JtCHt9b8= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 22/45] KVM: arm64: CCA: Handle RMI_EXIT_RIPAS_CHANGE Date: Mon, 3 Aug 2026 14:43:38 +0100 Message-ID: <20260803134403.80630-23-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" The guest can request that a region of its protected address space is switched between RIPAS_RAM and RIPAS_EMPTY (and back) using RSI_IPA_STATE_SET. This causes a guest exit with the RMI_EXIT_RIPAS_CHANGE code. We treat this as a request to convert a protected region to unprotected (or back), exiting to the VMM to make the necessary changes to the guest_memfd and memslot mappings. On the next entry the RIPAS changes are committed by making RMI_RTT_SET_RIPAS calls. The VMM may wish to reject the RIPAS change requested by the guest. For now it can only do this by no longer scheduling the VCPU as we don't currently have a usecase for returning that rejection to the guest, but by postponing the RMI_RTT_SET_RIPAS changes to entry we leave the door open for adding a new ioctl in the future for this purpose. Signed-off-by: Steven Price --- Changes since v15: * Propagate negative error returns. Changes since v14: * Use addition rather than bitwise OR for adding the shared_bit in realm_unmap_shared_range(), this handles the case where the region includes the last address (which means 'end' already has the bit set). Changes since v13: * Switch to the new RMI_RTT_UNPROT_UNMAP range-based API. * Drop ugly hack for RMM bug which errored when the RIPAS was already set to the desired value. Changes since v12: * Switch to the new RMM v2.0 RMI_RTT_DATA_UNMAP which can unmap an address range. Changes since v11: * Combine the "Allow VMM to set RIPAS" patch into this one to avoid adding functions before they are used. * Drop the CAP for setting RIPAS and adapt to changes from previous patches. Changes since v10: * Add comment explaining the assignment of rec->run->exit.ripas_base in kvm_complete_ripas_change(). Changes since v8: * Make use of ripas_change() from a previous patch to implement realm_set_ipa_state(). * Update exit.ripas_base after a RIPAS change so that, if instead of entering the guest we exit to user space, we don't attempt to repeat the RIPAS change (triggering an error from the RMM). Changes since v7: * Rework the loop in realm_set_ipa_state() to make it clear when the 'next' output value of rmi_rtt_set_ripas() is used. New patch for v7: The code was previously split awkwardly between two other patches. --- arch/arm64/include/asm/kvm_rmi.h | 6 + arch/arm64/kvm/mmu.c | 8 +- arch/arm64/kvm/rmi.c | 473 +++++++++++++++++++++++++++++++ 3 files changed, 484 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 1e5026039458..751659a48be3 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -107,6 +107,12 @@ int kvm_rec_exit(struct kvm_vcpu *vcpu, int rec_run_st= atus); int kvm_rec_handle_request(struct kvm_vcpu *vcpu); bool kvm_rec_handle_hvc(struct kvm_vcpu *vcpu, int *ret); =20 +void kvm_realm_unmap_range(struct kvm *kvm, + unsigned long ipa, + unsigned long size, + bool unmap_private, + bool may_block); + static inline bool kvm_realm_is_private_address(struct realm *realm, unsigned long addr) { diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index cd06881c1497..dcc2ab08d0e4 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -319,6 +319,7 @@ static void invalidate_icache_guest_page(void *va, size= _t size) * @start: The intermediate physical base address of the range to unmap * @size: The size of the area to unmap * @may_block: Whether or not we are permitted to block + * @only_shared: If true then protected mappings should not be unmapped * * Clear a range of stage-2 mappings, lowering the various ref-counts. Mu= st * be called while holding mmu_lock (unless for freeing the stage2 pgd bef= ore @@ -326,7 +327,7 @@ static void invalidate_icache_guest_page(void *va, size= _t size) * with things behind our backs. */ static void __unmap_stage2_range(struct kvm_s2_mmu *mmu, phys_addr_t start= , u64 size, - bool may_block) + bool may_block, bool only_shared) { struct kvm *kvm =3D kvm_s2_mmu_to_kvm(mmu); phys_addr_t end =3D start + size; @@ -343,7 +344,7 @@ void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phy= s_addr_t start, if (kvm_vm_is_protected(kvm_s2_mmu_to_kvm(mmu))) return; =20 - __unmap_stage2_range(mmu, start, size, may_block); + __unmap_stage2_range(mmu, start, size, may_block, false); } =20 void kvm_stage2_flush_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, phys= _addr_t end) @@ -2467,7 +2468,8 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_= gfn_range *range) =20 __unmap_stage2_range(&kvm->arch.mmu, range->start << PAGE_SHIFT, (range->end - range->start) << PAGE_SHIFT, - range->may_block); + range->may_block, + !(range->attr_filter & KVM_FILTER_PRIVATE)); =20 kvm_nested_s2_unmap(kvm, range->may_block); return false; diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 92085b88f427..a7202054c8e6 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -35,6 +35,83 @@ static int get_start_level(struct realm *realm) return 4 - stage2_pgtable_levels(realm->ia_bits); } =20 +static int find_map_level(struct realm *realm, + unsigned long start, + unsigned long end) +{ + int level =3D KVM_PGTABLE_LAST_LEVEL; + + while (level > get_start_level(realm)) { + unsigned long map_size =3D rmi_rtt_level_mapsize(level - 1); + + if (!IS_ALIGNED(start, map_size) || + (start + map_size) > end) + break; + + level--; + } + + return level; +} + +static unsigned long rmi_range_entry_size(int rmi_size) +{ + if (WARN_ON(rmi_size > KVM_PGTABLE_LAST_LEVEL)) + return 0; + + return kvm_granule_size(KVM_PGTABLE_LAST_LEVEL - rmi_size); +} + +static int undelegate_range_desc(unsigned long desc) +{ + unsigned long size =3D rmi_range_entry_size(RMI_ADDR_RANGE_SIZE(desc)); + unsigned long count =3D RMI_ADDR_RANGE_COUNT(desc); + unsigned long addr =3D RMI_ADDR_RANGE_ADDR(desc); + unsigned long state =3D RMI_ADDR_RANGE_STATE(desc); + + if (state =3D=3D RMI_OP_MEM_UNDELEGATED) + return 0; + + if (size * count =3D=3D 0) + return 0; + + return rmi_undelegate_range(addr, size * count); +} + +static phys_addr_t alloc_delegated_granule(struct kvm_mmu_memory_cache *mc) +{ + phys_addr_t phys; + void *virt; + + if (mc) { + virt =3D kvm_mmu_memory_cache_alloc(mc); + } else { + virt =3D (void *)__get_free_page(GFP_ATOMIC | __GFP_ZERO | + __GFP_ACCOUNT); + } + + if (!virt) + return PHYS_ADDR_MAX; + + phys =3D virt_to_phys(virt); + if (rmi_delegate_page(phys)) { + free_page((unsigned long)virt); + return PHYS_ADDR_MAX; + } + + return phys; +} + +static phys_addr_t alloc_rtt(struct kvm_mmu_memory_cache *mc) +{ + phys_addr_t phys =3D alloc_delegated_granule(mc); + + if (phys !=3D PHYS_ADDR_MAX) + kvm_account_pgtable_pages(phys_to_virt(phys), 1); + + return phys; +} + static void free_rtt(phys_addr_t phys) { if (free_delegated_page(phys)) @@ -43,6 +120,32 @@ static void free_rtt(phys_addr_t phys) kvm_account_pgtable_pages(phys_to_virt(phys), -1); } =20 +static long realm_rtt_create(struct realm *realm, + unsigned long addr, + int level, + phys_addr_t phys) +{ + addr =3D ALIGN_DOWN(addr, rmi_rtt_level_mapsize(level - 1)); + return rmi_rtt_create(virt_to_phys(realm->rd), phys, addr, level); +} + +static long realm_rtt_fold(struct realm *realm, + unsigned long addr, + int level, + phys_addr_t *rtt_granule) +{ + unsigned long out_rtt; + long ret; + + addr =3D ALIGN_DOWN(addr, rmi_rtt_level_mapsize(level - 1)); + ret =3D rmi_rtt_fold(virt_to_phys(realm->rd), addr, level, &out_rtt); + + if (rtt_granule) + *rtt_granule =3D out_rtt; + + return ret; +} + /* * realm_rtt_destroy - Destroy an RTT at @level for @addr. * @@ -66,6 +169,43 @@ static long realm_rtt_destroy(struct realm *realm, unsi= gned long addr, return ret; } =20 +static int realm_create_rtt_levels(struct realm *realm, + unsigned long ipa, + int level, + int max_level, + struct kvm_mmu_memory_cache *mc) +{ + while (level++ < max_level) { + phys_addr_t rtt =3D alloc_rtt(mc); + long ret; + + if (rtt =3D=3D PHYS_ADDR_MAX) + return -ENOMEM; + + ret =3D realm_rtt_create(realm, ipa, level, rtt); + if (ret < 0) { + free_rtt(rtt); + return ret; + } + + if (RMI_RETURN_STATUS(ret) =3D=3D RMI_ERROR_RTT && + RMI_RETURN_INDEX(ret) =3D=3D level - 1) { + /* The RTT already exists, continue */ + free_rtt(rtt); + continue; + } + + if (ret) { + WARN(1, "Failed to create RTT at level %d: %ld\n", + level, ret); + free_rtt(rtt); + return -ENXIO; + } + } + + return 0; +} + static int realm_tear_down_rtt_level(struct realm *realm, int level, unsigned long start, unsigned long end) { @@ -162,6 +302,64 @@ static int realm_tear_down_rtt_range(struct realm *rea= lm, start, end); } =20 +/* + * Returns 0 on successful fold, a negative value on error, a positive val= ue if + * we were not able to fold all tables at this level. + */ +static int realm_fold_rtt_level(struct realm *realm, int level, + unsigned long start, unsigned long end) +{ + int not_folded =3D 0; + ssize_t map_size; + unsigned long addr, next_addr; + + if (WARN_ON(level > KVM_PGTABLE_LAST_LEVEL)) + return -EINVAL; + + map_size =3D rmi_rtt_level_mapsize(level - 1); + + for (addr =3D start; addr < end; addr =3D next_addr) { + phys_addr_t rtt_granule; + long ret; + unsigned long align_addr =3D ALIGN(addr, map_size); + + next_addr =3D ALIGN(addr + 1, map_size); + + ret =3D realm_rtt_fold(realm, align_addr, level, &rtt_granule); + if (ret < 0) + return ret; + + switch (RMI_RETURN_STATUS(ret)) { + case RMI_SUCCESS: + free_rtt(rtt_granule); + break; + case RMI_ERROR_RTT: + if (level =3D=3D KVM_PGTABLE_LAST_LEVEL || + RMI_RETURN_INDEX(ret) < level) { + not_folded++; + break; + } + /* Recurse a level deeper */ + ret =3D realm_fold_rtt_level(realm, + level + 1, + addr, + next_addr); + if (ret < 0) { + return ret; + } else if (ret =3D=3D 0) { + /* Try again at this level */ + next_addr =3D addr; + } + break; + default: + WARN_ON(1); + return -ENXIO; + } + } + + return not_folded; +} + static int realm_destroy_rtts(struct kvm *kvm) { struct realm *realm =3D &kvm->arch.realm; @@ -206,6 +404,279 @@ int kvm_realm_teardown_stage2(struct kvm *kvm) return realm_destroy_rtts(kvm); } =20 +static void realm_unmap_shared_range(struct kvm *kvm, + unsigned long start, + unsigned long end, + bool may_block) +{ + struct realm *realm =3D &kvm->arch.realm; + unsigned long rd =3D virt_to_phys(realm->rd); + unsigned long next_addr, addr; + unsigned long shared_bit =3D BIT(realm->ia_bits - 1); + + if (start >=3D end) + return; + + start +=3D shared_bit; + end +=3D shared_bit; + + for (addr =3D start; addr < end; addr =3D next_addr) { + long ret; + + ret =3D rmi_rtt_unprot_unmap(rd, addr, end, RMI_ADDR_TYPE_NONE, + 0, &next_addr, NULL, NULL); + if (WARN_ON(ret < 0)) + return; + + switch (RMI_RETURN_STATUS(ret)) { + case RMI_SUCCESS: + break; + case RMI_ERROR_RTT: { + int err_level =3D RMI_RETURN_INDEX(ret); + int level =3D find_map_level(realm, addr, end); + + if (err_level >=3D level) { + /* Nothing present, so skip */ + next_addr =3D addr + rmi_rtt_level_mapsize(err_level); + break; + } + + ret =3D realm_create_rtt_levels(realm, addr, err_level, + level, NULL); + if (WARN_ON(ret)) + return; + /* Retry with the RTT levels in place */ + next_addr =3D addr; + break; + } + default: + WARN_ON(1); + return; + } + + if (may_block) + cond_resched_rwlock_write(&kvm->mmu_lock); + } + + realm_fold_rtt_level(realm, get_start_level(realm) + 1, + start, end); +} + +static void realm_unmap_private_range(struct kvm *kvm, + unsigned long start, + unsigned long end, + bool may_block) +{ + struct realm *realm =3D &kvm->arch.realm; + unsigned long rd =3D virt_to_phys(realm->rd); + unsigned long next_addr, addr; + long ret; + + for (addr =3D start; addr < end; addr =3D next_addr) { + unsigned long out_range; + unsigned long flags =3D RMI_ADDR_TYPE_SINGLE; + /* TODO: Optimise using RMI_ADDR_TYPE_LIST */ + +retry: + ret =3D rmi_rtt_data_unmap(rd, addr, end, flags, 0, + &next_addr, &out_range, NULL); + if (WARN_ON(ret < 0)) + return; + + if (RMI_RETURN_STATUS(ret) =3D=3D RMI_ERROR_RTT) { + phys_addr_t rtt; + + if (next_addr > addr) + continue; /* UNASSIGNED */ + + rtt =3D alloc_rtt(NULL); + if (WARN_ON(rtt =3D=3D PHYS_ADDR_MAX)) + return; + ret =3D realm_rtt_create(realm, addr, + RMI_RETURN_INDEX(ret) + 1, rtt); + if (WARN_ON(ret)) { + free_rtt(rtt); + return; + } + goto retry; + } else if (WARN_ON(ret)) { + continue; + } + + ret =3D undelegate_range_desc(out_range); + if (WARN_ON(ret)) + break; + + if (may_block) + cond_resched_rwlock_write(&kvm->mmu_lock); + } + + realm_fold_rtt_level(realm, get_start_level(realm) + 1, + start, end); +} + +void kvm_realm_unmap_range(struct kvm *kvm, unsigned long start, + unsigned long size, bool unmap_private, + bool may_block) +{ + unsigned long end =3D start + size; + struct realm *realm =3D &kvm->arch.realm; + + if (!kvm_realm_is_created(kvm)) + return; + + end =3D min(BIT(realm->ia_bits - 1), end); + + realm_unmap_shared_range(kvm, start, end, may_block); + if (unmap_private) + realm_unmap_private_range(kvm, start, end, may_block); +} + +enum ripas_action { + RIPAS_INIT, + RIPAS_SET, +}; + +static int ripas_change(struct kvm *kvm, + struct kvm_vcpu *vcpu, + unsigned long ipa, + unsigned long end, + enum ripas_action action, + unsigned long *top_ipa) +{ + struct realm *realm =3D &kvm->arch.realm; + phys_addr_t rd_phys =3D virt_to_phys(realm->rd); + phys_addr_t rec_phys; + struct kvm_mmu_memory_cache *memcache =3D NULL; + long ret =3D 0; + + if (vcpu) { + rec_phys =3D vcpu->arch.rec.rec_phys; + memcache =3D &vcpu->arch.mmu_page_cache; + + WARN_ON(action !=3D RIPAS_SET); + } else { + WARN_ON(action !=3D RIPAS_INIT); + } + + while (ipa < end) { + unsigned long next =3D ~0; + + switch (action) { + case RIPAS_INIT: + ret =3D rmi_rtt_init_ripas(rd_phys, ipa, end, &next); + break; + case RIPAS_SET: + ret =3D rmi_rtt_set_ripas(rd_phys, rec_phys, ipa, end, + &next); + break; + } + + if (ret < 0) + goto out; + + switch (RMI_RETURN_STATUS(ret)) { + case RMI_SUCCESS: + ipa =3D next; + break; + case RMI_ERROR_RTT: { + int err_level =3D RMI_RETURN_INDEX(ret); + int level =3D find_map_level(realm, ipa, end); + + /* + * If the operation failed at deeper level than + * what is required for the address range, this + * implies encountering an unexpected entry, + * (e.g., RIPAS_DESTROYED), which the RMM prevents + * us from modifying. This is only applicable for + * RMI_RTT_INIT_RIPAS. All the other requests + * are generated by the Realm and thus RMM should + * be able to allow the transition. + */ + if (action =3D=3D RIPAS_INIT && WARN_ON_ONCE(err_level >=3D level)) + return -ENXIO; + + ret =3D realm_create_rtt_levels(realm, ipa, err_level, + level, memcache); + if (ret) + goto out; + /* Retry with the RTT levels in place */ + break; + } + default: + WARN_ON(1); + ret =3D -ENXIO; + goto out; + } + } + +out: + if (top_ipa) + *top_ipa =3D ipa; + + return ret; +} + +static int realm_set_ipa_state(struct kvm_vcpu *vcpu, + unsigned long start, + unsigned long end, + unsigned long ripas, + unsigned long *top_ipa) +{ + struct kvm *kvm =3D vcpu->kvm; + int ret =3D ripas_change(kvm, vcpu, start, end, RIPAS_SET, top_ipa); + + if (!ret && ripas =3D=3D RMI_EMPTY && *top_ipa !=3D start) + realm_unmap_private_range(kvm, start, *top_ipa, false); + + return ret; +} + +static int kvm_complete_ripas_change(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct realm_rec *rec =3D &vcpu->arch.rec; + unsigned long base =3D rec->run->exit.ripas_base; + unsigned long top =3D rec->run->exit.ripas_top; + unsigned long ripas =3D rec->run->exit.ripas_value; + unsigned long top_ipa =3D base; + int ret; + + do { + kvm_mmu_topup_memory_cache(&vcpu->arch.mmu_page_cache, + kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu)); + write_lock(&kvm->mmu_lock); + ret =3D realm_set_ipa_state(vcpu, base, top, ripas, &top_ipa); + write_unlock(&kvm->mmu_lock); + + if (ret =3D=3D -ENOMEM) { + /* If no progress, then stop */ + if (top_ipa =3D=3D base) + break; + base =3D top_ipa; + continue; + } + + if (WARN_RATELIMIT(ret, + "Unable to satisfy RIPAS_CHANGE for %#lx - %#lx, ripas: %#lx\n", + base, top, ripas)) + break; + + base =3D top_ipa; + } while (base < top); + + /* + * If this function is called again before the REC_ENTER call then + * avoid calling realm_set_ipa_state() again by changing to the value + * of ripas_base for the part that has already been covered. The RMM + * ignores the contains of the rec_exit structure so this doesn't + * affect the RMM. + */ + rec->run->exit.ripas_base =3D base; + + return 1; +} + int kvm_rec_handle_request(struct kvm_vcpu *vcpu) { struct realm_rec *rec =3D &vcpu->arch.rec; @@ -224,6 +695,8 @@ int kvm_rec_handle_request(struct kvm_vcpu *vcpu) vcpu_get_reg(vcpu, rt); } break; + case RMI_EXIT_RIPAS_CHANGE: + return kvm_complete_ripas_change(vcpu); default: KVM_BUG(1, vcpu->kvm, "Unhandled realm exit_reason"); return -ENXIO; --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 4268942BC39; Mon, 3 Aug 2026 13:46: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=1785764768; cv=none; b=OiBBSbYWd9Mz0Bn70Xsb7cgXMSNsL2Yeipfpzf3l39z59nnU/Pe82s0JM14p7cgRMOev6gX1cwlEgah+H87H3jVReFRXoXa37zhQJUCrOaB0GjNCDKDTazumrnvubmBb6V8kZVMPsCmW4+4PK2eRs3t8kb/OPyhpIJ2wQReaHSQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764768; c=relaxed/simple; bh=CJCPAyYgqv4fPdlGip9kwuE1OWw16g9Pdh7gjimsqNI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=flWpGyL0WORmu7Gt6/qgFu9LzmU5nG8xs/i+GafAsPl11ZnJAIkV69cA8/Zio9w/iTOuwnw9Jw9i6g5U33FwmhBK28WBXuHb7R/Q0NWliE3qSuMJ9+5AjjHpkFBam4uTLmHUFnaz01PSd0KzxOdDCxwsXNW+g3K0U0PS9pdM4pA= 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=tAouudPP; 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="tAouudPP" 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 6EB6E165C; Mon, 3 Aug 2026 06:46:01 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 3E3463F66F; Mon, 3 Aug 2026 06:46:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764765; bh=CJCPAyYgqv4fPdlGip9kwuE1OWw16g9Pdh7gjimsqNI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tAouudPPJNvM5S0TTa8h/DpZOL8DSiCeLndx4ycCgBZ6L+Wl4idXo2WSclevCp5GY bRUOtcP3gopsqxDTBw/hjW79ND1Qi6HeHlppIXAWTP8kjPcfTYFPCMVWO1MhuImwdG FhB5GasZ5RQuVHiBj1rPts2zeiJr6EeNEcXJ2Cyg= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 23/45] KVM: arm64: CCA: Handle realm MMIO emulation Date: Mon, 3 Aug 2026 14:43:39 +0100 Message-ID: <20260803134403.80630-24-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" MMIO emulation for a realm cannot be done directly with the VM's registers as they are protected from the host. However, for emulatable data aborts, the RMM uses GPRS[0] to provide the read/written value. We can transfer this from/to the equivalent VCPU's register entry and then depend on the generic MMIO handling code in KVM. For a MMIO read, the value is placed in the shared RecExit structure during kvm_handle_mmio_return() rather than in the VCPU's register entry. Signed-off-by: Steven Price --- Changes since v15: * Adapt to the new exit flow. Changes since v7: * New comment for rec_exit_sync_dabt() explaining the call to vcpu_set_reg(). Changes since v5: * Inject SEA to the guest is an emulatable MMIO access triggers a data abort. * kvm_handle_mmio_return() - disable kvm_incr_pc() for a REC (as the PC isn't under the host's control) and move the REC_ENTER_EMULATED_MMIO flag setting to this location (as that tells the RMM to skip the instruction). --- arch/arm64/kvm/inject_fault.c | 4 +++- arch/arm64/kvm/mmio.c | 16 ++++++++++++---- arch/arm64/kvm/rmi-exit.c | 10 ++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index 89982bd3345f..6492397b73d7 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -228,7 +228,9 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is= _pabt, u32 addr) =20 static void __kvm_inject_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr) { - if (vcpu_el1_is_32bit(vcpu)) + if (unlikely(vcpu_is_rec(vcpu))) + vcpu->arch.rec.run->enter.flags |=3D REC_ENTER_FLAG_INJECT_SEA; + else if (vcpu_el1_is_32bit(vcpu)) inject_abt32(vcpu, iabt, addr); else inject_abt64(vcpu, iabt, addr); diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c index e2285ed8c91d..a8c125205695 100644 --- a/arch/arm64/kvm/mmio.c +++ b/arch/arm64/kvm/mmio.c @@ -6,6 +6,7 @@ =20 #include #include +#include #include =20 #include "trace.h" @@ -138,14 +139,21 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu) trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, &data); data =3D vcpu_data_host_to_guest(vcpu, data, len); - vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), data); + + if (vcpu_is_rec(vcpu)) + vcpu->arch.rec.run->enter.gprs[0] =3D data; + else + vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), data); } =20 /* * The MMIO instruction is emulated and should not be re-executed * in the guest. */ - kvm_incr_pc(vcpu); + if (vcpu_is_rec(vcpu)) + vcpu->arch.rec.run->enter.flags |=3D REC_ENTER_FLAG_EMULATED_MMIO; + else + kvm_incr_pc(vcpu); =20 return 1; } @@ -167,14 +175,14 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t f= ault_ipa) * No valid syndrome? Ask userspace for help if it has * volunteered to do so, and bail out otherwise. * - * In the protected VM case, there isn't much userspace can do + * In the protected/realm VM case, there isn't much userspace can do * though, so directly deliver an exception to the guest. */ if (!kvm_vcpu_dabt_isvalid(vcpu)) { trace_kvm_mmio_nisv(*vcpu_pc(vcpu), esr, kvm_vcpu_get_hfar(vcpu), fault_ipa); =20 - if (vcpu_is_protected(vcpu)) + if (vcpu_is_protected(vcpu) || vcpu_is_rec(vcpu)) return kvm_inject_sea_dabt(vcpu, kvm_vcpu_get_hfar(vcpu)); =20 if (test_bit(KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER, diff --git a/arch/arm64/kvm/rmi-exit.c b/arch/arm64/kvm/rmi-exit.c index 04e6535552cb..1749cde2edff 100644 --- a/arch/arm64/kvm/rmi-exit.c +++ b/arch/arm64/kvm/rmi-exit.c @@ -37,6 +37,16 @@ static void rec_exit_sync(struct kvm_vcpu *vcpu) kvm_make_request(KVM_REQ_RMI, vcpu); break; } + case ESR_ELx_EC_DABT_LOW: + /* + * The RMM reports the value of an MMIO write in gprs[0], + * irrespective of the register named by the instruction. + */ + if (kvm_vcpu_dabt_iswrite(vcpu) && + kvm_vcpu_dabt_isvalid(vcpu)) + vcpu_set_reg(vcpu, kvm_vcpu_dabt_get_rd(vcpu), + rec->run->exit.gprs[0]); + break; } } =20 --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 4508442C502; Mon, 3 Aug 2026 13:46:10 +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=1785764771; cv=none; b=UnR3Qs+Hp+tri6Up95XwRGG7RB+FiHeNVTDAkYYgEPM9yUhDcvZs+/NLBnUAMCFXVIfqNDNZuD7hv9HNBFGtdqRXzFrRr67LtXyR832g1z0oQnnvwS9w/2nY+wOeczRyzQ4gDnO/e5To52bjnLUS+TCGi7avt4/HgKe+K4+EldI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764771; c=relaxed/simple; bh=CzDXgxOuepxzu+QGvZRaCZEmtV4jtA47VV79b/Le9OU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RfuzhBxBLC2NWgBnn4FJLaWuG4uFoe7omsUvtrQS0Rsn+Jq8RS8kqF6jRw/Ik0tri7semkyufOgeojFZZZ9B/BfkHgqjPGZ/twmlT9OkswuKAj/qxohB1nZR78YCi7I+5FqPwHmmFEqid4n9jH7WD4J6eHDjRe0ufPl3bzwUjDM= 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=NYqxGDxy; 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="NYqxGDxy" 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 B87191655; Mon, 3 Aug 2026 06:46:05 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id CF2AB3F66F; Mon, 3 Aug 2026 06:46:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764769; bh=CzDXgxOuepxzu+QGvZRaCZEmtV4jtA47VV79b/Le9OU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NYqxGDxysx6UdyDzvxP/Xv5joe9UD6endoboLrwwEK1v+Rf39naqjpmrJacfzmPnz MfV/rAtSkaj1j6ke0cqNbWX6msfj067eDNiXuvILizBUH5nLQXeaiO+Xlw4aMbI3v9 Jri+KHjpNBec5BJgL5FI76wASDvQfgwBg6BRMqoI= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 24/45] KVM: arm64: Expose support for private memory Date: Mon, 3 Aug 2026 14:43:40 +0100 Message-ID: <20260803134403.80630-25-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" Select KVM_GENERIC_MEMORY_ATTRIBUTES and provide the necessary support functions. Reviewed-by: Suzuki K Poulose Signed-off-by: Steven Price --- Changes since v14: * Switch to guest_memfd in-place memory conversion and drop support for KVM_VM_MEMORY_ATTRIBUTES. Changes since v13: * Also update documentation to show that KVM_CAP_MEMORY_ATTRIBUTES is used on arm64. Changes since v12: * Only define kvm_arch_has_private_mem() when CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES is set to avoid build issues when KVM is disabled. Changes since v10: * KVM_GENERIC_PRIVATE_MEM replacd with KVM_GENERIC_MEMORY_ATTRIBUTES. Changes since v9: * Drop the #ifdef CONFIG_KVM_PRIVATE_MEM guard from the definition of kvm_arch_has_private_mem() Changes since v2: * Switch kvm_arch_has_private_mem() to a macro to avoid overhead of a function call. * Guard definitions of kvm_arch_{pre,post}_set_memory_attributes() with #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES. * Early out in kvm_arch_post_set_memory_attributes() if the WARN_ON should trigger. --- arch/arm64/include/asm/kvm_host.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm= _host.h index 15d42d1993bb..146c52f867c0 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1510,6 +1510,8 @@ struct kvm *kvm_arch_alloc_vm(void); =20 #define vcpu_is_protected(vcpu) kvm_vm_is_protected((vcpu)->kvm) =20 +#define kvm_arch_has_private_mem(kvm) ((kvm)->arch.is_realm) + int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature); bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu); =20 --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id F35C542EEA3; Mon, 3 Aug 2026 13:46: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=1785764776; cv=none; b=pjbTDNZTO79tU+lMw15jmut9Yz26P3nJ4y6sCe3zIX0aEBC42Z6t9hdohyHs7hrLqI7tp+w83UunjtQB2UP/iv5Vv22CML1k0Nfpt8+8lY/k2/zuDbKebpc3u1F9JvABwyLH7XqagUhwCki2X40uctWYEsK1NFt2HgUEghQSiPE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764776; c=relaxed/simple; bh=m0q9iQzfENu+IKhVoifkCF21JYCMmwdvHCqfJcAPwSA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AN1PtwhLskijYenNwy8ElfhvQ+68LwubmgU8xd8xrEayycpccnJ9g3RW6IqgoGCU4JVouszY18xzTVB30N+NtxoZz4ukP4WP2T1X1oCw9pWxdO1YghDQhQYnUnkEjDU7mjM2fLjf0odfOthfJKih8dfJlCyVOcghVpOzUNskdzU= 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=V2ITscyG; 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="V2ITscyG" 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 82CCB1476; Mon, 3 Aug 2026 06:46:10 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 25FCB3F66F; Mon, 3 Aug 2026 06:46:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764774; bh=m0q9iQzfENu+IKhVoifkCF21JYCMmwdvHCqfJcAPwSA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=V2ITscyGrIwMX4uOOOQowYWBHyZljrJUHnrmxNALBcYB57/yWYVkLVKGxxXMAZ1ER IrEYy6XnYC5/OIb8KDdhwtFqMCxZ/yrhkkkA3xZ5M2Ncn/HxPGLObK4SkAJUKncYVv dWe60VEONtq033OE1n/aRwowa6u4+qalhg1K2YBQ= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 25/45] KVM: arm64: CCA: Create the realm descriptor Date: Mon, 3 Aug 2026 14:43:41 +0100 Message-ID: <20260803134403.80630-26-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" Creating a realm involves first creating a realm descriptor (RD). This involves passing the configuration information to the RMM. Do this as part of realm_ensure_created() so that the realm is created when it is first needed. The call to realm_ensure_created() will be added in a later patch. Signed-off-by: Steven Price --- Changes since v15: * The page for realm parameters is now only temporarily allocated in realm_create_rd(). * Deal with negative error codes. Changes since v14: * Explicitly set hash_algo =3D RMI_HASH_SHA_256 (which is the default). * Support SRO flow during realm creation. Changes since v13: * The RMM no longer uses AUX granules, so no need to ask it how many it needs. * Adapted to other changes. Changes since v12: * Since RMM page size is now equal to the host's page size various calculations are simplified. * Switch to using range based APIs to delegate/undelegate. * VMID handling is now handled entirely by the RMM. --- arch/arm64/kvm/rmi.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index a7202054c8e6..31eedf78a752 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -462,6 +462,83 @@ static void realm_unmap_shared_range(struct kvm *kvm, start, end); } =20 +static int realm_create_rd(struct kvm *kvm) +{ + struct realm *realm =3D &kvm->arch.realm; + struct realm_params *params __free(free_page) =3D NULL; + void *rd =3D NULL; + phys_addr_t rd_phys, params_phys, top_delegated; + size_t pgd_size =3D kvm_pgtable_stage2_pgd_size(kvm->arch.mmu.vtcr); + long rmi_ret; + int r; + + realm->ia_bits =3D VTCR_EL2_IPA(kvm->arch.mmu.vtcr); + + if (WARN_ON(realm->rd)) + return -EEXIST; + + params =3D (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT); + if (!params) + return -ENOMEM; + + rd =3D (void *)__get_free_page(GFP_KERNEL_ACCOUNT); + if (!rd) + return -ENOMEM; + + rd_phys =3D virt_to_phys(rd); + if (rmi_delegate_page(rd_phys)) { + r =3D -ENXIO; + goto free_rd; + } + + if (rmi_delegate_range(kvm->arch.mmu.pgd_phys, pgd_size, + &top_delegated)) { + r =3D -ENXIO; + goto out_undelegate_tables; + } + + params->s2sz =3D VTCR_EL2_IPA(kvm->arch.mmu.vtcr); + params->rtt_level_start =3D get_start_level(realm); + params->rtt_num_start =3D pgd_size / PAGE_SIZE; + params->rtt_base =3D kvm->arch.mmu.pgd_phys; + params->hash_algo =3D RMI_HASH_SHA_256; + + if (kvm->arch.arm_pmu) { + params->pmu_num_ctrs =3D kvm->arch.nr_pmu_counters; + params->flags0 |=3D RMI_REALM_PARAM_FLAG_PMU; + } + + if (kvm_lpa2_is_enabled()) + params->flags0 |=3D RMI_REALM_PARAM_FLAG_LPA2; + + params_phys =3D virt_to_phys(params); + + rmi_ret =3D rmi_realm_create(rd_phys, params_phys, realm->sro); + if (rmi_ret) { + r =3D rmi_ret < 0 ? rmi_ret : -ENXIO; + goto out_undelegate_tables; + } + + realm->rd =3D rd; + kvm_set_realm_state(kvm, REALM_STATE_NEW); + + return 0; + +out_undelegate_tables: + if (WARN_ON(rmi_undelegate_range(kvm->arch.mmu.pgd_phys, + top_delegated - kvm->arch.mmu.pgd_phys))) { + /* Leak the pages if they cannot be returned */ + kvm->arch.mmu.pgt =3D NULL; + } + if (WARN_ON(rmi_undelegate_page(rd_phys))) { + /* Leak the page if it isn't returned */ + return r; + } +free_rd: + free_page((unsigned long)rd); + return r; +} + static void realm_unmap_private_range(struct kvm *kvm, unsigned long start, unsigned long end, @@ -632,6 +709,24 @@ static int realm_set_ipa_state(struct kvm_vcpu *vcpu, return ret; } =20 +static int __maybe_unused realm_ensure_created(struct kvm *kvm) +{ + lockdep_assert_held(&kvm->arch.config_lock); + + switch (kvm_realm_state(kvm)) { + case REALM_STATE_NONE: + break; + case REALM_STATE_NEW: + return 0; + case REALM_STATE_DEAD: + return -ENXIO; + default: + return -EBUSY; + } + + return realm_create_rd(kvm); +} + static int kvm_complete_ripas_change(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id C85BD419FCC; Mon, 3 Aug 2026 13:46:19 +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=1785764781; cv=none; b=YYiGjrdKfpBkCBy2hepVqiR0O3legtmlMr6VstjiIryYPVBhZvY9v56l0rAuvQdtWv568CQxC+Y5nJ0CHM/dS5/5EOrzvA03tWsbAbEux7stdJ/68nqz2fQoSm+7pOpmTrNmLsUah3nVicWM5h+LuRMm7pR4K0K717RrFFGzYrk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764781; c=relaxed/simple; bh=y+n05dedLTYxg5ZLsPACFxdkDqdOljcQG5V8xZ9rCk8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EDpzqwBbHSKmIOVEE9Dou7L7stzMvPYy3LDfFA8hGaBXnYXzJaflP2MMJ3ht3UQMUhw5ZMuaUISuKzaQiXyIvwzTXoYtt4uc1i36f2opOeHs1g64HCJPznzOlak0yJW67Sbgrbtt8fPagI99WITd4TCpGMujNm+49gj1FDHBaFY= 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=dLgpxo4z; 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="dLgpxo4z" 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 579A01476; Mon, 3 Aug 2026 06:46:15 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 045D53F66F; Mon, 3 Aug 2026 06:46:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764779; bh=y+n05dedLTYxg5ZLsPACFxdkDqdOljcQG5V8xZ9rCk8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dLgpxo4zAgonL3u1UZQW16FNr0tkHTWq+u8XN801444UaWQwj3cNPLHFZV/g/q9bv utGAGRHPzpNxIi09DswgCJiH9prQ8LIqz2mKv8zUZNlyj7HcmEzR4+anRr0AaZM/Fm 7BCD6eePeunUq9I/g/+cbwloljmbwTkLJcpUclBA= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 26/45] KVM: arm64: CCA: Activate realms on first vCPU run Date: Mon, 3 Aug 2026 14:43:42 +0100 Message-ID: <20260803134403.80630-27-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" Use kvm_arch_vcpu_run_pid_change() to check if this is the first time the realm guest has run. If this is the first run then activate the realm. Signed-off-by: Steven Price --- Changes since v12: * Fix commit message * Change realm_state checks to be >=3D REALM_STATE_ACTIVE to avoid a dead guest being revived by kvm_activate_realm(). --- arch/arm64/include/asm/kvm_rmi.h | 1 + arch/arm64/kvm/arm.c | 6 +++++ arch/arm64/kvm/rmi.c | 45 ++++++++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 751659a48be3..90563183a717 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -98,6 +98,7 @@ void kvm_init_rmi(void); u32 kvm_rmm_ipa_limit(void); =20 int kvm_init_realm(struct kvm *kvm); +int kvm_activate_realm(struct kvm *kvm); void kvm_destroy_realm(struct kvm *kvm); int kvm_realm_teardown_stage2(struct kvm *kvm); void kvm_destroy_rec(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 3ad2f1d5b9e2..b7c308817d45 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1034,6 +1034,12 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vc= pu) return ret; } =20 + if (kvm_is_realm(vcpu->kvm)) { + ret =3D kvm_activate_realm(kvm); + if (ret) + return ret; + } + mutex_lock(&kvm->arch.config_lock); set_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags); mutex_unlock(&kvm->arch.config_lock); diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 31eedf78a752..c8ec766d3dc0 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -709,7 +709,7 @@ static int realm_set_ipa_state(struct kvm_vcpu *vcpu, return ret; } =20 -static int __maybe_unused realm_ensure_created(struct kvm *kvm) +static int realm_ensure_created(struct kvm *kvm) { lockdep_assert_held(&kvm->arch.config_lock); =20 @@ -829,7 +829,7 @@ int noinstr kvm_rec_enter(struct kvm_vcpu *vcpu) return ret; } =20 -static int __maybe_unused kvm_create_rec(struct kvm_vcpu *vcpu) +static int kvm_create_rec(struct kvm_vcpu *vcpu) { struct user_pt_regs *vcpu_regs =3D vcpu_gp_regs(vcpu); unsigned long mpidr =3D kvm_vcpu_get_mpidr_aff(vcpu); @@ -932,6 +932,47 @@ void kvm_destroy_rec(struct kvm_vcpu *vcpu) rec->run_phys =3D 0; } =20 +int kvm_activate_realm(struct kvm *kvm) +{ + struct realm *realm =3D &kvm->arch.realm; + struct kvm_vcpu *vcpu; + unsigned long i; + int ret; + + if (kvm_realm_state(kvm) >=3D REALM_STATE_ACTIVE) + return 0; + + if (!irqchip_in_kernel(kvm)) { + /* Userspace irqchip not yet supported with realms */ + return -EOPNOTSUPP; + } + + guard(mutex)(&kvm->arch.config_lock); + /* Check again with the lock held */ + if (kvm_realm_state(kvm) >=3D REALM_STATE_ACTIVE) + return 0; + + ret =3D realm_ensure_created(kvm); + if (ret) + return ret; + + /* Mark state as dead in case we fail */ + kvm_set_realm_state(kvm, REALM_STATE_DEAD); + + kvm_for_each_vcpu(i, vcpu, kvm) { + ret =3D kvm_create_rec(vcpu); + if (ret) + return ret; + } + + ret =3D rmi_realm_activate(virt_to_phys(realm->rd)); + if (ret) + return -ENXIO; + + kvm_set_realm_state(kvm, REALM_STATE_ACTIVE); + return 0; +} + void kvm_destroy_realm(struct kvm *kvm) { struct realm *realm =3D &kvm->arch.realm; --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id DDB8C41A4FB; Mon, 3 Aug 2026 13:46:24 +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=1785764787; cv=none; b=ITIfz1VWAKirjRPIPWjtUuZeuBX58d8Pua960+WQpyO3PTUqByRY0G4Gkq4NUOf1xgbj+Fad01eJYCmeIZAF0QrRbMpVoJFvmEoQeyjU7+Rj7ubl9R1ugbBQkito5Qql3g/Xlg1VjDtAoUvu1KjoTTae2CnM+GoAKgYzgZvIXIA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764787; c=relaxed/simple; bh=eKE4/Sm5/GuxJ8UFVqD6W1rOa6RVJlIeYRdiWlAXcYM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jPnkYS4B+UTDaqh7uZeS4HOdi9et9J4F1Yu+n/cjQzGFAEKIvd7IQ68bLnwqOdxbTEv1N8yBegP6X/XMYsKX8vL9f81LcXXOWRfF58FqvFaoCyLLEx+A8sluPJvE+olSlgUlD9/rQctpiQVA/XQEz+DhrckOJ1UsOu4Y151pVvA= 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=lnKop/iQ; 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="lnKop/iQ" 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 327EE1476; Mon, 3 Aug 2026 06:46:20 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B3CEB3F66F; Mon, 3 Aug 2026 06:46:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764784; bh=eKE4/Sm5/GuxJ8UFVqD6W1rOa6RVJlIeYRdiWlAXcYM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lnKop/iQ1vBgwO3c98+NFveOLzdZl5BN79cNYbyzjdR0a5hDnfW+j44/XXRARHA1F MnJAghBGoIZx63J99eUKA+YLh71dsj20fxRkv5vZoZLEwwgzb52ROJTE9HtVnOdsYl 1YaophYOu1qIb8iM84RtUxb7aCN6sJywHCpAQ+fY= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 27/45] KVM: arm64: CCA: Allow populating initial contents Date: Mon, 3 Aug 2026 14:43:43 +0100 Message-ID: <20260803134403.80630-28-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" The VMM needs to populate the realm with some data before starting (e.g. a kernel and initrd). This is measured by the RMM and used as part of the attestation later on. Signed-off-by: Steven Price --- Changes since v15: * Handle negative error codes Changes since v14: * Holding of locks slots_lock and config_lock have been moved up the callstack with lockdesp assertions placed in the lower functions. * Add overflow check into kvm_arm_rmi_populate(). Changes since v13: * Rename realm_create_protected_data_page() to realm_data_map_init(). Changes since v12: * The ioctl now updates the structure with the amount populated rather than returning this through the ioctl return code. * Use the new RMM v2.0 range based RMI calls. * Adapt to upstream changes in kvm_gmem_populate(). Changes since v11: * The multiplex CAP is gone and there's a new ioctl which makes use of the generic kvm_gmem_populate() functionality. Changes since v7: * Improve the error codes. * Other minor changes from review. Changes since v6: * Handle host potentially having a larger page size than the RMM granule. * Drop historic "par" (protected address range) from populate_par_region() - it doesn't exist within the current architecture. * Add a cond_resched() call in kvm_populate_realm(). Changes since v5: * Refactor to use PFNs rather than tracking struct page in realm_create_protected_data_page(). * Pull changes from a later patch (in the v5 series) for accessing pages from a guest memfd. * Do the populate in chunks to avoid holding locks for too long and triggering RCU stall warnings. --- arch/arm64/include/asm/kvm_rmi.h | 4 ++ arch/arm64/kvm/Kconfig | 1 + arch/arm64/kvm/arm.c | 13 ++++ arch/arm64/kvm/rmi.c | 119 +++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 90563183a717..03f8bd2d13a2 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -108,6 +108,10 @@ int kvm_rec_exit(struct kvm_vcpu *vcpu, int rec_run_st= atus); int kvm_rec_handle_request(struct kvm_vcpu *vcpu); bool kvm_rec_handle_hvc(struct kvm_vcpu *vcpu, int *ret); =20 +struct kvm_arm_rmi_populate; + +int kvm_arm_rmi_populate(struct kvm *kvm, + struct kvm_arm_rmi_populate *arg); void kvm_realm_unmap_range(struct kvm *kvm, unsigned long ipa, unsigned long size, diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 189e8ad78b22..83b95e836b4d 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -37,6 +37,7 @@ menuconfig KVM select SCHED_INFO select GUEST_PERF_EVENTS if PERF_EVENTS select KVM_GUEST_MEMFD + select HAVE_KVM_ARCH_GMEM_POPULATE select ARM_RMM help Support hosting virtualized guest machines. diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index b7c308817d45..f1b26b263bf0 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -2154,6 +2154,19 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned in= t ioctl, unsigned long arg) return -EFAULT; return kvm_vm_ioctl_get_reg_writable_masks(kvm, &range); } + case KVM_ARM_RMI_POPULATE: { + struct kvm_arm_rmi_populate req; + int ret; + + if (!kvm_is_realm(kvm)) + return -ENXIO; + if (copy_from_user(&req, argp, sizeof(req))) + return -EFAULT; + ret =3D kvm_arm_rmi_populate(kvm, &req); + if (copy_to_user(argp, &req, sizeof(req))) + return -EFAULT; + return ret; + } default: return -EINVAL; } diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index c8ec766d3dc0..d18c241f7eb2 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -609,6 +609,76 @@ void kvm_realm_unmap_range(struct kvm *kvm, unsigned l= ong start, realm_unmap_private_range(kvm, start, end, may_block); } =20 +static int realm_data_map_init(struct kvm *kvm, unsigned long ipa, + kvm_pfn_t dst_pfn, kvm_pfn_t src_pfn, + unsigned long flags) +{ + struct realm *realm =3D &kvm->arch.realm; + phys_addr_t rd =3D virt_to_phys(realm->rd); + phys_addr_t dst_phys, src_phys; + long ret; + + lockdep_assert_held(&kvm->slots_lock); + lockdep_assert_held(&kvm->arch.config_lock); + + dst_phys =3D __pfn_to_phys(dst_pfn); + src_phys =3D __pfn_to_phys(src_pfn); + + if (rmi_delegate_page(dst_phys)) + return -ENXIO; + +retry: + ret =3D rmi_rtt_data_map_init(rd, dst_phys, ipa, src_phys, flags); + if (ret >=3D 0 && RMI_RETURN_STATUS(ret) =3D=3D RMI_ERROR_RTT) { + /* Create missing RTTs and retry */ + int level =3D RMI_RETURN_INDEX(ret); + + KVM_BUG_ON(level >=3D KVM_PGTABLE_LAST_LEVEL, kvm); + + ret =3D realm_create_rtt_levels(realm, ipa, level, + level + 1, NULL); + if (!ret) + goto retry; + } + + if (ret && WARN_ON(rmi_undelegate_page(dst_phys))) { + /* Leak the page if the undelegate fails */ + get_page(pfn_to_page(dst_pfn)); + } + + return ret <=3D 0 ? ret : -ENXIO; +} + +static int populate_region_cb(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, + struct page *src_page, void *opaque) +{ + unsigned long data_flags =3D *(unsigned long *)opaque; + phys_addr_t ipa =3D gfn_to_gpa(gfn); + + return realm_data_map_init(kvm, ipa, pfn, page_to_pfn(src_page), + data_flags); +} + +static long populate_region(struct kvm *kvm, + gfn_t base_gfn, + unsigned long pages, + u64 uaddr, + unsigned long data_flags) +{ + long ret =3D 0; + + lockdep_assert_held(&kvm->slots_lock); + lockdep_assert_held(&kvm->arch.config_lock); + + if (!uaddr) + return -EINVAL; + + ret =3D kvm_gmem_populate(kvm, base_gfn, u64_to_user_ptr(uaddr), pages, + false, populate_region_cb, &data_flags); + + return ret; +} + enum ripas_action { RIPAS_INIT, RIPAS_SET, @@ -727,6 +797,55 @@ static int realm_ensure_created(struct kvm *kvm) return realm_create_rd(kvm); } =20 +int kvm_arm_rmi_populate(struct kvm *kvm, + struct kvm_arm_rmi_populate *args) +{ + unsigned long data_flags =3D 0; + unsigned long ipa_start =3D args->base; + unsigned long ipa_end =3D ipa_start + args->size; + long pages_populated; + int ret; + + if (args->reserved || + (args->flags & ~KVM_ARM_RMI_POPULATE_FLAGS_MEASURE) || + args->base + args->size < args->base || + !IS_ALIGNED(ipa_start, PAGE_SIZE) || + !IS_ALIGNED(ipa_end, PAGE_SIZE) || + !IS_ALIGNED(args->source_uaddr, PAGE_SIZE)) + return -EINVAL; + + if (args->flags & KVM_ARM_RMI_POPULATE_FLAGS_MEASURE) + data_flags |=3D RMI_MEASURE_CONTENT; + + mutex_lock(&kvm->slots_lock); + mutex_lock(&kvm->arch.config_lock); + + ret =3D realm_ensure_created(kvm); + if (ret) + goto out_unlock; + + if (args->size =3D=3D 0) + goto out_unlock; + + pages_populated =3D populate_region(kvm, gpa_to_gfn(ipa_start), + args->size >> PAGE_SHIFT, + args->source_uaddr, data_flags); + + if (pages_populated < 0) { + ret =3D pages_populated; + goto out_unlock; + } + + args->size -=3D pages_populated << PAGE_SHIFT; + args->source_uaddr +=3D pages_populated << PAGE_SHIFT; + args->base +=3D pages_populated << PAGE_SHIFT; + +out_unlock: + mutex_unlock(&kvm->arch.config_lock); + mutex_unlock(&kvm->slots_lock); + return ret; +} + static int kvm_complete_ripas_change(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E3A1043230A; Mon, 3 Aug 2026 13:46:28 +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=1785764790; cv=none; b=MCgj4H7Ns+cSEqItLTTqD05yAAEXiMLeR8BGq7EvfICoplc+f1+Owxrjp9LoJNQhnNzrkU7QZntlbUvfGT0iedDvCU/bK6GSYVZNliGI0Z+d/0h7WXbdekdHC93z6lHL3CsBY8ekvJPiUwGSo1sYX1IB5uspfV9M+MDSdc9getc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764790; c=relaxed/simple; bh=W30500oBfBmJ6/xAl04uVtK46drltLrN652Rd4ULSFg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=e5iCf6F74tWOWyg8Gpz1Fx7OJffJ4yK7sn3daGkOsabzOeZRGk9QhKwaIVB68K4WpMAXy8wCiujp3lHffxpFUumW+JMQIBlio7hW1Yza/thFCN8n0x/4faVohZoMFQB+4cn5/hpK8Zg/XScyKQSLA1CL0ygO45xu2DvpG7iHpdI= 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=d5xcZQy4; 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="d5xcZQy4" 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 661011476; Mon, 3 Aug 2026 06:46:24 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 94A513F66F; Mon, 3 Aug 2026 06:46:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764788; bh=W30500oBfBmJ6/xAl04uVtK46drltLrN652Rd4ULSFg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=d5xcZQy4139yVmA+Nhewrcaf6jL53MCaYkcke2saHsgyRXhcUeEM19vnEHK2ZqEHs MkUl9T8z39xWuDpxYv98F0LWDYyt8HG3KOjVEWXUrY4knAKm4Lq5MD/ppD99horeVo wGJA66zSUO0YMdnMaEtHcoDEvyh3VGNP8z5EYXLk= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 28/45] KVM: arm64: CCA: Set RIPAS of initial memslots Date: Mon, 3 Aug 2026 14:43:44 +0100 Message-ID: <20260803134403.80630-29-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" The memory which the realm guest accesses must be set to RIPAS_RAM. Iterate over the memslots and set all gmem memslots to RIPAS_RAM. Signed-off-by: Steven Price --- New patch for v12. --- arch/arm64/kvm/rmi.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index d18c241f7eb2..4f362fd21477 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -779,6 +779,14 @@ static int realm_set_ipa_state(struct kvm_vcpu *vcpu, return ret; } =20 +static int realm_init_ipa_state(struct kvm *kvm, + unsigned long gfn, + unsigned long pages) +{ + return ripas_change(kvm, NULL, gfn_to_gpa(gfn), gfn_to_gpa(gfn + pages), + RIPAS_INIT, NULL); +} + static int realm_ensure_created(struct kvm *kvm) { lockdep_assert_held(&kvm->arch.config_lock); @@ -797,6 +805,32 @@ static int realm_ensure_created(struct kvm *kvm) return realm_create_rd(kvm); } =20 +static int set_ripas_of_protected_regions(struct kvm *kvm) +{ + struct kvm_memslots *slots; + struct kvm_memory_slot *memslot; + int idx, bkt; + int ret =3D 0; + + lockdep_assert_held(&kvm->arch.config_lock); + + idx =3D srcu_read_lock(&kvm->srcu); + + slots =3D kvm_memslots(kvm); + kvm_for_each_memslot(memslot, bkt, slots) { + if (!kvm_slot_has_gmem(memslot)) + continue; + + ret =3D realm_init_ipa_state(kvm, memslot->base_gfn, + memslot->npages); + if (ret) + break; + } + srcu_read_unlock(&kvm->srcu, idx); + + return ret; +} + int kvm_arm_rmi_populate(struct kvm *kvm, struct kvm_arm_rmi_populate *args) { @@ -1084,6 +1118,10 @@ int kvm_activate_realm(struct kvm *kvm) return ret; } =20 + ret =3D set_ripas_of_protected_regions(kvm); + if (ret) + return ret; + ret =3D rmi_realm_activate(virt_to_phys(realm->rd)); if (ret) return -ENXIO; --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id DBF4F41A510; Mon, 3 Aug 2026 13:46:33 +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=1785764795; cv=none; b=N9RQIWkT/yKzsn8vURcr8nhNySewFgwjFXUPEUPMxPfHF5OiEgcz/arOHUnPIiEhUMeH0k423xzCVH35wwR9ZzV3NuYgwxHDVJEuvKN/evIG4PJmfCugq+ELg89Iq3ax5RfXyz4pngrCZ6lu/Fwpz4cCW5DCj3PpJaQnwrIdBHw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764795; c=relaxed/simple; bh=NFSfPCxyievxPmI0fZcETNfy26RUT29BhgsqoB26FYY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NLmIV3Rekrx5t7j+cWXsiVwTZ9q6aXCrdLa3mVYbB5cme/9be+aSRexBa9gOqgmz9tm+iLMOthZLSwb6zlCm4DoViomqggBp30yPoDIo+xeagZJYuff2xJBu0wcTWnpH7znn6kZ6wbYPwoHIJsAyYhvbIY5RE4Mu+lqK456LNgQ= 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=F4ErkSTn; 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="F4ErkSTn" 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 31B931476; Mon, 3 Aug 2026 06:46:29 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id DE78A3F66F; Mon, 3 Aug 2026 06:46:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764793; bh=NFSfPCxyievxPmI0fZcETNfy26RUT29BhgsqoB26FYY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=F4ErkSTn2hDZx9iy+8jfoTUqKEgeaOPECpa1Ubp0cNa31gGPAbSDuIBl6hqBv+9/r k0P3KS/jnEj0GHLqLM1t1jtXekb42IuERTYzkqkDQRGZmJuekhLLZxP0duWmjcJ4Ir Hdht0EFF9Y9KHu+uJY1ybHAmx1yMb2hjDR11wOQc= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 29/45] KVM: arm64: CCA: Support runtime faulting of memory Date: Mon, 3 Aug 2026 14:43:45 +0100 Message-ID: <20260803134403.80630-30-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" At runtime if the realm guest accesses memory which hasn't yet been mapped then KVM needs to either populate the region or fault the guest. For memory in the lower (protected) region of IPA a fresh page is provided to the RMM which will zero the contents. For memory in the upper (shared) region of IPA, the memory from the memslot is mapped into the realm VM non secure. Signed-off-by: Steven Price --- Changes since v15: * Handle negative error codes. Changes since v13: * Numerous changes due to rebasing. * Fix addr_range_desc() to encode the correct block size. Changes since v12: * Switch to RMM v2.0 range based APIs. Changes since v11: * Adapt to upstream changes. Changes since v10: * RME->RMI renaming. * Adapt to upstream gmem changes. Changes since v9: * Fix call to kvm_stage2_unmap_range() in kvm_free_stage2_pgd() to set may_block to avoid stall warnings. * Minor coding style fixes. Changes since v8: * Propagate the may_block flag. * Minor comments and coding style changes. Changes since v7: * Remove redundant WARN_ONs for realm_create_rtt_levels() - it will internally WARN when necessary. Changes since v6: * Handle PAGE_SIZE being larger than RMM granule size. * Some minor renaming following review comments. Changes since v5: * Reduce use of struct page in preparation for supporting the RMM having a different page size to the host. * Handle a race when delegating a page where another CPU has faulted on a the same page (and already delegated the physical page) but not yet mapped it. In this case simply return to the guest to either use the mapping from the other CPU (or refault if the race is lost). * The changes to populate_par_region() are moved into the previous patch where they belong. Changes since v4: * Code cleanup following review feedback. * Drop the PTE_SHARED bit when creating unprotected page table entries. This is now set by the RMM and the host has no control of it and the spec requires the bit to be set to zero. Changes since v2: * Avoid leaking memory if failing to map it in the realm. * Correctly mask RTT based on LPA2 flag (see rtt_get_phys()). * Adapt to changes in previous patches. --- arch/arm64/include/asm/kvm_emulate.h | 8 + arch/arm64/include/asm/kvm_rmi.h | 5 + arch/arm64/kvm/mmu.c | 97 ++++++++---- arch/arm64/kvm/rmi.c | 220 +++++++++++++++++++++++++++ 4 files changed, 304 insertions(+), 26 deletions(-) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/= kvm_emulate.h index 2e69fe494716..8b6f9d26b5d8 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -712,6 +712,14 @@ static inline bool kvm_realm_is_created(struct kvm *kv= m) return kvm_is_realm(kvm) && kvm_realm_state(kvm) !=3D REALM_STATE_NONE; } =20 +static inline gpa_t kvm_gpa_from_fault(struct kvm *kvm, phys_addr_t ipa) +{ + if (!kvm_is_realm(kvm)) + return ipa; + + return ipa & ~BIT(kvm->arch.realm.ia_bits - 1); +} + static inline bool vcpu_is_rec(const struct kvm_vcpu *vcpu) { return kvm_is_realm(vcpu->kvm); diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 03f8bd2d13a2..967c0a6e8e9c 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -6,6 +6,7 @@ #ifndef __ASM_KVM_RMI_H #define __ASM_KVM_RMI_H =20 +#include #include =20 /** @@ -117,6 +118,10 @@ void kvm_realm_unmap_range(struct kvm *kvm, unsigned long size, bool unmap_private, bool may_block); +int realm_map_ipa(struct kvm *kvm, phys_addr_t ipa, + kvm_pfn_t pfn, unsigned long map_size, + enum kvm_pgtable_prot prot, + struct kvm_mmu_memory_cache *memcache); =20 static inline bool kvm_realm_is_private_address(struct realm *realm, unsigned long addr) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index dcc2ab08d0e4..79119cb136b0 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -334,8 +334,15 @@ static void __unmap_stage2_range(struct kvm_s2_mmu *mm= u, phys_addr_t start, u64 =20 lockdep_assert_held_write(&kvm->mmu_lock); WARN_ON(size & ~PAGE_MASK); - WARN_ON(stage2_apply_range(mmu, start, end, KVM_PGT_FN(kvm_pgtable_stage2= _unmap), - may_block)); + + if (kvm_is_realm(kvm)) { + kvm_realm_unmap_range(kvm, start, size, !only_shared, + may_block); + } else { + WARN_ON(stage2_apply_range(mmu, start, end, + KVM_PGT_FN(kvm_pgtable_stage2_unmap), + may_block)); + } } =20 void kvm_stage2_unmap_range(struct kvm_s2_mmu *mmu, phys_addr_t start, @@ -358,7 +365,10 @@ static void stage2_flush_memslot(struct kvm *kvm, phys_addr_t addr =3D memslot->base_gfn << PAGE_SHIFT; phys_addr_t end =3D addr + PAGE_SIZE * memslot->npages; =20 - kvm_stage2_flush_range(&kvm->arch.mmu, addr, end); + if (kvm_is_realm(kvm)) + kvm_realm_unmap_range(kvm, addr, end - addr, false, true); + else + kvm_stage2_flush_range(&kvm->arch.mmu, addr, end); } =20 /** @@ -1137,6 +1147,10 @@ void stage2_unmap_vm(struct kvm *kvm) struct kvm_memory_slot *memslot; int idx, bkt; =20 + /* For realms this is handled by the RMM so nothing to do here */ + if (kvm_is_realm(kvm)) + return; + idx =3D srcu_read_lock(&kvm->srcu); mmap_read_lock(current->mm); write_lock(&kvm->mmu_lock); @@ -1641,18 +1655,20 @@ static int gmem_abort(const struct kvm_s2_fault_des= c *s2fd) bool perm_fault =3D kvm_vcpu_trap_is_permission_fault(s2fd->vcpu); enum kvm_pgtable_walk_flags flags =3D KVM_PGTABLE_WALK_SHARED; enum kvm_pgtable_prot prot =3D KVM_PGTABLE_PROT_R; - struct kvm_pgtable *pgt =3D s2fd->vcpu->arch.hw_mmu->pgt; + struct kvm_vcpu *vcpu =3D s2fd->vcpu; + struct kvm_pgtable *pgt =3D vcpu->arch.hw_mmu->pgt; + gpa_t gpa =3D kvm_gpa_from_fault(vcpu->kvm, s2fd->fault_ipa); unsigned long mmu_seq; struct page *page; - struct kvm *kvm =3D s2fd->vcpu->kvm; + struct kvm *kvm =3D vcpu->kvm; void *memcache =3D NULL; kvm_pfn_t pfn; gfn_t gfn; int ret; =20 if (!perm_fault) { - memcache =3D get_mmu_memcache(s2fd->vcpu); - ret =3D topup_mmu_memcache(s2fd->vcpu, memcache); + memcache =3D get_mmu_memcache(vcpu); + ret =3D topup_mmu_memcache(vcpu, memcache); if (ret) return ret; } @@ -1660,10 +1676,10 @@ static int gmem_abort(const struct kvm_s2_fault_des= c *s2fd) if (s2fd->nested) gfn =3D kvm_s2_trans_output(s2fd->nested) >> PAGE_SHIFT; else - gfn =3D s2fd->fault_ipa >> PAGE_SHIFT; + gfn =3D gpa >> PAGE_SHIFT; =20 - write_fault =3D kvm_is_write_fault(s2fd->vcpu); - exec_fault =3D kvm_vcpu_trap_is_exec_fault(s2fd->vcpu); + write_fault =3D kvm_is_write_fault(vcpu); + exec_fault =3D kvm_vcpu_trap_is_exec_fault(vcpu); =20 VM_WARN_ON_ONCE(write_fault && exec_fault); =20 @@ -1673,7 +1689,7 @@ static int gmem_abort(const struct kvm_s2_fault_desc = *s2fd) =20 ret =3D kvm_gmem_get_pfn(kvm, s2fd->memslot, gfn, &pfn, &page, NULL); if (ret) { - kvm_prepare_memory_fault_exit(s2fd->vcpu, s2fd->fault_ipa, PAGE_SIZE, + kvm_prepare_memory_fault_exit(vcpu, gpa, PAGE_SIZE, write_fault, exec_fault, false); return ret; } @@ -1693,7 +1709,14 @@ static int gmem_abort(const struct kvm_s2_fault_desc= *s2fd) kvm_fault_lock(kvm); if (mmu_invalidate_retry(kvm, mmu_seq)) { ret =3D -EAGAIN; - goto out_unlock; + goto out_release_page; + } + + if (kvm_is_realm(kvm)) { + prot &=3D ~KVM_PGTABLE_PROT_X; + ret =3D realm_map_ipa(kvm, s2fd->fault_ipa, pfn, + PAGE_SIZE, prot, memcache); + goto out_release_page; } =20 if (perm_fault) { @@ -1710,7 +1733,7 @@ static int gmem_abort(const struct kvm_s2_fault_desc = *s2fd) memcache, flags); } =20 -out_unlock: +out_release_page: kvm_release_faultin_page(kvm, page, !!ret, prot & KVM_PGTABLE_PROT_W); kvm_fault_unlock(kvm); =20 @@ -1896,7 +1919,7 @@ static int kvm_s2_fault_get_vma_info(const struct kvm= _s2_fault_desc *s2fd, * mapping size to ensure we find the right PFN and lay down the * mapping in the right place. */ - s2vi->gfn =3D ALIGN_DOWN(s2fd->fault_ipa, s2vi->vma_pagesize) >> PAGE_SHI= FT; + s2vi->gfn =3D kvm_gpa_from_fault(kvm, ALIGN_DOWN(s2fd->fault_ipa, s2vi->v= ma_pagesize)) >> PAGE_SHIFT; =20 s2vi->mte_allowed =3D kvm_vma_mte_allowed(vma); =20 @@ -2092,12 +2115,15 @@ static int kvm_s2_fault_map(const struct kvm_s2_fau= lt_desc *s2fd, if (!perm_fault_granule && !s2vi->map_non_cacheable && kvm_has_mte(kvm)) sanitise_mte_tags(kvm, pfn, mapping_size); =20 - /* - * Under the premise of getting a FSC_PERM fault, we just need to relax - * permissions only if mapping_size equals perm_fault_granule. Otherwise, - * kvm_pgtable_stage2_map() should be called to change block size. - */ - if (mapping_size =3D=3D perm_fault_granule) { + if (kvm_is_realm(kvm)) { + ret =3D realm_map_ipa(kvm, s2fd->fault_ipa, pfn, mapping_size, + prot, memcache); + } else if (mapping_size =3D=3D perm_fault_granule) { + /* + * Under the premise of getting a FSC_PERM fault, we just need to relax + * permissions only if mapping_size equals perm_fault_granule. Otherwise, + * kvm_pgtable_stage2_map() should be called to change block size. + */ /* * Drop the SW bits in favour of those stored in the * PTE, which will be preserved. @@ -2263,6 +2289,13 @@ int kvm_handle_guest_sea(struct kvm_vcpu *vcpu) return 0; } =20 +static bool shared_ipa_fault(struct kvm *kvm, phys_addr_t fault_ipa) +{ + gpa_t gpa =3D kvm_gpa_from_fault(kvm, fault_ipa); + + return (gpa !=3D fault_ipa); +} + /** * kvm_handle_guest_abort - handles all 2nd stage aborts * @vcpu: the VCPU pointer @@ -2373,8 +2406,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) nested =3D &nested_trans; } =20 - gfn =3D ipa >> PAGE_SHIFT; + gfn =3D kvm_gpa_from_fault(vcpu->kvm, ipa) >> PAGE_SHIFT; memslot =3D gfn_to_memslot(vcpu->kvm, gfn); + hva =3D gfn_to_hva_memslot_prot(memslot, gfn, &writable); write_fault =3D kvm_is_write_fault(vcpu); if (kvm_is_error_hva(hva) || (write_fault && !writable)) { @@ -2417,7 +2451,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) * of the page size. */ ipa |=3D FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu)); - ret =3D io_mem_abort(vcpu, ipa); + ret =3D io_mem_abort(vcpu, kvm_gpa_from_fault(vcpu->kvm, ipa)); goto out_unlock; } =20 @@ -2445,7 +2479,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) !write_fault && !kvm_vcpu_trap_is_exec_fault(vcpu)); =20 - if (kvm_slot_has_gmem(memslot)) + if (kvm_slot_has_gmem(memslot) && + (kvm_memslot_is_gmem_only(memslot) || + !shared_ipa_fault(vcpu->kvm, fault_ipa))) ret =3D gmem_abort(&s2fd); else ret =3D user_mem_abort(&s2fd); @@ -2482,6 +2518,10 @@ bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_ran= ge *range) if (!kvm->arch.mmu.pgt || kvm_vm_is_protected(kvm)) return false; =20 + /* We don't support aging for Realms */ + if (kvm_is_realm(kvm)) + return true; + return KVM_PGT_FN(kvm_pgtable_stage2_test_clear_young)(kvm->arch.mmu.pgt, range->start << PAGE_SHIFT, size, true); @@ -2498,6 +2538,10 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gf= n_range *range) if (!kvm->arch.mmu.pgt || kvm_vm_is_protected(kvm)) return false; =20 + /* We don't support aging for Realms */ + if (kvm_is_realm(kvm)) + return true; + return KVM_PGT_FN(kvm_pgtable_stage2_test_clear_young)(kvm->arch.mmu.pgt, range->start << PAGE_SHIFT, size, false); @@ -2677,10 +2721,11 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, return -EFAULT; =20 /* - * Only support guest_memfd backed memslots with mappable memory, since - * there aren't any CoCo VMs that support only private memory on arm64. + * Only support guest_memfd backed memslots with mappable memory, + * unless the guest is a CCA realm guest. */ - if (kvm_slot_has_gmem(new) && !kvm_memslot_is_gmem_only(new)) + if (kvm_slot_has_gmem(new) && !kvm_memslot_is_gmem_only(new) && + !kvm_is_realm(kvm)) return -EINVAL; =20 hva =3D new->userspace_addr; diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 4f362fd21477..3ef185bc8210 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -649,6 +649,226 @@ static int realm_data_map_init(struct kvm *kvm, unsig= ned long ipa, return ret <=3D 0 ? ret : -ENXIO; } =20 +static unsigned long addr_range_desc(unsigned long phys, unsigned long siz= e, + unsigned long state) +{ + unsigned long count =3D 1; + unsigned long out; + int rmi_size; + + for (rmi_size =3D KVM_PGTABLE_LAST_LEVEL; rmi_size >=3D 0; rmi_size--) { + unsigned long entry_size =3D rmi_range_entry_size(rmi_size); + + if (size =3D=3D entry_size) + break; + if (size > entry_size) { + rmi_size =3D -1; + break; + } + } + + if (rmi_size < 0) { + /* + * Only support mapping at the page level granularity when + * it's an unusual length. This should get us back onto a larger + * block size for the subsequent mappings. + */ + rmi_size =3D 0; + count =3D MIN(size >> PAGE_SHIFT, PTRS_PER_PTE - 1); + } + + WARN_ON(phys & ~PAGE_MASK); + + out =3D FIELD_PREP(RMI_ADDR_RANGE_SIZE_MASK, rmi_size) | + FIELD_PREP(RMI_ADDR_RANGE_COUNT_MASK, count) | + FIELD_PREP(RMI_ADDR_RANGE_STATE_MASK, state); + out |=3D phys & PAGE_MASK; + + return out; +} + +static int realm_map_protected(struct kvm *kvm, + unsigned long ipa, + kvm_pfn_t pfn, + unsigned long map_size, + struct kvm_mmu_memory_cache *memcache) +{ + struct realm *realm =3D &kvm->arch.realm; + phys_addr_t phys =3D __pfn_to_phys(pfn); + phys_addr_t base_phys =3D phys; + phys_addr_t rd =3D virt_to_phys(realm->rd); + phys_addr_t delegated_phys; + unsigned long base_ipa =3D ipa; + unsigned long ipa_top; + long ret =3D 0; + + if (WARN_ON(!IS_ALIGNED(map_size, PAGE_SIZE) || + !IS_ALIGNED(ipa, map_size))) + return -EINVAL; + + if (rmi_delegate_range(phys, map_size, &delegated_phys)) { + if (delegated_phys =3D=3D phys) { + /* + * It's likely we raced with another VCPU on the same + * fault. Assume the other VCPU has handled the fault + * and return to the guest. + */ + return 0; + } + /* Partial delegation - map as much as we can */ + map_size =3D delegated_phys - phys; + } + + ipa_top =3D ipa + map_size; + + while (ipa < ipa_top) { + unsigned long flags =3D RMI_ADDR_TYPE_SINGLE; + unsigned long range_desc =3D addr_range_desc(phys, ipa_top - ipa, + RMI_OP_MEM_DELEGATED); + unsigned long out_top; + + ret =3D rmi_rtt_data_map(rd, ipa, ipa_top, flags, range_desc, + &out_top); + if (ret < 0) + goto err_undelegate; + + if (RMI_RETURN_STATUS(ret) =3D=3D RMI_ERROR_RTT) { + /* Create missing RTTs and retry */ + int level =3D RMI_RETURN_INDEX(ret); + + if (WARN_ON(level >=3D KVM_PGTABLE_LAST_LEVEL)) + goto err_undelegate; + ret =3D realm_create_rtt_levels(realm, ipa, level, + level + 1, + memcache); + if (ret) + goto err_undelegate; + + continue; + } + + if (WARN_ON(ret)) + goto err_undelegate; + + phys +=3D out_top - ipa; + ipa =3D out_top; + } + + return 0; + +err_undelegate: + realm_unmap_private_range(kvm, base_ipa, ipa, true); + if (WARN_ON(rmi_undelegate_range(base_phys, map_size))) { + /* Page can't be returned to NS world so is lost */ + get_page(phys_to_page(base_phys)); + } + return ret < 0 ? ret : -ENXIO; +} + +static int realm_map_non_secure(struct kvm *kvm, + unsigned long ipa, + kvm_pfn_t pfn, + unsigned long size, + enum kvm_pgtable_prot prot, + struct kvm_mmu_memory_cache *memcache) +{ + struct realm *realm =3D &kvm->arch.realm; + unsigned long attr, flags =3D 0; + phys_addr_t rd =3D virt_to_phys(realm->rd); + phys_addr_t phys =3D __pfn_to_phys(pfn); + unsigned long ipa_top =3D ipa + size; + long ret; + + if (WARN_ON(!IS_ALIGNED(size, PAGE_SIZE))) + return -EINVAL; + + switch (prot & (KVM_PGTABLE_PROT_DEVICE | KVM_PGTABLE_PROT_NORMAL_NC)) { + case KVM_PGTABLE_PROT_DEVICE | KVM_PGTABLE_PROT_NORMAL_NC: + return -EINVAL; + case KVM_PGTABLE_PROT_DEVICE: + attr =3D MT_S2_FWB_DEVICE_nGnRE; + break; + case KVM_PGTABLE_PROT_NORMAL_NC: + attr =3D MT_S2_FWB_NORMAL_NC; + break; + default: + attr =3D MT_S2_FWB_NORMAL; + } + + flags |=3D FIELD_PREP(RMI_RTT_UNPROT_MAP_FLAGS_MEMATTR, attr); + + if (prot & KVM_PGTABLE_PROT_R) + flags |=3D FIELD_PREP(RMI_RTT_UNPROT_MAP_FLAGS_S2AP, RMI_S2AP_DIRECT_REA= D); + if (prot & KVM_PGTABLE_PROT_W) + flags |=3D FIELD_PREP(RMI_RTT_UNPROT_MAP_FLAGS_S2AP, RMI_S2AP_DIRECT_WRI= TE); + + flags |=3D RMI_ADDR_TYPE_SINGLE; + + while (ipa < ipa_top) { + unsigned long range_desc =3D addr_range_desc(phys, ipa_top - ipa, + RMI_OP_MEM_UNDELEGATED); + unsigned long out_top; + + ret =3D rmi_rtt_unprot_map(rd, ipa, ipa_top, flags, range_desc, + &out_top); + if (ret < 0) + return ret; + + if (RMI_RETURN_STATUS(ret) =3D=3D RMI_ERROR_RTT) { + /* Create missing RTTs and retry */ + int level =3D RMI_RETURN_INDEX(ret); + int req_level =3D find_map_level(realm, ipa, ipa_top); + + /* + * There already exists a mapping at the level. May be + * we are relaxing a permission for the given range ? + */ + if (level >=3D req_level) { + realm_unmap_shared_range(kvm, ipa, ipa_top, true); + continue; + } + + ret =3D realm_create_rtt_levels(realm, ipa, level, + req_level, + memcache); + if (ret) + return ret; + + ret =3D rmi_rtt_unprot_map(rd, ipa, ipa_top, flags, + range_desc, &out_top); + if (ret < 0) + return ret; + } + + if (ret && RMI_RETURN_STATUS(ret) !=3D RMI_ERROR_RTT) + return ret; + + phys +=3D out_top - ipa; + ipa =3D out_top; + } + + return 0; +} + +int realm_map_ipa(struct kvm *kvm, phys_addr_t ipa, + kvm_pfn_t pfn, unsigned long map_size, + enum kvm_pgtable_prot prot, + struct kvm_mmu_memory_cache *memcache) +{ + struct realm *realm =3D &kvm->arch.realm; + + ipa =3D ALIGN_DOWN(ipa, map_size); + if (!kvm_realm_is_private_address(realm, ipa)) { + return realm_map_non_secure(kvm, ipa, pfn, map_size, prot, + memcache); + } + + /* It's impossible to map protected pages read-only. */ + if (WARN_ON(!(prot & KVM_PGTABLE_PROT_W))) + return -EFAULT; + return realm_map_protected(kvm, ipa, pfn, map_size, memcache); +} + static int populate_region_cb(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, struct page *src_page, void *opaque) { --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1D322432E9F; Mon, 3 Aug 2026 13:46:38 +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=1785764799; cv=none; b=b2qaFa08BkO6cbie+27uKzcm8kRYh3xYLfDeCnHopW/x1ijc9kDUxDfWMHX32gODuxa+a9f08yI6vguNzKlPS8tCvKCk7w3YtUDqcVM5FFXbzqq8vIpOrcjXsay7C2eY+Ak0jOJ+g93MFR7BsNBDVZ4400h87iSGqKdG9kaChmc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764799; c=relaxed/simple; bh=odu8NptFW0KFxtwMsH3fTdQCuF7RttUpNWz6E9NwzIY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Zo53yb0Mfoo+V3jg1e0guaNT2xWtCiPhGga0ZRVi84jbeDVACV0N3c/uuC2bGRlWhu+IXgV2sI2WqIp7p9OnVfhiZzf0jGeV2ADQZirOpsFYu8DMcH1av1MxU0XrKgHHunFzQ/jsqBW9b22fj7cajjMCYphpGaiuBw1E+41WLoc= 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=lYaxabVx; 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="lYaxabVx" 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 A25CB1476; Mon, 3 Aug 2026 06:46:33 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 8F6EC3F66F; Mon, 3 Aug 2026 06:46:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764797; bh=odu8NptFW0KFxtwMsH3fTdQCuF7RttUpNWz6E9NwzIY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lYaxabVx+BG5cVdnrkCJSESIcgwXAawnVwmq/1E1jw9pjfMIhMUpV25qz6JA45pwe NLz5mqn14RQguzwyOtZQ1WggvKqurLieTvwCptEGJ52bv9WVJhmWsAUiXRLwZLCBHX c+dQsC53RXmSzAl0xGVSOr7im9zrAqLu0aiMzAmM= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 30/45] KVM: arm64: CCA: Handle realm vCPU load Date: Mon, 3 Aug 2026 14:43:46 +0100 Message-ID: <20260803134403.80630-31-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" When loading a realm VCPU much of the work is handled by the RMM so only some of the actions are required. Rearrange kvm_arch_vcpu_load() slightly so we can bail out early for a realm guest. Signed-off-by: Steven Price --- arch/arm64/kvm/arm.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index f1b26b263bf0..96e536d2dda8 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -707,7 +707,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) struct kvm_s2_mmu *mmu; int *last_ran; =20 - if (is_protected_kvm_enabled()) + if (is_protected_kvm_enabled() || kvm_is_realm(vcpu->kvm)) goto nommu; =20 if (vcpu_has_nv(vcpu)) @@ -751,12 +751,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) kvm_vgic_load(vcpu); kvm_vcpu_load_debug(vcpu); kvm_vcpu_load_fgt(vcpu); - if (has_vhe()) - kvm_vcpu_load_vhe(vcpu); - kvm_arch_vcpu_load_fp(vcpu); - kvm_vcpu_pmu_restore_guest(vcpu); - if (kvm_arm_is_pvtime_enabled(&vcpu->arch)) - kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu); =20 if (kvm_vcpu_should_clear_twe(vcpu)) vcpu->arch.hcr_el2 &=3D ~HCR_TWE; @@ -778,6 +772,17 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) &vcpu->arch.vgic_cpu.vgic_v3); } =20 + /* No additional state needs to be loaded on Realmed VMs */ + if (vcpu_is_rec(vcpu)) + return; + + if (has_vhe()) + kvm_vcpu_load_vhe(vcpu); + kvm_arch_vcpu_load_fp(vcpu); + kvm_vcpu_pmu_restore_guest(vcpu); + if (kvm_arm_is_pvtime_enabled(&vcpu->arch)) + kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu); + if (!cpumask_test_cpu(cpu, vcpu->kvm->arch.supported_cpus)) vcpu_set_on_unsupported_cpu(vcpu); =20 --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D35834334AD; Mon, 3 Aug 2026 13:46:42 +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=1785764804; cv=none; b=dyFWAkxaooScY0NgFDEBf69ttc20NktB2b8CZVJcw5tyhOjmr+xOGFgK4JJDghEiAYJAt9d6g9rVJvEzLmecfftg1RVbYTVHxFBL3NhBZFqMA28pvXIaDBfVvMmy1K/Eg2GyP9+dhu7ghoANmnh5qZY4ZiWPsNeXUj+EP1H7vIc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764804; c=relaxed/simple; bh=UZ1cXeVFfJIYr/MkjIsCfrnNWtsKIftqp2z8gXgFYYo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LWcVQ06UbEXrLYRlEWhk3TXHPxqPEOEkJWaBdQ1s6ar1cISeODrYF8AFI0BzYF5A17G40R6k4vW4cGSIVgXMcJ2sh2OlXUq2LuVmX/HyivOY6MSSSItFRRZTh8mtsOq9RCGytOoSIqktDJGJwlSHzOJb3KcOFZKAPbZy/yK9KXU= 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=W3LooCD+; 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="W3LooCD+" 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 463A41655; Mon, 3 Aug 2026 06:46:38 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 0E05D3F66F; Mon, 3 Aug 2026 06:46:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764802; bh=UZ1cXeVFfJIYr/MkjIsCfrnNWtsKIftqp2z8gXgFYYo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=W3LooCD+HK0xyDhY2QDTyYyUXzUE5XKFzZ0Cm5DJh1bQJdaSUn9h80h8D0m/xqpSX gLJ6TK/5cnCz2SZ4WPnKq/9LS2uKkU20Vvjj89RrB4xUSfyAP6HKv0/BOwOGORM345 tarsaFvGUhSdSgyNDYHod5otiTXGEe30U1Qz9C+E= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 31/45] KVM: arm64: CCA: Validate register access for Realm VMs Date: Mon, 3 Aug 2026 14:43:47 +0100 Message-ID: <20260803134403.80630-32-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" The RMM only allows setting the GPRS (x0-x30) and PC for a realm guest. Check this in kvm_arm_set_reg() so that the VMM can receive a suitable error return if other registers are written to. The RMM makes similar restrictions for reading of the guest's registers (this is *confidential* compute after all), however we don't impose the restriction here. This allows the VMM to read (stale) values from the registers which might be useful to read back the initial values even if the RMM doesn't provide the latest version. For migration of a realm VM, a new interface will be needed so that the VMM can receive an (encrypted) blob of the VM's state. Reviewed-by: Gavin Shan Reviewed-by: Suzuki K Poulose Reviewed-by: Joey Gouly Signed-off-by: Steven Price --- Changes since v5: * Upper GPRS can be set as part of a HOST_CALL return, so fix up the test to allow them. --- arch/arm64/kvm/guest.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index b01d6622b872..3e970c4f6214 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -73,6 +73,25 @@ static u64 core_reg_offset_from_id(u64 id) return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE); } =20 +static bool kvm_realm_validate_core_reg(u64 off) +{ + /* + * Note that GPRs can only sometimes be controlled by the VMM. + * For PSCI only X0-X6 are used, higher registers are ignored (restored + * from the REC). + * For HOST_CALL all of X0-X30 are copied to the RsiHostCall structure. + * For emulated MMIO X0 is always used. + * PC can only be set before the realm is activated. + */ + switch (off) { + case KVM_REG_ARM_CORE_REG(regs.regs[0]) ... + KVM_REG_ARM_CORE_REG(regs.regs[30]): + case KVM_REG_ARM_CORE_REG(regs.pc): + return true; + } + return false; +} + static int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off) { int size; @@ -716,12 +735,34 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const stru= ct kvm_one_reg *reg) return kvm_arm_sys_reg_get_reg(vcpu, reg); } =20 +/* + * The RMI ABI only enables setting some GPRs and PC. The selection of GPRs + * that are available depends on the Realm state and the reason for the la= st + * exit. All other registers are reset to architectural or otherwise defi= ned + * reset values by the RMM, except for a few configuration fields that + * correspond to Realm parameters. + */ +static bool validate_realm_set_reg(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + if ((reg->id & KVM_REG_ARM_COPROC_MASK) =3D=3D KVM_REG_ARM_CORE) { + u64 off =3D core_reg_offset_from_id(reg->id); + + return kvm_realm_validate_core_reg(off); + } + + return false; +} + int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { /* We currently use nothing arch-specific in upper 32 bits */ if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 !=3D KVM_REG_ARM64 >> 32) return -EINVAL; =20 + if (kvm_is_realm(vcpu->kvm) && !validate_realm_set_reg(vcpu, reg)) + return -EINVAL; + switch (reg->id & KVM_REG_ARM_COPROC_MASK) { case KVM_REG_ARM_CORE: return set_core_reg(vcpu, reg); case KVM_REG_ARM_FW: --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 76F1D401A08; Mon, 3 Aug 2026 13:46:47 +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=1785764808; cv=none; b=moXanNS2Gj6NBgXIuGQLz1u+nvuTjteiU2HsS70EA1FYRbG3hi8F+d29+CQRBKAQL/8Trv+Bl3b6WukQuNuQ7bVpTCBgrlsI6UhBmX+eboANqt9kinwQMaWeNmxHPS5My70B68ILggZIbC2LstLdyxDU27vPKBbK4S7jqVyjTTk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764808; c=relaxed/simple; bh=rE5FH9m6cgbxv4oXJ1XSPENbjK143njy6sCuV+SL+fo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W42DXkZvaKu5hhQyO1qQSeeMHURiYYoLMqKfJwT0jSJQ+gtDSy9GpvmOF+kEa2HRqargi5WVBO2g3gxEqCSUTWj2pbcyxaG5YDb+iduPFYtBLM7qQwdWLsK3VA5sp3JR/b/tDhWkzf04bloDZp3XMQTevD1Yk5hwgC1HJS6uFrI= 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=ckVzX19e; 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="ckVzX19e" 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 F0C2F1476; Mon, 3 Aug 2026 06:46:42 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id BBB873F66F; Mon, 3 Aug 2026 06:46:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764807; bh=rE5FH9m6cgbxv4oXJ1XSPENbjK143njy6sCuV+SL+fo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ckVzX19es7E2Ac9HZIzWyIGBb0UzHKb0HeLvoqyl/wXBsBzXU7/zUXzLh4mmsAvX4 Wm246oY5mYIzCBXgMKG4ozQJ5tKXpAHRkweVj+5xPjNI/WM94dTBtrdz7+yvWPt5v8 PyzLiCgxjHUyFZW2jNGDGl+CiSG8LmHDkA3EOOhQ= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 32/45] KVM: arm64: CCA: Handle Realm PSCI requests Date: Mon, 3 Aug 2026 14:43:48 +0100 Message-ID: <20260803134403.80630-33-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" Some PSCI commands cause a REC exit and the host has to call RMI_PSCI_COMPLETE to provide the status value to return to the guest. Co-developed-by: Suzuki K Poulose Signed-off-by: Suzuki K Poulose Signed-off-by: Steven Price --- Changes since v15: * Adapt to new exit handling. Changes since v14: * Dropped the support for providing the target REC for a PSCI call (as per v2.0-bet2 spec). Changes since v13: * The ioctl KVM_ARM_VCPU_RMI_PSCI_COMPLETE has gone. The RMI call is made automatically just before entering the REC again. Changes since v12: * Change return code for non-realms to -ENXIO to better represent that the ioctl is invalid for non-realms (checkpatch is insistent that "ENOSYS means 'invalid syscall nr' and nothing else"). Changes since v11: * RMM->RMI renaming. Changes since v6: * Use vcpu_is_rec() rather than kvm_is_realm(vcpu->kvm). * Minor renaming/formatting fixes. --- arch/arm64/include/asm/kvm_rmi.h | 2 ++ arch/arm64/kvm/rmi.c | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 967c0a6e8e9c..0fb685004d5c 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -123,6 +123,8 @@ int realm_map_ipa(struct kvm *kvm, phys_addr_t ipa, enum kvm_pgtable_prot prot, struct kvm_mmu_memory_cache *memcache); =20 +int realm_psci_complete(struct kvm_vcpu *source, unsigned long status); + static inline bool kvm_realm_is_private_address(struct realm *realm, unsigned long addr) { diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 3ef185bc8210..3f31ad25680f 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -3,6 +3,7 @@ * Copyright (C) 2023-2026 ARM Ltd. */ =20 +#include #include =20 #include @@ -120,6 +121,17 @@ static void free_rtt(phys_addr_t phys) kvm_account_pgtable_pages(phys_to_virt(phys), -1); } =20 +int realm_psci_complete(struct kvm_vcpu *source, unsigned long status) +{ + long ret; + + ret =3D rmi_psci_complete(source->arch.rec.rec_phys, status); + if (ret) + return -ENXIO; + + return 0; +} + static long realm_rtt_create(struct realm *realm, unsigned long addr, int level, @@ -1145,6 +1157,30 @@ static int kvm_complete_ripas_change(struct kvm_vcpu= *vcpu) return 1; } =20 +static int kvm_rec_complete_psci(struct kvm_vcpu *vcpu) +{ + struct rec_run *run =3D vcpu->arch.rec.run; + unsigned long status =3D PSCI_RET_DENIED; + unsigned long ret =3D vcpu_get_reg(vcpu, 0); + int r; + + switch (run->exit.gprs[0]) { + case PSCI_0_2_FN64_CPU_ON: { + if (ret !=3D PSCI_RET_SUCCESS && + ret !=3D PSCI_RET_ALREADY_ON) + status =3D PSCI_RET_DENIED; + else + status =3D PSCI_RET_SUCCESS; + break; + } + default: + return 1; + } + + r =3D realm_psci_complete(vcpu, status); + return r ?: 1; +} + int kvm_rec_handle_request(struct kvm_vcpu *vcpu) { struct realm_rec *rec =3D &vcpu->arch.rec; @@ -1163,6 +1199,8 @@ int kvm_rec_handle_request(struct kvm_vcpu *vcpu) vcpu_get_reg(vcpu, rt); } break; + case RMI_EXIT_PSCI: + return kvm_rec_complete_psci(vcpu); case RMI_EXIT_RIPAS_CHANGE: return kvm_complete_ripas_change(vcpu); default: --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 618BD41CB47; Mon, 3 Aug 2026 13:46:52 +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=1785764813; cv=none; b=LyQkMEkTe7xUtIo8o3hm4yswpovL9kswdOhYZTej6LSl/qNbJn4+eXDTwukhE3eKkvqf1iz2N3PEO3BM9Y+94kiuq4ybFN1LYEHP5kYVS5zSmklW/o2Qo/j0jMwJFS3JRnRuyCxVNnCg5kOPz6RrpFr+yNpm9UIJHcPERnxqb9s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764813; c=relaxed/simple; bh=tOBslaJ98uztlGsY7JxHxX4R0AkDQJN14zYapGPHB9A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sa5JbvRTT9WiaxMgqhyhmDH9loJIVgvnuD3r3Cxh1FaNg7teZxqoEfxPOg634nHlA+IkFNPtLmDaEHM/+lko0Kbgz9xoc57d6VJKvrpfPL1Uv4KSiNDQUTN7rPf2xUe9VHVId9VRGv2vuAMT3c+DU7XqXiRgpg/S0nUeGwgimGc= 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=va0zPPo4; 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="va0zPPo4" 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 DC78D1655; Mon, 3 Aug 2026 06:46:47 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 74DCB3F66F; Mon, 3 Aug 2026 06:46:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764811; bh=tOBslaJ98uztlGsY7JxHxX4R0AkDQJN14zYapGPHB9A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=va0zPPo4ixfUqTb4IhQPPk9m3XqIELYDEWP5J7e4dvfXFMvMkXnsc7c96jh26kTxV PVvk6ycb1FDT+kSz6Jr0wFqkNbDlHN67DOU2Cg90f/GmRBultW10i3TcihCv7RyF7Y YbapyHir86nROK91GDfhU3avvLi5u/LE8jUaUE4s= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 33/45] KVM: arm64: WARN on injected undef exceptions Date: Mon, 3 Aug 2026 14:43:49 +0100 Message-ID: <20260803134403.80630-34-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" The RMM doesn't allow injection of a undefined exception into a realm guest. Add a WARN to catch if this ever happens. Signed-off-by: Steven Price --- Changes since v15: * Switch to KVM_BUG() to mark the VM as bugged as well. Changes since v6: * if (x) WARN(1, ...) makes no sense, just WARN(x, ...)! --- arch/arm64/kvm/inject_fault.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index 6492397b73d7..718419f40c1d 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -327,6 +327,7 @@ void kvm_inject_size_fault(struct kvm_vcpu *vcpu) */ void kvm_inject_undefined(struct kvm_vcpu *vcpu) { + KVM_BUG(vcpu_is_rec(vcpu), vcpu->kvm, "Unexpected undefined exception inj= ection to REC"); if (vcpu_el1_is_32bit(vcpu)) inject_undef32(vcpu); else --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5C59641D11A; Mon, 3 Aug 2026 13:46:57 +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=1785764818; cv=none; b=ITm+tGCdBRPlOM5inCZZsl9xbizorkOqeQxQvWOfrwZQbmp6y1Jz7sHX35FM0ZlotkK4dN6vQSDeKRYUDzH8ZjrTe2xJ9gRPsQUxkXM8ioRjBmtl6IyFwbfjpUQWUKk3SAE2oQdpReZE7r665TwgoQa0DH9zbyCZWNC5GgDdcas= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764818; c=relaxed/simple; bh=2KRm6eRn0QWTkHE5OMOiCijHYTpfxylpHK/uPx5dLJw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OzEH0Nnis1a0T6p78JvzuiU+sU/ctnF8z/Keq0EqCyNamRMv6oA5Br+uLnwU9YHd9NILkPmTNCJcWq6cXtImsBxbWh+t9k814+305DCWsLUHCK1kUBo1nQZMvoznN7Oh9R5Ok4STXj+TllYE6YekAGAMyQLR4UpR2AcA11nYm28= 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=bqAarQIx; 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="bqAarQIx" 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 BF88D1476; Mon, 3 Aug 2026 06:46:52 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 605463F66F; Mon, 3 Aug 2026 06:46:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764816; bh=2KRm6eRn0QWTkHE5OMOiCijHYTpfxylpHK/uPx5dLJw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bqAarQIxdAf3s67O3BvmyONBrvxd1DvSvDCaopaGCJshv6KfRGoH3K1/D/dQlkQJH weUjyAoZOnsQtFkNU3Ktrd95T2RQ7t/2grgNzmpxAv+MAuGwY7zGrZgHcIyopAGDR9 G8ET27p+3lErz3/+s4bWvHT9kCQjxGGVI22w7/XE= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Joey Gouly , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 34/45] KVM: arm64: CCA: Allow userspace to inject aborts Date: Mon, 3 Aug 2026 14:43:50 +0100 Message-ID: <20260803134403.80630-35-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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: Joey Gouly Extend KVM_SET_VCPU_EVENTS to support realms, where KVM cannot set the system registers, and the RMM must perform it on next REC entry. Signed-off-by: Joey Gouly Signed-off-by: Steven Price Reviewed-by: Gavin Shan Reviewed-by: Suzuki K Poulose --- Documentation/virt/kvm/api.rst | 2 ++ arch/arm64/kvm/guest.c | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 802601eaf560..1c9488df7e06 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -1317,6 +1317,8 @@ User space may need to inject several types of events= to the guest. Set the pending SError exception state for this VCPU. It is not possible to 'cancel' an Serror that has been made pending. =20 +User space cannot inject SErrors into Realms. + If the guest performed an access to I/O memory which could not be handled = by userspace, for example because of missing instruction syndrome decode information or because there is no device mapped at the accessed IPA, then diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 3e970c4f6214..5469c9a97fad 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -827,6 +827,30 @@ int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu, u64 esr =3D events->exception.serror_esr; int ret =3D 0; =20 + if (vcpu_is_rec(vcpu)) { + /* Cannot inject SError into a Realm. */ + if (serror_pending) + return -EINVAL; + + /* + * If a data abort is pending, set the flag and let the RMM + * inject an SEA when the REC is scheduled to be run. + */ + if (ext_dabt_pending) { + /* + * Can only inject SEA into a Realm if the previous exit + * was due to a data abort of an Unprotected IPA. + */ + if (!(vcpu->arch.rec.run->enter.flags & REC_ENTER_FLAG_EMULATED_MMIO)) + return -EINVAL; + + vcpu->arch.rec.run->enter.flags &=3D ~REC_ENTER_FLAG_EMULATED_MMIO; + vcpu->arch.rec.run->enter.flags |=3D REC_ENTER_FLAG_INJECT_SEA; + } + + return 0; + } + /* * Immediately commit the pending SEA to the vCPU's architectural * state which is necessary since we do not return a pending SEA --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6BFEE43990D; Mon, 3 Aug 2026 13:47: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=1785764823; cv=none; b=Ad11gqmKo51KcikQ7W4wfCFY3btoi2wLEydtPlhaZEz5SsFAGV5m3b3a2uxDmqaccxdMlqN+g88cOovGWf8jMOodgwVzlVtV4oM4pfA11s7jny45QYu4+qh3bYrzMQETBliIFaznUbkJFo+CsGm0KAGU1zZkcXjCAvNVc6uUmBQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764823; c=relaxed/simple; bh=R90GSqHKgNKLq0IbPcgJ2Xy7BoduOtRWpnHj0KKueKk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IEzgrtT0Q4S6ytopHvmG59/igKgl/FBuOinG4YV1TmtMsP3x7b0ra2a9VmhrQMx+atqewh0PiA8pv5h4W36a1kwU+BdNKkuAaWxxMF6eANBKPsWkl6zN/jOGoGC/UwYe8ZFUuA/PRMpnQMMfP4oZh2F/2X+y6HKdDpvPnsDy4Ho= 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=W5i9r3b6; 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="W5i9r3b6" 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 D6C3C1655; Mon, 3 Aug 2026 06:46:57 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 4B96F3F66F; Mon, 3 Aug 2026 06:46:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764821; bh=R90GSqHKgNKLq0IbPcgJ2Xy7BoduOtRWpnHj0KKueKk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=W5i9r3b6l4ACstwJ4hcdMWGUNalMjpqK3Kfd2nYwLQ/rPRTuQYAK7sF0ZcIktlg2B HasUL/a8gkc/mzH1Bv24AeL0mjMDbypOSPJ+yuhJ4kIVYfC73yJuZiUsIlugGhPmd6 /2xke7+wX/ywgclM9eJm8JOCYys0O6htTk+rDxZ8= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Joey Gouly , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 35/45] KVM: arm64: CCA: Support RSI_HOST_CALL Date: Mon, 3 Aug 2026 14:43:51 +0100 Message-ID: <20260803134403.80630-36-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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: Joey Gouly Realm VMs can talk to the hypervisor using the RSI_HOST_CALL SMC. The RMM forwards this to the host and KVM handles them as regular hypercalls. Signed-off-by: Joey Gouly Signed-off-by: Steven Price --- Changes since v15: * Adapt to new exit handling. Changes since v7: * Avoid turning a negative return from kvm_smccc_call_handler() into a error response to the guest. Instead propagate the error back to user space. Changes since v4: * Setting GPRS is now done by kvm_rec_enter() rather than rec_exit_host_call() (see previous patch - arm64: RME: Handle realm enter/exit). This fixes a bug where the registers set by user space were being ignored. --- arch/arm64/kvm/rmi-exit.c | 1 + arch/arm64/kvm/rmi.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/arch/arm64/kvm/rmi-exit.c b/arch/arm64/kvm/rmi-exit.c index 1749cde2edff..7cde820bb77b 100644 --- a/arch/arm64/kvm/rmi-exit.c +++ b/arch/arm64/kvm/rmi-exit.c @@ -164,6 +164,7 @@ int kvm_rec_exit(struct kvm_vcpu *vcpu, int rec_run_ret) case RMI_EXIT_SERROR: return ARM_EXCEPTION_EL1_SERROR; case RMI_EXIT_PSCI: + case RMI_EXIT_HOST_CALL: rec_exit_hvc(vcpu); kvm_make_request(KVM_REQ_RMI, vcpu); return ARM_EXCEPTION_TRAP; diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 3f31ad25680f..904df7c7245d 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -1203,6 +1203,10 @@ int kvm_rec_handle_request(struct kvm_vcpu *vcpu) return kvm_rec_complete_psci(vcpu); case RMI_EXIT_RIPAS_CHANGE: return kvm_complete_ripas_change(vcpu); + case RMI_EXIT_HOST_CALL: + for (int i =3D 0; i < REC_RUN_GPRS; i++) + rec->run->enter.gprs[i] =3D vcpu_get_reg(vcpu, i); + break; default: KVM_BUG(1, vcpu->kvm, "Unhandled realm exit_reason"); return -ENXIO; --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 4216F4399D8; Mon, 3 Aug 2026 13:47:07 +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=1785764828; cv=none; b=l2UruXuxwQMs1TkYBnTJDgZeSJ3HwMnBkLm+nurE3KjbO/ONg8clX9rI5CDVAZKWz5qpfptiojRP54q5un5Y2ivAcjAHfVM2RPdWkkB9bGewUiDw7K1EZ/p3Pz6psAhER+xVn7mKtBu74joA836AZm1R9ggYI5PjVJpk4baaT5g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764828; c=relaxed/simple; bh=f5XF4TndoxoVxH50VEJOC2RYRGtrrvhd8+1pRFIhR/0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GMCIODAQu1/clUMS9WgQ5TqKCMVI9pJ+GOe1MZVy3hoWqlWp1hqesnchuiK1ew+/NEOAjWK4zfST0P4cZAMr4biMY3p0rC/4tn5snfvaLCUnS7ihlFQ3p9KJ7dj+x9Bkrd0zKmpyk0drFANLukkbyHYMRrG77d7cvF/nx21mmX0= 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=fJKmpKXh; 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="fJKmpKXh" 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 B0C2F1476; Mon, 3 Aug 2026 06:47:02 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 42F073F66F; Mon, 3 Aug 2026 06:47:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764826; bh=f5XF4TndoxoVxH50VEJOC2RYRGtrrvhd8+1pRFIhR/0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fJKmpKXhuohGrp+3530yeKrJT8csfLjS8y+WM81FheaAhbBObS+HTTmpyOPHsyN/Q lxjnqi59afiuuWgqyqp8XMuWOTxf8nVkgBF7I31tYQNp5KgYNh1VqpduBnXt8VlHOu OrhjHSsvfZbniqZnMDiulGx9pVTcoAk23iHUyph8= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Suzuki K Poulose , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 36/45] KVM: arm64: CCA: Allow checking SVE on VM instance Date: Mon, 3 Aug 2026 14:43:52 +0100 Message-ID: <20260803134403.80630-37-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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: Suzuki K Poulose Given we have different types of VMs supported, check the support for SVE for the given instance of the VM to accurately report the status. Signed-off-by: Suzuki K Poulose Signed-off-by: Steven Price Reviewed-by: Gavin Shan Reviewed-by: Joey Gouly --- Changes since v10: * RME->RMI renaming. * Adapt to move CAP check to kvm_realm_ext_allowed(). --- arch/arm64/include/asm/kvm_rmi.h | 2 ++ arch/arm64/kvm/arm.c | 2 ++ arch/arm64/kvm/rmi.c | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 0fb685004d5c..13933f0e555d 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -98,6 +98,8 @@ struct realm_rec { void kvm_init_rmi(void); u32 kvm_rmm_ipa_limit(void); =20 +bool kvm_rmi_supports_sve(void); + int kvm_init_realm(struct kvm *kvm); int kvm_activate_realm(struct kvm *kvm); void kvm_destroy_realm(struct kvm *kvm); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 96e536d2dda8..3242108be7c5 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -151,6 +151,8 @@ static bool kvm_realm_ext_allowed(long ext) case KVM_CAP_ARM_RMI: case KVM_CAP_SYNC_MMU: return true; + case KVM_CAP_ARM_SVE: + return kvm_rmi_supports_sve(); } return false; } diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 904df7c7245d..0d46768022df 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -26,6 +26,11 @@ static bool rmi_has_feature(int reg, unsigned long featu= re) return !!u64_get_bits(rmi_feat_reg(reg), feature); } =20 +bool kvm_rmi_supports_sve(void) +{ + return rmi_has_feature(0, RMI_FEATURE_REGISTER_0_SVE); +} + u32 kvm_rmm_ipa_limit(void) { return u64_get_bits(rmi_feat_reg(0), RMI_FEATURE_REGISTER_0_S2SZ); --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 009AA41229C; Mon, 3 Aug 2026 13:47:12 +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=1785764833; cv=none; b=iRfbagzNTL+ok/sXNJb4Ay0CVsEl0LKLfamucJYLIqbU70nBih4QwjWfQvLGZD4GCpEvwOm9jGJePsl5Yo3/JMGoB51jkOoe24EFKiY9pzgbOTnzNC9hhw7BGltvXbCvByFxJvjLGGQazq0aqGz5SSISfkq0JpvL+MBGr0Et4JI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764833; c=relaxed/simple; bh=/DkC06ykICbYbu8lRH1puAEPBlPtvdphP1WP+AibYYM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KHHD5GoBg9D5CtpndVZcR3YdtBaWq7ARJebqeGrgUWVDUKSPxvDDxHrHC8YNfJCLSGU9Kb+ltgluX8x1T/U21JIa1D6BWjkBZPe9cNMNLBz2I1jTzQKgEEes+3Lb4oWJW45cp0dbae+a3gTxfKBup9R+JKz3zpQYYOIXK3RgCDk= 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=nJL02zq6; 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="nJL02zq6" 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 82BB21476; Mon, 3 Aug 2026 06:47:07 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 2C9473F66F; Mon, 3 Aug 2026 06:47:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764831; bh=/DkC06ykICbYbu8lRH1puAEPBlPtvdphP1WP+AibYYM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nJL02zq6f5gv2qEXZaqhk/tOZBNFN9bDgX8UixwRkjIKrvCAKwKZcDJ+ZJ0tJbOXT NkoKF6RmOClf968xdoAMBUGuCh4pPem5XWXc6jZ2r77v4TvZKKAK6x52gHQHBMKE84 cnV6TMf69xNqmNSdLkP7hrsubVrpbPWLsOaanzpA= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 37/45] KVM: arm64: CCA: Prevent Device mappings for realms Date: Mon, 3 Aug 2026 14:43:53 +0100 Message-ID: <20260803134403.80630-38-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" Physical device assignment is not yet supported. RMM v2.0 does add the relevant APIs, but device assignment is a big topic so will be handled in a future patch series. For now prevent device mappings when the guest is a realm. Signed-off-by: Steven Price --- Changes from v6: * Fix the check in user_mem_abort() to prevent all pages that are not guest_memfd() from being mapped into the protected half of the IPA. Changes from v5: * Also prevent accesses in user_mem_abort() --- arch/arm64/kvm/mmu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 79119cb136b0..dc27f3dfb337 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1261,6 +1261,10 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr= _t guest_ipa, if (is_protected_kvm_enabled()) return -EPERM; =20 + /* We don't support mapping special pages into a Realm */ + if (kvm_is_realm(kvm)) + return -EPERM; + size +=3D offset_in_page(guest_ipa); guest_ipa &=3D PAGE_MASK; =20 --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 84CD641229C; Mon, 3 Aug 2026 13:47:16 +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=1785764838; cv=none; b=JeEuh1FYefxwRZrfHQELo7A8P193P2xRzFXVjDlyVU3IuRW6zcQ7HAErjNsKYmqzhPbfqUFctPNScePUdoD09ark+xk90HAiLrRySSPups0tVmVWn0LT1mPraVrLGxlqGazDF2XjJDqKftazVo8y2jnGkcmZ7vd1JD0ybNHRwhI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764838; c=relaxed/simple; bh=9dDPYOK56JspwvgV/TEJkMLfs8tJYVd/42IM7MAl10c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Yp+jaRqhhQBQ4NXpX1FWwUNthFEo1hgPJROR+sqorlUhnt1bsddJRgsrbSdkmbLIxzxWxlNrHqxt3OaIk6Y0nNQoC4DYb3EWGeRSmLIZ3NlQSKYA4laluBpGnapolIOvPE55jHBs8mOYa10uIbdqwCpjO80pDNh16Vks5z4YK00= 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=I0icL62Y; 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="I0icL62Y" 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 1093D1476; Mon, 3 Aug 2026 06:47:12 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 0D46D3F66F; Mon, 3 Aug 2026 06:47:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764836; bh=9dDPYOK56JspwvgV/TEJkMLfs8tJYVd/42IM7MAl10c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=I0icL62YVCEWoYnpV0o0Dj3sRfoLSWq7PhtCgYUM2wbZOCRcPMkTEr+EgW5oDRWdM 7VV6oN95D4tvpPttnHaQojMt53FikPOUSAJ9QGL1p/ilu8Kqn10Y24inqXzQHMyUHT qll0PeG43i7MwR/sIKhlOAEulFt/kd31HI+dyrX4= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Jean-Philippe Brucker , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 38/45] KVM: arm64: CCA: Propagate breakpoint and watchpoint counts to userspace Date: Mon, 3 Aug 2026 14:43:54 +0100 Message-ID: <20260803134403.80630-39-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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: Jean-Philippe Brucker The RMM describes the maximum number of BPs/WPs available to the guest in the Feature Register 0. Propagate those numbers into ID_AA64DFR0_EL1, which is visible to userspace. A VMM needs this information in order to set up realm parameters. Signed-off-by: Jean-Philippe Brucker Signed-off-by: Steven Price Reviewed-by: Gavin Shan Reviewed-by: Suzuki K Poulose Reviewed-by: Joey Gouly --- arch/arm64/include/asm/kvm_rmi.h | 2 ++ arch/arm64/kvm/rmi.c | 19 +++++++++++++++++++ arch/arm64/kvm/sys_regs.c | 3 +++ 3 files changed, 24 insertions(+) diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 13933f0e555d..7d27c17276bf 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -98,6 +98,8 @@ struct realm_rec { void kvm_init_rmi(void); u32 kvm_rmm_ipa_limit(void); =20 +u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val); + bool kvm_rmi_supports_sve(void); =20 int kvm_init_realm(struct kvm *kvm); diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 0d46768022df..de893308148e 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -36,6 +36,25 @@ u32 kvm_rmm_ipa_limit(void) return u64_get_bits(rmi_feat_reg(0), RMI_FEATURE_REGISTER_0_S2SZ); } =20 +u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val) +{ + u32 bps =3D u64_get_bits(rmi_feat_reg(0), RMI_FEATURE_REGISTER_0_NUM_BPS); + u32 wps =3D u64_get_bits(rmi_feat_reg(0), RMI_FEATURE_REGISTER_0_NUM_WPS); + u32 ctx_cmps; + + /* Ensure CTX_CMPs is still valid */ + ctx_cmps =3D FIELD_GET(ID_AA64DFR0_EL1_CTX_CMPs, val); + ctx_cmps =3D min(bps, ctx_cmps); + + val &=3D ~(ID_AA64DFR0_EL1_BRPs_MASK | ID_AA64DFR0_EL1_WRPs_MASK | + ID_AA64DFR0_EL1_CTX_CMPs); + val |=3D FIELD_PREP(ID_AA64DFR0_EL1_BRPs_MASK, bps) | + FIELD_PREP(ID_AA64DFR0_EL1_WRPs_MASK, wps) | + FIELD_PREP(ID_AA64DFR0_EL1_CTX_CMPs, ctx_cmps); + + return val; +} + static int get_start_level(struct realm *realm) { return 4 - stage2_pgtable_levels(realm->ia_bits); diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 5d5c579d4579..e0fe9f2562bc 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2142,6 +2142,9 @@ static u64 sanitise_id_aa64dfr0_el1(const struct kvm_= vcpu *vcpu, u64 val) /* Hide BRBE from guests */ val &=3D ~ID_AA64DFR0_EL1_BRBE_MASK; =20 + if (vcpu_is_rec(vcpu)) + return kvm_realm_reset_id_aa64dfr0_el1(vcpu, val); + return val; } =20 --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 803D641229C; Mon, 3 Aug 2026 13:47:21 +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=1785764843; cv=none; b=Zjph0jG4zPqE0/8Wnb7qyL2Zz9ftFwI9Fp6K7uJr7uoMxEmMx3taWxsWL85WkyFr9RL7feugTe4vVHc7aBQiatLP1YOtJQFU5llkYnjxMUWN5VcVj7WYhqXpqzmX49XybcD9wkGQbCMa++pp2xfdW67K3sQfzWynT1pfM0BMGE8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764843; c=relaxed/simple; bh=9GDpZgOYe45/M0EdsvXuzkys8UNvJZkiOkdd7cYeySA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=L98/oiIJoPBrEOyFqNKZRCMRU7uiOgBgO8q4KSbfBHDXcaMX/9ExcFWyBJiPxavejR5IQUsyn8pKU5kUiWWTjVSnJEAMli40Q/UkZcvEVEVKBjZWxdGMjo3GUGU6HKbFhXkrH5LQM5Qi/nRhtU+EgVKq/5+EV4k8owgS6/sdkj4= 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=XAXMpK/d; 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="XAXMpK/d" 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 123A51476; Mon, 3 Aug 2026 06:47:17 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 8C7123F66F; Mon, 3 Aug 2026 06:47:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764841; bh=9GDpZgOYe45/M0EdsvXuzkys8UNvJZkiOkdd7cYeySA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XAXMpK/d97ZEIgFIHrUDtd7m2Qct79oQT26ZenfnneS44RgoOeCBw3jxwASyQm5YG J1EHb9sAy+mqqRv0JZLvJP+euQT4QorG8fejp/MZ0k89yBqEuIoOkHR31Y9XbpDLYz +e7CQBAFa+Hxb6DTXhsi6GQSy+NK06mWy6D6g0Rw= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Jean-Philippe Brucker , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 39/45] KVM: arm64: CCA: Set breakpoint parameters through SET_ONE_REG Date: Mon, 3 Aug 2026 14:43:55 +0100 Message-ID: <20260803134403.80630-40-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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: Jean-Philippe Brucker Allow userspace to configure the number of breakpoints and watchpoints of a Realm VM through KVM_SET_ONE_REG ID_AA64DFR0_EL1. The KVM sys_reg handler checks the user value against the maximum value given by RMM (arm64_check_features() gets it from the read_sanitised_id_aa64dfr0_el1() reset handler). Userspace discovers that it can write these fields by issuing a KVM_ARM_GET_REG_WRITABLE_MASKS ioctl. Signed-off-by: Jean-Philippe Brucker Signed-off-by: Steven Price Reviewed-by: Gavin Shan Reviewed-by: Suzuki K Poulose --- arch/arm64/kvm/guest.c | 7 +++++++ arch/arm64/kvm/rmi.c | 3 +++ arch/arm64/kvm/sys_regs.c | 17 +++++++++++------ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 5469c9a97fad..3ed563e85572 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -735,6 +735,8 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct= kvm_one_reg *reg) return kvm_arm_sys_reg_get_reg(vcpu, reg); } =20 +#define KVM_REG_ARM_ID_AA64DFR0_EL1 ARM64_SYS_REG(3, 0, 0, 5, 0) + /* * The RMI ABI only enables setting some GPRs and PC. The selection of GPRs * that are available depends on the Realm state and the reason for the la= st @@ -749,6 +751,11 @@ static bool validate_realm_set_reg(struct kvm_vcpu *vc= pu, u64 off =3D core_reg_offset_from_id(reg->id); =20 return kvm_realm_validate_core_reg(off); + } else { + switch (reg->id) { + case KVM_REG_ARM_ID_AA64DFR0_EL1: + return true; + } } =20 return false; diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index de893308148e..44ddee730863 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -505,6 +505,7 @@ static int realm_create_rd(struct kvm *kvm) void *rd =3D NULL; phys_addr_t rd_phys, params_phys, top_delegated; size_t pgd_size =3D kvm_pgtable_stage2_pgd_size(kvm->arch.mmu.vtcr); + u64 dfr0 =3D kvm_read_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1); long rmi_ret; int r; =20 @@ -537,6 +538,8 @@ static int realm_create_rd(struct kvm *kvm) params->rtt_level_start =3D get_start_level(realm); params->rtt_num_start =3D pgd_size / PAGE_SIZE; params->rtt_base =3D kvm->arch.mmu.pgd_phys; + params->num_bps =3D SYS_FIELD_GET(ID_AA64DFR0_EL1, BRPs, dfr0); + params->num_wps =3D SYS_FIELD_GET(ID_AA64DFR0_EL1, WRPs, dfr0); params->hash_algo =3D RMI_HASH_SHA_256; =20 if (kvm->arch.arm_pmu) { diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index e0fe9f2562bc..e47be8f8d259 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2174,6 +2174,9 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu, { u8 debugver =3D SYS_FIELD_GET(ID_AA64DFR0_EL1, DebugVer, val); u8 pmuver =3D SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, val); + u8 bps =3D SYS_FIELD_GET(ID_AA64DFR0_EL1, BRPs, val); + u8 wps =3D SYS_FIELD_GET(ID_AA64DFR0_EL1, WRPs, val); + u8 ctx_cmps =3D SYS_FIELD_GET(ID_AA64DFR0_EL1, CTX_CMPs, val); =20 /* * Prior to commit 3d0dba5764b9 ("KVM: arm64: PMU: Move the @@ -2193,10 +2196,11 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcp= u, val &=3D ~ID_AA64DFR0_EL1_PMUVer_MASK; =20 /* - * ID_AA64DFR0_EL1.DebugVer is one of those awkward fields with a - * nonzero minimum safe value. + * ID_AA64DFR0_EL1.DebugVer, BRPs and WRPs all have to be greater than + * zero. CTX_CMPs is never greater than BRPs. */ - if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP) + if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP || !bps || !wps || + ctx_cmps > bps) return -EINVAL; =20 if (ignore_feat_doublelock(vcpu, val)) { @@ -2429,10 +2433,11 @@ static int set_id_reg(struct kvm_vcpu *vcpu, const = struct sys_reg_desc *rd, mutex_lock(&vcpu->kvm->arch.config_lock); =20 /* - * Once the VM has started the ID registers are immutable. Reject any - * write that does not match the final register value. + * Once the VM has started or the Realm descriptor is created, the ID + * registers are immutable. Reject any write that does not match the + * final register value. */ - if (kvm_vm_has_ran_once(vcpu->kvm)) { + if (kvm_vm_has_ran_once(vcpu->kvm) || kvm_realm_is_created(vcpu->kvm)) { if (val !=3D read_id_reg(vcpu, rd)) ret =3D -EBUSY; else --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D9C6541229C; Mon, 3 Aug 2026 13:47:26 +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=1785764848; cv=none; b=ZHLXxg+vS1cJqdeSMtUUkvBx3Rdo7CJ38vELCuzoBzbMBnz7n6sUqa0fQCUmbWsy0h8H/V6F0qh7a3F1EFnGPGnBvDSOeA4+pScMMSyW/o4qTCsSsu9A0q4kQEpFSig/9xlpMAwTrjeJIx+kfm8Twi7gt4id0VFEHgUVq4uz0YY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764848; c=relaxed/simple; bh=oMhQ9nECs1uP7/C+1tKXuLBGIgQ34GA4GrC0OcJHPVw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ui4l5/5Ptl3cpFMremJX37jJ1UFgZfr3Ldf4ODoOLxYWTAkKck0YLu4TLiuP7KQkDdp8QEPrscMQqdh37BB1k2ZUFZgBOk2euEAN/DPWTJNBqiGL82krB4twHPBUnRm9v6nca+H5QseLZ2syqkhLG6B/bysnbP4ndArBwjmB5IE= 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=oyMYroVe; 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="oyMYroVe" 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 645A21476; Mon, 3 Aug 2026 06:47:22 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 745213F66F; Mon, 3 Aug 2026 06:47:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764846; bh=oMhQ9nECs1uP7/C+1tKXuLBGIgQ34GA4GrC0OcJHPVw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oyMYroVeMruikwg0kZoF6oTwb/YKSr6sFLfbsK4gOsXkaB+iPQuE3k9RVzreIJl1P ouj1EMXYE95vwWwh0GHVTT0/Rnr4c+Wp07GS98bYtCM72A229gmqxmGCxsSERjTTSE Z8WngXCy/R9vN180IGM7XNsRwmF0D4UQ6Uy8oCLE= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Jean-Philippe Brucker , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 40/45] KVM: arm64: CCA: Propagate max SVE vector length from the RMM Date: Mon, 3 Aug 2026 14:43:56 +0100 Message-ID: <20260803134403.80630-41-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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: Jean-Philippe Brucker RMM provides the maximum vector length it supports for a guest in its feature register. Make it visible to the rest of KVM and to userspace via KVM_REG_ARM64_SVE_VLS. Signed-off-by: Jean-Philippe Brucker Signed-off-by: Steven Price Reviewed-by: Gavin Shan Reviewed-by: Suzuki K Poulose --- arch/arm64/include/asm/kvm_host.h | 2 +- arch/arm64/include/asm/kvm_rmi.h | 1 + arch/arm64/kvm/guest.c | 2 +- arch/arm64/kvm/reset.c | 12 ++++++++++-- arch/arm64/kvm/rmi.c | 6 ++++++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm= _host.h index 146c52f867c0..ee565b8e55a0 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -79,9 +79,9 @@ enum kvm_mode kvm_get_mode(void); static inline enum kvm_mode kvm_get_mode(void) { return KVM_MODE_NONE; }; #endif =20 -extern unsigned int __ro_after_init kvm_sve_max_vl; extern unsigned int __ro_after_init kvm_host_sve_max_vl; int __init kvm_arm_init_sve(void); +unsigned int kvm_sve_get_max_vl(struct kvm *kvm); =20 u32 __attribute_const__ kvm_target_cpu(void); void kvm_reset_vcpu(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_= rmi.h index 7d27c17276bf..2789879b6701 100644 --- a/arch/arm64/include/asm/kvm_rmi.h +++ b/arch/arm64/include/asm/kvm_rmi.h @@ -97,6 +97,7 @@ struct realm_rec { =20 void kvm_init_rmi(void); u32 kvm_rmm_ipa_limit(void); +unsigned int kvm_realm_sve_max_vl(void); =20 u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val); =20 diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 3ed563e85572..f48fc0d5a249 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -375,7 +375,7 @@ static int set_sve_vls(struct kvm_vcpu *vcpu, const str= uct kvm_one_reg *reg) if (vq_present(vqs, vq)) max_vq =3D vq; =20 - if (max_vq > sve_vq_from_vl(kvm_sve_max_vl)) + if (max_vq > sve_vq_from_vl(kvm_sve_get_max_vl(vcpu->kvm))) return -EINVAL; =20 /* diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index c18cdca7d125..7b8681a602d4 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -46,7 +46,7 @@ unsigned int __ro_after_init kvm_host_sve_max_vl; #define VCPU_RESET_PSTATE_SVC (PSR_AA32_MODE_SVC | PSR_AA32_A_BIT | \ PSR_AA32_I_BIT | PSR_AA32_F_BIT) =20 -unsigned int __ro_after_init kvm_sve_max_vl; +static unsigned int __ro_after_init kvm_sve_max_vl; =20 int __init kvm_arm_init_sve(void) { @@ -76,9 +76,17 @@ int __init kvm_arm_init_sve(void) return 0; } =20 +unsigned int kvm_sve_get_max_vl(struct kvm *kvm) +{ + if (kvm_is_realm(kvm)) + return kvm_realm_sve_max_vl(); + else + return kvm_sve_max_vl; +} + static void kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu) { - vcpu->arch.sve_max_vl =3D kvm_sve_max_vl; + vcpu->arch.sve_max_vl =3D kvm_sve_get_max_vl(vcpu->kvm); =20 /* * Userspace can still customize the vector lengths by writing diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 44ddee730863..cf043db05720 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -36,6 +36,12 @@ u32 kvm_rmm_ipa_limit(void) return u64_get_bits(rmi_feat_reg(0), RMI_FEATURE_REGISTER_0_S2SZ); } =20 +unsigned int kvm_realm_sve_max_vl(void) +{ + return sve_vl_from_vq(u64_get_bits(rmi_feat_reg(0), + RMI_FEATURE_REGISTER_0_SVE_VL) + 1); +} + u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val) { u32 bps =3D u64_get_bits(rmi_feat_reg(0), RMI_FEATURE_REGISTER_0_NUM_BPS); --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5A37743B4A6; Mon, 3 Aug 2026 13:47:32 +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=1785764854; cv=none; b=MnDDRWiVOW3irHcsDpcKkUefWvO/aMu00sSq9kzNIbZasatEfb8xYOW6Y12Jm2AQti435Dlymvzq9PpIAb714rsyPGEsmLQO1U/hxlSyYEgyaHFwUexlKbf8JN8QxwRIfVnLZYCv+XxE147mKVnkAsVdCD986cQDNgQroy6Us/M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764854; c=relaxed/simple; bh=QbXqYIX01Dxf57p9QrsPRpSm8WGko41S0UwAnL78VD8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VsOitjwfgEzG6uYdPaG5n+1XgwN8EysrbiT9FYtxsEa17Tof4mFbf5movVWMxBPSfvBBx3bpVhyG+GMR+/quJrt8HUaySkf09iDxSKFpqcrrifjapZScl9JgJhP4WMORPK9wO+QH7SpouANB83p9IOO7cay0aKmtU+xOEgmGE6w= 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=qqOZ1lUn; 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="qqOZ1lUn" 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 C0566165C; Mon, 3 Aug 2026 06:47:27 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id CFF663F66F; Mon, 3 Aug 2026 06:47:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764851; bh=QbXqYIX01Dxf57p9QrsPRpSm8WGko41S0UwAnL78VD8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qqOZ1lUn+6MK9Ys8IBGQjQ++t3wZu7QB6Sf4KJ9fhMBHZThChHEOEqymmPSBX5py9 JVpMxkFSfLpVEdVhFJNqrYyMqiW6pjyKBlOtptob2bNVjmVPqAOteFIoMi6Ayxnu7d 201D44sgbfzPJxgfcomiabDQuPlPralDcF/xBkZg= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Jean-Philippe Brucker , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 41/45] KVM: arm64: CCA: Configure max SVE vector length for a Realm Date: Mon, 3 Aug 2026 14:43:57 +0100 Message-ID: <20260803134403.80630-42-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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: Jean-Philippe Brucker Obtain the max vector length configured by userspace on the vCPUs, and write it into the Realm parameters. By default the vCPU is configured with the max vector length reported by RMM, and userspace can reduce it with a write to KVM_REG_ARM64_SVE_VLS. Signed-off-by: Jean-Philippe Brucker Signed-off-by: Steven Price --- Changes since v6: * Rename max_vl/realm_max_vl to vl/last_vl - there is nothing "maximum" about them, we're just checking that all realms have the same vector length --- arch/arm64/kvm/guest.c | 3 ++- arch/arm64/kvm/rmi.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index f48fc0d5a249..452cf5d3152e 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -361,7 +361,7 @@ static int set_sve_vls(struct kvm_vcpu *vcpu, const str= uct kvm_one_reg *reg) if (!vcpu_has_sve(vcpu)) return -ENOENT; =20 - if (kvm_arm_vcpu_sve_finalized(vcpu)) + if (kvm_arm_vcpu_sve_finalized(vcpu) || kvm_realm_is_created(vcpu->kvm)) return -EPERM; /* too late! */ =20 if (WARN_ON(vcpu->arch.sve_state)) @@ -754,6 +754,7 @@ static bool validate_realm_set_reg(struct kvm_vcpu *vcp= u, } else { switch (reg->id) { case KVM_REG_ARM_ID_AA64DFR0_EL1: + case KVM_REG_ARM64_SVE_VLS: return true; } } diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index cf043db05720..0f66a0e970cd 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -504,6 +504,39 @@ static void realm_unmap_shared_range(struct kvm *kvm, start, end); } =20 +static int realm_init_sve_param(struct kvm *kvm, struct realm_params *para= ms) +{ + unsigned long i; + struct kvm_vcpu *vcpu; + int vl, last_vl =3D -1; + + if (!kvm_has_sve(kvm)) + return 0; + + /* + * Get the preferred SVE configuration, set by userspace with the + * KVM_ARM_VCPU_SVE feature and KVM_REG_ARM64_SVE_VLS pseudo-register. + */ + kvm_for_each_vcpu(i, vcpu, kvm) { + if (!kvm_arm_vcpu_sve_finalized(vcpu)) + return -EINVAL; + + vl =3D vcpu->arch.sve_max_vl; + + /* We need all vCPUs to have the same SVE config */ + if (last_vl >=3D 0 && last_vl !=3D vl) + return -EINVAL; + + last_vl =3D vl; + } + + if (last_vl > 0) { + params->sve_vl =3D sve_vq_from_vl(last_vl) - 1; + params->flags0 |=3D RMI_REALM_PARAM_FLAG_SVE; + } + return 0; +} + static int realm_create_rd(struct kvm *kvm) { struct realm *realm =3D &kvm->arch.realm; @@ -556,6 +589,10 @@ static int realm_create_rd(struct kvm *kvm) if (kvm_lpa2_is_enabled()) params->flags0 |=3D RMI_REALM_PARAM_FLAG_LPA2; =20 + r =3D realm_init_sve_param(kvm, params); + if (r) + goto out_undelegate_tables; + params_phys =3D virt_to_phys(params); =20 rmi_ret =3D rmi_realm_create(rd_phys, params_phys, realm->sro); --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 0745C41DDE6; Mon, 3 Aug 2026 13:47:36 +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=1785764858; cv=none; b=QmFXidzG6n3280WjYFDta8kb0eq2UzTg11PB3rlKwoJoocn3CKJe9Bw7eJZpWBv0T991PtoI+cmKzimI4tRH4nRaXNTu/DjlOjLQcul8omnLrkuOnSpz9tBctxL51DWFb5cXmwLtmfyBjm8JCpO6QqUcJ6I2sD+IlYYGRLPYng0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764858; c=relaxed/simple; bh=XwWksQKK5JHoi1/bsiLim1Ro0hK67xh7Nvsm2bnB00A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=I8qLNTtblSOW4v199kLhB3hRX2KrNkWNC3OH1ceUX54ura6sQW1wNi3I1MIr+nj/UNFYkLurpW9ka21lzoxbxCsNgO79zp6yjDprEGA6n6thyUkiNuU+hhRXj1+kdEYkpP8gz8TeEq2nCinLmVEGex4HnbyDVd5b/KXjJZVP8z4= 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=KRcutHS6; 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="KRcutHS6" 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 4BBB31655; Mon, 3 Aug 2026 06:47:32 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 2DA923F66F; Mon, 3 Aug 2026 06:47:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764856; bh=XwWksQKK5JHoi1/bsiLim1Ro0hK67xh7Nvsm2bnB00A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KRcutHS6jo2IEonPBEtf0bVzFKWBrrVHuYAMNQw4/yXHJI7ZmocJa7bh08of9PeVM K/bQKGpM8ILOlNuGLgc7Zl/lxBuFMCelKCAXtH49AzvWeEbcFfBFZcR9lWNh3Qa9// Alg96p+r5ajufnOUfjSMJTh/W+18TrMEUCKU89Ek= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Jean-Philippe Brucker , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 42/45] KVM: arm64: CCA: Provide register list for unfinalized RECs Date: Mon, 3 Aug 2026 14:43:58 +0100 Message-ID: <20260803134403.80630-43-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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: Jean-Philippe Brucker KVM_GET_REG_LIST should not be called before SVE is finalized. The ioctl handler currently returns -EPERM in this case. But because it uses kvm_arm_vcpu_is_finalized(), it now also rejects the call for unfinalized REC even though finalizing the REC can only be done late, after Realm descriptor creation. Move the check to copy_sve_reg_indices(). One adverse side effect of this change is that a KVM_GET_REG_LIST call that only probes for the array size will now succeed even if SVE is not finalized, but that seems harmless since the following KVM_GET_REG_LIST with the full array will fail. Signed-off-by: Jean-Philippe Brucker Signed-off-by: Steven Price Reviewed-by: Gavin Shan --- arch/arm64/kvm/arm.c | 4 ---- arch/arm64/kvm/guest.c | 10 +++++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 3242108be7c5..fd4e13ff17cf 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1967,10 +1967,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp, if (unlikely(!kvm_vcpu_initialized(vcpu))) break; =20 - r =3D -EPERM; - if (!kvm_arm_vcpu_is_finalized(vcpu)) - break; - r =3D -EFAULT; if (copy_from_user(®_list, user_list, sizeof(reg_list))) break; diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 452cf5d3152e..128fec56993a 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -617,8 +617,8 @@ static unsigned long num_sve_regs(const struct kvm_vcpu= *vcpu) if (!vcpu_has_sve(vcpu)) return 0; =20 - /* Policed by KVM_GET_REG_LIST: */ - WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu)); + if (!kvm_arm_vcpu_sve_finalized(vcpu)) + return 1; /* KVM_REG_ARM64_SVE_VLS */ =20 return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */) + 1; /* KVM_REG_ARM64_SVE_VLS */ @@ -635,9 +635,6 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *= vcpu, if (!vcpu_has_sve(vcpu)) return 0; =20 - /* Policed by KVM_GET_REG_LIST: */ - WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu)); - /* * Enumerate this first, so that userspace can save/restore in * the order reported by KVM_GET_REG_LIST: @@ -647,6 +644,9 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *= vcpu, return -EFAULT; ++num_regs; =20 + if (!kvm_arm_vcpu_sve_finalized(vcpu)) + return num_regs; + for (i =3D 0; i < slices; i++) { for (n =3D 0; n < SVE_NUM_ZREGS; n++) { reg =3D KVM_REG_ARM64_SVE_ZREG(n, i); --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D822D411FB8; Mon, 3 Aug 2026 13:47:41 +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=1785764863; cv=none; b=gprIT/0f/UVqd2SEU9sRWYswGMDD2hCcF7g+rEL8mRycYd9gZtWKAZ6s4HIsXQipeLu5cC0MuzHVdFoS5IAVC1t6fJvKVk2dfGz5oW4B9n5qMXktO46GVurPSYQS5jFeHvMXCGDQvsG/ILW0sfJzeztijwIS+W9wGP63M/Hz6z8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764863; c=relaxed/simple; bh=R2faogoYaXkfqGHnF6vJJOqEqJmwTNS9i4WmOVnJpXU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PXxk8mvSKdmbU63JreL3XN+4tEiW4PdKhGPd8/rawb7VE+xa0BTorViayfPGHT5Fl7MrcRHzTvx4EUsMTFEGxHYyLl7WF6dTEZ/6B/84L0K2QP47p0jC4E4u16nOMchHiOhZ8EBrRogSN3NNth4pT/Dsea2zgAwDC2//TDJ4PEs= 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=L2kzcxfN; 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="L2kzcxfN" 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 4476F1682; Mon, 3 Aug 2026 06:47:37 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id AF5953F66F; Mon, 3 Aug 2026 06:47:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764861; bh=R2faogoYaXkfqGHnF6vJJOqEqJmwTNS9i4WmOVnJpXU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=L2kzcxfNo7YvQZHwHUvytAoOCsvqwAZjp2yIrej4A/tCEVrQFYgI9A1zh/bsKM3ln o2Uw8B3zLqzRgyVXSdR3Ft7VLe8kUHA0ZpPaObfA6+0/InN1ic49ooPc+xyq8bXuaN OFXTMbYb+O1oqY32MCax05LIPihjbjopyz24QpnE= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Jean-Philippe Brucker , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi , Steven Price Subject: [PATCH v16 43/45] KVM: arm64: CCA: Provide an accurate register list Date: Mon, 3 Aug 2026 14:43:59 +0100 Message-ID: <20260803134403.80630-44-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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: Jean-Philippe Brucker Userspace can set a few registers with KVM_SET_ONE_REG (9 GP registers at runtime, and 3 system registers during initialization). Update the register list returned by KVM_GET_REG_LIST. Signed-off-by: Jean-Philippe Brucker Signed-off-by: Steven Price --- Changes since v11: * Reworked due to upstream changes. Changes since v8: * Minor type changes following review. Changes since v7: * Reworked on upstream changes. --- arch/arm64/kvm/guest.c | 6 ++++++ arch/arm64/kvm/hypercalls.c | 4 ++-- arch/arm64/kvm/sys_regs.c | 27 +++++++++++++++++++++------ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 128fec56993a..5e495dd39e39 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -620,6 +620,9 @@ static unsigned long num_sve_regs(const struct kvm_vcpu= *vcpu) if (!kvm_arm_vcpu_sve_finalized(vcpu)) return 1; /* KVM_REG_ARM64_SVE_VLS */ =20 + if (kvm_is_realm(vcpu->kvm)) + return 1; /* KVM_REG_ARM64_SVE_VLS */ + return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */) + 1; /* KVM_REG_ARM64_SVE_VLS */ } @@ -647,6 +650,9 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *= vcpu, if (!kvm_arm_vcpu_sve_finalized(vcpu)) return num_regs; =20 + if (kvm_is_realm(vcpu->kvm)) + return num_regs; + for (i =3D 0; i < slices; i++) { for (n =3D 0; n < SVE_NUM_ZREGS; n++) { reg =3D KVM_REG_ARM64_SVE_ZREG(n, i); diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index b11b8821c9fb..82278ccb19ae 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -414,14 +414,14 @@ void kvm_arm_teardown_hypercalls(struct kvm *kvm) =20 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) { - return ARRAY_SIZE(kvm_arm_fw_reg_ids); + return kvm_is_realm(vcpu->kvm) ? 0 : ARRAY_SIZE(kvm_arm_fw_reg_ids); } =20 int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindice= s) { int i; =20 - for (i =3D 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) { + for (i =3D 0; i < kvm_arm_get_fw_num_regs(vcpu); i++) { if (put_user(kvm_arm_fw_reg_ids[i], uindices++)) return -EFAULT; } diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index e47be8f8d259..6d805160d70e 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -5540,18 +5540,18 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, = const struct kvm_one_reg *reg sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); } =20 -static unsigned int num_demux_regs(void) +static inline unsigned int num_demux_regs(struct kvm_vcpu *vcpu) { - return CSSELR_MAX; + return kvm_is_realm(vcpu->kvm) ? 0 : CSSELR_MAX; } =20 -static int write_demux_regids(u64 __user *uindices) +static int write_demux_regids(struct kvm_vcpu *vcpu, u64 __user *uindices) { u64 val =3D KVM_REG_ARM64 | KVM_REG_SIZE_U32 | KVM_REG_ARM_DEMUX; unsigned int i; =20 val |=3D KVM_REG_ARM_DEMUX_ID_CCSIDR; - for (i =3D 0; i < CSSELR_MAX; i++) { + for (i =3D 0; i < num_demux_regs(vcpu); i++) { if (put_user(val | i, uindices)) return -EFAULT; uindices++; @@ -5595,11 +5595,26 @@ static bool copy_reg_to_user(const struct sys_reg_d= esc *reg, u64 __user **uind) return true; } =20 +static inline bool kvm_realm_sys_reg_hidden_user(const struct kvm_vcpu *vc= pu, + u64 reg) +{ + switch (reg) { + case SYS_ID_AA64DFR0_EL1: + case SYS_PMCR_EL0: + return false; + } + return true; +} + static int walk_one_sys_reg(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, u64 __user **uind, unsigned int *total) { + if (vcpu_is_rec(vcpu) && + kvm_realm_sys_reg_hidden_user(vcpu, reg_to_encoding(rd))) + return 0; + /* * Ignore registers we trap but don't save, * and for which no custom user accessor is provided. @@ -5637,7 +5652,7 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 _= _user *uind) =20 unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu) { - return num_demux_regs() + return num_demux_regs(vcpu) + walk_sys_regs(vcpu, (u64 __user *)NULL); } =20 @@ -5650,7 +5665,7 @@ int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcp= u, u64 __user *uindices) return err; uindices +=3D err; =20 - return write_demux_regids(uindices); + return write_demux_regids(vcpu, uindices); } =20 #define KVM_ARM_FEATURE_ID_RANGE_INDEX(r) \ --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 0A57C41DDE8; Mon, 3 Aug 2026 13:47:46 +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=1785764868; cv=none; b=oBb910zwZ/xpmqKuAZCbIeSnlsaWmNz+fn+a47RfrgSXFuu6vSMHLKy9+SvadkyoKrZnHg7HqNzTatjaj2lCnVUodCy47sE6vA5Nij97kZtxtVLovHw508AX0l8nFn/5mcnJvfyD+5xGxwLQkD8n9BMYMt1eOuHqSgQxND0zoZU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764868; c=relaxed/simple; bh=hU5/Y8gLAYSgHVaaIBAsTIEwnwJD0RpetBq00JLKOGU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Owq2nJjq89b1WvcY2A6p8ubsAWE+uXi/Ytl0jT+MWBwLlvEPZJ55q5N8yfLWDfIcRWbpMaFe5GVzTllM3AM98EPv7x8Y4TNNwi8IaZQMm6cGDPzwhJri/zXESfhKY2VcqjErTnIXXvRFgbVFJLfbZNx+15UY+5kpC/w5TI9LFBM= 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=EqPEZkcE; 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="EqPEZkcE" 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 656931476; Mon, 3 Aug 2026 06:47:42 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B81D03F66F; Mon, 3 Aug 2026 06:47:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764866; bh=hU5/Y8gLAYSgHVaaIBAsTIEwnwJD0RpetBq00JLKOGU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EqPEZkcECjXMW/VhDiaE+juIi+dG8W9nNkF9DspL9f2NlLZ43EJqeEQim6ialXL4w FlZ1572dutPCpiphYSWqn+cTBE5ZA8q66IxT8CVQCvY+uOj/OyA6HspeF9UpttJ+CB RwogHDCHvHnoka54u8OW8QPpszwgy5yfxCARZVd4= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 44/45] KVM: arm64: CCA: Require ICH_HCR_EL2.TDIR for realms Date: Mon, 3 Aug 2026 14:44:00 +0100 Message-ID: <20260803134403.80630-45-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" KVM advertises realm support when the RMM is available, and allows userspace to create a VM with KVM_VM_TYPE_ARM_REALM on that basis. On CPUs that lack ICH_HCR_EL2.TDIR, KVM uses ICH_HCR_EL2.TC for normal guests so that ICC_DIR_EL1 is still trapped via the common GICv3 CPU interface trap. Realms cannot rely on the normal hyp-side trap handling for that fallback, so advertising RMI support on such systems lets userspace create a realm that cannot safely run. Require the finalized ARM64_HAS_ICH_HCR_EL2_TDIR capability when reporting KVM_CAP_ARM_RMI and when accepting KVM_VM_TYPE_ARM_REALM. This leaves normal VM creation unchanged on systems that need the TC workaround. Signed-off-by: Steven Price --- New patch for v16 --- arch/arm64/kvm/arm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index fd4e13ff17cf..7edc572dd8ab 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -125,6 +125,12 @@ static bool vgic_present, kvm_arm_initialised; =20 static DEFINE_PER_CPU(unsigned char, kvm_hyp_initialized); =20 +static bool kvm_arm_rmi_supported(void) +{ + return static_key_enabled(&kvm_rmi_is_available) && + cpus_have_final_cap(ARM64_HAS_ICH_HCR_EL2_TDIR); +} + bool is_kvm_arm_initialised(void) { return kvm_arm_initialised; @@ -256,7 +262,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long typ= e) return -EINVAL; =20 if (type & KVM_VM_TYPE_ARM_REALM) { - if (!static_branch_unlikely(&kvm_rmi_is_available)) + if (!kvm_arm_rmi_supported()) return -EINVAL; kvm_set_realm_state(kvm, REALM_STATE_NONE); kvm->arch.is_realm =3D true; @@ -537,7 +543,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long = ext) r =3D kvm_supports_cacheable_pfnmap(); break; case KVM_CAP_ARM_RMI: - r =3D static_key_enabled(&kvm_rmi_is_available); + r =3D kvm_arm_rmi_supported(); break; =20 default: --=20 2.43.0 From nobody Fri Oct 2 08:25:49 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 53A994137A6; Mon, 3 Aug 2026 13:47:52 +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=1785764873; cv=none; b=OaoMWGriEDT1M9wP4kc9SI9IzIBoRopbjLBeLEG73YbBDicfE3O6ZHPs7rb77z8jR1wo0Rd/QPIj01gZ9dLlnPm+ZGESVhp7mohLv9fJ3Y9g9KIQBNeUgaTB7XIJNz1TEFg3iFEGWYzWa5Oi7JIW0J91KEV/2cmmACCOjKVis+I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785764873; c=relaxed/simple; bh=QnE3jwjHNmpdPreZ13KHzHAPGae+2/Nd+IwbjiYeo94=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZQ9DB/MhTcGUilAKBzJ8rzWZ+wunxPPELJdfsC9mPsqP0gP2Ju7NOvi4qNNZBiVNEWkyzIWnA4UoLL4MvuaIyhGilF6cSdn47e2pOv8i+/XHNFUdttAyS7WUcFcDlXfVduYH2tOMl1M9lh2AOqd2vIuVb5wAFBlJNgw6pJZ9Krk= 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=Cf9Ke1ba; 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="Cf9Ke1ba" 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 C59B91476; Mon, 3 Aug 2026 06:47:47 -0700 (PDT) Received: from e122027.cambridge.arm.com (e122027.cambridge.arm.com [10.1.25.28]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id ED9273F66F; Mon, 3 Aug 2026 06:47:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785764871; bh=QnE3jwjHNmpdPreZ13KHzHAPGae+2/Nd+IwbjiYeo94=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Cf9Ke1bagJBW0N8q+wEcwjaspUtxNKe+/HsAhtisu5RMDOw2ZUFrvOQLNS/Bhu5My Z7vabVyu/g5HFt88pDKF+y9uk8xMYmHx8UjononARJkoZfwedm+mHbKeKld8quc6WZ PsbeRh759wKxW22DoIhydh7YB7pqO2Or8O++qP8Q= From: Steven Price To: kvm@vger.kernel.org, kvmarm@lists.linux.dev Cc: Steven Price , Catalin Marinas , Marc Zyngier , Will Deacon , James Morse , Oliver Upton , Suzuki K Poulose , Zenghui Yu , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Joey Gouly , Alexandru Elisei , Christoffer Dall , Fuad Tabba , linux-coco@lists.linux.dev, Ganapatrao Kulkarni , Gavin Shan , Shanker Donthineni , Alper Gun , "Aneesh Kumar K . V" , Emi Kisanuki , Vishal Annapurve , WeiLin.Chang@arm.com, Lorenzo Pieralisi Subject: [PATCH v16 45/45] KVM: arm64: CCA: Enable realms to be created Date: Mon, 3 Aug 2026 14:44:01 +0100 Message-ID: <20260803134403.80630-46-steven.price@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260803134403.80630-1-steven.price@arm.com> References: <20260803134403.80630-1-steven.price@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" All the pieces are now in place, so enable kvm_rmi_is_available when the RMM is detected. Signed-off-by: Steven Price --- arch/arm64/kvm/rmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c index 0f66a0e970cd..c242dfc2c7a6 100644 --- a/arch/arm64/kvm/rmi.c +++ b/arch/arm64/kvm/rmi.c @@ -1556,5 +1556,6 @@ void kvm_init_rmi(void) if (rmm_check_features()) return; =20 - /* Future patch will enable static branch kvm_rmi_is_available */ + kvm_info("Realm guests supported\n"); + static_branch_enable(&kvm_rmi_is_available); } --=20 2.43.0