coco/TSM: Implement host-side support for Arm CCA TDISP setup
Subsystems (7)
v4 cover coco/TSM: Implement host-side support for Arm CCA TDISP setup
This patch series implements the host-side changes needed for end-to-end Arm CCA TDISP setup. It adds the RMI/RHI plumbing required to create and manage Realm vdev objects, service device-attestation object requests, and complete the KVM/RMM flows needed for device run-time transitions.
The series is based on the RMM 2.0bet1 specification [1] and the RHI v1.0 BET1 specification [5].
At a high level, the series adds support for:
- host-side vdev communication and lifecycle management
- host handling of RHI DA object read/size requests
- host-side fetching and caching of interface reports and measurements
- KVM handling of vdev request/complete exits
- KVM handling of map/validation exits and teardown on granule destroy
- vdev transition to TDISP RUN state
- enabling DA in Realm create parameters
The series builds upon the TSM framework patches posted at [2] and depends on the KVM CCA patchset [3]. A git repository containing all related changes is available at [4]. kvmtool repo is at [6]
Previous posting:
Changes from v3:
https://lore.kernel.org/all/[email protected]
* updated the patches to follow the RMM 2.0bet1 specification
* moved vdev request-exit handling to the last patch in the series. This is expected to be dropped once the corresponding spec update lands
* dropped the vdev and pdev arguments from rmi_rtt_dev_validate(). The spec update for that change is still pending. The validation call is now made from the REC enter path
* added a response field to KVM_EXIT_ARM64_TIO so the VMM can pass the ioctl return status back to the exit handler
* dropped vcpu_fd from arm64_vdev_device_memmap_guest_req. Once vdev request handling is removed from the series, the ioctl path will no longer need vcpu_fd
* reworked the host-side vdev lifecycle to better match the RMM 2.0bet1 flow,
* updated the vdev flows to match the revised interfaces: populate MMIO BAR ranges in rmi_vdev_create(), rename the interface-report and measurement update commands, and drop vcpu_fd from the guest MMIO map request path
Changes from v1:
* rebase to latest kernel and core TSM changes
* address review feedback
rfc-v1: https://lore.kernel.org/all/[email protected]
There is no rfc-v2 posting. This series is marked rfc-v3 to stay aligned with the rest of the CCA patchsets that are being posted as v3.
[1] https://developer.arm.com/documentation/den0137/2-0bet1/
[2] https://lore.kernel.org/all/[email protected]
[3] https://lore.kernel.org/all/[email protected]
[4] https://gitlab.arm.com/linux-arm/linux-cca.git cca/topics/cca-tdisp-upstream-rfc-v4
[5] https://developer.arm.com/documentation/den0148/latest/
[6] https://gitlab.arm.com/linux-arm/kvmtool-cca.git cca/topics/cca-tdisp-upstream-rfc-v4
Aneesh Kumar K.V (Arm) (16):
iommu/arm-smmu-v3: Discover RME support and realm IRQ topology iommu/arm-smmu-v3: Save the programmed MSI message in msi_desc iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing iommu/arm-smmu-v3: Track realm pSMMU users with refcount_t
coco: host: arm64: Add support for virtual device communication
coco: host: arm64: Add support for RMM vdev objects
coco: host: arm64: Add pdev stream key refresh and purge helpers
coco: host: arm64: Add helpers to unlock and destroy RMM vdev
coco: host: arm64: Add support for da object read RHI handling
coco: host: arm64: Add helper for cached object fetches
coco: host: arm64: Fetch interface report via RMI
coco: host: arm64: Fetch device measurements via RMI
coco: host: KVM: arm64: Handle vdev validate-mapping exits
KVM: arm64: Unmap device mappings when a private granule is destroyed
coco: host: arm64: Transition vdevs to TDISP RUN state
KVM: arm64: CCA: enable DA in realm create parameters
Documentation/virt/kvm/api.rst | 20 + arch/arm64/include/asm/kvm_rmi.h | 4 + arch/arm64/include/asm/rmi_cmds.h | 193 ++++++ arch/arm64/include/asm/rmi_smc.h | 98 ++- arch/arm64/include/uapi/asm/rmi-da.h | 47 ++ arch/arm64/kernel/rmi.c | 51 ++ arch/arm64/kvm/rmi-exit.c | 37 ++ arch/arm64/kvm/rmi.c | 279 ++++++++- drivers/iommu/arm/arm-smmu-v3/Makefile | 2 +- .../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 7 + .../iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c | 297 +++++++++ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 86 ++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 16 + drivers/virt/coco/arm-cca-host/arm-cca.c | 188 +++++- drivers/virt/coco/arm-cca-host/rmi-da.c | 569 +++++++++++++++++- drivers/virt/coco/arm-cca-host/rmi-da.h | 40 ++ include/uapi/linux/iommufd.h | 1 + include/uapi/linux/kvm.h | 11 + 18 files changed, 1929 insertions(+), 17 deletions(-) create mode 100644 arch/arm64/include/uapi/asm/rmi-da.h create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c
Signature · 1 line
2.43.0
RFC PATCH v4 1/16 iommu/arm-smmu-v3: Discover RME support and realm IRQ topology
Detect RME-capable SMMUv3 instances from IDR0.RME_IMPL and record the capability in arm_smmu_device.
When RMM is active, query RMI_PSMMU_INFO to discover how realm-side notifications are delivered. For pSMMUs that expose realm interrupts, store the reported evtq/gerror/priq IRQs, reserve extra MSI vectors when RMM uses MSI delivery, and register threaded handlers that acknowledge notifications through RMI_PSMMU_IRQ_NOTIFY / RMI_PSMMU_EVENT_CONSUME.
Also add the RMI command/structure definitions needed for PSMMU_INFO and interrupt notification, along with arm_smmu_device state for the physical base address and realm IRQs.
If RMM reports a CMDQ sync interrupt requirement, keep the IRQ plumbing but leave ARM_SMMU_FEAT_RME disabled.
--- arch/arm64/include/asm/rmi_cmds.h | 52 ++++++++ arch/arm64/include/asm/rmi_smc.h | 32 ++++- drivers/iommu/arm/arm-smmu-v3/Makefile | 2 +- .../iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c | 124 ++++++++++++++++++ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 81 +++++++++++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 10 ++ 6 files changed, 297 insertions(+), 4 deletions(-) create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c
arch/arm64/include/asm/rmi_cmds.h +52 -0
@@ -811,4 +811,56 @@ static inline unsigned long rmi_pdev_stream_disconnect(unsigned long pdev1_phys,return res.a0; } +static inline unsigned long rmi_psmmu_info (unsigned long psmmu_phys, +unsigned long psmmu_info_phys) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_PSMMU_INFO , + psmmu_phys, psmmu_info_phys, &res); + +return res.a0; +} + +struct rmi_psmmu_event_details { +u64 flags; +u64 event_num; +u64 stream_id;/* valid only if we have VSMMU event */ +u64 fetch_addr; +u64 input_addr; +u64 syndrome; +}; + +static inline unsigned long rmi_psmmu_irq_notify (unsigned long psmmu_phys, +unsigned long irqs,struct rmi_psmmu_event_details *event) +{ +struct arm_smccc_1_2_regs regs = { + .a0 =SMC_RMI_PSMMU_IRQ_NOTIFY , + .a1 = psmmu_phys, + .a2 = irqs, + }; + +arm_smccc_1_2_invoke (®s, ®s); + + event->flags = regs.a1; + event->event_num = regs.a2; + event->stream_id = regs.a3; + event->fetch_addr = regs.a4; + event->input_addr = regs.a5; + event->syndrome = regs.a6; + +return regs.a0; +} + +static inline unsigned long rmi_psmmu_event_consume (unsigned long psmmu_phys, +unsigned long irqs) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_PSMMU_EVENT_CONSUME , + psmmu_phys, irqs, &res); + +return res.a0; +} +#endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/asm/rmi_smc.h +31 -1
@@ -101,7 +101,7 @@#define SMC_RMI_PDEV_MEC_UPDATE SMC_RMI_CALL(0x01ed)#define SMC_RMI_VSMMU_EVENT_COMPLETE SMC_RMI_CALL(0x01ee) -#define SMC_RMI_PSMMU_EVENT_DISCARD SMC_RMI_CALL(0x01f0) +#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)
@@ -129,6 +129,7 @@#define SMC_RMI_OP_MEM_RECLAIM SMC_RMI_CALL(0x0209)#define SMC_RMI_OP_CANCEL SMC_RMI_CALL(0x020a)#define SMC_RMI_PDEV_SET_PROT SMC_RMI_CALL(0x020b) +#define SMC_RMI_PSMMU_INFO SMC_RMI_CALL(0x020e)#define RMI_ABI_MAJOR_VERSION 2#define RMI_ABI_MINOR_VERSION 0
@@ -595,4 +596,33 @@ struct rmi_pdev_stream_params { }; }; +#define RMI_PSMMU_IRQCFG_IRQ_DISABLED 0x0 +#define RMI_PSMMU_IRQCFG_IRQ_WIRED 0x1 +#define RMI_PSMMU_IRQCFG_IRQ_MSI 0x2 +#define RMI_PSMMU_IRQCFG_MASK GENMASK(1, 0) +struct rmi_psmmu_info { +union { +struct { +u64 flags; +union { +u32 gerror_intr_num; +u8 padding1[8 ]; + }; +union { +u32 eventq_intr_num; +u8 padding2[8 ]; + }; +union { +u32 priq_intr_num; +u8 padding3[8 ]; + }; +union { +u32 cmdq_sync_intr_num; +u8 padding4[8 ]; + }; + }; +u8 padding5[0x1000 ]; + }; +}; +#endif /* __ASM_RMI_SMC_H */
drivers/iommu/arm/arm-smmu-v3/Makefile +1 -1
@@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_ARM_SMMU_V3) += arm_smmu_v3.o -arm_smmu_v3-y := arm-smmu-v3.o +arm_smmu_v3-y := arm-smmu-v3.o arm-smmu-v3-realm.o arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_IOMMUFD) += arm-smmu-v3-iommufd.o arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o arm_smmu_v3-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c new file +124 -0
124 lines not on this page · raw message
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +79 -2
138 lines not on this page · raw message
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +10 -0
@@ -20,6 +20,7 @@ struct arm_vsmmu;/* MMIO registers */ #define ARM_SMMU_IDR0 0x0 +#define IDR0_RME_IMPL (1 << 30)#define IDR0_ST_LVL GENMASK(28, 27)#define IDR0_ST_LVL_2LVL 1#define IDR0_STALL_MODEL GENMASK(25, 24)
@@ -739,6 +740,7 @@ struct arm_smmu_device {struct device *impl_dev;const struct arm_smmu_impl_ops *impl_ops; +phys_addr_t base_phys;void __iomem *base;void __iomem *page1;
@@ -767,6 +769,9 @@ struct arm_smmu_device {#define ARM_SMMU_FEAT_HD (1 << 22)#define ARM_SMMU_FEAT_S2FWB (1 << 23)#define ARM_SMMU_FEAT_BBML2 (1 << 24) +#define ARM_SMMU_FEAT_RME (1 << 25) +#define ARM_SMMU_FEAT_RME_IRQ (1 << 26) +#define ARM_SMMU_FEAT_RME_MSI (1 << 27)u32 features;#define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0)
@@ -782,6 +787,9 @@ struct arm_smmu_device {int gerr_irq;int combined_irq; +int realm_gerr_irq; +int realm_evtq_irq; +int realm_pri_irq;unsigned long oas;/* PA */ unsigned long pgsize_bitmap;
@@ -1096,4 +1104,6 @@ static inline int arm_vmaster_report_event(struct arm_smmu_vmaster *vmaster, }#endif /* CONFIG_ARM_SMMU_V3_IOMMUFD */ +void arm_smmu_setup_realm_irqs (struct arm_smmu_device *smmu); +#endif /* _ARM_SMMU_V3_H */
Signature · 1 line
2.43.0
Re: [RFC PATCH v4 01/16] iommu/arm-smmu-v3: Discover RME support and realm IRQ topology
Quoted 17 lines · Aneesh Kumar K.V (Arm)
+++
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.cdrivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c new file +15
-0@@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* Copyright (C) 2026 ARM Ltd. +*/ + +#include <linux/interrupt.h> +#include <asm/rmi_smc.h> +#include <asm/rmi_cmds.h> + +#include "arm-smmu-v3.h" + +#define RMI_PSMMU_IRQ_GERROR BIT(0) +#define RMI_PSMMU_IRQ_EVENTQ BIT(1) +#define RMI_PSMMU_IRQ_PRIQ BIT(2) +#define RMI_PSMMU_IRQ_CMDQ BIT(3)
[...]
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c line 37
Quoted 6 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c new file +6
-0+if (irq == smmu->realm_evtq_irq) + notify_flags =RMI_PSMMU_IRQ_EVENTQ ; +else if (irq == smmu->realm_gerr_irq) + notify_flags =RMI_PSMMU_IRQ_GERROR ; +else if (irq == smmu->realm_pri_irq) + notify_flags =RMI_PSMMU_IRQ_PRIQ ;
These are defined as BIT(x)...
Quoted 2 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c new file +2
-0+if (rmi_psmmu_irq_notify (smmu->base_phys, + notify_flags, &event)) {
[...]
Review
Quoted 1 line
(quoted diff) +1
-0+ rmi_psmmu_event_consume(smmu->base_phys, notify_flags);
.. and passed to RMI_PSMMU_IRQ_NOTIFY and RMI_PSMMU_EVENT_CONSUME.
RMI_PSMMU_IRQ_NOTIFY takes RmiPsmmuIrqSet type, which is a 4-bit field that has a range of [BIT(0), BIT(3)]. So this is correct.
However, RMI_PSMMU_EVENT_CONSUME takes RmiPsmmuIrq type, which is a 2-bit field that has a range of [0x0, 0x3]. So this seems wrong.
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c line 88
Quoted 11 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c new file +11
-0+void arm_smmu_setup_realm_irqs (struct arm_smmu_device *smmu) +{ +int irq, ret; + + irq = smmu->realm_evtq_irq; +if (irq) { + ret =devm_request_threaded_irq (smmu->dev, irq,NULL , + arm_smmu_realm_notify_thread, +IRQF_ONESHOT , +"arm-smmu-v3-realm-evtq" , + smmu);
These IRQ numbers are raw numbers forwarded by firmware and then returned by RMI_PSMMU_INFO:
+ if ((psmmu_info->flags & RMI_PSMMU_IRQCFG_MASK) ==
+ RMI_PSMMU_IRQCFG_IRQ_WIRED) {
+ smmu->realm_gerr_irq = psmmu_info->gerror_intr_num;
+ smmu->realm_evtq_irq = psmmu_info->eventq_intr_num;
+ smmu->realm_pri_irq = psmmu_info->priq_intr_num;
Should they be converted to Linux IRQ numbers before forwarded to devm_request_threaded_irq?
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h struct arm_smmu_device { · line 792
Quoted 7 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +3
-0@@ -782,6 +787,9 @@ struct arm_smmu_device {int gerr_irq;int combined_irq; +int realm_gerr_irq; +int realm_evtq_irq; +int realm_pri_irq;
Nit: this series adds a few realm-specific things in the top SMMU structure. Maybe a "struct arm_realm_psmmu" can make them clearer.
Thanks
Nicolin
Re: [RFC PATCH v4 01/16] iommu/arm-smmu-v3: Discover RME support and realm IRQ topology
Quoted 35 lines · Nicolin Chen
Quoted 17 lines · Aneesh Kumar K.V (Arm)
+++
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.cdrivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c new file +15
-0@@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* Copyright (C) 2026 ARM Ltd. +*/ + +#include <linux/interrupt.h> +#include <asm/rmi_smc.h> +#include <asm/rmi_cmds.h> + +#include "arm-smmu-v3.h" + +#define RMI_PSMMU_IRQ_GERROR BIT(0) +#define RMI_PSMMU_IRQ_EVENTQ BIT(1) +#define RMI_PSMMU_IRQ_PRIQ BIT(2) +#define RMI_PSMMU_IRQ_CMDQ BIT(3)[...]
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c line 37
Quoted 6 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c new file +6
-0+if (irq == smmu->realm_evtq_irq) + notify_flags =RMI_PSMMU_IRQ_EVENTQ ; +else if (irq == smmu->realm_gerr_irq) + notify_flags =RMI_PSMMU_IRQ_GERROR ; +else if (irq == smmu->realm_pri_irq) + notify_flags =RMI_PSMMU_IRQ_PRIQ ;These are defined as BIT(x)...
Quoted 2 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c new file +2
-0+if (rmi_psmmu_irq_notify (smmu->base_phys, + notify_flags, &event)) {[...]
Review
Quoted 1 line
(quoted diff) +1
-0+ rmi_psmmu_event_consume(smmu->base_phys, notify_flags);.. and passed to
RMI_PSMMU_IRQ_NOTIFYandRMI_PSMMU_EVENT_CONSUME.
Quoted 6 lines
RMI_PSMMU_IRQ_NOTIFYtakes RmiPsmmuIrqSet type, which is a 4-bit field that has a range of [BIT(0), BIT(3)]. So this is correct.However,
RMI_PSMMU_EVENT_CONSUMEtakes RmiPsmmuIrq type, which is a 2-bit field that has a range of [0x0,0x3]. So this seems wrong.
Updated that to
#define RMI_PSMMU_IRQ_PEND_GERROR BIT(0)
#define RMI_PSMMU_IRQ_PEND_EVENTQ BIT(1)
#define RMI_PSMMU_IRQ_PEND_PRIQ BIT(2)
#define RMI_PSMMU_IRQ_PEND_CMDQ BIT(3)
#define RMI_PSMMU_IRQ_GERROR 0
#define RMI_PSMMU_IRQ_EVENTQ 1
#define RMI_PSMMU_IRQ_PRIQ 2
#define RMI_PSMMU_IRQ_CMDQ 3
and
if (irq == smmu->realm.evtq_irq) {
notify_flags = RMI_PSMMU_IRQ_PEND_EVENTQ;
psmmu_irq = RMI_PSMMU_IRQ_EVENTQ;
} else if (irq == smmu->realm.gerr_irq) {...
rmi_psmmu_event_consume(smmu->base_phys, psmmu_irq);
Quoted 22 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c line 88
Quoted 12 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c new file +11
-0+void arm_smmu_setup_realm_irqs (struct arm_smmu_device *smmu) +{ +int irq, ret; + + irq = smmu->realm_evtq_irq; +if (irq) { + ret =devm_request_threaded_irq (smmu->dev, irq,NULL , + arm_smmu_realm_notify_thread, +IRQF_ONESHOT , +"arm-smmu-v3-realm-evtq" , + smmu);These IRQ numbers are raw numbers forwarded by firmware and then returned by
RMI_PSMMU_INFO:drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +5
-0+if ((psmmu_info->flags &RMI_PSMMU_IRQCFG_MASK ) == +RMI_PSMMU_IRQCFG_IRQ_WIRED ) { + smmu->realm_gerr_irq = psmmu_info->gerror_intr_num; + smmu->realm_evtq_irq = psmmu_info->eventq_intr_num; + smmu->realm_pri_irq = psmmu_info->priq_intr_num;
Quoted 3 lines
Should they be converted to Linux IRQ numbers before forwarded to
devm_request_threaded_irq?
Yes, that needs conversion. I guess we can use the irq_domain associated with the non-Realm IRQ number to create the mappings?
Something like:
+static struct irq_domain *arm_smmu_get_wired_irq_domain(struct arm_smmu_device *smmu) +{
+ int irqs[] = {
+ smmu->combined_irq,
+ smmu->evtq.q.irq,
+ smmu->gerr_irq,
+ smmu->priq.q.irq,
+ };
+ struct irq_domain *domain = NULL;
+ struct irq_data *irq_data;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+ if (irqs[i] <= 0)
+ continue;
+
+ irq_data = irq_get_irq_data(irqs[i]);
+ if (!irq_data || !irq_data->domain)
+ return ERR_PTR(-EINVAL);
+
+ if (domain && domain != irq_data->domain)
+ return ERR_PTR(-EINVAL);
+
+ domain = irq_data->domain;
+ }
+
+ return domain ?: ERR_PTR(-ENXIO);
+}
Quoted 12 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h struct arm_smmu_device { · line 792
Quoted 8 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +3
-0@@ -782,6 +787,9 @@ struct arm_smmu_device {int gerr_irq;int combined_irq; +int realm_gerr_irq; +int realm_evtq_irq; +int realm_pri_irq;Nit: this series adds a few realm-specific things in the top SMMU structure. Maybe a "struct
arm_realm_psmmu" can make them clearer.
Added
struct arm_smmu_realm {
int gerr_irq;
int evtq_irq;
int pri_irq;
struct mutex mutex;
refcount_t users;
};-aneesh
Re: [RFC PATCH v4 01/16] iommu/arm-smmu-v3: Discover RME support and realm IRQ topology
Quoted 17 lines · Aneesh Kumar K.V
(quoted diff) +17
-0+static struct irq_domain *arm_smmu_get_wired_irq_domain(struct arm_smmu_device *smmu) +{ + int irqs[] = { + smmu->combined_irq, + smmu->evtq.q.irq, + smmu->gerr_irq, + smmu->priq.q.irq, + }; + struct irq_domain *domain = NULL; + struct irq_data *irq_data; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(irqs); i++) { + if (irqs[i] <= 0) + continue; + + irq_data = irq_get_irq_data(irqs[i]);
Review
Quoted 10 lines
(quoted diff) +10
-0+ if (!irq_data || !irq_data->domain) + return ERR_PTR(-EINVAL); + + if (domain && domain != irq_data->domain) + return ERR_PTR(-EINVAL); + + domain = irq_data->domain; + } + + return domain ?: ERR_PTR(-ENXIO);
I'm not excited to see code like this in a driver. Please put a helper function someplace else to translate whatever the RMM value is into a normal linux irq number?
But this feels wrong to me, interrupts need to come through the FW side, ACPI or DT. Having RMM pass the value outside that infrastructure is going to be painful. None of this is trusted, why is it working like this vs just adding more interrupt lines to the FW description?
A naked integer is not enough to describe an interrupt in the system, and guessing that it is connected to other interrupts in the psmmu seems like an uncomfortable leap to me.
Jason
RFC PATCH v4 2/16 iommu/arm-smmu-v3: Save the programmed MSI message in msi_desc
In reply to Aneesh Kumar K.V (Arm)Cache the MSI message in desc->msg from arm_smmu_write_msi_msg(). The realm support code later reads the MSI address and data through irq_get_msi_desc(), so it needs the descriptor to reflect the last programmed message.
This matches the caching done by __pci_write_msi_msg().
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +3 -0
@@ -4012,6 +4012,9 @@ static void arm_smmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)if (smmu->features &ARM_SMMU_FEAT_PRI ) max_config_index =PRIQ_MSI_INDEX ; +/* save the programmed msi message details */ + desc->msg = *msg; +/* Don't try to config for Realm interrupts. */ if (desc->msi_index > max_config_index)return ;
Signature · 1 line
2.43.0
RFC PATCH v4 3/16 iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
In reply to Aneesh Kumar K.V (Arm)Add initial plumbing for Realm pSMMU integration in the arm-smmu-v3 iommufd path.
Changes include:
- add RMI SMC IDs and helper wrappers for pSMMU activate and ST_L2 create/destroy
- add RMI pSMMU parameter structure definitions
- add IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 UAPI/internal type support
- add arm-smmu-v3 realm viommu init/vdevice hooks
- store SMMU MMIO physical base and realm initialization state in arm_smmu_device
This enables basic realm pSMMU setup and vdevice stream-table operations.
--- arch/arm64/include/asm/rmi_cmds.h | 7 + arch/arm64/include/asm/rmi_smc.h | 18 +++ arch/arm64/kernel/rmi.c | 39 +++++ .../arm/arm-smmu-v3/arm-smmu-v3-iommufd.c | 7 + .../iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c | 148 ++++++++++++++++++ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 4 + include/uapi/linux/iommufd.h | 1 + 8 files changed, 225 insertions(+)
arch/arm64/include/asm/rmi_cmds.h +7 -0
@@ -863,4 +863,11 @@ static inline unsigned long rmi_psmmu_event_consume(unsigned long psmmu_phys, return res.a0; } +int rmi_psmmu_activate (unsigned long psmmu_phys, +unsigned long psmmu_params_phys,unsigned long *rmi_ret); +int rmi_psmmu_st_l2_create (unsigned long psmmu_phys, +unsigned long stream_id,unsigned long *rmi_ret); +int rmi_psmmu_st_l2_destroy (unsigned long psmmu_phys, +unsigned long stream_id,unsigned long *rmi_ret); +#endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/asm/rmi_smc.h +18 -0
@@ -625,4 +625,22 @@ struct rmi_psmmu_info { }; }; +#define RMI_PSMMU_FLAG_MSI BIT(0) +#define RMI_PSMMU_FLAG_ATS BIT(1) +#define RMI_PSMMU_FLAG_PRI BIT(2) +struct rmi_psmmu_params { +union { +struct { +u64 flags; +u64 grr_addr; +u64 grr_data; +u64 eventq_addr; +u64 eventq_data; +u64 priq_addr; +u64 priq_data; + }; +u8 padding5[0x1000 ]; + }; +}; +#endif /* __ASM_RMI_SMC_H */
arch/arm64/kernel/rmi.c +39 -0
@@ -423,6 +423,45 @@ unsigned long rmi_sro_execute(struct rmi_sro_state *sro)return regs.a0; } +int rmi_psmmu_activate (unsigned long psmmu_phys, +unsigned long psmmu_params_phys,unsigned long *rmi_ret) +{ + struct rmi_sro_state *sro __free(sro) = +rmi_sro_init (SMC_RMI_PSMMU_ACTIVATE , psmmu_phys, psmmu_params_phys); +if (!sro) +return -ENOMEM ; + + *rmi_ret =rmi_sro_execute (sro); + +return 0 ; +} + +int rmi_psmmu_st_l2_create (unsigned long psmmu_phys, +unsigned long stream_id,unsigned long *rmi_ret) +{ + struct rmi_sro_state *sro __free(sro) = +rmi_sro_init (SMC_RMI_PSMMU_ST_L2_CREATE , psmmu_phys, stream_id); +if (!sro) +return -ENOMEM ; + + *rmi_ret =rmi_sro_execute (sro); + +return 0 ; +} + +int rmi_psmmu_st_l2_destroy (unsigned long psmmu_phys, +unsigned long stream_id,unsigned long *rmi_ret) +{ + struct rmi_sro_state *sro __free(sro) = +rmi_sro_init (SMC_RMI_PSMMU_ST_L2_DESTROY , psmmu_phys, stream_id); +if (!sro) +return -ENOMEM ; + + *rmi_ret =rmi_sro_execute (sro); + +return 0 ; +} +static int rmi_configure (void ) { struct rmm_config *config __free(free_page) = NULL;
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +7 -0
@@ -437,6 +437,9 @@ size_t arm_smmu_get_viommu_size(struct device *dev,if (viommu_type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ) return VIOMMU_STRUCT_SIZE(struct arm_vsmmu, core); +if (viommu_type ==IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 ) + return VIOMMU_STRUCT_SIZE(struct arm_vsmmu, core); +if (!smmu->impl_ops || !smmu->impl_ops->get_viommu_size)return 0 ;return smmu->impl_ops->get_viommu_size (viommu_type);
@@ -464,6 +467,10 @@ int arm_vsmmu_init(struct iommufd_viommu *viommu,return 0 ; } +if (viommu->type ==IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 ) +return arm_realm_smmu_v3_init (viommu, user_data); + +return smmu->impl_ops->vsmmu_init (vsmmu, user_data); }
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +148 -0
157 lines not on this page · raw message
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +1 -0
@@ -3956,6 +3956,7 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu)if (ret)return ret; + smmu->realm_initialized = false;if (smmu->impl_ops && smmu->impl_ops->init_structures)return smmu->impl_ops->init_structures (smmu);
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +4 -0
@@ -811,6 +811,8 @@ struct arm_smmu_device {struct rb_root streams;struct mutex streams_mutex; + +bool realm_initialized; };struct arm_smmu_stream {
@@ -1073,6 +1075,8 @@ arm_vsmmu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags, const struct iommu_user_data *user_data);int arm_vsmmu_cache_invalidate (struct iommufd_viommu *viommu,struct iommu_user_data_array *array); +int arm_realm_smmu_v3_init (struct iommufd_viommu *viommu, +const struct iommu_user_data *user_data);#else #define arm_smmu_get_viommu_size NULL#define arm_smmu_hw_info NULL
include/uapi/linux/iommufd.h +1 -0
@@ -1055,6 +1055,7 @@ enum iommu_viommu_type {IOMMU_VIOMMU_TYPE_DEFAULT =0 ,IOMMU_VIOMMU_TYPE_ARM_SMMUV3 =1 ,IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV =2 , + IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 = 3, };/**
Signature · 1 line
2.43.0
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c void arm_smmu_setup_realm_irqs(struct arm_smmu_device *smmu) · line 196
Quoted 4 lines · Aneesh Kumar K.V (Arm)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +4
-0+static const struct iommufd_viommu_ops arm_realm_smmu_v3_ops = { + .destroy = arm_realm_smmu_v3_destroy, + .alloc_domain_nested = arm_vsmmu_alloc_domain_nested, + .cache_invalidate = arm_vsmmu_cache_invalidate,
I don't think realm vsmmu should include NS nested domain ops. I wonder if adding here is for some covert reason that prevents us from registering viommu/vdevice objects?
Quoted 7 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +7
-0+static int arm_realm_smmu_v3_vdevice_init (struct iommufd_vdevice *vdev) +{ +struct device *dev =iommufd_vdevice_to_device (vdev); +struct arm_smmu_master *master =dev_iommu_priv_get (dev); +// fixme which stream to pick +/* At this moment, iommufd only supports PCI device that has one SID */ +struct arm_smmu_stream *stream = &master->streams[0 ];
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c void arm_smmu_setup_realm_irqs(struct arm_smmu_device *smmu) · line 176
Quoted 10 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +10
-0+struct arm_smmu_device *smmu = master->smmu; +unsigned long rmi_ret =0 ; +int ret; + +if (!smmu->realm_initialized) +return -EINVAL ; + + ret =rmi_psmmu_st_l2_create (smmu->base_phys, +ALIGN_DOWN (stream->id,STRTAB_NUM_L2_STES ), + &rmi_ret);
The "vdevice" is for a PSMMU stream table allocation..
Quoted 3 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +3
-0+int arm_realm_smmu_v3_init (struct iommufd_viommu *viommu, +const struct iommu_user_data *user_data) +{
[...]
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c void arm_smmu_setup_realm_irqs(struct arm_smmu_device *smmu) · line 257
Quoted 3 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +3
-0+psmmu_activate: + ret =rmi_psmmu_activate (smmu->base_phys,virt_to_phys (params), + &rmi_ret);
.. and the "viommu" is also for PSMMU activation...
include/uapi/linux/iommufd.h enum iommu_viommu_type { · line 1058
Quoted 6 lines
+++
b/include/uapi/linux/iommufd.hinclude/uapi/linux/iommufd.h +1
-0@@ -1055,6 +1055,7 @@ enum iommu_viommu_type {IOMMU_VIOMMU_TYPE_DEFAULT =0 ,IOMMU_VIOMMU_TYPE_ARM_SMMUV3 =1 ,IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV =2 , + IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 = 3,
.. and we demand userspace (VMM) to use IOMMU_VIOMMU_ALLOC ioctl, even if VMM does not actually expose a guest-level SMMU instance. Thus, no user_data.
I can get the reasoning behind the flow using this viommu/vdevice.
But, on the other hand, I can imagine that a Realm VSMMU would add a new flag with a user_data to this VIOMMU. Then, this flow would give some troubles to VMM (QEMU for example):
- For VM with a guest-level SMMU, QEMU creates a realm instance where IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 (with vsmmu) can be allocated.
- For VM w/o a guest-level SMMU, QEMU won't create such a realm instance, while still required to invoke the ioctl (w/o vsmmu).
Taking a step back, I wonder if we really need to use iommufd for PSMMU activation and its stream table allocations?
Here are some facts:
- An iommufd has a ctx, that's one per VM. Similarly, a Realm has an RD.
- For an RMI command that needs an RD, it makes sense to be per iommufd ctx, e.g. RMI_VSMMU_* or RMI_VDEV_* commands.
- PSMMU commands are global; they don't need RD. So they don't seem necessary to tie to an iommufd ctx.
Instead, could the PSMMU activation be done after RMI_PSMMU_INFO check? Is there any reason not to do that? A safer timing might be at the device assignment stage?
Speaking of which, RMI_PSMMU_ST_L2_CREATE doesn't seem necessary to be invoked in a vdevice context either. Maybe it should align with iommufd idev's lifecycle?
Nicolin
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 74 lines · Nicolin Chen
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c void arm_smmu_setup_realm_irqs(struct arm_smmu_device *smmu) · line 196
Quoted 4 lines · Aneesh Kumar K.V (Arm)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +4
-0+static const struct iommufd_viommu_ops arm_realm_smmu_v3_ops = { + .destroy = arm_realm_smmu_v3_destroy, + .alloc_domain_nested = arm_vsmmu_alloc_domain_nested, + .cache_invalidate = arm_vsmmu_cache_invalidate,I don't think realm vsmmu should include NS nested domain ops. I wonder if adding here is for some covert reason that prevents us from registering viommu/vdevice objects?
Quoted 7 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +7
-0+static int arm_realm_smmu_v3_vdevice_init (struct iommufd_vdevice *vdev) +{ +struct device *dev =iommufd_vdevice_to_device (vdev); +struct arm_smmu_master *master =dev_iommu_priv_get (dev); +// fixme which stream to pick +/* At this moment, iommufd only supports PCI device that has one SID */ +struct arm_smmu_stream *stream = &master->streams[0 ];drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c void arm_smmu_setup_realm_irqs(struct arm_smmu_device *smmu) · line 176
Quoted 10 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +10
-0+struct arm_smmu_device *smmu = master->smmu; +unsigned long rmi_ret =0 ; +int ret; + +if (!smmu->realm_initialized) +return -EINVAL ; + + ret =rmi_psmmu_st_l2_create (smmu->base_phys, +ALIGN_DOWN (stream->id,STRTAB_NUM_L2_STES ), + &rmi_ret);The "vdevice" is for a PSMMU stream table allocation..
Quoted 3 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +3
-0+int arm_realm_smmu_v3_init (struct iommufd_viommu *viommu, +const struct iommu_user_data *user_data) +{[...]
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c void arm_smmu_setup_realm_irqs(struct arm_smmu_device *smmu) · line 257
Quoted 3 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +3
-0+psmmu_activate: + ret =rmi_psmmu_activate (smmu->base_phys,virt_to_phys (params), + &rmi_ret);.. and the "viommu" is also for PSMMU activation...
include/uapi/linux/iommufd.h enum iommu_viommu_type { · line 1058
Quoted 6 lines
+++
b/include/uapi/linux/iommufd.hinclude/uapi/linux/iommufd.h +1
-0@@ -1055,6 +1055,7 @@ enum iommu_viommu_type {IOMMU_VIOMMU_TYPE_DEFAULT =0 ,IOMMU_VIOMMU_TYPE_ARM_SMMUV3 =1 ,IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV =2 , + IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 = 3,.. and we demand userspace (VMM) to use
IOMMU_VIOMMU_ALLOCioctl, even if VMM does not actually expose a guest-level SMMU instance. Thus, nouser_data.I can get the reasoning behind the flow using this viommu/vdevice.
But, on the other hand, I can imagine that a Realm VSMMU would add a new flag with a
user_datato this VIOMMU. Then, this flow would give some troubles to VMM (QEMU for example):- For VM with a guest-level SMMU, QEMU creates a realm instance where
IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3(with vsmmu) can be allocated.
- For VM w/o a guest-level SMMU, QEMU won't create such a realm instance, while still required to invoke the ioctl (w/o vsmmu).Taking a step back, I wonder if we really need to use iommufd for PSMMU activation and its stream table allocations?
Here are some facts:
- An iommufd has a ctx, that's one per VM. Similarly, a Realm has an RD.
- For an RMI command that needs an RD, it makes sense to be per iommufd ctx, e.g. RMI_VSMMU_* or RMI_VDEV_* commands.
- PSMMU commands are global; they don't need RD. So they don't seem necessary to tie to an iommufd ctx.
Quoted 4 lines
Instead, could the PSMMU activation be done after
RMI_PSMMU_INFOcheck? Is there any reason not to do that? A safer timing might be at the device assignment stage?
One of the reasons I added IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 was to avoid creating a psmmu object when we are not using a PCI passthrough VM. That is also the reason for all the refcounting around the psmmu objects.
If we are okay with creating psmmu objects early, then I guess we can go with the above approach.
Quoted 5 lines
Speaking of which,
RMI_PSMMU_ST_L2_CREATEdoesn't seem necessary to be invoked in a vdevice context either. Maybe it should align with iommufd idev's lifecycle?
-aneesh
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 3 lines · Aneesh Kumar K.V
Quoted 1 line · Nicolin Chen
On Mon, Apr 27, 2026 at 02:23:31PM +0530, Aneesh Kumar K.V (Arm) wrote:
...
Quoted 32 lines
Quoted 27 lines
.. and we demand userspace (VMM) to use
IOMMU_VIOMMU_ALLOCioctl, even if VMM does not actually expose a guest-level SMMU instance. Thus, nouser_data.I can get the reasoning behind the flow using this viommu/vdevice.
But, on the other hand, I can imagine that a Realm VSMMU would add a new flag with a
user_datato this VIOMMU. Then, this flow would give some troubles to VMM (QEMU for example):- For VM with a guest-level SMMU, QEMU creates a realm instance where
IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3(with vsmmu) can be allocated.
- For VM w/o a guest-level SMMU, QEMU won't create such a realm instance, while still required to invoke the ioctl (w/o vsmmu).Taking a step back, I wonder if we really need to use iommufd for PSMMU activation and its stream table allocations?
Here are some facts:
- An iommufd has a ctx, that's one per VM. Similarly, a Realm has an RD.
- For an RMI command that needs an RD, it makes sense to be per iommufd ctx, e.g. RMI_VSMMU_* or RMI_VDEV_* commands.
- PSMMU commands are global; they don't need RD. So they don't seem necessary to tie to an iommufd ctx.Quoted 4 lines
Instead, could the PSMMU activation be done after
RMI_PSMMU_INFOcheck? Is there any reason not to do that? A safer timing might be at the device assignment stage?
Quoted 8 lines
One of the reasons I added
IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3was to avoid creating a psmmu object when we are not using a PCI passthrough VM. That is also the reason for all the refcounting around the psmmu objects.If we are okay with creating psmmu objects early, then I guess we can go with the above approach.
How about?
modified drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c
@@ -437,9 +437,6 @@
if (viommu_type == IOMMU_VIOMMU_TYPE_ARM_SMMUV3)
return VIOMMU_STRUCT_SIZE(struct arm_vsmmu, core);
- if (viommu_type == IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3)
- return VIOMMU_STRUCT_SIZE(struct arm_vsmmu, core);
-
if (!smmu->impl_ops || !smmu->impl_ops->get_viommu_size)
return 0;
return smmu->impl_ops->get_viommu_size(viommu_type);
@@ -463,14 +460,13 @@
vsmmu->vmid = s2_parent->s2_cfg.vmid;
if (viommu->type == IOMMU_VIOMMU_TYPE_ARM_SMMUV3) {
+ if (arm_smmu_is_realm_viommu(viommu))
+ return arm_realm_smmu_v3_init(viommu, user_data);
+
viommu->ops = &arm_vsmmu_ops; return 0;
}
- if (viommu->type == IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3)
- return arm_realm_smmu_v3_init(viommu, user_data);
-
-
return smmu->impl_ops->vsmmu_init(vsmmu, user_data);
}
modified drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c
@@ -239,21 +239,27 @@
return 0;
}
+bool arm_smmu_is_realm_viommu(struct iommufd_viommu *viommu)
+{
+ struct kvm *kvm;
+
+ if (!viommu->kvm_file)
+ return false;
+
+ kvm = viommu->kvm_file->private_data;
+ return kvm_is_realm(kvm);
+}
+
int arm_realm_smmu_v3_init(struct iommufd_viommu *viommu,
const struct iommu_user_data *user_data)
{
int ret = 0;
- struct kvm *kvm;
struct rmi_psmmu_params *params;
struct arm_smmu_device *smmu =
container_of(viommu->iommu_dev, struct arm_smmu_device, iommu);
unsigned long rmi_ret;
- if (!viommu->kvm_file)
- return -EINVAL;
-
- kvm = viommu->kvm_file->private_data;
- if (!kvm_is_realm(kvm))
+ if (!arm_smmu_is_realm_viommu(viommu))
return -EINVAL;
if (!(smmu->features & ARM_SMMU_FEAT_RME))
modified drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4515,8 +4515,6 @@
int ret;
mutex_init(&smmu->streams_mutex);
- mutex_init(&smmu->realm.mutex);
- refcount_set(&smmu->realm.users, 0);
smmu->streams = RB_ROOT;
ret = arm_smmu_init_queues(smmu);
@@ -5578,6 +5576,8 @@
return -ENODEV;
}
+ mutex_init(&smmu->realm.mutex);
+ refcount_set(&smmu->realm.users, 0);
smmu->features |= ARM_SMMU_FEAT_RME_IRQ;
return 0;
modified drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1282,6 +1282,7 @@
const struct iommu_user_data *user_data);
int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu,
struct iommu_user_data_array *array);
+bool arm_smmu_is_realm_viommu(struct iommufd_viommu *viommu);
int arm_realm_smmu_v3_init(struct iommufd_viommu *viommu,
const struct iommu_user_data *user_data);
#else
modified include/uapi/linux/iommufd.h
@@ -1068,7 +1068,6 @@
* VMM must wire the HYP_OWN bit to 0 in guest VINTF_CONFIG register
*/
IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV = 2,
- IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 = 3,
};
/**
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c int arm_vsmmu_init(struct iommufd_viommu *viommu, · line 465
Quoted 7 lines · Aneesh Kumar K.V
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0@@ -463,14 +460,13 @@ vsmmu->vmid = s2_parent->s2_cfg.vmid;if (viommu->type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ) { +if (arm_smmu_is_realm_viommu (viommu)) +return arm_realm_smmu_v3_init (viommu, user_data); +
I think the realm vsmmu is going to require a different info struct than the normal psmmu case, isn't it?
If so it needs its own enum value.
It would be nice to see a draft patch showing how the real vsmmu works on top of the RMM spec for it. If we are using a viommu object then non-vsmmu case should be identical just with an option in the info struct to not create the vsmmu object.
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 13 lines · Jason Gunthorpe
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c int arm_vsmmu_init(struct iommufd_viommu *viommu, · line 465
Quoted 7 lines · Aneesh Kumar K.V
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0@@ -463,14 +460,13 @@ vsmmu->vmid = s2_parent->s2_cfg.vmid;if (viommu->type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ) { +if (arm_smmu_is_realm_viommu (viommu)) +return arm_realm_smmu_v3_init (viommu, user_data); +I think the realm vsmmu is going to require a different info struct than the normal psmmu case, isn't it?
Quoted 6 lines
If so it needs its own enum value.
It would be nice to see a draft patch showing how the real vsmmu works on top of the RMM spec for it. If we are using a viommu object then non-vsmmu case should be identical just with an option in the info struct to not create the vsmmu object.
Actually, the PSMMU-only viommu object in this series only adds a type with no viommu data structure.
I've drafted the vsmmu case on top of the series, so it would add a structure reusing the same IOMMU_VIOMMU_TYPE_ARM_SMMUV3 with a flag:
+/**
+ * enum iommu_viommu_arm_realm_vsmmuv3_flags - Flags for ARM SMMUv3 Realm
+ * @IOMMU_VIOMMU_ARM_REALM_SMMUV3_FLAGS_VSMMU: Indicates whether the Realm has
+ * a guest-visible VSMMU instance
+ */
+enum iommu_viommu_arm_realm_vsmmuv3_flags {
+ IOMMU_VIOMMU_ARM_REALM_SMMUV3_FLAGS_VSMMU = 1 << 0,
+};
+
+/**
+ * struct iommu_viommu_arm_realm_vsmmuv3 - ARM Realm VSMMUv3 parameters
+ * (IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3)
+ * @flags: Combination of enum iommu_viommu_arm_realm_vsmmuv3_flags
+ * @reg_base: MMIO base address of the VSMMU in the guest VM
+ * @reg_top: MMIO top address of the VSMMU in the guest VM
+ * @aidr: AIDR register value of the VSMMU in the guest VM
+ * @idr: IDR register values of the VSMMU in the guest VM
+ */
+struct iommu_viommu_arm_realm_vsmmuv3 {
+ __aligned_u64 flags;
+ __aligned_le64 reg_base;
+ __aligned_le64 reg_top;
+ __aligned_le64 aidr;
+ __aligned_le64 idr[7];
+};
I think this should work. But I still feel awkward that a non-vsmmu case has to allocate a viommu object for a set of RMI commands that don't need an Realm Descriptor. Things could be cleaner if we allow RMI_PSMMU_ACTIVATE and RMI_PSMMU_ST_L2_CREATE to be independent on a viommu; then leave IOMMU_VIOMMU_TYPE_ARM_SMMUV3 to vsmmu-visiable case.
Nicolin
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 21 lines · Nicolin Chen
Quoted 13 lines · Jason Gunthorpe
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c int arm_vsmmu_init(struct iommufd_viommu *viommu, · line 465
Quoted 7 lines · Aneesh Kumar K.V
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0@@ -463,14 +460,13 @@ vsmmu->vmid = s2_parent->s2_cfg.vmid;if (viommu->type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ) { +if (arm_smmu_is_realm_viommu (viommu)) +return arm_realm_smmu_v3_init (viommu, user_data); +I think the realm vsmmu is going to require a different info struct than the normal psmmu case, isn't it?
Quoted 6 lines
If so it needs its own enum value.
It would be nice to see a draft patch showing how the real vsmmu works on top of the RMM spec for it. If we are using a viommu object then non-vsmmu case should be identical just with an option in the info struct to not create the vsmmu object.
Quoted 6 lines
Actually, the PSMMU-only viommu object in this series only adds a type with no viommu data structure.
I've drafted the vsmmu case on top of the series, so it would add a structure reusing the same
IOMMU_VIOMMU_TYPE_ARM_SMMUV3with a flag:
Oh. I replied too fast that I didn't notice this is under the standard IOMMU_VIOMMU_TYPE_ARM_SMMUV3 used by non-secure vSTE.
That doesn't look correct for a no-vsmmu case..
Nicolin
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 25 lines · Nicolin Chen
Quoted 24 lines · Nicolin Chen
Quoted 13 lines · Jason Gunthorpe
Review line 465
Quoted 7 lines · Aneesh Kumar K.V
(quoted diff) +3
-0@@ -463,14 +460,13 @@ vsmmu->vmid = s2_parent->s2_cfg.vmid; if (viommu->type == IOMMU_VIOMMU_TYPE_ARM_SMMUV3) { + if (arm_smmu_is_realm_viommu(viommu)) + return arm_realm_smmu_v3_init(viommu, user_data); +I think the realm vsmmu is going to require a different info struct than the normal psmmu case, isn't it?
Quoted 6 lines
If so it needs its own enum value.
It would be nice to see a draft patch showing how the real vsmmu works on top of the RMM spec for it. If we are using a viommu object then non-vsmmu case should be identical just with an option in the info struct to not create the vsmmu object.
Actually, the PSMMU-only viommu object in this series only adds a type with no viommu data structure.
Quoted 6 lines
Quoted 3 lines
I've drafted the vsmmu case on top of the series, so it would add a structure reusing the same
IOMMU_VIOMMU_TYPE_ARM_SMMUV3with a flag:Oh. I replied too fast that I didn't notice this is under the standard
IOMMU_VIOMMU_TYPE_ARM_SMMUV3used by non-secure vSTE.
The original patches were OK:
@@ -1055,6 +1055,7 @@ enum iommu_viommu_type {
IOMMU_VIOMMU_TYPE_DEFAULT = 0,
IOMMU_VIOMMU_TYPE_ARM_SMMUV3 = 1,
IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV = 2,
+ IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 = 3,
That's where everything should be placed, including your new struct above.
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
In reply to Nicolin ChenQuoted 15 lines · Nicolin Chen
(quoted diff) +15
-0+/** + * enum iommu_viommu_arm_realm_vsmmuv3_flags - Flags for ARM SMMUv3 Realm + * @IOMMU_VIOMMU_ARM_REALM_SMMUV3_FLAGS_VSMMU: Indicates whether the Realm has + * a guest-visible VSMMU instance + */ +enum iommu_viommu_arm_realm_vsmmuv3_flags { + IOMMU_VIOMMU_ARM_REALM_SMMUV3_FLAGS_VSMMU = 1 << 0, +}; + +/** + * struct iommu_viommu_arm_realm_vsmmuv3 - ARM Realm VSMMUv3 parameters + * (IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3) + * @flags: Combination of enum iommu_viommu_arm_realm_vsmmuv3_flags + * @reg_base: MMIO base address of the VSMMU in the guest VM + * @reg_top: MMIO top address of the VSMMU in the guest VM
Review
Quoted 10 lines
(quoted diff) +10
-0+ * @aidr: AIDR register value of the VSMMU in the guest VM + * @idr: IDR register values of the VSMMU in the guest VM + */ +struct iommu_viommu_arm_realm_vsmmuv3 { + __aligned_u64 flags; + __aligned_le64 reg_base; + __aligned_le64 reg_top; + __aligned_le64 aidr; + __aligned_le64 idr[7]; +};
Yeah, broadly what I would expect. Pass everything needed to execute RMI_VSMMU_CREATE through this struct.
Is there anything more than RMI_VSMMU_CREATE needed from a RMM perspective? What about that dpt/ats stuff?
Quoted 3 lines
I think this should work. But I still feel awkward that a non-vsmmu case has to allocate a viommu object for a set of RMI commands that don't need an Realm Descriptor.
It is for the RMI_VDEV_CREATE which needs the RD:
case IOMMU_VDEVICE_TSM_BIND: rc = tsm_bind(vdev->idev->dev, kvm, vdev->virt_id); break;
It has to be tied to a vdevice on a viommu to pick up the kvm and vSID.
If we don't do that we need a new way to get the virt_id and kvm into the flow, which doesn't really seem worthwhile to me.
Quoted 3 lines
Things could be cleaner if we allow
RMI_PSMMU_ACTIVATEandRMI_PSMMU_ST_L2_CREATEto be independent on a viommu; then leaveIOMMU_VIOMMU_TYPE_ARM_SMMUV3to vsmmu-visiable case.
This is why I asked in the other message if RMM spec is clear that PSMMU and STE are not required for anything but VDEV_CREATE. If so, the PDEV create and SPDM stuff is fuly independent.
Which is why I'm saying the split doesn't make sense. PSMMU, interrupts, STE, VDEV are all related objects that should be managed together by the SMMUv3 driver. You need a PDEV to create a STE, and you need a STE to create a VDEV.
PDEV is the SPDM channel and should be managed by the TSM driver.
So, I think the IOMMU_VDEVICE_TSM_BIND is not justified. "BIND" should happen when the SMMUv3 realm viommu ops create the vdevice. The same way the vcmdq sets up the VSID tables when the vdevice is created. Is there a reason to have it in its own command?
Further the implementation of IOMMU_VDEVICE_TSM_BIND in this series *requires* a viommu to work. So OK, let's lean into that. (to be clear I am saying delete tsm_bind)
It means the other arches will have to implement viommu APIs in their iommu drivers before they have really defined their actual secure vIOMMU definitions. That seems manageable.
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 31 lines · Jason Gunthorpe
Quoted 15 lines · Nicolin Chen
(quoted diff) +15
-0+/** + * enum iommu_viommu_arm_realm_vsmmuv3_flags - Flags for ARM SMMUv3 Realm + * @IOMMU_VIOMMU_ARM_REALM_SMMUV3_FLAGS_VSMMU: Indicates whether the Realm has + * a guest-visible VSMMU instance + */ +enum iommu_viommu_arm_realm_vsmmuv3_flags { + IOMMU_VIOMMU_ARM_REALM_SMMUV3_FLAGS_VSMMU = 1 << 0, +}; + +/** + * struct iommu_viommu_arm_realm_vsmmuv3 - ARM Realm VSMMUv3 parameters + * (IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3) + * @flags: Combination of enum iommu_viommu_arm_realm_vsmmuv3_flags + * @reg_base: MMIO base address of the VSMMU in the guest VM + * @reg_top: MMIO top address of the VSMMU in the guest VMReview
Quoted 10 lines
(quoted diff) +10
-0+ * @aidr: AIDR register value of the VSMMU in the guest VM + * @idr: IDR register values of the VSMMU in the guest VM + */ +struct iommu_viommu_arm_realm_vsmmuv3 { + __aligned_u64 flags; + __aligned_le64 reg_base; + __aligned_le64 reg_top; + __aligned_le64 aidr; + __aligned_le64 idr[7]; +};Yeah, broadly what I would expect. Pass everything needed to execute
RMI_VSMMU_CREATEthrough this struct.
Quoted 2 lines
Is there anything more than
RMI_VSMMU_CREATEneeded from a RMM perspective? What about that dpt/ats stuff?
DPT is a bit hacky currently..
Prior to RMM v2.0 ABI, DPT was allocated statically in RMM; there was no RMI command for DPT allocations.
Now, with RMM v2.0 ABI, DPT can be managed via RMIs. I am making it follow GPT at this point, similar to the static idea. But, in the long run, I will think of decoupling, but I haven't looked at that closely.
Quoted 10 lines
Quoted 3 lines
I think this should work. But I still feel awkward that a non-vsmmu case has to allocate a viommu object for a set of RMI commands that don't need an Realm Descriptor.
It is for the
RMI_VDEV_CREATEwhich needs the RD:case IOMMU_VDEVICE_TSM_BIND: rc = tsm_bind(vdev->idev->dev, kvm, vdev->virt_id); break;
Quoted 5 lines
It has to be tied to a vdevice on a viommu to pick up the kvm and vSID.
If we don't do that we need a new way to get the
virt_idand kvm into the flow, which doesn't really seem worthwhile to me.
Okay. I see the gap now...
For tsm_bind: idev has dev, idev has kvm, but idev has no vBDF.
Maybe we could allow vdevice to have no viommu? In which way, VMM can forward vBDF independently. If VMM has a vsmmu instance, then it can allocate vdevice in the traditional way.
The viommu object here is an empty vehicle that almost has no use but to allow another vehicle (vdevice) on top to forward vBDF. It makes VMM code a bit awkward: there is no iommu instance, so VMM doesn't enable iommu driver, then there is no good place to alloc the viomu object for VIOMMU_TYPE_ARM_REALM_SMMUV3.
Quoted 7 lines
Quoted 3 lines
Things could be cleaner if we allow
RMI_PSMMU_ACTIVATEandRMI_PSMMU_ST_L2_CREATEto be independent on a viommu; then leaveIOMMU_VIOMMU_TYPE_ARM_SMMUV3to vsmmu-visiable case.This is why I asked in the other message if RMM spec is clear that PSMMU and STE are not required for anything but
VDEV_CREATE. If so, the PDEV create and SPDM stuff is fuly independent.
I think the spec is clear. And you are right PDEV is independent, only linked to PSMMU when VDEV is created.
Quoted 7 lines
Which is why I'm saying the split doesn't make sense. PSMMU, interrupts, STE, VDEV are all related objects that should be managed together by the SMMUv3 driver. You need a PDEV to create a STE, and you need a STE to create a VDEV.
PDEV is the SPDM channel and should be managed by the TSM driver.
Quoted 8 lines
So, I think the
IOMMU_VDEVICE_TSM_BINDis not justified. "BIND" should happen when the SMMUv3 realm viommu ops create the vdevice. The same way the vcmdq sets up the VSID tables when the vdevice is created. Is there a reason to have it in its own command?Further the implementation of
IOMMU_VDEVICE_TSM_BINDin this series *requires* a viommu to work. So OK, let's lean into that. (to be clear I am saying deletetsm_bind)
Yea, IOMMU_VDEVICE_TSM_BIND feels redundant..
Thanks
Nicolin
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 7 lines · Nicolin Chen
Quoted 3 lines · Jason Gunthorpe
On Tue, Sep 01, 2026 at 10:13:04AM -0700, Nicolin Chen wrote:
Is there anything more thanRMI_VSMMU_CREATEneeded from a RMM perspective? What about that dpt/ats stuff?DPT is a bit hacky currently..
Quoted 7 lines
Prior to RMM v2.0 ABI, DPT was allocated statically in RMM; there was no RMI command for DPT allocations.
Now, with RMM v2.0 ABI, DPT can be managed via RMIs. I am making it follow GPT at this point, similar to the static idea. But, in the long run, I will think of decoupling, but I haven't looked at that closely.
Did a quick check. It's clear.
DPT is a system-wise global thing, not per SMMU or per realm. Each table or entry is indexed by part of 48-bit in PA corresponding to to a protected IPA. One thing that is related to a realm is a VMID in the leaf entry. So, it should unlikely be coupling with VSMMU.
The other stuff is to map VSMMU's MMIO region in its IPA space but it should be a part of the VSMMU-CREATE package.
Nicolin
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
In reply to Nicolin ChenQuoted 5 lines · Nicolin Chen
The viommu object here is an empty vehicle that almost has no use but to allow another vehicle (vdevice) on top to forward vBDF. It makes VMM code a bit awkward: there is no iommu instance, so VMM doesn't enable iommu driver, then there is no good place to alloc the viomu object for
VIOMMU_TYPE_ARM_REALM_SMMUV3.
It would have to allocate singletons viommu for each psmmu as part of setting up the vdevices.
Somehow I'd rather the vmm deal with that then invent a whole new set of uapis and flows..
At best maybe we can invent a kernel side helper to create the singletons like the auto domains, but IDK if it is really so hard for the VMM (especially compared with how hard everything else is in CC)
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
In reply to Nicolin ChenQuoted 54 lines · Nicolin Chen
Quoted 13 lines · Jason Gunthorpe
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c int arm_vsmmu_init(struct iommufd_viommu *viommu, · line 465
Quoted 7 lines · Aneesh Kumar K.V
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0@@ -463,14 +460,13 @@ vsmmu->vmid = s2_parent->s2_cfg.vmid;if (viommu->type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ) { +if (arm_smmu_is_realm_viommu (viommu)) +return arm_realm_smmu_v3_init (viommu, user_data); +I think the realm vsmmu is going to require a different info struct than the normal psmmu case, isn't it?
Quoted 6 lines
If so it needs its own enum value.
It would be nice to see a draft patch showing how the real vsmmu works on top of the RMM spec for it. If we are using a viommu object then non-vsmmu case should be identical just with an option in the info struct to not create the vsmmu object.
Actually, the PSMMU-only viommu object in this series only adds a type with no viommu data structure.
I've drafted the vsmmu case on top of the series, so it would add a structure reusing the same
IOMMU_VIOMMU_TYPE_ARM_SMMUV3with a flag:(quoted diff) +25
-0+/** + * enum iommu_viommu_arm_realm_vsmmuv3_flags - Flags for ARM SMMUv3 Realm + * @IOMMU_VIOMMU_ARM_REALM_SMMUV3_FLAGS_VSMMU: Indicates whether the Realm has + * a guest-visible VSMMU instance + */ +enum iommu_viommu_arm_realm_vsmmuv3_flags { + IOMMU_VIOMMU_ARM_REALM_SMMUV3_FLAGS_VSMMU = 1 << 0, +}; + +/** + * struct iommu_viommu_arm_realm_vsmmuv3 - ARM Realm VSMMUv3 parameters + * (IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3) + * @flags: Combination of enum iommu_viommu_arm_realm_vsmmuv3_flags + * @reg_base: MMIO base address of the VSMMU in the guest VM + * @reg_top: MMIO top address of the VSMMU in the guest VM + * @aidr: AIDR register value of the VSMMU in the guest VM + * @idr: IDR register values of the VSMMU in the guest VM + */ +struct iommu_viommu_arm_realm_vsmmuv3 { + __aligned_u64 flags; + __aligned_le64 reg_base; + __aligned_le64 reg_top; + __aligned_le64 aidr; + __aligned_le64 idr[7]; +};
Quoted 6 lines
I think this should work. But I still feel awkward that a non-vsmmu case has to allocate a viommu object for a set of RMI commands that don't need an Realm Descriptor. Things could be cleaner if we allow
RMI_PSMMU_ACTIVATEandRMI_PSMMU_ST_L2_CREATEto be independent on a viommu; then leaveIOMMU_VIOMMU_TYPE_ARM_SMMUV3to vsmmu-visiable case.
RMI_VSMMU_CREATE requires an RD, RD won't be available during viomm_alloc right?
-aneesh
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
In reply to Jason GunthorpeQuoted 13 lines · Jason Gunthorpe
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c int arm_vsmmu_init(struct iommufd_viommu *viommu, · line 465
Quoted 7 lines · Aneesh Kumar K.V
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0@@ -463,14 +460,13 @@ vsmmu->vmid = s2_parent->s2_cfg.vmid;if (viommu->type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ) { +if (arm_smmu_is_realm_viommu (viommu)) +return arm_realm_smmu_v3_init (viommu, user_data); +I think the realm vsmmu is going to require a different info struct than the normal psmmu case, isn't it?
Quoted 7 lines
If so it needs its own enum value.
It would be nice to see a draft patch showing how the real vsmmu works on top of the RMM spec for it. If we are using a viommu object then non-vsmmu case should be identical just with an option in the info struct to not create the vsmmu object.
Based on feedback on other emails in this thread, I have now implemented this without using a vdevice or viommu. This should make the CCA and non-CCA cases similar.
This ends up adding:
modified drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4324,6 +4324,8 @@ static const struct iommu_ops arm_smmu_ops = {
.def_domain_type = arm_smmu_def_domain_type,
.get_viommu_size = arm_smmu_get_viommu_size,
.viommu_init = arm_vsmmu_init,
+ .tsm_bind = arm_smmu_realm_tsm_bind,
+ .tsm_unbind = arm_smmu_realm_tsm_unbind,
.user_pasid_table = 1,
.owner = THIS_MODULE,
.default_domain_ops = &(const struct iommu_domain_ops) {
and
+int arm_smmu_realm_tsm_bind(struct device *dev, struct kvm *kvm) +{
+ struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+ int ret;
+
+ if (!kvm_is_realm(kvm))
+ return 0;
+
+ ret = arm_realm_smmu_get(master->smmu);
+ if (ret)
+ return ret;
+
+ ret = arm_realm_smmu_stream_get(master);
+ if (ret)
+ arm_realm_smmu_put(master->smmu);
+ return ret;
+}
+
+void arm_smmu_realm_tsm_unbind(struct device *dev, struct kvm *kvm) +{
+ struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+
+ if (!kvm_is_realm(kvm))
+ return;
+
+ arm_realm_smmu_stream_put(master);
+ arm_realm_smmu_put(master->smmu);
+}
and tsm op iotcl now becomes
iommufd_device_tsm_op_ioctl()
switch (cmd->type) {
case IOMMU_DEVICE_TSM_BIND:
if (!idev->tsm_iommu_bound && ops->tsm_bind) {
if (WARN_ON_ONCE(!ops->tsm_unbind)) {
ret = -EOPNOTSUPP;
break;
}
ret = ops->tsm_bind(idev->dev, kvm);
if (ret)
break;
idev->tsm_iommu_bound = true;
iommu_bound = true;
}
ret = tsm_bind(idev->dev, kvm, cmd->tdi_id);
if (ret && iommu_bound) {
ops->tsm_unbind(idev->dev, kvm);
idev->tsm_iommu_bound = false;
}
break;
case IOMMU_DEVICE_TSM_UNBIND:
__iommufd_device_tsm_unbind(idev);
ret = 0;
break;
default:
ret = -EINVAL;
break;
}I am yet to clean up the changes. I just wanted to share that we can possibly drop the vdevice/viommu requirement.
-aneesh
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 17 lines · Aneesh Kumar K.V
Quoted 15 lines · Jason Gunthorpe
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c int arm_vsmmu_init(struct iommufd_viommu *viommu, · line 465
Quoted 7 lines · Aneesh Kumar K.V
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c +3
-0@@ -463,14 +460,13 @@ vsmmu->vmid = s2_parent->s2_cfg.vmid;if (viommu->type ==IOMMU_VIOMMU_TYPE_ARM_SMMUV3 ) { +if (arm_smmu_is_realm_viommu (viommu)) +return arm_realm_smmu_v3_init (viommu, user_data); +I think the realm vsmmu is going to require a different info struct than the normal psmmu case, isn't it?
If so it needs its own enum value.
Quoted 8 lines
Quoted 4 lines
It would be nice to see a draft patch showing how the real vsmmu works on top of the RMM spec for it. If we are using a viommu object then non-vsmmu case should be identical just with an option in the info struct to not create the vsmmu object.
Based on feedback on other emails in this thread, I have now implemented this without using a vdevice or viommu. This should make the CCA and non-CCA cases similar.
That wasn't the feedback. The feedback was to use the viommu and not make a bunch of new stuff..
Quoted 6 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +6
-0+int arm_smmu_realm_tsm_bind (struct device *dev,struct kvm *kvm) +{ +struct arm_smmu_master *master =dev_iommu_priv_get (dev); +int ret; + +if (!kvm_is_realm (kvm))
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c void arm_smmu_setup_realm_irqs(struct arm_smmu_device *smmu) · line 271
Quoted 10 lines
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +10
-0+return 0 ; + + ret =arm_realm_smmu_get (master->smmu); +if (ret) +return ret; + + ret =arm_realm_smmu_stream_get (master); +if (ret) +arm_realm_smmu_put (master->smmu); +return ret;
It still makes no sense this doesn't do the VDEV_CREATE too.
Quoted 16 lines
iommufd_device_tsm_op_ioctl()switch (cmd->type) { case IOMMU_DEVICE_TSM_BIND: if (!idev->tsm_iommu_bound && ops->tsm_bind) { if (WARN_ON_ONCE(!ops->tsm_unbind)) { ret = -EOPNOTSUPP; break; } ret = ops->tsm_bind(idev->dev, kvm); if (ret) break; idev->tsm_iommu_bound = true; iommu_bound = true; } ret = tsm_bind(idev->dev, kvm, cmd->tdi_id);
Yuk! Now this uAPI doesn't make any sense when you have an actual viommu involved, we can't take tdi_id from userspace, it must come from the vdevice.
I don't want two confusingly different flows, this stuff is hard enough to keep straight.
Your first version was better, we just need to commit to using the viommu for everyone on every arch and drop the the tsm_bind() API and IOMMU_DEVICE_TSM_BIND interface.
The only draw back is the VMM has to manage a litte bit more.
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 23 lines · Jason Gunthorpe
Quoted 22 lines · Aneesh Kumar K.V
Quoted 19 lines · Jason Gunthorpe
Review line 465
Quoted 7 lines · Aneesh Kumar K.V
(quoted diff) +3
-0@@ -463,14 +460,13 @@ vsmmu->vmid = s2_parent->s2_cfg.vmid; if (viommu->type == IOMMU_VIOMMU_TYPE_ARM_SMMUV3) { + if (arm_smmu_is_realm_viommu(viommu)) + return arm_realm_smmu_v3_init(viommu, user_data); +I think the realm vsmmu is going to require a different info struct than the normal psmmu case, isn't it?
If so it needs its own enum value.
It would be nice to see a draft patch showing how the real vsmmu works on top of the RMM spec for it. If we are using a viommu object then non-vsmmu case should be identical just with an option in the info struct to not create the vsmmu object.
Quoted 7 lines
Quoted 3 lines
Based on feedback on other emails in this thread, I have now implemented this without using a vdevice or viommu. This should make the CCA and non-CCA cases similar.
That wasn't the feedback. The feedback was to use the viommu and not make a bunch of new stuff..
That rework was done before I saw your discussion with Nicolin.
To reiterate, for this configuration:
- The viommu will use a stage-1 bypass configuration.
- A new IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 type will create the viommu. The psmmu will be activated at this point to avoid creating psmmu objects early. We will reference-count it to ensure that the same psmmu is shared across realm guests.
- Creating a vdevice will invoke SMC_RMI_PSMMU_ST_L2_CREATE.
I am unclear about the vdev_create suggestion. Creating a vdevice requires an RD, which is created later in the flow above. How do you suggest linking vdevice_alloc to vdev_create?
From the RMM's perspective, the sequence is as follows:
viommu alloc
[ rmm ] SMC_RMI_PSMMU_ACTIVATE 2b400000 8819bb000 > RMI_INCOMPLETE 0 10008 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 2 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 1 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 1 0 [ rmm ] L1 StrTab: PA 0x881baa000 VA 0x80003c0000 size 0x2000 [ rmm ] CMDQ: PA 0x88066a000 VA 0x80003c2000 [ rmm ] EVTQ: PA 0x8815c5000 VA 0x80003c3000 [ rmm ] PSMMU 0x2b400000 activated [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0 [ rmm ] SMC_RMI_PSMMU_ST_L2_CREATE 2b400000 300 > RMI_INCOMPLETE 0 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 1 0 [ rmm ] smmu->strtab_base[12] 0x0 @0x80003c0060 [ rmm ] L1STD[12] 0x8819bb007 for SID 0x300: L2 table VA 0x80003d0000 PA 0x8819bb000 [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0
vdevice alloc
[ rmm ] SMC_RMI_PSMMU_ST_L2_CREATE 2b400000 200 > RMI_INCOMPLETE 0 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 882648098 1 > RMI_INCOMPLETE 1 0 [ rmm ] smmu->strtab_base[8] 0x0 @0x80003c0040 [ rmm ] L1STD[8] 0x882506007 for SID 0x200: L2 table VA 0x80003cc000 PA 0x882506000 [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0
RD gets allocated here
[ rmm ] SMC_RMI_REALM_CREATE 881b03000 8819a1000 > RMI_INCOMPLETE 0 24 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881605098 9 > RMI_INCOMPLETE 9 0 [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0
-aneesh
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 44 lines · Aneesh Kumar K.V
Quoted 23 lines · Jason Gunthorpe
Quoted 22 lines · Aneesh Kumar K.V
Quoted 19 lines · Jason Gunthorpe
Review line 465
Quoted 7 lines · Aneesh Kumar K.V
(quoted diff) +3
-0@@ -463,14 +460,13 @@ vsmmu->vmid = s2_parent->s2_cfg.vmid; if (viommu->type == IOMMU_VIOMMU_TYPE_ARM_SMMUV3) { + if (arm_smmu_is_realm_viommu(viommu)) + return arm_realm_smmu_v3_init(viommu, user_data); +I think the realm vsmmu is going to require a different info struct than the normal psmmu case, isn't it?
If so it needs its own enum value.
It would be nice to see a draft patch showing how the real vsmmu works on top of the RMM spec for it. If we are using a viommu object then non-vsmmu case should be identical just with an option in the info struct to not create the vsmmu object.
Quoted 7 lines
Quoted 3 lines
Based on feedback on other emails in this thread, I have now implemented this without using a vdevice or viommu. This should make the CCA and non-CCA cases similar.
That wasn't the feedback. The feedback was to use the viommu and not make a bunch of new stuff..
That rework was done before I saw your discussion with Nicolin.
To reiterate, for this configuration:
- The viommu will use a stage-1 bypass configuration.
- A newIOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3type will create the viommu. The psmmu will be activated at this point to avoid creating psmmu objects early. We will reference-count it to ensure that the same psmmu is shared across realm guests.
- Creating a vdevice will invokeSMC_RMI_PSMMU_ST_L2_CREATE.
Quoted 4 lines
I am unclear about the
vdev_createsuggestion. Creating a vdevice requires an RD, which is created later in the flow above. How do you suggest linkingvdevice_alloctovdev_create?
I was able to prototype the following flow:
- The viommu uses a stage-1 bypass configuration.
- A new IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3 type creates the viommu. The pSMMU is activated at this point to avoid creating pSMMU objects early. It is reference-counted so that the same pSMMU can be shared across realm guests.
- The realm is created during viommu allocation, ensuring that the vSMMU can be created here.
- Creating a vdevice invokes SMC_RMI_PSMMU_ST_L2_CREATE.
- This is followed by tsm_bind() if the device has an established TSM link.
static int arm_realm_smmu_v3_vdevice_init(struct iommufd_vdevice *vdev)
{
struct device *dev = iommufd_vdevice_to_device(vdev);
struct kvm *kvm = vdev->viommu->kvm_file->private_data;
struct arm_smmu_device *smmu;
struct arm_smmu_stream *stream;
struct arm_smmu_master *master;
unsigned long rmi_ret = 0;
unsigned long l2_sid;
int ret;
if (!tsm_is_configured(dev))
return 0;
master = dev_iommu_priv_get(dev);
/* FIXME which stream to pick */
/* At this moment, iommufd only supports PCI device that has one SID */
stream = &master->streams[0];
smmu = master->smmu;
l2_sid = ALIGN_DOWN(stream->id, STRTAB_NUM_L2_STES);
{
guard(mutex)(&smmu->realm.mutex);
if (!arm_realm_smmu_active(smmu))
return -EINVAL;
ret = rmi_psmmu_st_l2_create(smmu->base_phys, l2_sid,
&rmi_ret);
if (ret || rmi_ret) {
if (!ret)
return -EIO;
if (RMI_RETURN_STATUS(rmi_ret) != RMI_ERROR_PSMMU_ST ||
RMI_RETURN_INDEX(rmi_ret) != 2) {
dev_warn(dev, "failed to create realm stream mapping\n");
return -EIO;
}
/* The L2 stream table already exists. */
}
}
vdev->destroy = arm_realm_smmu_v3_vdevice_destroy;
return tsm_bind(dev, kvm, vdev->virt_id);
} - tsm_bind() calls cca_tsm_bind(), which in turn calls vdev_create().
- After boot, the guest locks the device. This generates an RHI request that reaches cca_tsm_guest_req() with RHI_DA_TDI_CONFIG_LOCKED.
- cca_tsm_guest_req() now handles TSM_REQ_SET_TDI_STATE requests for the unlocked, locked, and running states.
@@ -513,10 +514,16 @@ static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi,
if (copy_from_user((void *)&req_obj, req.user, req_len))
return -EFAULT;
- if (req_obj.tdi_state != RHI_DA_TDI_CONFIG_RUN)
+ switch (req_obj.tdi_state) {
+ case RHI_DA_TDI_CONFIG_UNLOCKED:
+ return cca_vdev_device_unlock(pdev);
+ case RHI_DA_TDI_CONFIG_LOCKED:
+ return cca_vdev_device_lock(pdev);
+ case RHI_DA_TDI_CONFIG_RUN:
+ return cca_vdev_device_start(pdev);
+ default:
return -EINVAL;
-
- return cca_vdev_device_start(pdev);
+ }
}
-aneesh
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 36 lines · Aneesh Kumar K.V
static int
arm_realm_smmu_v3_vdevice_init(struct iommufd_vdevice *vdev){ struct device *dev = iommufd_vdevice_to_device(vdev); struct kvm *kvm = vdev->viommu->kvm_file->private_data; struct arm_smmu_device *smmu; struct arm_smmu_stream *stream; struct arm_smmu_master *master; unsigned long rmi_ret = 0; unsigned long l2_sid; int ret; if (!tsm_is_configured(dev)) return 0; master = dev_iommu_priv_get(dev); /* FIXME which stream to pick */ /* At this moment, iommufd only supports PCI device that has one SID */ stream = &master->streams[0]; smmu = master->smmu; l2_sid = ALIGN_DOWN(stream->id, STRTAB_NUM_L2_STES); { guard(mutex)(&smmu->realm.mutex); if (!arm_realm_smmu_active(smmu)) return -EINVAL; ret = rmi_psmmu_st_l2_create(smmu->base_phys, l2_sid, &rmi_ret); if (ret || rmi_ret) { if (!ret) return -EIO; if (RMI_RETURN_STATUS(rmi_ret) != RMI_ERROR_PSMMU_ST || RMI_RETURN_INDEX(rmi_ret) != 2) { dev_warn(dev, "failed to create realm stream mapping\n");
Quoted 8 lines
return -EIO; } /* The L2 stream table already exists. */ } } vdev->destroy = arm_realm_smmu_v3_vdevice_destroy; return tsm_bind(dev, kvm, vdev->virt_id);
I think we should drop tsm_bind() as an abstraction. It doesn't make sense to take that round about path when we are calling RMIs directly above. It was intended to be an abstraction, but it isn't working out with this viommu based abstraction.
Quoted 8 lines
(quoted diff) +3
-1@@ -513,10 +514,16 @@ static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, if (copy_from_user((void *)&req_obj, req.user, req_len)) return -EFAULT; - if (req_obj.tdi_state != RHI_DA_TDI_CONFIG_RUN) + switch (req_obj.tdi_state) { + case RHI_DA_TDI_CONFIG_UNLOCKED: + return cca_vdev_device_unlock(pdev);
Review static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, · line 527
Quoted 10 lines
(quoted diff) +6
-2+ case RHI_DA_TDI_CONFIG_LOCKED: + return cca_vdev_device_lock(pdev); + case RHI_DA_TDI_CONFIG_RUN: + return cca_vdev_device_start(pdev); + default: return -EINVAL; - - return cca_vdev_device_start(pdev); + } }
This stuff cannot flow through sysfs. The VMM must support running in a sandbox so it cannot easially call out to sysfs while the VM is running. That makes the sandboxing more complex and ugly. The flow we have now relies on fd passing from the launcher into the sandbox to get things like vfio and iommufd into the VMM.
So these actions really should work the same way unless there is a strong reason to do otherwise.
Given these are all acting on bound devices, and those can only be created by iommufd, it makes more sense to feed the operations through iommufd into the viommu and vdevice ops. AMD wanted to create such general command ops anyhow for their viommu emulation (non cc).
And.. then you don't need struct pci_tdi. The vdevice is effectively the tdi and the existing locking scheme in iommufd for vdevice takes care of everything the tsm code was trying to do, except in a way that applies to every viommu out there.. This actually makes a lot of sense because the tdi is not really separable from vfio. You cannot have a tdi without a kvm and you cannot link a pci dev to a kvm without vfio.
Finally, there is really nothing about the viommu_ops that has much to do with smmuv3. It would be fairly straightforward for the tsm_ops to be able to create the viommu and provide the viommu_ops. We can get there based on the IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3.
This then would open up a much nicer split where arm-cca-guest.ko can provide a realm smmuv3, and inside those viommu_ops are all the realm & tdi related ops, psmmu, vsmmu, vdevice, "guest req".
The arm-cca-guest can just make a simple function call to SMMUv3 to get the phys and interrupts. Somehow I think Will would like this better than adding to SMMUv3.
Now that the viommu stuff is more developed on the iommufd end, and the RMM spec is more complete with vsmmu, I think this arrangement becomes visible.
What do you think?
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 43 lines · Jason Gunthorpe
Quoted 42 lines · Aneesh Kumar K.V
static int
arm_realm_smmu_v3_vdevice_init(struct iommufd_vdevice *vdev){ struct device *dev = iommufd_vdevice_to_device(vdev); struct kvm *kvm = vdev->viommu->kvm_file->private_data; struct arm_smmu_device *smmu; struct arm_smmu_stream *stream; struct arm_smmu_master *master; unsigned long rmi_ret = 0; unsigned long l2_sid; int ret; if (!tsm_is_configured(dev)) return 0; master = dev_iommu_priv_get(dev); /* FIXME which stream to pick */ /* At this moment, iommufd only supports PCI device that has one SID */ stream = &master->streams[0]; smmu = master->smmu; l2_sid = ALIGN_DOWN(stream->id, STRTAB_NUM_L2_STES); { guard(mutex)(&smmu->realm.mutex); if (!arm_realm_smmu_active(smmu)) return -EINVAL; ret = rmi_psmmu_st_l2_create(smmu->base_phys, l2_sid, &rmi_ret); if (ret || rmi_ret) { if (!ret) return -EIO; if (RMI_RETURN_STATUS(rmi_ret) != RMI_ERROR_PSMMU_ST || RMI_RETURN_INDEX(rmi_ret) != 2) { dev_warn(dev, "failed to create realm stream mapping\n"); return -EIO; } /* The L2 stream table already exists. */ } }
Quoted 8 lines
Quoted 2 lines
vdev->destroy = arm_realm_smmu_v3_vdevice_destroy; return tsm_bind(dev, kvm, vdev->virt_id);I think we should drop
tsm_bind()as an abstraction. It doesn't make sense to take that round about path when we are calling RMIs directly above. It was intended to be an abstraction, but it isn't working out with this viommu based abstraction.
I was considering using the viommu only for explicit pSMMU/vSMMU setup, SID/STE management, and realm stream-table creation. I expected other operations, such as vdevice creation and lock/run state transitions, to be driven by IOMMUFD ioctls and dispatched to the TSM backend through abstractions such as tsm_bind() and tsm_guest_req(). This results in the following split:
- Arm SMMU: pSMMU/vSMMU setup, SID/STE management, and Realm stream-table creation.
- PCI TSM: device association, bind lifetime, DSM lookup, and TDI state.
- arm-cca-host: PDEV/VDEV operations, TDISP transitions, reports, measurements, and IDE interaction.
- IOMMUFD: route userspace requests using the vdevice ID.
Quoted 17 lines
Quoted 17 lines
(quoted diff) +8
-3@@ -513,10 +514,16 @@ static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, if (copy_from_user((void *)&req_obj, req.user, req_len)) return -EFAULT; - if (req_obj.tdi_state != RHI_DA_TDI_CONFIG_RUN) + switch (req_obj.tdi_state) { + case RHI_DA_TDI_CONFIG_UNLOCKED: + return cca_vdev_device_unlock(pdev); + case RHI_DA_TDI_CONFIG_LOCKED: + return cca_vdev_device_lock(pdev); + case RHI_DA_TDI_CONFIG_RUN: + return cca_vdev_device_start(pdev); + default: return -EINVAL; - - return cca_vdev_device_start(pdev);
Quoted 9 lines
Review static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, · line 527
Quoted 2 lines
(quoted diff) +1
-0+ } }This stuff cannot flow through sysfs. The VMM must support running in a sandbox so it cannot easially call out to sysfs while the VM is running. That makes the sandboxing more complex and ugly. The flow we have now relies on fd passing from the launcher into the sandbox to get things like vfio and iommufd into the VMM.
This does not go through sysfs. It uses the following IOMMUFD ioctl:
IOCTL_OP(IOMMU_VDEVICE_TSM_REQ, iommufd_vdevice_tsm_req_ioctl,
struct iommu_vdevice_tsm_req, tsm_code),
I need to spend more time considering your suggestion to handle guest requests through viommu_ops rather than as TSM backend operations. The split described below seemed more natural to me.
- Arm SMMU: pSMMU/vSMMU setup, SID/STE management, and Realm stream-table creation.
- PCI TSM: device association, bind lifetime, DSM lookup, and TDI state.
- arm-cca-host: PDEV/VDEV operations, TDISP transitions, reports, measurements, and IDE interaction.
- IOMMUFD: route userspace requests using the vdevice ID.
It is not yet clear to me whether operations such as MMIO validation (TSM_REQ_VALIDATE_MMIO), setting the TDI lock/unlock/run state (TSM_REQ_SET_TDI_STATE), querying TDISP object details (TSM_REQ_OBJECT_INFO), and reading or regenerating TDISP objects (TSM_REQ_READ_OBJECT and TSM_REQ_REGEN_OBJECT) belong in viommu_ops.
Meanwhile, I will clean up my changes and post them as a patch series so that we can review them more closely?
Quoted 29 lines
So these actions really should work the same way unless there is a strong reason to do otherwise.
Given these are all acting on bound devices, and those can only be created by iommufd, it makes more sense to feed the operations through iommufd into the viommu and vdevice ops. AMD wanted to create such general command ops anyhow for their viommu emulation (non cc).
And.. then you don't need struct
pci_tdi. The vdevice is effectively the tdi and the existing locking scheme in iommufd for vdevice takes care of everything the tsm code was trying to do, except in a way that applies to every viommu out there.. This actually makes a lot of sense because the tdi is not really separable from vfio. You cannot have a tdi without a kvm and you cannot link a pci dev to a kvm without vfio.Finally, there is really nothing about the
viommu_opsthat has much to do with smmuv3. It would be fairly straightforward for thetsm_opsto be able to create the viommu and provide theviommu_ops. We can get there based on theIOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3.This then would open up a much nicer split where arm-cca-guest.ko can provide a realm smmuv3, and inside those
viommu_opsare all the realm & tdi related ops, psmmu, vsmmu, vdevice, "guest req".The arm-cca-guest can just make a simple function call to SMMUv3 to get the phys and interrupts. Somehow I think Will would like this better than adding to SMMUv3.
Quoted 7 lines
Now that the viommu stuff is more developed on the iommufd end, and the RMM spec is more complete with vsmmu, I think this arrangement becomes visible.
What do you think?
Jason
-aneesh
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 16 lines · Aneesh Kumar K.V
Quoted 8 lines
Quoted 2 lines
vdev->destroy = arm_realm_smmu_v3_vdevice_destroy; return tsm_bind(dev, kvm, vdev->virt_id);I think we should drop
tsm_bind()as an abstraction. It doesn't make sense to take that round about path when we are calling RMIs directly above. It was intended to be an abstraction, but it isn't working out with this viommu based abstraction.I was considering using the viommu only for explicit pSMMU/vSMMU setup, SID/STE management, and realm stream-table creation. I expected other operations, such as vdevice creation and lock/run state transitions, to be driven by IOMMUFD ioctls and dispatched to the TSM backend through abstractions such as
tsm_bind()andtsm_guest_req(). This results in the following split:
Quoted 6 lines
- Arm SMMU: pSMMU/vSMMU setup, SID/STE management, and Realm stream-table creation.
- PCI TSM: device association, bind lifetime, DSM lookup, and TDI state.
- arm-cca-host: PDEV/VDEV operations, TDISP transitions, reports, measurements, and IDE interaction.
- IOMMUFD: route userspace requests using the vdevice ID.
I don't really like it, I think the viommu code should handle the VDEV and VSMU, TSM should handle SPDM.
"TDI state" is the existance of a iommufd vdevice, it doesn't make sense to have a seperate "TDI state" concept and a parallel set of APIs out side the iommufd object model that concretely defines the lifecylce of the VDEV.
Is there a reason to have this split aside from it matches the tsm prototypes that were sketched?
Quoted 26 lines
Quoted 16 lines
Quoted 16 lines
(quoted diff) +8
-3@@ -513,10 +514,16 @@ static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, if (copy_from_user((void *)&req_obj, req.user, req_len)) return -EFAULT; - if (req_obj.tdi_state != RHI_DA_TDI_CONFIG_RUN) + switch (req_obj.tdi_state) { + case RHI_DA_TDI_CONFIG_UNLOCKED: + return cca_vdev_device_unlock(pdev); + case RHI_DA_TDI_CONFIG_LOCKED: + return cca_vdev_device_lock(pdev); + case RHI_DA_TDI_CONFIG_RUN: + return cca_vdev_device_start(pdev); + default: return -EINVAL; - - return cca_vdev_device_start(pdev);Quoted 9 lines
Review static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, · line 527
Quoted 2 lines
(quoted diff) +1
-0+ } }This stuff cannot flow through sysfs. The VMM must support running in a sandbox so it cannot easially call out to sysfs while the VM is running. That makes the sandboxing more complex and ugly. The flow we have now relies on fd passing from the launcher into the sandbox to get things like vfio and iommufd into the VMM.
Quoted 4 lines
This does not go through sysfs. It uses the following IOMMUFD ioctl:
IOCTL_OP(IOMMU_VDEVICE_TSM_REQ,
iommufd_vdevice_tsm_req_ioctl,
structiommu_vdevice_tsm_req,tsm_code),
I see, I saw this when I was grepping:
static ssize_t tsm_request_store(struct device *dev,
struct device_attribute *attr, const char *__buf, size_t count)
Which the name and sysfs parts confused me, it looked like core code. Turns out it is the sample driver.
Quoted 11 lines
I need to spend more time considering your suggestion to handle guest requests through
viommu_opsrather than as TSM backend operations. The split described below seemed more natural to me.- Arm SMMU: pSMMU/vSMMU setup, SID/STE management, and Realm stream-table creation.
- PCI TSM: device association, bind lifetime, DSM lookup, and TDI state.
- arm-cca-host: PDEV/VDEV operations, TDISP transitions, reports, measurements, and IDE interaction.
- IOMMUFD: route userspace requests using the vdevice ID.
Quoted 5 lines
It is not yet clear to me whether operations such as MMIO validation (
TSM_REQ_VALIDATE_MMIO), setting the TDI lock/unlock/run state (TSM_REQ_SET_TDI_STATE), querying TDISP object details (TSM_REQ_OBJECT_INFO), and reading or regenerating TDISP objects (TSM_REQ_READ_OBJECTandTSM_REQ_REGEN_OBJECT) belong inviommu_ops.
They way I'm looking at it is the "TDI" is the RMM's VDEV.
The RMM VDEV has to be created from an iommufd vdevice and be 1:1 with that. Thus the iommufd vdevice is the TDI.
Therefore, the struct cca_host_tdi should be the driver specific struct of a struct iommufd_vdevice.
So if you want to get the information in the cca_host_tdi you have to come in through the viommu ops with a vdevice object in hand.
This seems like a much cleaner logical seperation than trying to maintain a cca_host_tdi external to the iommufd vdevice object that actually directly controls its lifecycle.
So if you did this then the cca_tsm_guest_req would flow through some generic viommu op similar to what AMD proposed:
struct iommu_viommu_op {
__u32 size;
__u32 vdevice_id;
__u32 viommu_type; // enum iommu_viommu_type
__u32 operation; // unique enum per type
__u32 req_len;
__u32 resp_len;
__aligned_u64 req_uptr;
__aligned_u64 resp_uptr;
};enum {
IOMMUFD_VIOMMU_OP_CCA_OBJECT_SIZE
IOMMUFD_VIOMMU_OP_CCA_OBJECT_READ
IOMMUFD_VIOMMU_OP_CCA_UPDATE_INTERFACE_REPORT
IOMMUFD_VIOMMU_OP_CCA_UPDATE_MEASUREMENTS
IOMMUFD_VIOMMU_OP_CCA_VDEV_MAP
IOMMUFD_VIOMMU_OP_CCA_SET_TDI_STATE
And none of the TDI information leaks out side the iommufd world.
The iommufd side change to introduce CCA support would then only be adding the IOCTL for iommu_viommu_op and some fiddling with how the viommu is created.
Then everyone can use the same infrastructure for their related problems.
Quoted 2 lines
Meanwhile, I will clean up my changes and post them as a patch series so that we can review them more closely?
Well, OK, but I'm am still very interested in focusing on the viommu. I cc'd you on another thread so you can see the other topics I'm looking at here that all come down to very similar patterns.
I think the TDI related tsm ops were developed well before iommufd was completed and you have raised a good point now to re-evaluate if the we even need them since we now understand that the iommufd vdevice is in fact the concrete TDI object in the uAPI.
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 141 lines · Jason Gunthorpe
Quoted 16 lines · Aneesh Kumar K.V
Quoted 8 lines
Quoted 2 lines
vdev->destroy = arm_realm_smmu_v3_vdevice_destroy; return tsm_bind(dev, kvm, vdev->virt_id);I think we should drop
tsm_bind()as an abstraction. It doesn't make sense to take that round about path when we are calling RMIs directly above. It was intended to be an abstraction, but it isn't working out with this viommu based abstraction.I was considering using the viommu only for explicit pSMMU/vSMMU setup, SID/STE management, and realm stream-table creation. I expected other operations, such as vdevice creation and lock/run state transitions, to be driven by IOMMUFD ioctls and dispatched to the TSM backend through abstractions such as
tsm_bind()andtsm_guest_req(). This results in the following split:Quoted 6 lines
- Arm SMMU: pSMMU/vSMMU setup, SID/STE management, and Realm stream-table creation.
- PCI TSM: device association, bind lifetime, DSM lookup, and TDI state.
- arm-cca-host: PDEV/VDEV operations, TDISP transitions, reports, measurements, and IDE interaction.
- IOMMUFD: route userspace requests using the vdevice ID.I don't really like it, I think the viommu code should handle the VDEV and VSMU, TSM should handle SPDM.
"TDI state" is the existance of a iommufd vdevice, it doesn't make sense to have a seperate "TDI state" concept and a parallel set of APIs out side the iommufd object model that concretely defines the lifecylce of the VDEV.
Is there a reason to have this split aside from it matches the tsm prototypes that were sketched?
Quoted 26 lines
Quoted 16 lines
Quoted 16 lines
(quoted diff) +8
-3@@ -513,10 +514,16 @@ static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, if (copy_from_user((void *)&req_obj, req.user, req_len)) return -EFAULT; - if (req_obj.tdi_state != RHI_DA_TDI_CONFIG_RUN) + switch (req_obj.tdi_state) { + case RHI_DA_TDI_CONFIG_UNLOCKED: + return cca_vdev_device_unlock(pdev); + case RHI_DA_TDI_CONFIG_LOCKED: + return cca_vdev_device_lock(pdev); + case RHI_DA_TDI_CONFIG_RUN: + return cca_vdev_device_start(pdev); + default: return -EINVAL; - - return cca_vdev_device_start(pdev);Quoted 9 lines
Review static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, · line 527
Quoted 2 lines
(quoted diff) +1
-0+ } }This stuff cannot flow through sysfs. The VMM must support running in a sandbox so it cannot easially call out to sysfs while the VM is running. That makes the sandboxing more complex and ugly. The flow we have now relies on fd passing from the launcher into the sandbox to get things like vfio and iommufd into the VMM.
Quoted 4 lines
This does not go through sysfs. It uses the following IOMMUFD ioctl:
IOCTL_OP(IOMMU_VDEVICE_TSM_REQ,
iommufd_vdevice_tsm_req_ioctl,
structiommu_vdevice_tsm_req,tsm_code),I see, I saw this when I was grepping:
static
ssize_ttsm_request_store(struct device *dev,
structdevice_attribute*attr, const char*__buf,size_tcount)Which the name and sysfs parts confused me, it looked like core code. Turns out it is the sample driver.
Quoted 11 lines
I need to spend more time considering your suggestion to handle guest requests through
viommu_opsrather than as TSM backend operations. The split described below seemed more natural to me.- Arm SMMU: pSMMU/vSMMU setup, SID/STE management, and Realm stream-table creation.
- PCI TSM: device association, bind lifetime, DSM lookup, and TDI state.
- arm-cca-host: PDEV/VDEV operations, TDISP transitions, reports, measurements, and IDE interaction.
- IOMMUFD: route userspace requests using the vdevice ID.Quoted 5 lines
It is not yet clear to me whether operations such as MMIO validation (
TSM_REQ_VALIDATE_MMIO), setting the TDI lock/unlock/run state (TSM_REQ_SET_TDI_STATE), querying TDISP object details (TSM_REQ_OBJECT_INFO), and reading or regenerating TDISP objects (TSM_REQ_READ_OBJECTandTSM_REQ_REGEN_OBJECT) belong inviommu_ops.They way I'm looking at it is the "TDI" is the RMM's VDEV.
The RMM VDEV has to be created from an iommufd vdevice and be 1:1 with that. Thus the iommufd vdevice is the TDI.
Therefore, the struct
cca_host_tdishould be the driver specific struct of a structiommufd_vdevice.So if you want to get the information in the
cca_host_tdiyou have to come in through the viommu ops with a vdevice object in hand.This seems like a much cleaner logical seperation than trying to maintain a
cca_host_tdiexternal to the iommufd vdevice object that actually directly controls its lifecycle.So if you did this then the
cca_tsm_guest_reqwould flow through some generic viommu op similar to what AMD proposed:struct iommu_viommu_op { __u32 size; __u32 vdevice_id; __u32 viommu_type; // enum iommu_viommu_type __u32 operation; // unique enum per type __u32 req_len; __u32 resp_len; __aligned_u64 req_uptr; __aligned_u64 resp_uptr; };enum {
IOMMUFD_VIOMMU_OP_CCA_OBJECT_SIZE
IOMMUFD_VIOMMU_OP_CCA_OBJECT_READ
IOMMUFD_VIOMMU_OP_CCA_UPDATE_INTERFACE_REPORT
IOMMUFD_VIOMMU_OP_CCA_UPDATE_MEASUREMENTS
IOMMUFD_VIOMMU_OP_CCA_VDEV_MAP
IOMMUFD_VIOMMU_OP_CCA_SET_TDI_STATEAnd none of the TDI information leaks out side the iommufd world.
The iommufd side change to introduce CCA support would then only be adding the IOCTL for
iommu_viommu_opand some fiddling with how the viommu is created.Then everyone can use the same infrastructure for their related problems.
Quoted 2 lines
Meanwhile, I will clean up my changes and post them as a patch series so that we can review them more closely?
Quoted 9 lines
Well, OK, but I'm am still very interested in focusing on the viommu. I cc'd you on another thread so you can see the other topics I'm looking at here that all come down to very similar patterns.
I think the TDI related tsm ops were developed well before iommufd was completed and you have raised a good point now to re-evaluate if the we even need them since we now understand that the iommufd vdevice is in fact the concrete TDI object in the uAPI.
I looked into this, and it becomes fairly complicated. We can move all vdev/TDI-related code to arm-smmu-realm-v3.c, but that would result in:
1. Adding more CCA-specific code to the SMMU driver.
2. arm-cca-host continuing to own the TSM link setup (IDE).
3. Adding callbacks from the device communication helpers back into arm-cca-host, since device communication still goes through DOE.
4. Moving the device communication helpers to firmware/arm-rmm and adding something like:
static const struct arm_rmm_pdev_comm_ops cca_dev_comm_ops = {
.send = cca_dev_comm_send,
.get_cache = cca_dev_comm_get_cache, .refresh_stream_keys = cca_dev_comm_refresh_stream_keys,
};
The locking also becomes more complex. Unlocking a vdev can trigger a stream key refresh, which is owned by arm-cca-host. Currently, the locking is simpler, using pci_tsm_rwsem and pci_tsm_pf0::lock. With the SMMU driver owning the vdev/TDI, we would have:
- pci_tsm_rwsem protecting the lifetime and registration state of pdev->tsm.
- pci_tsm::tdi_lock protecting the function's pci_tdi pointer.
- pci_tsm_pf0::lock protecting DSM-wide connect and disconnect operations, including probing and removing functions managed by that DSM.
- The lock associated with arm_rmm_pdev_comm protecting the shared PDEV communication buffers and cache state used for ARM RMM communication.
I have a working prototype, but it requires quite a bit of cleanup and rebasing before it can be posted as a clean patch series. Let me know if you still want to proceed with this approach.
In summary, this requires three subsystems (arm-smmu-realm-v3, arm-cca-host, and firmware/arm_rmm) to interact closely, with clearly defined locking rules. Previously, all of this was contained within arm-cca-host.
-aneesh
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 2 lines · Aneesh Kumar K.V
I looked into this, and it becomes fairly complicated. We can move all vdev/TDI-related code to
arm-smmu-realm-v3.c, but that would result in:
I was going for the opposite, you'd move everything out of arm-smmu-v3 and into the arm-cca-host and obtain the viommu through tsm_ops not through iommu_ops.
I guess I pointed to that in another email.
The only thing arm-smmu-v3 should provide is a simple function to give the pdev phys and irq parameters. arm-cca-host calls that when it creates an viommu object.
Quoted 6 lines
1. Adding more CCA-specific code to the SMMU driver.
2. arm-cca-host continuing to own the TSM link setup (IDE).
3. Adding callbacks from the device communication helpers back into arm-cca-host, since device communication still goes through DOE.
4. Moving the device communication helpers tofirmware/arm-rmmand adding something like:
With the above change you don't need to do any of this.
Quoted 4 lines
The locking also becomes more complex. Unlocking a vdev can trigger a stream key refresh, which is owned by arm-cca-host. Currently, the locking is simpler, using
pci_tsm_rwsemandpci_tsm_pf0::lock. With the SMMU driver owning the vdev/TDI, we would have:
You can't really avoid something, the vdev *IS* the TDI and the ops to effect it come in through the iommufd path. The ideal version is the tdi is never used outside the iommufd path so you don't need to mesh the locking quite as carefully.
Quoted 3 lines
-
pci_tsm_rwsemprotecting the lifetime and registration state ofpdev->tsm.
-pci_tsm::tdi_lockprotecting the function'spci_tdipointer.
Like here, why is there a pci_tdi linked to pci_tsm? Anything coming in outside the iommufd locking is very suspect.
And the iommufd locking should spill over to the TSM, you should not be able to remove a tsm while a viommu object exists.
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 9 lines · Jason Gunthorpe
Quoted 2 lines · Aneesh Kumar K.V
I looked into this, and it becomes fairly complicated. We can move all vdev/TDI-related code to
arm-smmu-realm-v3.c, but that would result in:I was going for the opposite, you'd move everything out of arm-smmu-v3 and into the arm-cca-host and obtain the viommu through
tsm_opsnot throughiommu_ops.
Quoted 6 lines
I guess I pointed to that in another email.
The only thing arm-smmu-v3 should provide is a simple function to give the pdev phys and irq parameters. arm-cca-host calls that when it creates an viommu object.
So ended up with
static const struct tsm_viommu_ops cca_tsm_viommu_ops = {
.owner = THIS_MODULE,
.type = IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3, .get_size = cca_viommu_get_size,
.init = cca_viommu_init,
};
struct cca_viommu {
struct cca_psmmu *psmmu;
struct iommu_viommu_provider *iommu_provider;
const struct iommufd_viommu_ops *iommu_ops; // backing SMMU ops
};// backing ops are mostly used for
static struct iommu_domain * cca_viommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
const struct iommu_user_data *user_data)
{
struct cca_viommu *cca = viommu->provider_data;
return cca->iommu_ops->alloc_domain_nested(viommu, flags, user_data);
}static int cca_viommu_cache_invalidate(struct iommufd_viommu *viommu,
struct iommu_user_data_array *array)
{
struct cca_viommu *cca = viommu->provider_data;
return cca->iommu_ops->cache_invalidate(viommu, array);
}struct cca_vdevice {
struct iommufd_vdevice core;
struct pci_tsm_context *tsm_context;
struct cca_host_tdi host_tdi;
u32 l2_sid;
};static const struct iommufd_viommu_ops cca_viommu_ops = {
.destroy = cca_viommu_destroy,
.alloc_domain_nested = cca_viommu_alloc_domain_nested, .cache_invalidate = cca_viommu_cache_invalidate, .vdevice_size = VDEVICE_STRUCT_SIZE(struct cca_vdevice, core), .vdevice_init = cca_vdevice_init,
.vdevice_tsm_req = cca_vdevice_tsm_req,
};
and on iommu side
struct iommu_viommu_provider {
size_t size;
int (*init)(struct iommufd_viommu *viommu, struct device *dev,
enum iommu_viommu_type type,
struct iommu_domain *parent_domain,
const struct iommu_user_data *user_data);
int (*get_params)(struct iommu_viommu_provider *provider,
struct device *dev, enum iommu_viommu_type type,
void *params, size_t params_size);
void (*release)(struct iommu_viommu_provider *provider);
void *data;
};The TSM disconnect path will now fail while any vdevice is alive or active. Destroying a vdevice will unlock and destroy the VDEV. I think we can also unmap its MMIO mappings at that point, provided we track the mapping requests in a list alongside the vdevice details.
All CCA operations will use pci_tsm_pf0::lock, though I think the locking can be made more fine-grained.
I will send a cleaned-up series so that we can review the code changes.
-aneesh
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 19 lines · Aneesh Kumar K.V
Quoted 9 lines · Jason Gunthorpe
Quoted 2 lines · Aneesh Kumar K.V
I looked into this, and it becomes fairly complicated. We can move all vdev/TDI-related code to
arm-smmu-realm-v3.c, but that would result in:I was going for the opposite, you'd move everything out of arm-smmu-v3 and into the arm-cca-host and obtain the viommu through
tsm_opsnot throughiommu_ops.Quoted 6 lines
I guess I pointed to that in another email.
The only thing arm-smmu-v3 should provide is a simple function to give the pdev phys and irq parameters. arm-cca-host calls that when it creates an viommu object.
Quoted 8 lines
So ended up with
static const struct
tsm_viommu_opscca_tsm_viommu_ops= {
.owner =THIS_MODULE,
.type =IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3, .get_size =cca_viommu_get_size,
.init =cca_viommu_init,
};
OK, may also be fine in the main tsm ops?
Quoted 4 lines
struct cca_viommu {
struct cca_psmmu *psmmu;
struct iommu_viommu_provider *iommu_provider;
const struct iommufd_viommu_ops *iommu_ops; // backing SMMU ops??
The viommu created for a RMM owned vSMMU should have no connection to the normal SMMU driver? It just needs the psmmu information.
We need to adjust iommufd side to know that this object cannot accept an iommu_domain, only a kvm fd. I don't want to pass in a fake iommu_domain that has nothing to do with how RMM will operate things.
Quoted 9 lines
static struct
iommu_domain* cca_viommu_alloc_domain_nested(structiommufd_viommu*viommu, u32 flags,
const structiommu_user_data*user_data){ struct cca_viommu *cca = viommu->provider_data; return cca->iommu_ops->alloc_domain_nested(viommu, flags, user_data); }
Quoted 7 lines
static int cca_viommu_cache_invalidate(struct
iommufd_viommu*viommu,
structiommu_user_data_array*array){ struct cca_viommu *cca = viommu->provider_data; return cca->iommu_ops->cache_invalidate(viommu, array); }
These ops should fail (just be NULL) not reflect to a psmmu.
Quoted 4 lines
struct cca_vdevice {
struct iommufd_vdevice core;
struct pci_tsm_context *tsm_context;
struct cca_host_tdi host_tdi;Is the extra tdi struct still needed? Isn't cca_vdevice the tdi struct?
Quoted 15 lines
u32 l2_sid; };static const struct
iommufd_viommu_opscca_viommu_ops= {
.destroy =cca_viommu_destroy,
.alloc_domain_nested =cca_viommu_alloc_domain_nested, .cache_invalidate =cca_viommu_cache_invalidate, .vdevice_size =VDEVICE_STRUCT_SIZE(struct cca_vdevice, core), .vdevice_init =cca_vdevice_init,
.vdevice_tsm_req =cca_vdevice_tsm_req,
};and on iommu side
Quoted 12 lines
struct iommu_viommu_provider {
size_t size;
int (*init)(struct iommufd_viommu *viommu, struct device *dev,
enum iommu_viommu_type type,
struct iommu_domain *parent_domain,
const struct iommu_user_data *user_data);
int (*get_params)(struct iommu_viommu_provider *provider,
struct device *dev, enum iommu_viommu_type type,
void *params, size_t params_size);
void (*release)(struct iommu_viommu_provider *provider);
void *data;
};Not sure what this is?
Quoted 2 lines
The TSM disconnect path will now fail while any vdevice is alive or active.
Yes, that's makes sense.
Quoted 1 line
Destroying a vdevice will unlock and destroy the VDEV.
Yes
Quoted 3 lines
I think we can also unmap its MMIO mappings at that point, provided we track the mapping requests in a list alongside the vdevice details.
The mmio is owned by vfio, there should be a handshake in VFIO to remove mmio when it becomes private, otherwise I don't think we need to do anything more?
Quoted 2 lines
All CCA operations will use
pci_tsm_pf0::lock, though I think the locking can be made more fine-grained.
Sure
Quoted 1 line
I will send a cleaned-up series so that we can review the code changes.
Does it seems reasonable to you? Was there any oddness with modeling the vdev/bind through the viommu?
Anyhow I'll look more closely when you are ready. Thanks
Jason
Tian, Kevin
maintainerRE: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 4 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, September 9, 2026 8:46 PMOn Wed, Sep 09, 2026 at 03:39:31PM +0530, Aneesh Kumar K.V wrote:
[...]
Quoted 9 lines
Quoted 2 lines
The TSM disconnect path will now fail while any vdevice is alive or active.
Yes, that's makes sense.
Quoted 1 line
Destroying a vdevice will unlock and destroy the VDEV.
Yes
Quoted 7 lines
Quoted 3 lines
I think we can also unmap its MMIO mappings at that point, provided we track the mapping requests in a list alongside the vdevice details.
The mmio is owned by vfio, there should be a handshake in VFIO to remove mmio when it becomes private, otherwise I don't think we need to do anything more?
for TDX a callback in VFIO is invoked to revoke the dmabuf.
btw I didn't see any dmabuf related in this series (even in a hackish way as Yilun sent out last year). Is it not required by CCA or just skipped now waiting for the framework to be settled?
Quoted 11 lines
Quoted 3 lines
All CCA operations will use
pci_tsm_pf0::lock, though I think the locking can be made more fine-grained.Sure
Quoted 1 line
I will send a cleaned-up series so that we can review the code changes.
Does it seems reasonable to you? Was there any oddness with modeling the vdev/bind through the viommu?
Try to catch up the implied changes to other arch's...
So viommu will become the abstraction point for tsm operations and directly talks to the tsm driver instead of going through the merged tsm_ops (bind/unbind/guest_req).
currently what tsm_ops provides additionally is more about synchronization with connect/disconnect, otherwise just calls into underlying tsm driver. As long as viommu creation holds a reference to tsm then disconnection is blocked then it's safe.
Is that the rationale behind?
and IOMMU_VDEVICE_TSM_BIND will be removed. Seems originally this series does SMC_RMI_VDEV_CREATE and SMC_RMI_VDEV_LOCK both in tsm bind op. Then the proposal is moving them all to vdevice creation time so no separate bind step is required.
Does it mean that ARM CCA is essentially an early-bind model i.e. the TDI starts in locked state from guest p.o.v.?
but https://lore.kernel.org/all/[email protected]/ seems to indicate that guest_req() still handles the bind request from the guest:
"
- cca_tsm_guest_req() now handles TSM_REQ_SET_TDI_STATE requests for the unlocked, locked, and running states.
"
a bit confusing, but maybe due to stale info cited from different timing...
for TDX we're currently pursuing a late-bind model (i.e. TDI starts in shared state in guest), so a separate bind interface is still necessary. We could look at whether it should be an explicit @bind viommu op or carried by @guest_req (say, if most preparation works can be moved to vdevice creation).
any other suggested changes to think about?
btw per past discussions VFIO should block some operations (reset, etc.) while a TDI is locked. Do we expect a callback into VFIO to notify the locked state, or require VFIO's own interface to place a cdev into a special state which prevents sensitive operations even before binding it to iommufd (and allow creating TDI vdevice only on such idevice)?
Thanks
Kevin
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 9 lines · Kevin
Quoted 3 lines
The mmio is owned by vfio, there should be a handshake in VFIO to remove mmio when it becomes private, otherwise I don't think we need to do anything more?
for TDX a callback in VFIO is invoked to revoke the dmabuf.
btw I didn't see any dmabuf related in this series (even in a hackish way as Yilun sent out last year). Is it not required by CCA or just skipped now waiting for the framework to be settled?
I think just one step at a time :\ I think CCA needs it as well, you also cannot safely leave private MMIO floating around the host userspace on CCA.
Quoted 3 lines
So viommu will become the abstraction point for tsm operations and directly talks to the tsm driver instead of going through the merged
tsm_ops(bind/unbind/guest_req).
More precisely for what was being called the TDI - ie it is the abstraction point for the host side of a guest virtual PCI device.
iommufd vdevice already represents this, so we use it again.
Quoted 4 lines
currently what
tsm_opsprovides additionally is more about synchronization with connect/disconnect, otherwise just calls into underlying tsm driver. As long as viommu creation holds a reference to tsm then disconnection is blocked then it's safe.
Yes, this already has to be true or our lifecylce model is nonsense. Once the iommufd creates the vdevice the guest is running and we cannot disconnect it without unplugging it from the guest. Thus the locking can rely on that. Within an iommufd ioctl context the vdev and underlying connection must be stable.
Quoted 1 line
and
IOMMU_VDEVICE_TSM_BINDwill be removed.
Replaced, the same logical operations should flow through the viommu command ioctl
Quoted 4 lines
Seems originally this series
doesSMC_RMI_VDEV_CREATEandSMC_RMI_VDEV_LOCKboth in tsm bind op. Then the proposal is moving them all to vdevice creation time so no separate bind step is required.
Hmm, lock still should be guest visible on CCA, and the device has to start up in the guest as TDISP unlocked. I'm not 100% on the RMI side of the flow, but this does not look right.
VDEV create should be done before the realm is started. We need this setup right because Linux VM is going to validate the vdev during boot if it is affiliated to a vSMMU. lock should be done only when requested by the guest. The guest must start with a normal unlocked T=0 PCI device.
Quoted 2 lines
Does it mean that ARM CCA is essentially an early-bind model i.e. the TDI starts in locked state from guest p.o.v.?
No
Quoted 7 lines
but https://lore.kernel.org/all/[email protected]/ seems to indicate that
guest_req()still handles the bind request from the guest:"
-cca_tsm_guest_req()now handlesTSM_REQ_SET_TDI_STATErequests for the unlocked, locked, and running states.
"
Right the guest side request to lock should come that way.
Quoted 7 lines
a bit confusing, but maybe due to stale info cited from different timing...
for TDX we're currently pursuing a late-bind model (i.e. TDI starts in shared state in guest), so a separate bind interface is still necessary. We could look at whether it should be an explicit @bind viommu op or carried by @guest_req (say, if most preparation works can be moved to vdevice creation).
It should go over the viommu command ioctl. It looked like there was alway some iommu specific format to the command in the tsm version of this, so that is the appropriate way.
Quoted 5 lines
btw per past discussions VFIO should block some operations (reset, etc.) while a TDI is locked. Do we expect a callback into VFIO to notify the locked state, or require VFIO's own interface to place a cdev into a special state which prevents sensitive operations even before binding it to iommufd (and allow creating TDI vdevice only on such idevice)?
At a minimum I think we have to synchronize with vfio, somehow, that when the device enforces its private MMIO so it can unmap it. Thay may be an argument we need a few standard viommu ops so the core code can capture lock/unlocks and do this prep work. Or maybe a special cdev state is simpler.
This should be figured out before any uapi is settled.
I don't know about reset, that sounds like something the pci core should deal with?
Jason
Tian, Kevin
maintainerRE: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 10 lines
From: Jason Gunthorpe <[email protected]>
Sent: Thursday, September 10, 2026 8:47 PMQuoted 6 lines · Kevin
Quoted 3 lines
The mmio is owned by vfio, there should be a handshake in VFIO to remove mmio when it becomes private, otherwise I don't think we need to do anything more?
for TDX a callback in VFIO is invoked to revoke the dmabuf.
Quoted 7 lines
Quoted 3 lines
btw I didn't see any dmabuf related in this series (even in a hackish way as Yilun sent out last year). Is it not required by CCA or just skipped now waiting for the framework to be settled?
I think just one step at a time :\ I think CCA needs it as well, you also cannot safely leave private MMIO floating around the host userspace on CCA.
Good to know
Quoted 15 lines
Quoted 4 lines
So viommu will become the abstraction point for tsm operations and directly talks to the tsm driver instead of going through the merged
tsm_ops(bind/unbind/guest_req).More precisely for what was being called the TDI - ie it is the abstraction point for the host side of a guest virtual PCI device.
iommufd vdevice already represents this, so we use it again.
Quoted 4 lines
currently what
tsm_opsprovides additionally is more about synchronization with connect/disconnect, otherwise just calls into underlying tsm driver. As long as viommu creation holds a reference to tsm then disconnection is blocked then it's safe.
Quoted 5 lines
Yes, this already has to be true or our lifecylce model is nonsense. Once the iommufd creates the vdevice the guest is running and we cannot disconnect it without unplugging it from the guest. Thus the locking can rely on that. Within an iommufd ioctl context the vdev and underlying connection must be stable.
btw looks a related suggestion is having the tsm driver (arm-cca-host here) implement the viommu ops while leaving the original smmu driver largely intact, and "obtain the viommu through tsm_ops not through iommu_ops".
It's not super clear to me about the implication behind after reading related discussions and what the "obtain" part means.
Could you help elaborate this part?
The old way is kind of:
vdevice_tsm_ops -> tsm_ops -> tsm driver -> iommu driver
then it will become:
viommu_ops (tsm related) -> tsm_driver
where tsm driver will fully handle tsm related viommu_ops?
Quoted 15 lines
Quoted 2 lines
and
IOMMU_VDEVICE_TSM_BINDwill be removed.Replaced, the same logical operations should flow through the viommu command ioctl
Quoted 4 lines
Seems originally this series
doesSMC_RMI_VDEV_CREATEandSMC_RMI_VDEV_LOCKboth in tsm bind op. Then the proposal is moving them all to vdevice creation time so no separate bind step is required.Hmm, lock still should be guest visible on CCA, and the device has to start up in the guest as TDISP unlocked. I'm not 100% on the RMI side of the flow, but this does not look right.
Quoted 5 lines
VDEV create should be done before the realm is started. We need this setup right because Linux VM is going to validate the vdev during boot if it is affiliated to a vSMMU. lock should be done only when requested by the guest. The guest must start with a normal unlocked T=0 PCI device.
Okay then this part is aligned cross all vendors. Thanks for clarification!
Quoted 36 lines
Quoted 3 lines
Does it mean that ARM CCA is essentially an early-bind model i.e. the TDI starts in locked state from guest p.o.v.?
No
Quoted 1 line
but https://lore.kernel.org/all/[email protected]/ seems to
indicate
Quoted 6 lines
that
guest_req()still handles the bind request from the guest:"
-cca_tsm_guest_req()now handlesTSM_REQ_SET_TDI_STATErequests for the unlocked, locked, and running states.
"Right the guest side request to lock should come that way.
Quoted 7 lines
a bit confusing, but maybe due to stale info cited from different timing...
for TDX we're currently pursuing a late-bind model (i.e. TDI starts in shared state in guest), so a separate bind interface is still necessary. We could look at whether it should be an explicit @bind viommu op or carried by @guest_req (say, if most preparation works can be moved to vdevice
creation).
It should go over the viommu command ioctl. It looked like there was alway some iommu specific format to the command in the tsm version of this, so that is the appropriate way.
Quoted 5 lines
btw per past discussions VFIO should block some operations (reset, etc.) while a TDI is locked. Do we expect a callback into VFIO to notify the locked state, or require VFIO's own interface to place a cdev into a special state which prevents sensitive operations even before binding it to iommufd (and allow creating TDI vdevice only on such idevice)?
Quoted 7 lines
At a minimum I think we have to synchronize with vfio, somehow, that when the device enforces its private MMIO so it can unmap it. Thay may be an argument we need a few standard viommu ops so the core code can capture lock/unlocks and do this prep work. Or maybe a special cdev state is simpler.
This should be figured out before any uapi is settled.
Agree
Quoted 4 lines
I don't know about reset, that sounds like something the pci core should deal with?
yes the pci core sounds a better place to handle it.
btw I held the impression of blocked operations from past discussion [1]. Initial attempt tried to proactively unbind the TDI upon any operations which may transit the TDI to the ERROR state. Then the suggestion at the moment was:
" But now the suggestion is never let VFIO do unbind, instead VFIO should block these operations when device is bound. "
[1] https://lore.kernel.org/all/aEFmPaYorqaYCKBY@yilunxu-OptiPlex-7050/
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 18 lines · Kevin
Quoted 5 lines
Yes, this already has to be true or our lifecylce model is nonsense. Once the iommufd creates the vdevice the guest is running and we cannot disconnect it without unplugging it from the guest. Thus the locking can rely on that. Within an iommufd ioctl context the vdev and underlying connection must be stable.
btw looks a related suggestion is having the tsm driver (arm-cca-host here) implement the viommu ops while leaving the original smmu driver largely intact, and "obtain the viommu through
tsm_opsnot throughiommu_ops".It's not super clear to me about the implication behind after reading related discussions and what the "obtain" part means.
Could you help elaborate this part?
The old way is kind of:
Quoted 7 lines
vdevice_tsm_ops->tsm_ops-> tsm driver -> iommu driverthen it will become:
viommu_ops(tsm related) ->tsm_driverwhere tsm driver will fully handle tsm related
viommu_ops?
At least for ARM there is effectively no entanglement with the actual host iommu driver. The viommu is entirely provided by software in the RMM world, so it can have its own dedicated driver. In ARM T=1 transactions are alwayus routed to the RMM's iommu and there is no relation to the host.
I am interested how Intel works here, but I thought it was similar.
AMD is different and I suspect AMD will have to continue to use the viommu from the AMD iommu driver, but I am not sure.
Quoted 4 lines
btw I held the impression of blocked operations from past discussion [1]. Initial attempt tried to proactively unbind the TDI upon any operations which may transit the TDI to the ERROR state. Then the suggestion at the moment was:
With this construction the iommufd vdev is created and permanently exist as long as the VM and viommu exist.
How/when the tsm driver links this to a arch specific "bind/unbind" operation is more up to that driver, but I would expect what is thought of as "bind" should be the affiliation of the device's T=1 stream with the viommu and the target VM. It should not be sensitive to the TDISP state.
That is not prohibited, the TSM driver could do some auto "bind/unbind" whatever that means triggered by ops or tdisp state changing under the covers. But this cannot leak out as some kind of asynchronous vdev destruction.
Quoted 4 lines
" But now the suggestion is never let VFIO do unbind, instead VFIO should block these operations when device is bound. "
[1] https://lore.kernel.org/all/aEFmPaYorqaYCKBY@yilunxu-OptiPlex-7050/
IDK, if the host wants to put a device into error I don't see why the kernel should block it? There are many reasons a device can reach error, that needs to be handled.
Jason
Tian, Kevin
maintainerRE: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 30 lines
From: Jason Gunthorpe <[email protected]>
Sent: Tuesday, September 15, 2026 9:43 PMQuoted 18 lines · Kevin
Quoted 5 lines
Yes, this already has to be true or our lifecylce model is nonsense. Once the iommufd creates the vdevice the guest is running and we cannot disconnect it without unplugging it from the guest. Thus the locking can rely on that. Within an iommufd ioctl context the vdev and underlying connection must be stable.
btw looks a related suggestion is having the tsm driver (arm-cca-host here) implement the viommu ops while leaving the original smmu driver largely intact, and "obtain the viommu through
tsm_opsnot throughiommu_ops".It's not super clear to me about the implication behind after reading related discussions and what the "obtain" part means.
Could you help elaborate this part?
The old way is kind of:
Quoted 7 lines
vdevice_tsm_ops->tsm_ops-> tsm driver -> iommu driverthen it will become:
viommu_ops(tsm related) ->tsm_driverwhere tsm driver will fully handle tsm related
viommu_ops?
Quoted 7 lines
At least for ARM there is effectively no entanglement with the actual host iommu driver. The viommu is entirely provided by software in the RMM world, so it can have its own dedicated driver. In ARM T=1 transactions are alwayus routed to the RMM's iommu and there is no relation to the host.
I am interested how Intel works here, but I thought it was similar.
Largely yes. Main difference at Intel side is that TDX still relies on the host to initiate iotlb invalidation (upon notification from KVM on S-EPT change). Currently we put this logic in intel-iommu driver but it's more about wrapping invalidation info and passing it to the firmware. Moving it into the tsm driver should be straightforward.
Maybe there'll be other subtle connections to host iommu driver but it doesn't sound a hard problem to solve.
Quoted 3 lines
AMD is different and I suspect AMD will have to continue to use the viommu from the AMD iommu driver, but I am not sure.
ARM/Intel may support guest viommu in the future. So AMD's case is a good reference. Maybe for ARM/Intel we'll stay with two or more viommu ops: one from tsm driver (TDI w/o guest viommu), 2nd from the host iommu driver (legacy w/ guest viommu), 3rd from the host iommu driver (TDI w/ guest viommu), etc. We'll see...
Quoted 6 lines
Quoted 5 lines
btw I held the impression of blocked operations from past discussion [1]. Initial attempt tried to proactively unbind the TDI upon any operations which may transit the TDI to the ERROR state. Then the suggestion at the moment was:
Quoted 8 lines
With this construction the iommufd vdev is created and permanently exist as long as the VM and viommu exist.
How/when the tsm driver links this to a arch specific "bind/unbind" operation is more up to that driver, but I would expect what is thought of as "bind" should be the affiliation of the device's T=1 stream with the viommu and the target VM. It should not be sensitive to the TDISP state.
Not sure about this part.
Each arch has its own definition about the binding flow (about 'how'), but sharing a common step by sending TDISP message to transit the TDI into the CONFIG_LOCKED state upon guest request (i.e. 'when').
According to the TDISP spec, memory reads/writes with T bit set is accepted only when the TDI is in RUN state (except MSI/MSI-X writes are allowed with T bit set in LOCKED but I don't think any arch supports it yet).
So your definition of 'bind' essentially affiliate it to the RUN state?
Quoted 5 lines
That is not prohibited, the TSM driver could do some auto "bind/unbind" whatever that means triggered by ops or tdisp state changing under the covers. But this cannot leak out as some kind of asynchronous vdev destruction.
Maybe it'd be clearer using an example e.g. ARM to clarify the suggested split. Or wait for Aneesh's next version...
Quoted 10 lines
Quoted 5 lines
" But now the suggestion is never let VFIO do unbind, instead VFIO should block these operations when device is bound. "
[1] https://lore.kernel.org/all/aEFmPaYorqaYCKBY@yilunxu-OptiPlex-7050/
IDK, if the host wants to put a device into error I don't see why the kernel should block it? There are many reasons a device can reach error, that needs to be handled.
hmm that's a good point!
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 8 lines · Kevin
Quoted 7 lines
At least for ARM there is effectively no entanglement with the actual host iommu driver. The viommu is entirely provided by software in the RMM world, so it can have its own dedicated driver. In ARM T=1 transactions are alwayus routed to the RMM's iommu and there is no relation to the host.
I am interested how Intel works here, but I thought it was similar.
Quoted 8 lines
Largely yes. Main difference at Intel side is that TDX still relies on the host to initiate iotlb invalidation (upon notification from KVM on S-EPT change). Currently we put this logic in intel-iommu driver but it's more about wrapping invalidation info and passing it to the firmware. Moving it into the tsm driver should be straightforward.
Maybe there'll be other subtle connections to host iommu driver but it doesn't sound a hard problem to solve.
Okay, so I saw the driver posting for basic iommu support, can we try to rework that to be split out like Aneesh is doing so everything about TDX calls lives in tsm and intel iommu only provides a small API surface to exchange whatever details are needed to bootstrap TDX module?
Quoted 4 lines
Quoted 2 lines
AMD is different and I suspect AMD will have to continue to use the viommu from the AMD iommu driver, but I am not sure.
ARM/Intel may support guest viommu in the future.
ARM supports guest viommu today, it is in the public spec. Secure guest vSMMU is entirely handled inside the RMM and has no connection to the host iommu driver. It is a <100 line ++ on top of Aneesh's work, Nicolin posted a draft at one point in those threads.
I anticipate a future intel guest T=1 viommu should be the same.
Thus I expect Intel/ARM to have two viommus, one that handles the T=1 stream owned by the TSM driver and implemented entirely by calling TDX/RMM.
One that handles the T=0 stream owned by the iommu driver - and it already exists.
Quoted 1 line
So AMD's case is a good reference.
I think, AMD is completely different. I keep forgetting thier thing, but IIRC they have a secure DTE but instead of having the secure word control the translation it controls the RMP and you end up using the host's translation for T=1 traffic. This is fundamentally different from how Intel and ARM are doing it where the actually IOVA translate is under the control of the secure world.
Both Intel and ARM put the S-EPT into the iommu HW directly.
So, I expect Intel to have an API similar to ARM. When you create the TSM viommu you tell it if the TDX module should create a secure guest visible VT-d emulation. TDX module has to perform the entire emulation because it must be trusted. Existing viommu ops should cover the remaining to register pdevices as vdevices, provide the vBDF and so on.
Quoted 11 lines
Quoted 5 lines
How/when the tsm driver links this to a arch specific "bind/unbind" operation is more up to that driver, but I would expect what is thought of as "bind" should be the affiliation of the device's T=1 stream with the viommu and the target VM. It should not be sensitive to the TDISP state.
Not sure about this part.
Each arch has its own definition about the binding flow (about 'how'), but sharing a common step by sending TDISP message to transit the TDI into the
CONFIG_LOCKEDstate upon guest request (i.e. 'when').
Sure, the LOCKED command can be relayed from the guest, but that shouldn't be called BIND. locked/unlock/run/err is taking a iommufd vdev that is already affiliated with the VM to a specific TDISP state
Quoted 4 lines
According to the TDISP spec, memory reads/writes with T bit set is accepted only when the TDI is in RUN state (except MSI/MSI-X writes are allowed with T bit set in LOCKED but I don't think any arch supports it yet).
Sure
Quoted 1 line
So your definition of 'bind' essentially affiliate it to the RUN state?
No, it is informing the secure world that a physical PCI function is now a virtual PCI function, is a TDI, and is in a certain VM.
Outside virtual hotplug this is a permanent action when the VM is created.
Quoted 7 lines
Quoted 4 lines
That is not prohibited, the TSM driver could do some auto "bind/unbind" whatever that means triggered by ops or tdisp state changing under the covers. But this cannot leak out as some kind of asynchronous vdev destruction.
Maybe it'd be clearer using an example e.g. ARM to clarify the suggested split. Or wait for Aneesh's next version...
In ARM:
BIND is RMI_VDEV_CREATE it links a physical device to a virtual device in a realm.
RMI_VSMMU_CREATE can attach a vSMMU to the realm and there is some way to link the VDEV And the VSMMU together
Some sequence of RMI_VDEV_COMMUNICATE, RMI_VDEV_LOCK, RMI_VDEV_UNLOCK and a few others manipulate the UNLOCKED/LOCKED/RUN/ERR TDISP state of the VDEV.
I assume TDX has the same general shape, I don't know how you could implement this in a radically different way?
So iommufd viommu create calls RMI_VSMMU_CREATE
iommufd vdev create calls RMI_VDEV_CREATE iommufd viommu op ioctl calls the COMMUNICATE/LOCK/UNLOCK
Jason
Tian, Kevin
maintainerRE: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 18 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, September 16, 2026 8:40 PMQuoted 14 lines · Kevin
Quoted 7 lines
At least for ARM there is effectively no entanglement with the actual host iommu driver. The viommu is entirely provided by software in the RMM world, so it can have its own dedicated driver. In ARM T=1 transactions are alwayus routed to the RMM's iommu and there is no relation to the host.
I am interested how Intel works here, but I thought it was similar.
Largely yes. Main difference at Intel side is that TDX still relies on the host to initiate iotlb invalidation (upon notification from KVM on S-EPT change). Currently we put this logic in intel-iommu driver but it's more about wrapping invalidation info and passing it to the firmware. Moving it into the tsm driver should be straightforward.
Quoted 8 lines
Quoted 2 lines
Maybe there'll be other subtle connections to host iommu driver but it doesn't sound a hard problem to solve.
Okay, so I saw the driver posting for basic iommu support, can we try to rework that to be split out like Aneesh is doing so everything about TDX calls lives in tsm and intel iommu only provides a small API surface to exchange whatever details are needed to bootstrap TDX module?
Yeah that makes sense.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
AMD is different and I suspect AMD will have to continue to use the viommu from the AMD iommu driver, but I am not sure.
ARM/Intel may support guest viommu in the future.
ARM supports guest viommu today, it is in the public spec. Secure
sure, I meant the secure part. :)
Quoted 5 lines
guest vSMMU is entirely handled inside the RMM and has no connection to the host iommu driver. It is a <100 line ++ on top of Aneesh's work, Nicolin posted a draft at one point in those threads.
I anticipate a future intel guest T=1 viommu should be the same.
I expect so.
Quoted 4 lines
Thus I expect Intel/ARM to have two viommus, one that handles the T=1 stream owned by the TSM driver and implemented entirely by calling TDX/RMM.
and this one is special, not tying to existing IOAS/HWPT/attach/detach/etc. semantics.
Quoted 3 lines
One that handles the T=0 stream owned by the iommu driver - and it already exists.
sounds a clear split.
Quoted 9 lines
Quoted 2 lines
So AMD's case is a good reference.
I think, AMD is completely different. I keep forgetting thier thing, but IIRC they have a secure DTE but instead of having the secure word control the translation it controls the RMP and you end up using the host's translation for T=1 traffic. This is fundamentally different from how Intel and ARM are doing it where the actually IOVA translate is under the control of the secure world.
that reminds me...
Quoted 9 lines
Both Intel and ARM put the S-EPT into the iommu HW directly.
So, I expect Intel to have an API similar to ARM. When you create the TSM viommu you tell it if the TDX module should create a secure guest visible VT-d emulation. TDX module has to perform the entire emulation because it must be trusted. Existing viommu ops should cover the remaining to register pdevices as vdevices, provide the vBDF and so on.
will think more along that line.
Quoted 37 lines
Quoted 7 lines
Quoted 6 lines
How/when the tsm driver links this to a arch specific "bind/unbind" operation is more up to that driver, but I would expect what is thought of as "bind" should be the affiliation of the device's T=1 stream with the viommu and the target VM. It should not be sensitive to the TDISP state.
Quoted 5 lines
Not sure about this part.
Each arch has its own definition about the binding flow (about 'how'), but sharing a common step by sending TDISP message to transit the TDI into the
CONFIG_LOCKEDstate upon guest request (i.e. 'when').Sure, the LOCKED command can be relayed from the guest, but that shouldn't be called BIND. locked/unlock/run/err is taking a iommufd vdev that is already affiliated with the VM to a specific TDISP state
Quoted 4 lines
According to the TDISP spec, memory reads/writes with T bit set is accepted only when the TDI is in RUN state (except MSI/MSI-X writes are allowed with T bit set in LOCKED but I don't think any arch supports it yet).
Sure
Quoted 1 line
So your definition of 'bind' essentially affiliate it to the RUN state?
No, it is informing the secure world that a physical PCI function is now a virtual PCI function, is a TDI, and is in a certain VM.
Outside virtual hotplug this is a permanent action when the VM is created.
Quoted 5 lines
Quoted 4 lines
That is not prohibited, the TSM driver could do some auto "bind/unbind" whatever that means triggered by ops or tdisp state changing under the covers. But this cannot leak out as some kind of asynchronous vdev destruction.
Quoted 7 lines
Quoted 2 lines
Maybe it'd be clearer using an example e.g. ARM to clarify the suggested split. Or wait for Aneesh's next version...
In ARM:
BIND is
RMI_VDEV_CREATEit links a physical device to a virtual device in a realm.
TDX: TDH.TDI.CREATE
Quoted 3 lines
RMI_VSMMU_CREATEcan attach a vSMMU to the realm and there is some way to link the VDEV And the VSMMU together
TDX: TDH.DMAR.ADD
Quoted 5 lines
Some sequence of
RMI_VDEV_COMMUNICATE,RMI_VDEV_LOCK,RMI_VDEV_UNLOCK
and a few others manipulate the UNLOCKED/LOCKED/RUN/ERR TDISP state of the VDEV.
to locked: TDH.TDI.BIND
to unlocked: TDH.TDI.UNBIND
to RUN: TDH.TDI.START
plus some other commands required around those points
Quoted 3 lines
I assume TDX has the same general shape, I don't know how you could implement this in a radically different way?
yes it's similar.
Quoted 5 lines
So iommufd viommu create calls
RMI_VSMMU_CREATE
iommufd vdev create callsRMI_VDEV_CREATEiommufd viommu op ioctl calls the COMMUNICATE/LOCK/UNLOCK
so in this case BIND is essentially CREATE. Probably link/affiliate is a clearer name in description to avoid confusion with vendor specific bind command...
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
In reply to Jason GunthorpeQuoted 14 lines · Jason Gunthorpe
Quoted 13 lines · Kevin
Quoted 7 lines
At least for ARM there is effectively no entanglement with the actual host iommu driver. The viommu is entirely provided by software in the RMM world, so it can have its own dedicated driver. In ARM T=1 transactions are alwayus routed to the RMM's iommu and there is no relation to the host.
I am interested how Intel works here, but I thought it was similar.
Largely yes. Main difference at Intel side is that TDX still relies on the host to initiate iotlb invalidation (upon notification from KVM on S-EPT change). Currently we put this logic in intel-iommu driver but it's more about wrapping invalidation info and passing it to the firmware. Moving it into the tsm driver should be straightforward.
Quoted 7 lines
Quoted 2 lines
Maybe there'll be other subtle connections to host iommu driver but it doesn't sound a hard problem to solve.
Okay, so I saw the driver posting for basic iommu support, can we try to rework that to be split out like Aneesh is doing so everything about TDX calls lives in tsm and intel iommu only provides a small API surface to exchange whatever details are needed to bootstrap TDX module?
Are you referring to this series?
https://lore.kernel.org/linux-iommu/[email protected]/
It initializes the iommu managed by the secure world (the TDX module).
I’m happy to rework it as you suggested by moving most of the TDX- related code into the tsm driver and leaving the host iommu driver to provide only the necessary assistance.
Thanks,
baolu
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
In reply to Aneesh Kumar K.VQuoted 9 lines · Aneesh Kumar K.V
To reiterate, for this configuration:
- The viommu will use a stage-1 bypass configuration.
- A newIOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3type will create the viommu. The psmmu will be activated at this point to avoid creating psmmu objects early. We will reference-count it to ensure that the same psmmu is shared across realm guests.
- Creating a vdevice will invokeSMC_RMI_PSMMU_ST_L2_CREATE.
Quoted 3 lines
I am unclear about the
vdev_createsuggestion. Creating a vdevice requires an RD, which is created later in the flow above. How do you suggest linkingvdevice_alloctovdev_create?
I was thinking we'd make sure the KVM is associated with the viommu and/or possibly the S2 domain. That was always sort of broadly the idea in this space. There are several topics unrelated to CC that needed this.
In any case, when you create the iommufd viommu you should also do VSMMU_CREATE which needs the RD. It seems reasonable to assume the RD is available during vdevice create.
[There is an aside here I will mention: several other use cases need this idea of an "external" domain where the HWPT would be created but not controlled by iommufd or the iommu subsystem. Xen and Hyperv for example. There is probably some merit in thinking more about exactly what the nested parent domain should be for this viommu, but it isn't critical.]
Quoted 14 lines
From the RMM's perspective, the sequence is as follows:
viommu alloc
[ rmm ] SMC_RMI_PSMMU_ACTIVATE 2b400000 8819bb000 > RMI_INCOMPLETE 0 10008 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 2 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 1 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 1 0 [ rmm ] L1 StrTab: PA 0x881baa000 VA 0x80003c0000 size 0x2000 [ rmm ] CMDQ: PA 0x88066a000 VA 0x80003c2000 [ rmm ] EVTQ: PA 0x8815c5000 VA 0x80003c3000 [ rmm ] PSMMU 0x2b400000 activated [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0
Quoted 5 lines
[ rmm ] SMC_RMI_PSMMU_ST_L2_CREATE 2b400000 300 > RMI_INCOMPLETE 0 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 1 0 [ rmm ] smmu->strtab_base[12] 0x0 @0x80003c0060 [ rmm ] L1STD[12] 0x8819bb007 for SID 0x300: L2 table VA 0x80003d0000 PA 0x8819bb000 [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0
What was this one for during viommu alloc?
Quoted 8 lines
vdevice alloc
[ rmm ] SMC_RMI_PSMMU_ST_L2_CREATE 2b400000 200 > RMI_INCOMPLETE 0 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 882648098 1 > RMI_INCOMPLETE 1 0 [ rmm ] smmu->strtab_base[8] 0x0 @0x80003c0040 [ rmm ] L1STD[8] 0x882506007 for SID 0x200: L2 table VA 0x80003cc000 PA 0x882506000 [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0
Quoted 5 lines
RD gets allocated here
[ rmm ] SMC_RMI_REALM_CREATE 881b03000 8819a1000 > RMI_INCOMPLETE 0 24 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881605098 9 > RMI_INCOMPLETE 9 0 [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0
Why? The VMM needs to create the kvm before starting the iommu stuff.
I would expect that KVM knows it is going to a realm very early on? I had assumed the RD would also be created early by KVM?
What triggers RD creation? Why can't the VMM do it earlier?
Your followup said:
- The realm is created during viommu allocation, ensuring that the vSMMU can be created here.
Do you mean the SMMUv3 driver triggers RD creation? That feels wrong. Did you mean the VMM just does it earlier?
The draft in the next message looks promising, did you discover any other gotchas when exploring it?
When you repost this can you take some care to explain the general idea of this modelling in the commit messages so AMD and Intel can confirm they can use it for both their non-viommu and viommu cases?
Thanks,
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 71 lines · Jason Gunthorpe
Quoted 9 lines · Aneesh Kumar K.V
To reiterate, for this configuration:
- The viommu will use a stage-1 bypass configuration.
- A newIOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3type will create the viommu. The psmmu will be activated at this point to avoid creating psmmu objects early. We will reference-count it to ensure that the same psmmu is shared across realm guests.
- Creating a vdevice will invokeSMC_RMI_PSMMU_ST_L2_CREATE.Quoted 3 lines
I am unclear about the
vdev_createsuggestion. Creating a vdevice requires an RD, which is created later in the flow above. How do you suggest linkingvdevice_alloctovdev_create?I was thinking we'd make sure the KVM is associated with the viommu and/or possibly the S2 domain. That was always sort of broadly the idea in this space. There are several topics unrelated to CC that needed this.
In any case, when you create the iommufd viommu you should also doVSMMU_CREATEwhich needs the RD. It seems reasonable to assume the RD is available during vdevice create.[There is an aside here I will mention: several other use cases need this idea of an "external" domain where the HWPT would be created but not controlled by iommufd or the iommu subsystem. Xen and Hyperv for example. There is probably some merit in thinking more about exactly what the nested parent domain should be for this viommu, but it isn't critical.]
Quoted 14 lines
From the RMM's perspective, the sequence is as follows:
viommu alloc
[ rmm ] SMC_RMI_PSMMU_ACTIVATE 2b400000 8819bb000 > RMI_INCOMPLETE 0 10008 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 2 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 1 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 1 0 [ rmm ] L1 StrTab: PA 0x881baa000 VA 0x80003c0000 size 0x2000 [ rmm ] CMDQ: PA 0x88066a000 VA 0x80003c2000 [ rmm ] EVTQ: PA 0x8815c5000 VA 0x80003c3000 [ rmm ] PSMMU 0x2b400000 activated [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0Quoted 5 lines
[ rmm ] SMC_RMI_PSMMU_ST_L2_CREATE 2b400000 300 > RMI_INCOMPLETE 0 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881bac098 1 > RMI_INCOMPLETE 1 0 [ rmm ] smmu->strtab_base[12] 0x0 @0x80003c0060 [ rmm ] L1STD[12] 0x8819bb007 for SID 0x300: L2 table VA 0x80003d0000 PA 0x8819bb000 [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0What was this one for during viommu alloc?
Quoted 8 lines
vdevice alloc
[ rmm ] SMC_RMI_PSMMU_ST_L2_CREATE 2b400000 200 > RMI_INCOMPLETE 0 10004 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 882648098 1 > RMI_INCOMPLETE 1 0 [ rmm ] smmu->strtab_base[8] 0x0 @0x80003c0040 [ rmm ] L1STD[8] 0x882506007 for SID 0x200: L2 table VA 0x80003cc000 PA 0x882506000 [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0Quoted 5 lines
RD gets allocated here
[ rmm ] SMC_RMI_REALM_CREATE 881b03000 8819a1000 > RMI_INCOMPLETE 0 24 [ rmm ] SMC_RMI_OP_MEM_DONATE 0 881605098 9 > RMI_INCOMPLETE 9 0 [ rmm ] SMC_RMI_OP_CONTINUE 0 0 > RMI_SUCCESS 0 0Why? The VMM needs to create the kvm before starting the iommu stuff.
I would expect that KVM knows it is going to a realm very early on? I had assumed the RD would also be created early by KVM?
Quoted 9 lines
What triggers RD creation? Why can't the VMM do it earlier?
Your followup said:
- The realm is created during viommu allocation, ensuring that the vSMMU can be created here.Do you mean the SMMUv3 driver triggers RD creation? That feels wrong. Did you mean the VMM just does it earlier?
Currently, CCA creates the realm lazily as part of another operation. Realm creation is triggered by kvm_arm_rmi_populate() or kvm_arch_vcpu_run_pid_change()
The change looks like this:
modified arch/arm64/include/asm/kvm_rmi.h
@@ -102,6 +102,14 @@ u64 kvm_realm_reset_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
bool kvm_rmi_supports_sve(void);
int kvm_init_realm(struct kvm *kvm);
+#ifdef CONFIG_KVM
+int kvm_realm_ensure_created(struct kvm *kvm);
+#else
+static inline int kvm_realm_ensure_created(struct kvm *kvm) +{
+ return -EOPNOTSUPP;
+}
+#endif
int kvm_activate_realm(struct kvm *kvm);
void kvm_destroy_realm(struct kvm *kvm);
int kvm_realm_teardown_stage2(struct kvm *kvm);
modified arch/arm64/kvm/rmi.c
@@ -1120,6 +1120,20 @@ static int realm_ensure_created(struct kvm *kvm)
return realm_create_rd(kvm);
}
+int kvm_realm_ensure_created(struct kvm *kvm)
+{
+ int ret;
+
+ if (!kvm_is_realm(kvm))
+ return -EINVAL;
+
+ guard(mutex)(&kvm->arch.config_lock);
+ ret = realm_ensure_created(kvm);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kvm_realm_ensure_created);
+
int kvm_arm_rmi_init_ripas(struct kvm *kvm,
struct kvm_arm_rmi_init_ripas *args)
{
modified drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c
@@ -253,8 +253,9 @@ int arm_realm_smmu_v3_init(struct iommufd_viommu *viommu,
return -EINVAL;
kvm = viommu->kvm_file->private_data;
- if (!kvm_is_realm(kvm))
- return -EINVAL;
+ ret = kvm_realm_ensure_created(kvm);
+ if (ret)
+ return ret;
if (!(smmu->features & ARM_SMMU_FEAT_RME))
return -EOPNOTSUPP;
Quoted 4 lines
The draft in the next message looks promising, did you discover any other gotchas when exploring it?
Nothing significant. I still have questions about moving TDI flows such as vdev creation and guest requests into the SMMU driver instead of keeping them in arm-cca-host.ko, but I will follow up in the other thread.
Quoted 7 lines
When you repost this can you take some care to explain the general idea of this modelling in the commit messages so AMD and Intel can confirm they can use it for both their non-viommu and viommu cases?
Thanks,
Jason
-aneesh
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 6 lines · Aneesh Kumar K.V
Quoted 2 lines
Do you mean the SMMUv3 driver triggers RD creation? That feels wrong. Did you mean the VMM just does it earlier?
Currently, CCA creates the realm lazily as part of another operation. Realm creation is triggered by
kvm_arm_rmi_populate()orkvm_arch_vcpu_run_pid_change()
Okay, that's not what I would have guessed. But critically is there some way for userspace to specify any realm creation parameters (like rpv, ats_plane and so one) prior to the lazy creation?
Why lazy? Why not just have userspace provide the creation parameters and create the RD right then?
Jason
Suzuki K Poulose
reviewerRe: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Aneesh Kumar K.V
Quoted 2 lines
Do you mean the SMMUv3 driver triggers RD creation? That feels wrong. Did you mean the VMM just does it earlier?
Currently, CCA creates the realm lazily as part of another operation. Realm creation is triggered by
kvm_arm_rmi_populate()orkvm_arch_vcpu_run_pid_change()Okay, that's not what I would have guessed. But critically is there some way for userspace to specify any realm creation parameters (like rpv,
ats_planeand so one) prior to the lazy creation?
There would be, eventually. Based on the feedback from KVM arm64 maintainers, we are trying to keep the ABI as generic as possible as the normal VMs. Thus, for now we have not included the Realm specific parameter configuration (which was present in the earlier versions) in the latest version of the KVM support.
We have some ideas on how to do the configuration step. e.g. for MEC, see the following thread :
https://lore.kernel.org/all/[email protected]/
Quoted 3 lines
Why lazy? Why not just have userspace provide the creation parameters and create the RD right then?
Cheers
Suzuki
Quoted 2 lines
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
Quoted 19 lines · Suzuki K Poulose
Quoted 11 lines · Jason Gunthorpe
Quoted 6 lines · Aneesh Kumar K.V
Quoted 2 lines
Do you mean the SMMUv3 driver triggers RD creation? That feels wrong. Did you mean the VMM just does it earlier?
Currently, CCA creates the realm lazily as part of another operation. Realm creation is triggered by
kvm_arm_rmi_populate()orkvm_arch_vcpu_run_pid_change()Okay, that's not what I would have guessed. But critically is there some way for userspace to specify any realm creation parameters (like rpv,
ats_planeand so one) prior to the lazy creation?There would be, eventually. Based on the feedback from KVM arm64 maintainers, we are trying to keep the ABI as generic as possible as the normal VMs. Thus, for now we have not included the Realm specific parameter configuration (which was present in the earlier versions) in the latest version of the KVM support.
Quoted 4 lines
We have some ideas on how to do the configuration step. e.g. for MEC, see the following thread :
I see, well please convay to the KVM folks that the iommu side needs the RD to be setup prior to creating viommu objects and needs to be able to supply realm parameters like ats_plane to work..
Don't see a reason to twist the API to accomodate KVM being out of order for now. It is up to you if you want to try to do the lazy create or try to get a defined creation momement with parameters (I prefer this from an aesthetic perspective at least)
Jason
Re: [RFC PATCH v4 03/16] iommu/arm-smmu-v3: Add initial pSMMU realm viommu plumbing
In reply to Aneesh Kumar K.VQuoted 27 lines · Aneesh Kumar K.V
Quoted 21 lines · Nicolin Chen
But, on the other hand, I can imagine that a Realm VSMMU would add a new flag with a
user_datato this VIOMMU. Then, this flow would give some troubles to VMM (QEMU for example):- For VM with a guest-level SMMU, QEMU creates a realm instance where
IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3(with vsmmu) can be allocated.
- For VM w/o a guest-level SMMU, QEMU won't create such a realm instance, while still required to invoke the ioctl (w/o vsmmu).Taking a step back, I wonder if we really need to use iommufd for PSMMU activation and its stream table allocations?
Here are some facts:
- An iommufd has a ctx, that's one per VM. Similarly, a Realm has an RD.
- For an RMI command that needs an RD, it makes sense to be per iommufd ctx, e.g. RMI_VSMMU_* or RMI_VDEV_* commands.
- PSMMU commands are global; they don't need RD. So they don't seem necessary to tie to an iommufd ctx.Quoted 4 lines
Instead, could the PSMMU activation be done after
RMI_PSMMU_INFOcheck? Is there any reason not to do that? A safer timing might be at the device assignment stage?
Quoted 7 lines
One of the reasons I added
IOMMU_VIOMMU_TYPE_ARM_REALM_SMMUV3was to avoid creating a psmmu object when we are not using a PCI passthrough VM. That is also the reason for all the refcounting around the psmmu objects.If we are okay with creating psmmu objects early, then I guess we can go with the above approach.
Do you see any trouble if we implement in this way:
- Add "struct arm_smmu_realm *psmmu" in struct arm_smmu_device
- RMI_PSMMU_INFO in probe():
+ allocate a smmu->psmmu on success
+ keep smmu->psmmu->users = 0; psmmu is not activated
- Device binds to iommufd, creating idev
+ invoke an iommu op to a driver-level callback:
psmmu = smmu->psmmu; if (!psmmu) return 0; guard(mutex)(&psmmu->mutex); if (!smmu->psmmu->users) rmi_psmmu_activate(); psmmu->users++; rmi_psmmu_st_l2_create();
?
Nicolin
RFC PATCH v4 4/16 iommu/arm-smmu-v3: Track realm pSMMU users with refcount_t
In reply to Aneesh Kumar K.V (Arm)Replace the realm pSMMU active-state boolean with a refcount so activation/deactivation is tied to actual Realm vIOMMU lifetime.
- add realm_mutex and realm_users (refcount_t) to struct arm_smmu_device
- on first Realm init, activate pSMMU and set realm_users to 1
- on subsequent Realm inits, increment realm_users
- on Realm viommu destroy, decrement realm_users and call rmi_psmmu_deactivate() when the last user drops the count to 0
This removes duplicated state tracking and ensures pSMMU is deactivated only after the last Realm user is gone.
--- arch/arm64/include/asm/rmi_cmds.h | 1 + arch/arm64/kernel/rmi.c | 12 ++++++ .../iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c | 39 +++++++++++++++---- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 3 +- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 4 +- 5 files changed, 50 insertions(+), 9 deletions(-)
arch/arm64/include/asm/rmi_cmds.h +1 -0
@@ -865,6 +865,7 @@ static inline unsigned long rmi_psmmu_event_consume(unsigned long psmmu_phys,int rmi_psmmu_activate (unsigned long psmmu_phys,unsigned long psmmu_params_phys,unsigned long *rmi_ret); +int rmi_psmmu_deactivate (unsigned long psmmu_phys,unsigned long *rmi_ret);int rmi_psmmu_st_l2_create (unsigned long psmmu_phys,unsigned long stream_id,unsigned long *rmi_ret); int rmi_psmmu_st_l2_destroy(unsigned long psmmu_phys,
arch/arm64/kernel/rmi.c +12 -0
@@ -436,6 +436,18 @@ int rmi_psmmu_activate(unsigned long psmmu_phys,return 0 ; } +int rmi_psmmu_deactivate (unsigned long psmmu_phys,unsigned long *rmi_ret) +{ + struct rmi_sro_state *sro __free(sro) = +rmi_sro_init (SMC_RMI_PSMMU_DEACTIVATE , psmmu_phys); +if (!sro) +return -ENOMEM ; + + *rmi_ret =rmi_sro_execute (sro); + +return 0 ; +} +int rmi_psmmu_st_l2_create (unsigned long psmmu_phys,unsigned long stream_id,unsigned long *rmi_ret) {
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c +32 -7
@@ -124,9 +124,25 @@ void arm_smmu_setup_realm_irqs(struct arm_smmu_device *smmu) } } +static bool arm_realm_smmu_active (struct arm_smmu_device *smmu) +{ +lockdep_assert_held (&smmu->realm_mutex); +return refcount_read (&smmu->realm_users) >0 ; +} +static void arm_realm_smmu_v3_destroy (struct iommufd_viommu *viommu) { -/* When we add refcount psmmu deactivate here. */ +unsigned long rmi_ret; +struct arm_smmu_device *smmu = + container_of(viommu->iommu_dev, struct arm_smmu_device, iommu); + +guard (mutex)(&smmu->realm_mutex); +if (WARN_ON (!arm_realm_smmu_active (smmu))) +return ; + +if (refcount_dec_and_test (&smmu->realm_users) && + (rmi_psmmu_deactivate (smmu->base_phys, &rmi_ret) || rmi_ret)) +dev_warn (smmu->dev,"failed to deactivate realm pSMMU\n" ); }static void arm_realm_smmu_v3_vdevice_destroy (struct iommufd_vdevice *vdev)
@@ -140,7 +156,8 @@ static void arm_realm_smmu_v3_vdevice_destroy(struct iommufd_vdevice *vdev)unsigned long rmi_ret =0 ;int ret; -if (!smmu->realm_initialized) +guard (mutex)(&smmu->realm_mutex); +if (!arm_realm_smmu_active (smmu))return ; ret = rmi_psmmu_st_l2_destroy(smmu->base_phys,
@@ -168,7 +185,8 @@ static int arm_realm_smmu_v3_vdevice_init(struct iommufd_vdevice *vdev)unsigned long rmi_ret =0 ;int ret; -if (!smmu->realm_initialized) +guard (mutex)(&smmu->realm_mutex); +if (!arm_realm_smmu_active (smmu))return -EINVAL ; ret = rmi_psmmu_st_l2_create(smmu->base_phys,
@@ -229,12 +247,17 @@ int arm_realm_smmu_v3_init(struct iommufd_viommu *viommu,if (!(smmu->features &ARM_SMMU_FEAT_RME ))return -EOPNOTSUPP ; -if (smmu->realm_initialized) +mutex_lock (&smmu->realm_mutex); +if (arm_realm_smmu_active (smmu)) { +refcount_inc (&smmu->realm_users); goto psmmu_already_active; + } params = (struct rmi_psmmu_params *)get_zeroed_page (GFP_KERNEL ); -if (!params) -return -ENOMEM ; +if (!params) { + ret = -ENOMEM ; + goto out_unlock; + }/* No ATS and PRI support */ if (!(smmu->features &ARM_SMMU_FEAT_MSI ))
@@ -261,12 +284,14 @@ int arm_realm_smmu_v3_init(struct iommufd_viommu *viommu,dev_warn (smmu->dev,"failed to activate realm pSMMU\n" ); ret = -EIO ; }else { - smmu->realm_initialized = true; +refcount_set (&smmu->realm_users,1 ); } out_free:free_page ((unsigned long )params); psmmu_already_active:if (!ret) viommu->ops = &arm_realm_smmu_v3_ops; +out_unlock: +mutex_unlock (&smmu->realm_mutex);return ret; }
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +2 -1
@@ -3946,6 +3946,8 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu)int ret;mutex_init (&smmu->streams_mutex); +mutex_init (&smmu->realm_mutex); +refcount_set (&smmu->realm_users,0 ); smmu->streams =RB_ROOT ; ret =arm_smmu_init_queues (smmu);
@@ -3956,7 +3958,6 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu)if (ret)return ret; - smmu->realm_initialized = false;if (smmu->impl_ops && smmu->impl_ops->init_structures)return smmu->impl_ops->init_structures (smmu);
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +3 -1
@@ -13,6 +13,7 @@#include <linux/iommufd.h> #include <linux/kernel.h> #include <linux/mmzone.h> +#include <linux/refcount.h> #include <linux/sizes.h> struct arm_smmu_device ;
@@ -812,7 +813,8 @@ struct arm_smmu_device {struct rb_root streams;struct mutex streams_mutex; -bool realm_initialized; +struct mutex realm_mutex; +refcount_t realm_users; };struct arm_smmu_stream {
Signature · 1 line
2.43.0
RFC PATCH v4 5/16 coco: host: arm64: Add support for virtual device communication
In reply to Aneesh Kumar K.V (Arm)Add support for vdev_communicate with RMM.
--- arch/arm64/include/asm/rmi_cmds.h | 32 ++++++++++ arch/arm64/include/asm/rmi_smc.h | 7 +++ drivers/virt/coco/arm-cca-host/rmi-da.c | 83 ++++++++++++++++++++++--- drivers/virt/coco/arm-cca-host/rmi-da.h | 20 ++++++ 4 files changed, 135 insertions(+), 7 deletions(-)
arch/arm64/include/asm/rmi_cmds.h +32 -0
@@ -871,4 +871,36 @@ int rmi_psmmu_st_l2_create(unsigned long psmmu_phys,int rmi_psmmu_st_l2_destroy (unsigned long psmmu_phys,unsigned long stream_id,unsigned long *rmi_ret); +static inline unsigned long rmi_vdev_communicate (unsigned long rd_phys, +unsigned long pdev_phys,unsigned long vdev_phys, +unsigned long vdev_comm_data_phys) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_VDEV_COMMUNICATE , rd_phys, pdev_phys, + vdev_phys, vdev_comm_data_phys, &res); + +return res.a0; +} + +static inline unsigned long rmi_vdev_get_state (unsigned long vdev_phys, +enum rmi_vdev_state *state) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_VDEV_GET_STATE , vdev_phys, &res); + + *state = res.a1; +return res.a0; +} + +static inline unsigned long rmi_vdev_abort (unsigned long vdev_phys) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_VDEV_ABORT , vdev_phys, &res); + +return res.a0; +} +#endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/asm/rmi_smc.h +7 -0
@@ -643,4 +643,11 @@ struct rmi_psmmu_params { }; }; +enum rmi_vdev_state { +RMI_VDEV_NEW , +RMI_VDEV_UNLOCKED , +RMI_VDEV_LOCKED , +RMI_VDEV_STARTED , +RMI_VDEV_ERROR , +};#endif /* __ASM_RMI_SMC_H */
drivers/virt/coco/arm-cca-host/rmi-da.c +76 -7
138 lines not on this page · raw message
drivers/virt/coco/arm-cca-host/rmi-da.h +20 -0
@@ -116,6 +116,16 @@ struct cca_host_fn_dsc {enum dev_comm_type {PDEV_COMMUNICATE =0x1 , +VDEV_COMMUNICATE =0x2 , +}; + +struct cca_host_tdi { +struct pci_tdi tdi; +struct realm *realm; +void *rmm_vdev; +/* protected by cca_host_pdev_dsc.object_lock */ +struct cache_object *interface_report; +struct cache_object *measurements; }; static inline int insert_addr_range_sorted(struct rmi_addr_range *addr_range,
@@ -203,6 +213,16 @@ static inline struct cca_host_comm_data *to_cca_comm_data(struct pci_dev *pdev)return NULL ; } +static inline struct cca_host_tdi *to_cca_host_tdi (struct pci_dev *pdev) +{ +struct pci_tsm *tsm = pdev->tsm; + +if (!tsm || !tsm->tdi) +return NULL ; + + return container_of(tsm->tdi, struct cca_host_tdi, tdi); +} +int cca_pdev_create (struct pci_dev *pdev);int cca_pdev_collect_identity (struct pci_dev *pdev);bool cca_pdev_needs_key (struct pci_dev *pdev);
Signature · 1 line
2.43.0
RFC PATCH v4 6/16 coco: host: arm64: Add support for RMM vdev objects
In reply to Aneesh Kumar K.V (Arm)An RMM vdev object represents the binding between a device function and a Realm. For example, a vdev can represent a physical function of a PCIe device or a virtual function of a multi-function PCIe device. Each vdev is associated with one pdev.
--- arch/arm64/include/asm/rmi_cmds.h | 22 +++++ arch/arm64/include/asm/rmi_smc.h | 22 +++++ drivers/virt/coco/arm-cca-host/arm-cca.c | 27 +++++- drivers/virt/coco/arm-cca-host/rmi-da.c | 104 +++++++++++++++++++++++ drivers/virt/coco/arm-cca-host/rmi-da.h | 2 + 5 files changed, 176 insertions(+), 1 deletion(-)
arch/arm64/include/asm/rmi_cmds.h +22 -0
@@ -903,4 +903,26 @@ static inline unsigned long rmi_vdev_abort(unsigned long vdev_phys) return res.a0; } +static inline unsigned long rmi_vdev_create (unsigned long rd, +unsigned long pdev_phys,unsigned long vdev_phys, +unsigned long vdev_params_phys) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_VDEV_CREATE , rd, pdev_phys, + vdev_phys, vdev_params_phys, &res); + +return res.a0; +} + +static inline unsigned long rmi_vdev_lock (unsigned long rd, +unsigned long pdev_phys,unsigned long vdev_phys) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_VDEV_LOCK , rd, pdev_phys, vdev_phys, &res); + +return res.a0; +} +#endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/asm/rmi_smc.h +22 -0
@@ -650,4 +650,26 @@ enum rmi_vdev_state {RMI_VDEV_STARTED , RMI_VDEV_ERROR, }; + +#define MAX_VDEV_ADDR_RANGE 8 + +struct rmi_vdev_params { +union { +struct { +u64 flags; +u64 vdev_id; +u64 tdi_id; +u64 padding1; +u64 vsmmu_addr; +u64 vsid; +u64 num_addr_range; + }; +u8 padding2[0x200 ]; + }; +union {/* 0x200 */ +struct rmi_addr_range addr_range[MAX_VDEV_ADDR_RANGE ]; +u8 padding3[0x1000 -0x200 ]; + }; +}; +#endif /* __ASM_RMI_SMC_H */
drivers/virt/coco/arm-cca-host/arm-cca.c +26 -1
@@ -12,7 +12,8 @@#include <linux/vmalloc.h> #include <linux/cleanup.h> #include <linux/pci-doe.h> - +#include <linux/pci.h> +#include <linux/kvm_host.h> #include "rmi-da.h"
@@ -449,11 +450,35 @@ static void cca_tsm_disconnect(struct pci_dev *pdev) } } +static struct pci_tdi *cca_tsm_bind (struct pci_dev *pdev,struct kvm *kvm,u32 tdi_id) +{ +void *rmm_vdev; +struct pci_dev *dsm_dev = pdev->tsm->dsm_dev; +struct realm *realm = &kvm->arch.realm; + + struct cca_host_tdi *host_tdi __free(kfree) = +kzalloc (sizeof (struct cca_host_tdi ),GFP_KERNEL ); +if (!host_tdi) +return ERR_PTR (-ENOMEM ); + +pci_tsm_tdi_constructor (pdev, &host_tdi->tdi, kvm, tdi_id); +/* Assign the tdi such that vdev_create can use that to lookup */ + pdev->tsm->tdi = &host_tdi->tdi; + rmm_vdev =cca_vdev_create (realm, pdev, dsm_dev, tdi_id); +if (IS_ERR_OR_NULL (rmm_vdev)) { + pdev->tsm->tdi =NULL ; +return rmm_vdev; + } + +return &no_free_ptr (host_tdi)->tdi; +} +static struct pci_tsm_ops cca_link_pci_ops = { .probe = cca_tsm_pci_probe, .remove = cca_tsm_pci_remove, .connect = cca_tsm_connect, .disconnect = cca_tsm_disconnect, + .bind = cca_tsm_bind, };static void cca_link_tsm_remove (void *tsm_dev)
drivers/virt/coco/arm-cca-host/rmi-da.c +104 -0
107 lines not on this page · raw message
drivers/virt/coco/arm-cca-host/rmi-da.h +2 -0
@@ -233,5 +233,7 @@ int cca_pdev_stream_connect(struct pci_dev *pdev1, struct pci_dev *pdev2, unsigned long *stream_handle);int cca_pdev_disconnect_stream (struct pci_dev *pdev1,struct pci_dev *pdev2,unsigned long stream_handle); +void *cca_vdev_create (struct realm *realm,struct pci_dev *pdev, +struct pci_dev *pf0_dev,u32 guest_rid);#endif
Signature · 1 line
2.43.0
RFC PATCH v4 7/16 coco: host: arm64: Add pdev stream key refresh and purge helpers
In reply to Aneesh Kumar K.V (Arm)Add RMI command wrappers for PDEV stream key refresh and key purge, and plumb them into arm-cca host helper functions.
The new helpers follow the existing stream operation pattern: issue the RMI command for the local and optional peer pdev, then run the shared stream synchronization work before returning.
This prepares the arm-cca host code to refresh or purge stream keys during later vdev and stream state transitions.
--- arch/arm64/include/asm/rmi_cmds.h | 24 +++++++++++++++++ drivers/virt/coco/arm-cca-host/rmi-da.c | 35 +++++++++++++++++++++++++ drivers/virt/coco/arm-cca-host/rmi-da.h | 4 +++ 3 files changed, 63 insertions(+)
arch/arm64/include/asm/rmi_cmds.h +24 -0
@@ -925,4 +925,28 @@ static inline unsigned long rmi_vdev_lock(unsigned long rd, return res.a0; } +static inline unsigned long rmi_pdev_stream_key_refresh (unsigned long pdev1_phys, +unsigned long pdev2_phys,unsigned long stream_handle) +{ + +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_PDEV_STREAM_KEY_REFRESH , pdev1_phys, + pdev2_phys, stream_handle, &res); + +return res.a0; +} + +static inline unsigned long rmi_pdev_stream_key_purge (unsigned long pdev1_phys, +unsigned long pdev2_phys,unsigned long stream_handle) +{ + +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_PDEV_STREAM_KEY_PURGE , pdev1_phys, + pdev2_phys, stream_handle, &res); + +return res.a0; +} +#endif /* __ASM_RMI_CMDS_H */
drivers/virt/coco/arm-cca-host/rmi-da.c +35 -0
@@ -1038,3 +1038,38 @@ void *cca_vdev_create(struct realm *realm, struct pci_dev *pdev, err_out:return ERR_PTR (ret); } + +int cca_pdev_refresh_stream_key (struct pci_dev *pdev1, +struct pci_dev *pdev2,unsigned long stream_handle) +{ + +phys_addr_t rmm_pdev2_phys =0 ; +struct cca_host_pdev_dsc *pdev_dsc1 =to_cca_pdev_dsc (pdev1); + +if (pdev2) + rmm_pdev2_phys =virt_to_phys (to_cca_pdev_dsc (pdev2)->rmm_pdev); + +if (rmi_pdev_stream_key_refresh (virt_to_phys (pdev_dsc1->rmm_pdev), + rmm_pdev2_phys, stream_handle)) +return -EIO ; + +return submit_stream_work (pdev1, pdev2, stream_handle); +} + + +int cca_pdev_purge_stream_key (struct pci_dev *pdev1, +struct pci_dev *pdev2,unsigned long stream_handle) +{ + +phys_addr_t rmm_pdev2_phys =0 ; +struct cca_host_pdev_dsc *pdev_dsc1 =to_cca_pdev_dsc (pdev1); + +if (pdev2) + rmm_pdev2_phys =virt_to_phys (to_cca_pdev_dsc (pdev2)->rmm_pdev); + +if (rmi_pdev_stream_key_purge (virt_to_phys (pdev_dsc1->rmm_pdev), + rmm_pdev2_phys, stream_handle)) +return -EIO ; + +return submit_stream_work (pdev1, pdev2, stream_handle); +}
drivers/virt/coco/arm-cca-host/rmi-da.h +4 -0
@@ -235,5 +235,9 @@ int cca_pdev_disconnect_stream(struct pci_dev *pdev1, struct pci_dev *pdev2, unsigned long stream_handle);void *cca_vdev_create (struct realm *realm,struct pci_dev *pdev,struct pci_dev *pf0_dev,u32 guest_rid); +int cca_pdev_refresh_stream_key (struct pci_dev *pdev1, +struct pci_dev *pdev2,unsigned long stream_handle); +int cca_pdev_purge_stream_key (struct pci_dev *pdev1, +struct pci_dev *pdev2,unsigned long stream_handle);#endif
Signature · 1 line
2.43.0
RFC PATCH v4 8/16 coco: host: arm64: Add helpers to unlock and destroy RMM vdev
In reply to Aneesh Kumar K.V (Arm)- define the SMCCC IDs and inline wrappers for RMI_VDEV_UNLOCK and RMI_VDEV_DESTROY
- extend vdev_create() to treat communication failures as fatal and tear down the newly created vdev
- provide vdev_unlock_and_destroy() that drives the vdev back to the unlocked state, issues the destroy call, and frees the delegated granule
- hook the new helper into the TSM unbind path so host cleanup always unlock and destroy RMM vdev and releases cached buffers
--- arch/arm64/include/asm/rmi_cmds.h | 20 +++++++ arch/arm64/include/asm/rmi_smc.h | 2 + drivers/virt/coco/arm-cca-host/arm-cca.c | 25 +++++++++ drivers/virt/coco/arm-cca-host/rmi-da.c | 69 ++++++++++++++++++++++-- drivers/virt/coco/arm-cca-host/rmi-da.h | 3 ++ 5 files changed, 116 insertions(+), 3 deletions(-)
arch/arm64/include/asm/rmi_cmds.h +20 -0
@@ -949,4 +949,24 @@ static inline unsigned long rmi_pdev_stream_key_purge(unsigned long pdev1_phys, return res.a0; } +static inline unsigned long rmi_vdev_unlock (unsigned long rd, +unsigned long pdev_phys,unsigned long vdev_phys) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_VDEV_UNLOCK , rd, pdev_phys, vdev_phys, &res); + +return res.a0; +} + +static inline unsigned long rmi_vdev_destroy (unsigned long rd, +unsigned long pdev_phys,unsigned long vdev_phys) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_VDEV_DESTROY , rd, pdev_phys, vdev_phys, &res); + +return res.a0; +} +#endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/asm/rmi_smc.h +2 -0
@@ -649,6 +649,8 @@ enum rmi_vdev_state {RMI_VDEV_LOCKED ,RMI_VDEV_STARTED ,RMI_VDEV_ERROR , +RMI_VDEV_KEY_REFRESH , + RMI_VDEV_KEY_PURGE, };#define MAX_VDEV_ADDR_RANGE 8
drivers/virt/coco/arm-cca-host/arm-cca.c +25 -0
@@ -473,12 +473,37 @@ static struct pci_tdi *cca_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u32 treturn &no_free_ptr (host_tdi)->tdi; } +/* +* All device memory should be unmapped by now. +* 1. A pci device destroy will cause a driver remove (vfio) which will have +* done a dmabuf based unmap +* 2. A vdevice/idevice destroy from VMM should have done a unmap_private_range +* vm ioctl before +* 3. A guest unlock request should have done a rsi_invalidiate_mem_mapping +* before unlock rhi +* 4. vfio_pci_core_close_device() should trigger tsm unbind if vdevice is not +* already distroyed and that path involves vfio_pci_dma_buf_cleanup() which +* should get kvm to unmap the devmap +*/ +static void cca_tsm_unbind (struct pci_tdi *tdi) +{ +struct cca_host_tdi *host_tdi; +struct realm *realm = &tdi->kvm->arch.realm; + + host_tdi = container_of(tdi, struct cca_host_tdi, tdi); +cca_vdev_unlock_and_destroy (realm, tdi->pdev, tdi->pdev->tsm->dsm_dev); +kvfree (host_tdi->interface_report); +kvfree (host_tdi->measurements); +kfree (host_tdi); +} +static struct pci_tsm_ops cca_link_pci_ops = { .probe = cca_tsm_pci_probe, .remove = cca_tsm_pci_remove, .connect = cca_tsm_connect, .disconnect = cca_tsm_disconnect, .bind = cca_tsm_bind, + .unbind = cca_tsm_unbind, };static void cca_link_tsm_remove (void *tsm_dev)
drivers/virt/coco/arm-cca-host/rmi-da.c +66 -3
84 lines not on this page · raw message
drivers/virt/coco/arm-cca-host/rmi-da.h +3 -0
@@ -15,6 +15,7 @@#include <linux/wait.h> #include <asm/rmi_cmds.h> #include <asm/rmi_smc.h> +#include <asm/rhi.h> #define MAX_CACHE_OBJ_SIZE SZ_16M#define CACHE_CHUNK_SIZE SZ_4K
@@ -239,5 +240,7 @@ int cca_pdev_refresh_stream_key(struct pci_dev *pdev1, struct pci_dev *pdev2, unsigned long stream_handle);int cca_pdev_purge_stream_key (struct pci_dev *pdev1,struct pci_dev *pdev2,unsigned long stream_handle); +void cca_vdev_unlock_and_destroy (struct realm *realm,struct pci_dev *pdev, +struct pci_dev *pf0_dev);#endif
Signature · 1 line
2.43.0
RFC PATCH v4 9/16 coco: host: arm64: Add support for da object read RHI handling
In reply to Aneesh Kumar K.V (Arm)Device assignment-related RHI calls result in a REC exit, which is handled by the tsm guest_request callback.
--- arch/arm64/include/uapi/asm/rmi-da.h | 21 ++++++ drivers/virt/coco/arm-cca-host/arm-cca.c | 74 ++++++++++++++++++ drivers/virt/coco/arm-cca-host/rmi-da.c | 95 ++++++++++++++++++++++++ drivers/virt/coco/arm-cca-host/rmi-da.h | 3 + 4 files changed, 193 insertions(+) create mode 100644 arch/arm64/include/uapi/asm/rmi-da.h
arch/arm64/include/uapi/asm/rmi-da.h new file +21 -0
@@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#ifndef _UAPI__ASM_RMI_DA_H +#define _UAPI__ASM_RMI_DA_H + +#include <linux/types.h> + +struct arm64_vdev_object_size_guest_req { +__u32 req_type; +__u32 object_type; +}; +#define __RHI_DA_OBJECT_SIZE 0x1 + +struct arm64_vdev_object_read_guest_req { +__u32 req_type; +__u32 object_type; +__aligned_u64 offset; +}; +#define __RHI_DA_OBJECT_READ 0x2 + +#endif
drivers/virt/coco/arm-cca-host/arm-cca.c +74 -0
92 lines not on this page · raw message
drivers/virt/coco/arm-cca-host/rmi-da.c +95 -0
104 lines not on this page · raw message
drivers/virt/coco/arm-cca-host/rmi-da.h +3 -0
@@ -242,5 +242,8 @@ int cca_pdev_purge_stream_key(struct pci_dev *pdev1, struct pci_dev *pdev2, unsigned long stream_handle);void cca_vdev_unlock_and_destroy (struct realm *realm,struct pci_dev *pdev,struct pci_dev *pf0_dev); +int cca_vdev_get_object_size (struct pci_dev *pdev,int type); +int cca_vdev_read_cached_object (struct pci_dev *pdev,int type,unsigned long offset, +unsigned long max_len,void __user *user_buf);#endif
Signature · 1 line
2.43.0
RFC PATCH v4 10/16 coco: host: arm64: Add helper for cached object fetches
In reply to Aneesh Kumar K.V (Arm)Introduce vdev_fetch_object_work() so we have a single workqueue handler that refreshes any cached Realm object (interface report, measurements, certificates). The helper receives the cache buffer/offset/size via dev_comm_work, clears the existing contents under dsm_dev.object_lock, performs the VDEV_COMMUNICATE call, and uses the updated size to signal failures back to the caller once the work completes.
--- drivers/virt/coco/arm-cca-host/rmi-da.c | 26 +++++++++++++++++++++++++ drivers/virt/coco/arm-cca-host/rmi-da.h | 3 +++ 2 files changed, 29 insertions(+)
drivers/virt/coco/arm-cca-host/rmi-da.c +26 -0
@@ -1138,6 +1138,32 @@ void cca_vdev_unlock_and_destroy(struct realm *realm, host_tdi->realm =NULL ; } +static void __maybe_unused vdev_fetch_object_workfn (struct work_struct *work) +{ +int state; +struct pci_tsm *tsm; +struct cca_host_pdev_dsc *pdev_dsc; +struct dev_comm_work *setup_work; + + setup_work = container_of(work, struct dev_comm_work, work); + tsm = setup_work->tsm; + pdev_dsc =to_cca_pdev_dsc (tsm->dsm_dev); + +guard (mutex)(&pdev_dsc->object_lock); + +if (setup_work->cache_size) { +memset (setup_work->cache_buf,0 , setup_work->cache_size); + *setup_work->cache_offset =0 ; + } + state =do_dev_communicate (VDEV_COMMUNICATE , tsm,RMI_VDEV_ERROR ,NULL ); +/* return status through dev_comm_work.cache_cache */ +if (state ==RMI_VDEV_ERROR ) + setup_work->cache_size =0 ; +else +/* indicate success. This value is not used. */ + setup_work->cache_size =CACHE_CHUNK_SIZE ; +} +int cca_vdev_get_object_size (struct pci_dev *pdev,int type) {long len;
drivers/virt/coco/arm-cca-host/rmi-da.h +3 -0
@@ -28,6 +28,9 @@ struct cache_object {struct dev_comm_work {struct pci_tsm *tsm;int target_state; +u8 *cache_buf; +int *cache_offset; +int cache_size;struct work_struct work; };
Signature · 1 line
2.43.0
RFC PATCH v4 11/16 coco: host: arm64: Fetch interface report via RMI
In reply to Aneesh Kumar K.V (Arm)- define __RHI_DA_VDEV_GET_INTERFACE_REPORT for guest requests and expose the RMI SMC ID/wrapper for RMI_VDEV_GET_INTERFACE_REPORT
- teach the CCA host driver to handle the new guest request by fetching the report from RMM using rmi_vdev_get_interface_report() and refreshing the cached buffer
- add a helper that submits a DOE work to pull the latest report into the cache
This lets guests request up-to-date interface reports via RHI
--- arch/arm64/include/asm/rmi_cmds.h | 12 ++++++ arch/arm64/include/uapi/asm/rmi-da.h | 3 ++ drivers/virt/coco/arm-cca-host/arm-cca.c | 4 ++ drivers/virt/coco/arm-cca-host/rmi-da.c | 54 +++++++++++++++++++++++- drivers/virt/coco/arm-cca-host/rmi-da.h | 1 + 5 files changed, 73 insertions(+), 1 deletion(-)
arch/arm64/include/asm/rmi_cmds.h +12 -0
@@ -969,4 +969,16 @@ static inline unsigned long rmi_vdev_destroy(unsigned long rd, return res.a0; } +static inline unsigned long rmi_vdev_get_interface_report (unsigned long rd, +unsigned long pdev_phys, +unsigned long vdev_phys) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_VDEV_GET_INTERFACE_REPORT , + rd, pdev_phys, vdev_phys, &res); + +return res.a0; +} +#endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/uapi/asm/rmi-da.h +3 -0
@@ -18,4 +18,7 @@ struct arm64_vdev_object_read_guest_req { };#define __RHI_DA_OBJECT_READ 0x2 +/* No arguments to this guest request */ +#define __RHI_DA_VDEV_UPDATE_INTERFACE_REPORT 0x3 +#endif
drivers/virt/coco/arm-cca-host/arm-cca.c +4 -0
@@ -561,6 +561,10 @@ static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, enum pci_tsm_req_scope sco/* error */ return len; } +case __RHI_DA_VDEV_UPDATE_INTERFACE_REPORT: + { +return cca_vdev_update_interface_report (pdev); + }default :return -EINVAL ; }
drivers/virt/coco/arm-cca-host/rmi-da.c +53 -1
63 lines not on this page · raw message
drivers/virt/coco/arm-cca-host/rmi-da.h +1 -0
@@ -248,5 +248,6 @@ void cca_vdev_unlock_and_destroy(struct realm *realm, struct pci_dev *pdev,int cca_vdev_get_object_size (struct pci_dev *pdev,int type);int cca_vdev_read_cached_object (struct pci_dev *pdev,int type,unsigned long offset,unsigned long max_len,void __user *user_buf); +int cca_vdev_update_interface_report (struct pci_dev *pdev);#endif
Signature · 1 line
2.43.0
RFC PATCH v4 12/16 coco: host: arm64: Fetch device measurements via RMI
In reply to Aneesh Kumar K.V (Arm)- define __RHI_DA_VDEV_GET_MEASUREMENTS for guest requests and expose the RMI SMC ID/wrapper for RMI_VDEV_GET_DEV_MEASUREMENTS
- teach the CCA host driver to handle the new guest request by fetching the device measurements from RMM using rmi_vdev_get_device_measurements() and refreshing the cached buffer
- add a helper that submits a DOE work to pull the latest device measurements into the cache
This lets guests request up-to-date device measurements via RHI
--- arch/arm64/include/asm/rmi_cmds.h | 12 +++++ arch/arm64/include/asm/rmi_smc.h | 13 +++++ arch/arm64/include/uapi/asm/rmi-da.h | 8 +++ drivers/virt/coco/arm-cca-host/arm-cca.c | 16 ++++++ drivers/virt/coco/arm-cca-host/rmi-da.c | 68 ++++++++++++++++++++++++ drivers/virt/coco/arm-cca-host/rmi-da.h | 1 + 6 files changed, 118 insertions(+)
arch/arm64/include/asm/rmi_cmds.h +12 -0
@@ -981,4 +981,16 @@ static inline unsigned long rmi_vdev_get_interface_report(unsigned long rd, return res.a0; } +static inline unsigned long +rmi_vdev_get_device_measurements (unsigned long rd,unsigned long pdev_phys, +unsigned long vdev_phys, +unsigned long param_phys) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_VDEV_GET_MEASUREMENTS , + rd, pdev_phys, vdev_phys, param_phys, &res); + +return res.a0; +}#endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/asm/rmi_smc.h +13 -0
@@ -674,4 +674,17 @@ struct rmi_vdev_params { }; }; +#define RMI_VDEV_MEASURE_HASH 0x0 +#define RMI_VDEV_MEASURE_RAW 0x1 +struct rmi_vdev_measurement_params { +union { +u64 flags; +u8 padding0[256 ]; + }; +union { +u8 nonce[32 ]; +u8 padding1[256 ]; + }; +}; +#endif /* __ASM_RMI_SMC_H */
arch/arm64/include/uapi/asm/rmi-da.h +8 -0
@@ -21,4 +21,12 @@ struct arm64_vdev_object_read_guest_req {/* No arguments to this guest request */ #define __RHI_DA_VDEV_UPDATE_INTERFACE_REPORT 0x3 +struct arm64_vdev_device_measurement_guest_req { +__u32 req_type; +__u32 reserved; +__aligned_u64 flags; +__aligned_u64 nonce; +}; +#define __RHI_DA_VDEV_UPDATE_MEASUREMENTS 0x4 +#endif
drivers/virt/coco/arm-cca-host/arm-cca.c +16 -0
@@ -565,6 +565,22 @@ static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, enum pci_tsm_req_scope sco {return cca_vdev_update_interface_report (pdev); } +case __RHI_DA_VDEV_UPDATE_MEASUREMENTS: + { +int ret; +struct arm64_vdev_device_measurement_guest_req req_obj; + +if (req_len !=sizeof (req_obj)) +return -EINVAL ; + +if (copy_from_user ((void *)&req_obj, req.user, req_len)) +return -EFAULT ; + + ret =cca_vdev_update_device_measurements (pdev, + req_obj.flags, + (u8 *)req_obj.nonce); +return ret; + }default :return -EINVAL ; }
drivers/virt/coco/arm-cca-host/rmi-da.c +68 -0
71 lines not on this page · raw message
drivers/virt/coco/arm-cca-host/rmi-da.h +1 -0
@@ -249,5 +249,6 @@ int cca_vdev_get_object_size(struct pci_dev *pdev, int type);int cca_vdev_read_cached_object (struct pci_dev *pdev,int type,unsigned long offset,unsigned long max_len,void __user *user_buf);int cca_vdev_update_interface_report (struct pci_dev *pdev); +int cca_vdev_update_device_measurements (struct pci_dev *pdev,unsigned long flags,u8 *nonce);#endif
Signature · 1 line
2.43.0
RFC PATCH v4 13/16 coco: host: KVM: arm64: Handle vdev validate-mapping exits
In reply to Aneesh Kumar K.V (Arm)Add the RMM/RHI definitions needed for device-memory mapping exits and plumb them through the arm64 Realm host stack.
Teach KVM to handle RMI_EXIT_VDEV_VALIDATE_MAPPING by exposing the request to userspace as KVM_EXIT_ARM64_TIO, carrying the vdev id together with the GPA range and host PA supplied by RMM. On re-entry, complete the request with RMI_RTT_DEV_VALIDATE.
Also add realm_dev_mem_map() so the host CCA driver can install device-memory mappings for a vdev, and wire the PCI TSM state-change request path to call it.
--- Documentation/virt/kvm/api.rst | 20 +++ arch/arm64/include/asm/kvm_rmi.h | 4 + arch/arm64/include/asm/rmi_smc.h | 2 + arch/arm64/include/uapi/asm/rmi-da.h | 9 ++ arch/arm64/kvm/rmi-exit.c | 37 +++++ arch/arm64/kvm/rmi.c | 189 +++++++++++++++++++++++ drivers/virt/coco/arm-cca-host/arm-cca.c | 27 ++++ drivers/virt/coco/arm-cca-host/rmi-da.c | 21 +++ drivers/virt/coco/arm-cca-host/rmi-da.h | 2 + include/uapi/linux/kvm.h | 11 ++ 10 files changed, 322 insertions(+)
Documentation/virt/kvm/api.rst +20 -0
@@ -7454,6 +7454,26 @@ the ``KVM_EXIT_ARM_SEA_FLAG_GPA_VALID`` flag is set. Otherwise, the value of ``gpa`` is unknown. :: + /* KVM_EXIT_ARM64_TIO*/ + struct { + __u64 flags; + __u64 nr; + __u64 vdev_id; + __u64 gpa_base; + __u64 gpa_top; + __u64 pa_base; + __u64 response; + } cca_exit; + +Used on arm64 systems. When the VM capability ``KVM_CAP_ARM_RMI`` is +enabled, KVM generates a VM exit whenever the guest needs host assistance +to validate a device-memory GPA-to-PA mapping. The ``nr`` field records +the exit reason; currently the following values are defined: + +* ``RMI_EXIT_VDEV_VALIDATE_MAPPING``: the guest wants the host to validate or install a + device-memory mapping. + +The ``flags`` field must be zero. /* Fix the size of the union. */ char padding[256];
arch/arm64/include/asm/kvm_rmi.h +4 -0
@@ -126,4 +126,8 @@ static inline bool kvm_realm_is_private_address(struct realm *realm, return !(addr & BIT(realm->ia_bits - 1)); } +int realm_dev_mem_map (struct kvm *kvm,unsigned long pdev_phys, +unsigned long vdev_phys,unsigned long start_ipa, +unsigned long end_ipa,unsigned long start_pa); +#endif /* __ASM_KVM_RMI_H */
arch/arm64/include/asm/rmi_smc.h +2 -0
@@ -328,6 +328,7 @@ struct rec_params {#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_DEV_MEM_RESPONSE BIT(6)#define REC_RUN_GPRS 31#define REC_MAX_GIC_NUM_LRS 16
@@ -360,6 +361,7 @@ struct rec_enter {#define RMI_EXIT_RIPAS_CHANGE 0x04#define RMI_EXIT_HOST_CALL 0x05#define RMI_EXIT_SERROR 0x06 +#define RMI_EXIT_VDEV_VALIDATE_MAPPING 0x09 struct rec_exit { union { /* 0x000 */
arch/arm64/include/uapi/asm/rmi-da.h +9 -0
@@ -29,4 +29,13 @@ struct arm64_vdev_device_measurement_guest_req { };#define __RHI_DA_VDEV_UPDATE_MEASUREMENTS 0x4 +struct arm64_vdev_device_memmap_guest_req { +__u32 req_type; +__u32 reserved; +__aligned_u64 gpa_base; +__aligned_u64 gpa_top; +__aligned_u64 pa_base; +}; +#define __REC_DA_VDEV_MAP 0x5 +#endif
arch/arm64/kvm/rmi-exit.c +37 -0
@@ -129,6 +129,41 @@ static int rec_exit_host_call(struct kvm_vcpu *vcpu)return kvm_smccc_call_handler (vcpu); } +static inline void kvm_prepare_vdev_validate_mapping_exit (struct kvm_vcpu *vcpu, +gpa_t gpa_base,gpa_t gpa_top, +hpa_t pa_base,unsigned long vdev_id) +{ + vcpu->run->exit_reason =KVM_EXIT_ARM64_TIO ; + vcpu->run->cca_exit.nr =RMI_EXIT_VDEV_VALIDATE_MAPPING ; + vcpu->run->cca_exit.vdev_id = vdev_id; + vcpu->run->cca_exit.flags =0 ; + vcpu->run->cca_exit.gpa_base = gpa_base; + vcpu->run->cca_exit.gpa_top = gpa_top; + vcpu->run->cca_exit.pa_base = pa_base; + vcpu->run->cca_exit.response =0 ; +} + +static int rec_exit_vdev_validate_mapping (struct kvm_vcpu *vcpu) +{ +struct kvm *kvm = vcpu->kvm; +struct realm *realm = &kvm->arch.realm; +struct realm_rec *rec = &vcpu->arch.rec; +unsigned long base = rec->run->exit.dev_mem_base; +unsigned long top = rec->run->exit.dev_mem_top; + +if (!kvm_realm_is_private_address (realm, base) || + !kvm_realm_is_private_address (realm, top -1 )) { + + vcpu->run->cca_exit.response = -EINVAL ; +/* return to guest */ +return 1 ; + } + +kvm_prepare_vdev_validate_mapping_exit (vcpu, base, top, rec->run->exit.dev_mem_pa, + rec->run->exit.vdev_id_1); +return 0 ; +} +static void update_arch_timer_irq_lines (struct kvm_vcpu *vcpu) {struct realm_rec *rec = &vcpu->arch.rec;
@@ -198,6 +233,8 @@ int handle_rec_exit(struct kvm_vcpu *vcpu, int rec_run_ret)return rec_exit_ripas_change (vcpu);case RMI_EXIT_HOST_CALL :return rec_exit_host_call (vcpu); +case RMI_EXIT_VDEV_VALIDATE_MAPPING : +return rec_exit_vdev_validate_mapping (vcpu); } kvm_pr_unimpl("Unsupported exit reason: %u\n",
arch/arm64/kvm/rmi.c +189 -0
201 lines not on this page · raw message
drivers/virt/coco/arm-cca-host/arm-cca.c +27 -0
@@ -585,6 +585,33 @@ static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, enum pci_tsm_req_scope scoreturn -EINVAL ; } } +case PCI_TSM_REQ_STATE_CHANGE : + { +u32 req_type; + +if (get_user (req_type, (u32 __user *)req.user)) +return -EFAULT ; + +switch (req_type) { + +case __REC_DA_VDEV_MAP: + { +struct arm64_vdev_device_memmap_guest_req req_obj; + +if (req_len !=sizeof (req_obj)) +return -EINVAL ; + +if (copy_from_user ((void *)&req_obj, req.user, req_len)) +return -EFAULT ; + +return cca_vdev_device_map (pdev, req_obj.gpa_base, + req_obj.gpa_top, + req_obj.pa_base); + } +default : +return -EINVAL ; + } + }default :return -EINVAL ; }
drivers/virt/coco/arm-cca-host/rmi-da.c +21 -0
@@ -1377,3 +1377,24 @@ int cca_vdev_update_device_measurements(struct pci_dev *pdev, unsigned long flag/* get and update the interface report cache. */ return vdev_update_device_measurements_cache (pdev); } + +int cca_vdev_device_map (struct pci_dev *pdev,unsigned long gpa_base, +unsigned long gpa_top,unsigned long pa_base) +{ +struct kvm *kvm; +struct realm *realm; +phys_addr_t rmm_pdev_phys; +phys_addr_t rmm_vdev_phys; +struct cca_host_tdi *host_tdi; +struct cca_host_pdev_dsc *pdev_dsc; + + host_tdi =to_cca_host_tdi (pdev); + pdev_dsc =to_cca_pdev_dsc (pdev->tsm->dsm_dev); + kvm = host_tdi->tdi.kvm; + realm = &kvm->arch.realm; + rmm_vdev_phys =virt_to_phys (host_tdi->rmm_vdev); + rmm_pdev_phys =virt_to_phys (pdev_dsc->rmm_pdev); + +return realm_dev_mem_map (kvm, rmm_pdev_phys, rmm_vdev_phys, + gpa_base, gpa_top, pa_base); +}
drivers/virt/coco/arm-cca-host/rmi-da.h +2 -0
@@ -250,5 +250,7 @@ int cca_vdev_read_cached_object(struct pci_dev *pdev, int type, unsigned long of unsigned long max_len, void __user *user_buf);int cca_vdev_update_interface_report (struct pci_dev *pdev);int cca_vdev_update_device_measurements (struct pci_dev *pdev,unsigned long flags,u8 *nonce); +int cca_vdev_device_map (struct pci_dev *pdev,unsigned long gpa_base, +unsigned long gpa_top,unsigned long pa_base);#endif
include/uapi/linux/kvm.h +11 -0
@@ -192,6 +192,7 @@ struct kvm_exit_snp_req_certs {#define KVM_EXIT_ARM_SEA 41#define KVM_EXIT_ARM_LDST64B 42#define KVM_EXIT_SNP_REQ_CERTS 43 +#define KVM_EXIT_ARM64_TIO 44/* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */
@@ -496,6 +497,16 @@ struct kvm_run { } arm_sea;/* KVM_EXIT_SNP_REQ_CERTS */ struct kvm_exit_snp_req_certs snp_req_certs; +/* KVM_EXIT_ARM64_TIO*/ +struct { +__u64 flags; +__u64 nr; +__u64 vdev_id; +__u64 gpa_base; +__u64 gpa_top;/* input and output */ +__u64 pa_base; +__u64 response; + } cca_exit;/* Fix the size of the union. */ char padding[256 ]; };
Signature · 1 line
2.43.0
RFC PATCH v4 14/16 KVM: arm64: Unmap device mappings when a private granule is destroyed
In reply to Aneesh Kumar K.V (Arm)Ensure tearing down a private granule also tears down any RMM device mapping by reading the RTT entry, invoking the new RMI_VDEV_MEM_UNMAP, and remembering the entry’s RIPAS so we only free RAM pages.
Drive the device-unmap path when RIPAS transitions to EMPTY. Also roll back partially built device maps when errors occur.
--- arch/arm64/include/asm/rmi_smc.h | 1 + arch/arm64/kvm/rmi.c | 87 ++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 5 deletions(-)
arch/arm64/include/asm/rmi_smc.h +1 -0
@@ -199,6 +199,7 @@ enum rmi_ripas {RMI_EMPTY =0 ,RMI_RAM =1 ,RMI_DESTROYED =2 , + RMI_DEV = 3, };#define RMI_NO_MEASURE_CONTENT 0
arch/arm64/kvm/rmi.c +82 -5
141 lines not on this page · raw message
Signature · 1 line
2.43.0
RFC PATCH v4 15/16 coco: host: arm64: Transition vdevs to TDISP RUN state
In reply to Aneesh Kumar K.V (Arm)Add host-side support for guest requests that move a vdev into the TDISP RUN state.
Introduce the RMI helper for VDEV_START and a matching guest request payload for VDEV_SET_TDI_STATE. In the host CCA TSM request handler, accept only RHI_DA_TDI_CONFIG_RUN on the state-change path and invoke a new cca_vdev_device_start() helper.
The start helper issues RMI_VDEV_START for the bound pdev/vdev pair and then waits until firmware reports the vdev in the RMI_VDEV_STARTED state before returning to the caller.
--- arch/arm64/include/asm/rmi_cmds.h | 11 +++++++++++ arch/arm64/include/uapi/asm/rmi-da.h | 6 ++++++ drivers/virt/coco/arm-cca-host/arm-cca.c | 15 +++++++++++++++ drivers/virt/coco/arm-cca-host/rmi-da.c | 22 ++++++++++++++++++++++ drivers/virt/coco/arm-cca-host/rmi-da.h | 1 + 5 files changed, 55 insertions(+)
arch/arm64/include/asm/rmi_cmds.h +11 -0
@@ -993,4 +993,15 @@ rmi_vdev_get_device_measurements(unsigned long rd, unsigned long pdev_phys, return res.a0; } + +static inline unsigned long rmi_vdev_start (unsigned long rd,unsigned long pdev_phys, +unsigned long vdev_phys) +{ +struct arm_smccc_res res; + +arm_smccc_1_1_invoke (SMC_RMI_VDEV_START , rd, pdev_phys, vdev_phys, &res); + +return res.a0; +} +#endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/uapi/asm/rmi-da.h +6 -0
@@ -38,4 +38,10 @@ struct arm64_vdev_device_memmap_guest_req { };#define __REC_DA_VDEV_MAP 0x5 +struct arm64_vdev_set_tdi_state_guest_req { +__u32 req_type; +__u32 tdi_state; +}; +#define __RHI_DA_VDEV_SET_TDI_STATE 0x6 +#endif
drivers/virt/coco/arm-cca-host/arm-cca.c +15 -0
@@ -608,6 +608,21 @@ static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, enum pci_tsm_req_scope sco req_obj.gpa_top, req_obj.pa_base); } +case __RHI_DA_VDEV_SET_TDI_STATE: + { +struct arm64_vdev_set_tdi_state_guest_req req_obj; + +if (req_len !=sizeof (req_obj)) +return -EINVAL ; + +if (copy_from_user ((void *)&req_obj, req.user, req_len)) +return -EFAULT ; + +if (req_obj.tdi_state !=RHI_DA_TDI_CONFIG_RUN ) +return -EINVAL ; + +return cca_vdev_device_start (pdev); + }default :return -EINVAL ; }
drivers/virt/coco/arm-cca-host/rmi-da.c +22 -0
@@ -1398,3 +1398,25 @@ int cca_vdev_device_map(struct pci_dev *pdev, unsigned long gpa_base,return realm_dev_mem_map (kvm, rmm_pdev_phys, rmm_vdev_phys, gpa_base, gpa_top, pa_base); } + +int cca_vdev_device_start (struct pci_dev *pdev) +{ +phys_addr_t rmm_pdev_phys; +phys_addr_t rmm_vdev_phys; +struct cca_host_pdev_dsc *pdev_dsc; +struct cca_host_tdi *host_tdi; +struct realm *realm; +phys_addr_t rd_phys; + + host_tdi =to_cca_host_tdi (pdev); + rmm_vdev_phys =virt_to_phys (host_tdi->rmm_vdev); + realm = &host_tdi->tdi.kvm->arch.realm; + rd_phys =virt_to_phys (realm->rd); + + pdev_dsc =to_cca_pdev_dsc (pdev->tsm->dsm_dev); + rmm_pdev_phys =virt_to_phys (pdev_dsc->rmm_pdev); + +if (rmi_vdev_start (rd_phys, rmm_pdev_phys, rmm_vdev_phys)) +return -ENXIO ; +return submit_vdev_state_transition_work (pdev,RMI_VDEV_STARTED ); +}
drivers/virt/coco/arm-cca-host/rmi-da.h +1 -0
@@ -252,5 +252,6 @@ int cca_vdev_update_interface_report(struct pci_dev *pdev);int cca_vdev_update_device_measurements (struct pci_dev *pdev,unsigned long flags,u8 *nonce);int cca_vdev_device_map (struct pci_dev *pdev,unsigned long gpa_base,unsigned long gpa_top,unsigned long pa_base); +int cca_vdev_device_start (struct pci_dev *pdev);#endif
Signature · 1 line
2.43.0
RFC PATCH v4 16/16 KVM: arm64: CCA: enable DA in realm create parameters
In reply to Aneesh Kumar K.V (Arm)Now that we have all the required steps for DA in-place, enable DA while creating realm.
--- arch/arm64/include/asm/rmi_smc.h | 1 + arch/arm64/kvm/rmi.c | 3 +++ 2 files changed, 4 insertions(+)
arch/arm64/include/asm/rmi_smc.h +1 -0
@@ -268,6 +268,7 @@ struct rmm_config {#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) struct realm_params { union { /* 0x0 */
arch/arm64/kvm/rmi.c +3 -0
@@ -691,6 +691,9 @@ static int realm_create_rd(struct kvm *kvm)if (r) goto out_undelegate_tables; +/* For now default enable DA */ +if (rmm_has_reg2_feature (RMI_FEATURE_REGISTER_2_DA )) + params->flags |=RMI_REALM_PARAM_FLAG_DA ; params_phys =virt_to_phys (params);if (rmi_realm_create (rd_phys, params_phys)) {
Signature · 1 line
2.43.0
Jason Gunthorpe
maintainerQuoted 5 lines · Aneesh Kumar K.V (Arm)
This patch series implements the host-side changes needed for end-to-end Arm CCA TDISP setup. It adds the RMI/RHI plumbing required to create and manage Realm vdev objects, service device-attestation object requests, and complete the KVM/RMM flows needed for device run-time transitions.
So this is enough for the realm to see a physical PCI device inside it without any vSMMU inside the realm?
It is really weird to see a viommu for a case where there is no viommu..
It doesn't do anything except manage memory for the RMM..
It feels wrong that the arm-cca-guest module is calling RMI_PDEV_CREATE and RMI_VDEV_CREATE while the viommu is allocating STE memory for the PDEV. That doesn't make alot of sense? The STE is needed before VDEV_CREATE, right? So why not place it there in the flow?
If that's changed then the only thing the viommu does is manage the PSMMU, which again, seems like something VDEV_CREATE needs, so why is a viommu involved at all?
The smmu driver involvment would be much smaller if it was only the interrupt routing and some helper to return the psmmu addr for a struct device that the arm-cc-guest module can call to manage the psmmu?
But I'm also sitting here scratching my head a bit, did the tsm_ops design go the wrong way? Should we have run more of that through a viommu instead of tsm_ops? Bind is sort of an illogical operation without a viommu, even if it is a nop viommu.
I suppose it depends what it looks like when a real vsmmu is created.. That probably needs a special viommu object, and do we get into order problems if the lifecylce becomes split to tsm and viommu?
Quoted 11 lines
RHI v1.0 BET1 specification [5].
At a high level, the series adds support for:
- host-side vdev communication and lifecycle management
- host handling of RHI DA object read/size requests
- host-side fetching and caching of interface reports and measurements
- KVM handling of vdev request/complete exits
- KVM handling of map/validation exits and teardown on granule destroy
- vdev transition to TDISP RUN state
- enabling DA in Realm create parameters
Quoted 3 lines
The series builds upon the TSM framework patches posted at [2] and depends on the KVM CCA patchset [3]. A git repository containing all related changes is available at [4]. kvmtool repo is at [6]
It looks like it also needs the series that adds bind to iommufd too
Jason
Quoted 10 lines · Jason Gunthorpe
Quoted 5 lines · Aneesh Kumar K.V (Arm)
This patch series implements the host-side changes needed for end-to-end Arm CCA TDISP setup. It adds the RMI/RHI plumbing required to create and manage Realm vdev objects, service device-attestation object requests, and complete the KVM/RMM flows needed for device run-time transitions.
So this is enough for the realm to see a physical PCI device inside it without any vSMMU inside the realm?
There are multiple series, and this is the final one:
1. arm-cca-guest series
2. arm-cca-host IDE setup series
3. iommufd interface for TSM operations
4. arm-cca-host TDISP support (this series)
Quoted 4 lines
It is really weird to see a viommu for a case where there is no viommu..
We ended up with a viommu despite having no stage-1 SMMU or vSMMU because it held the KVM reference needed by item (3) above [1]. With the recent changes in that series [2], we now inherit the KVM details from VFIO through iommufd_device_bind. I can possibly look at using the idev for this instead.
[1] https://lore.kernel.org/all/[email protected]
[2] https://lore.kernel.org/all/[email protected]
Quoted 8 lines
It doesn't do anything except manage memory for the RMM..
It feels wrong that the arm-cca-guest module is calling
RMI_PDEV_CREATEandRMI_VDEV_CREATEwhile the viommu is allocating STE memory for the PDEV. That doesn't make alot of sense? The STE is needed beforeVDEV_CREATE, right? So why not place it there in the flow?
Quoted 4 lines
If that's changed then the only thing the viommu does is manage the PSMMU, which again, seems like something
VDEV_CREATEneeds, so why is a viommu involved at all?
We do not have a separate vdev-create operation; instead, we have tsm_bind. The required iommufd objects (idev/viommu) are set up before tsm_bind.
Currently, the primary reason for having a viommu is to obtain the KVM reference. Now that the KVM details are inherited from VFIO through iommufd_device_bind(), I can look at using the idev instead and dropping the viommu requirement.
Quoted 6 lines
The smmu driver involvment would be much smaller if it was only the interrupt routing and some helper to return the psmmu addr for a struct device that the arm-cc-guest module can call to manage the psmmu?
I designed this so that the PSMMU details are managed by the arm-smmu driver, with minimal involvement from arm-cca-host. If the arm-smmu driver does not set up the PSMMU correctly, tsm_bind, which is handled by arm-cca-host, can fail.
Quoted 20 lines
But I'm also sitting here scratching my head a bit, did the
tsm_opsdesign go the wrong way? Should we have run more of that through a viommu instead oftsm_ops? Bind is sort of an illogical operation without a viommu, even if it is a nop viommu.I suppose it depends what it looks like when a real vsmmu is created.. That probably needs a special viommu object, and do we get into order problems if the lifecylce becomes split to tsm and viommu?
Quoted 11 lines
RHI v1.0 BET1 specification [5].
At a high level, the series adds support for:
- host-side vdev communication and lifecycle management
- host handling of RHI DA object read/size requests
- host-side fetching and caching of interface reports and measurements
- KVM handling of vdev request/complete exits
- KVM handling of map/validation exits and teardown on granule destroy
- vdev transition to TDISP RUN state
- enabling DA in Realm create parameters
Quoted 7 lines
Quoted 3 lines
The series builds upon the TSM framework patches posted at [2] and depends on the KVM CCA patchset [3]. A git repository containing all related changes is available at [4]. kvmtool repo is at [6]
It looks like it also needs the series that adds bind to iommufd too
Jason
-aneesh
Jason Gunthorpe
maintainerQuoted 8 lines · Aneesh Kumar K.V
Quoted 2 lines
It is really weird to see a viommu for a case where there is no viommu..
We ended up with a viommu despite having no stage-1 SMMU or vSMMU because it held the KVM reference needed by item (3) above [1]. With the recent changes in that series [2], we now inherit the KVM details from VFIO through
iommufd_device_bind. I can possibly look at using the idev for this instead.
Okay, that's a good reason, but the whole thing just doesn't seem split right. There is code in arm-cca-guest and code in the viommu that are all working on the same thing. I don't think it makes logical sense split like this.
The viommu should be creating the vdev at the logical point in its flow, when the it creates its vdevice. It shouldn't be disjoint and separated.
Quoted 8 lines
Quoted 8 lines
It doesn't do anything except manage memory for the RMM..
It feels wrong that the arm-cca-guest module is calling
RMI_PDEV_CREATEandRMI_VDEV_CREATEwhile the viommu is allocating STE memory for the PDEV. That doesn't make alot of sense? The STE is needed beforeVDEV_CREATE, right? So why not place it there in the flow?
Quoted 7 lines
Quoted 3 lines
If that's changed then the only thing the viommu does is manage the PSMMU, which again, seems like something
VDEV_CREATEneeds, so why is a viommu involved at all?We do not have a separate vdev-create operation; instead, we have
tsm_bind. The required iommufd objects (idev/viommu) are set up beforetsm_bind.
You end up with *two* "vdev creation" operations, one through the new bind iommufd call and another through the actual vdevice create iommufd call, and they go do different modules. That seems like a messy flow.
If we are commited to a viommu then lets use the viommu for everything and have less code in arm-cca-guest. Get rid of bind as a tsm operation. Have the smmu driver do it when it creates the vdevice.
You can't call RMI_VDEV_CREATE outside the viommu anyhow as the vdev_id comes from the iommufd vdevice object's vsid.
This is probably going to work better long term anyhow as we can construct the vsmmu with exactly the same API surface, and a non-vsmmu case is really just some special variation of the viommu object that doesn't create do a RMI_VSMMU_CREATE.
Also, is it really OK to setup the psmmu after creating the pdev? RMM spec explicitly says that order is allowed? It is a litle bit counter intuitive.
Jason