[PATCH v2 12/14] hw/arm/smmuv3: Use iommu_index to represent the security context

Tao Tang posted 14 patches 2 days, 23 hours ago
Maintainers: Eric Auger <eric.auger@redhat.com>, Peter Maydell <peter.maydell@linaro.org>
[PATCH v2 12/14] hw/arm/smmuv3: Use iommu_index to represent the security context
Posted by Tao Tang 2 days, 12 hours ago
Resending patches 12–14/14 that were missing due to a send issue. Sorry
for the noise.

The Arm SMMUv3 architecture uses a SEC_SID (Secure StreamID) to select
the programming interface. To support future extensions like RME, which
defines four security states (Non-secure, Secure, Realm, and Root), the
QEMU model must cleanly separate these contexts for all operations.

This commit leverages the generic iommu_index to represent this
security context. The core IOMMU layer now uses the SMMU's .attrs_to_index
callback to map a transaction's ARMSecuritySpace attribute to the
corresponding iommu_index.

This index is then passed down to smmuv3_translate and used throughout
the model to select the correct register bank and processing logic. This
makes the iommu_index the clear QEMU equivalent of the architectural
SEC_SID, cleanly separating the contexts for all subsequent lookups.

Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
 hw/arm/smmuv3.c | 37 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index eec36d5fd2..c92cc0f06a 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1099,6 +1099,38 @@ static void smmuv3_fixup_event(SMMUEventInfo *event, hwaddr iova)
     }
 }

+static SMMUSecurityIndex smmuv3_attrs_to_security_index(MemTxAttrs attrs)
+{
+    switch (attrs.space) {
+    case ARMSS_Secure:
+        return SMMU_SEC_IDX_S;
+    case ARMSS_NonSecure:
+    default:
+        return SMMU_SEC_IDX_NS;
+    }
+}
+
+/*
+ * ARM SMMU IOMMU index mapping (implements SEC_SID from ARM SMMU):
+ * iommu_idx = 0: Non-secure transactions
+ * iommu_idx = 1: Secure transactions
+ *
+ * The iommu_idx parameter effectively implements the SEC_SID
+ * (Security Stream ID) attribute from the ARM SMMU architecture
+ * specification, which allows the SMMU to differentiate between
+ * secure and non-secure transactions at the hardware level.
+ */
+static int smmuv3_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs)
+{
+    return smmuv3_attrs_to_security_index(attrs);
+}
+
+static int smmuv3_num_indexes(IOMMUMemoryRegion *iommu)
+{
+    /* Support 2 IOMMU indexes for now: NS/S */
+    return SMMU_SEC_IDX_NUM;
+}
+
 /* Entry point to SMMU, does everything. */
 static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
                                       IOMMUAccessFlags flag, int iommu_idx)
@@ -1111,7 +1143,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
                            .inval_ste_allowed = false};
     SMMUTranslationStatus status;
     SMMUTransCfg *cfg = NULL;
-    SMMUSecurityIndex sec_idx = SMMU_SEC_IDX_NS;
+    SMMUSecurityIndex sec_idx = iommu_idx;
     IOMMUTLBEntry entry = {
         .target_as = &address_space_memory,
         .iova = addr,
@@ -1155,6 +1187,7 @@ epilogue:
         entry.perm = cached_entry->entry.perm;
         entry.translated_addr = CACHED_ENTRY_TO_ADDR(cached_entry, addr);
         entry.addr_mask = cached_entry->entry.addr_mask;
+        entry.target_as = cached_entry->entry.target_as;
         trace_smmuv3_translate_success(mr->parent_obj.name, sid, addr,
                                        entry.translated_addr, entry.perm,
                                        cfg->stage);
@@ -2534,6 +2567,8 @@ static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass,

     imrc->translate = smmuv3_translate;
     imrc->notify_flag_changed = smmuv3_notify_flag_changed;
+    imrc->attrs_to_index = smmuv3_attrs_to_index;
+    imrc->num_indexes = smmuv3_num_indexes;
 }

 static const TypeInfo smmuv3_type_info = {
--
2.34.1


[PATCH v2 13/14] hw/arm/smmuv3: Add property to enable Secure SMMU support
Posted by Tao Tang 2 days, 12 hours ago
Resending patches 12–14/14 that were missing due to a send issue. Sorry
for the noise.

This commit completes the initial implementation of the Secure SMMUv3
model by making the feature user-configurable.

A new boolean property, "secure-impl", is introduced to the device.
This property defaults to false, ensuring backward compatibility for
existing machine types that do not expect the secure programming
interface.

When "secure-impl" is set to true, the smmuv3_init_regs function now
initializes the secure register bank (bank[SMMU_SEC_IDX_S]). Crucially,
the S_IDR1.SECURE_IMPL bit is set according to this property,
correctly advertising the presence of the secure functionality to the
guest.

This patch ties together all the previous refactoring work. With this
property enabled, the banked registers, security-aware queues, and
other secure features become active, allowing a guest to probe and
configure the Secure SMMU.

Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
 hw/arm/smmuv3.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index c92cc0f06a..80fbc25cf5 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -351,6 +351,16 @@ static void smmuv3_init_regs(SMMUv3State *s)
     s->statusr = 0;
     s->bank[SMMU_SEC_IDX_NS].gbpa = SMMU_GBPA_RESET_VAL;

+    /* Initialize Secure bank (SMMU_SEC_IDX_S) */
+    memset(s->bank[SMMU_SEC_IDX_S].idr, 0, sizeof(s->bank[SMMU_SEC_IDX_S].idr));
+    s->bank[SMMU_SEC_IDX_S].idr[1] = FIELD_DP32(s->bank[SMMU_SEC_IDX_S].idr[1],
+                                                S_IDR1, SECURE_IMPL,
+                                                s->secure_impl);
+    s->bank[SMMU_SEC_IDX_S].idr[1] = FIELD_DP32(
+        s->bank[SMMU_SEC_IDX_S].idr[1], IDR1, SIDSIZE, SMMU_IDR1_SIDSIZE);
+    s->bank[SMMU_SEC_IDX_S].gbpa = SMMU_GBPA_RESET_VAL;
+    s->bank[SMMU_SEC_IDX_S].cmdq.entry_size = sizeof(struct Cmd);
+    s->bank[SMMU_SEC_IDX_S].eventq.entry_size = sizeof(struct Evt);
 }

 static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
@@ -2505,6 +2515,12 @@ static const Property smmuv3_properties[] = {
      * Defaults to stage 1
      */
     DEFINE_PROP_STRING("stage", SMMUv3State, stage),
+    /*
+     * SECURE_IMPL field in S_IDR1 register.
+     * Indicates whether secure state is implemented.
+     * Defaults to false (0)
+     */
+    DEFINE_PROP_BOOL("secure-impl", SMMUv3State, secure_impl, false),
 };

 static void smmuv3_instance_init(Object *obj)
--
2.34.1


[PATCH v2 14/14] hw/arm/smmuv3: Optional Secure bank migration via subsections
Posted by Tao Tang 2 days, 12 hours ago
Resending patches 12–14/14 that were missing due to a send issue. Sorry
for the noise.

Introduce a generic vmstate_smmuv3_bank that serializes a single SMMUv3
bank (registers and queues). Add a 'smmuv3/bank_s' subsection guarded by
secure_impl and a new 'migrate-secure-bank' property; when enabled, the S
bank is migrated. Add a 'smmuv3/gbpa_secure' subsection which is only sent
when GBPA differs from its reset value.

This keeps the existing migration stream unchanged by default and remains
backward compatible: older QEMUs can ignore unknown subsections, and with
'migrate-secure-bank' defaulting to off, the stream is identical to before.

This also prepares for future RME extensions (Realm/Root) by reusing the
bank subsection pattern.

Usage:
  -global arm-smmuv3,secure-impl=on,migrate-secure-bank=on

Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
 hw/arm/smmuv3.c         | 70 +++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/smmuv3.h |  1 +
 2 files changed, 71 insertions(+)

diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 80fbc25cf5..2a1e80d179 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -2450,6 +2450,53 @@ static const VMStateDescription vmstate_smmuv3_queue = {
     },
 };

+static const VMStateDescription vmstate_smmuv3_bank = {
+    .name = "smmuv3_bank",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32(features, SMMUv3RegBank),
+        VMSTATE_UINT8(sid_split, SMMUv3RegBank),
+        VMSTATE_UINT32_ARRAY(cr, SMMUv3RegBank, 3),
+        VMSTATE_UINT32(cr0ack, SMMUv3RegBank),
+        VMSTATE_UINT32(irq_ctrl, SMMUv3RegBank),
+        VMSTATE_UINT32(gerror, SMMUv3RegBank),
+        VMSTATE_UINT32(gerrorn, SMMUv3RegBank),
+        VMSTATE_UINT64(gerror_irq_cfg0, SMMUv3RegBank),
+        VMSTATE_UINT32(gerror_irq_cfg1, SMMUv3RegBank),
+        VMSTATE_UINT32(gerror_irq_cfg2, SMMUv3RegBank),
+        VMSTATE_UINT64(strtab_base, SMMUv3RegBank),
+        VMSTATE_UINT32(strtab_base_cfg, SMMUv3RegBank),
+        VMSTATE_UINT64(eventq_irq_cfg0, SMMUv3RegBank),
+        VMSTATE_UINT32(eventq_irq_cfg1, SMMUv3RegBank),
+        VMSTATE_UINT32(eventq_irq_cfg2, SMMUv3RegBank),
+        VMSTATE_STRUCT(cmdq, SMMUv3RegBank, 0,
+                       vmstate_smmuv3_queue, SMMUQueue),
+        VMSTATE_STRUCT(eventq, SMMUv3RegBank, 0,
+                       vmstate_smmuv3_queue, SMMUQueue),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static bool smmuv3_secure_bank_needed(void *opaque)
+{
+    SMMUv3State *s = opaque;
+
+    return s->secure_impl && s->migrate_secure_bank;
+}
+
+static const VMStateDescription vmstate_smmuv3_bank_s = {
+    .name = "smmuv3/bank_s",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = smmuv3_secure_bank_needed,
+    .fields = (const VMStateField[]) {
+        VMSTATE_STRUCT(bank[SMMU_SEC_IDX_S], SMMUv3State, 0,
+                       vmstate_smmuv3_bank, SMMUv3RegBank),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
 static bool smmuv3_gbpa_needed(void *opaque)
 {
     SMMUv3State *s = opaque;
@@ -2469,6 +2516,25 @@ static const VMStateDescription vmstate_gbpa = {
     }
 };

+static bool smmuv3_gbpa_secure_needed(void *opaque)
+{
+    SMMUv3State *s = opaque;
+
+    return s->secure_impl && s->migrate_secure_bank &&
+           s->bank[SMMU_SEC_IDX_S].gbpa != SMMU_GBPA_RESET_VAL;
+}
+
+static const VMStateDescription vmstate_gbpa_secure = {
+    .name = "smmuv3/gbpa_secure",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = smmuv3_gbpa_secure_needed,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32(bank[SMMU_SEC_IDX_S].gbpa, SMMUv3State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_smmuv3 = {
     .name = "smmuv3",
     .version_id = 1,
@@ -2502,6 +2568,8 @@ static const VMStateDescription vmstate_smmuv3 = {
     },
     .subsections = (const VMStateDescription * const []) {
         &vmstate_gbpa,
+        &vmstate_smmuv3_bank_s,
+        &vmstate_gbpa_secure,
         NULL
     }
 };
@@ -2521,6 +2589,8 @@ static const Property smmuv3_properties[] = {
      * Defaults to false (0)
      */
     DEFINE_PROP_BOOL("secure-impl", SMMUv3State, secure_impl, false),
+    DEFINE_PROP_BOOL("migrate-secure-bank", SMMUv3State,
+                     migrate_secure_bank, false),
 };

 static void smmuv3_instance_init(Object *obj)
diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
index 572f15251e..5ffb609fa2 100644
--- a/include/hw/arm/smmuv3.h
+++ b/include/hw/arm/smmuv3.h
@@ -71,6 +71,7 @@ struct SMMUv3State {
     QemuMutex mutex;
     char *stage;
     bool secure_impl;
+    bool migrate_secure_bank;
 };

 typedef enum {
--
2.34.1