Implement read/write handlers for the SMMU_S_INIT secure-only register.

Writing INV_ALL provides a mechanism for software to perform a global
invalidation of ALL caches within the SMMU, including IOTLBs and
configuration caches across all security states.

The MMIO dispatcher decodes the target register bank from the offset and
normalizes Secure-window offsets by subtracting SMMU_SECURE_REG_START
before switching on the bank-local offset. S_INIT is a Secure-only
register and its A_S_INIT constant is an absolute Secure-window offset,
so the handler matches it using A_S_INIT - SMMU_SECURE_REG_START and
rejects accesses through Non-secure banks.

Signed-off-by: Tao Tang <[email protected]>
Reviewed-by: Pierrick Bouvier <[email protected]>
---
 hw/arm/smmuv3.c     | 43 +++++++++++++++++++++++++++++++++++++++++++
 hw/arm/trace-events |  1 +
 2 files changed, 44 insertions(+)

diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index d69fc0898af..dc3fa618883 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -393,6 +393,21 @@ static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, 
STE *buf,
 
 }
 
+static void smmuv3_invalidate_all_caches(SMMUv3State *s)
+{
+    SMMUState *bs = &s->smmu_state;
+    trace_smmuv3_invalidate_all_caches();
+
+    /* Clear all cached configs including STE and CD */
+    if (bs->configs) {
+        g_hash_table_remove_all(bs->configs);
+    }
+
+    /* Invalidate all SMMU IOTLB entries */
+    smmu_inv_notifiers_all(&s->smmu_state);
+    smmu_iotlb_inv_all(bs);
+}
+
 static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
                                                  SMMUTransCfg *cfg,
                                                  SMMUEventInfo *event,
@@ -2206,7 +2221,29 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr 
offset,
 
         bank->eventq_irq_cfg2 = data;
         break;
+    case A_S_INIT - SMMU_SECURE_REG_START:
+        if (reg_sec_sid != SMMU_SEC_SID_S) {
+            goto unhandled;
+        }
+        if (data & R_S_INIT_INV_ALL_MASK) {
+            /*
+             * If SMMU_ROOT_CR0.GPCEN == 0, a write of 1 to INV_ALL when any
+             * SMMU_(*_)CR0.SMMUEN == 1, .... , is CONSTRAINED UNPREDICTABLE
+             * according to (IHI 0070G.b) 6.3.62 SMMU_S_INIT, Page 465.
+             */
+            if (!smmuv3_smmu_disabled_stable(s, SMMU_SEC_SID_NS) ||
+                !smmuv3_smmu_disabled_stable(s, SMMU_SEC_SID_S)) {
+                /* CONSTRAINED UNPREDICTABLE behavior: Ignore this write */
+                qemu_log_mask(LOG_GUEST_ERROR, "S_INIT write ignored: "
+                              "(S_)CR0.SMMUEN or (S_)CR0ACK.SMMUEN is set\n");
+                return MEMTX_OK;
+            }
+            smmuv3_invalidate_all_caches(s);
+        }
+        /* Synchronous emulation: invalidation completed instantly. */
+        break;
     default:
+    unhandled:
         qemu_log_mask(LOG_UNIMP,
                       "%s Unexpected 32-bit access to 0x%"PRIx64" (WI)\n",
                       __func__, offset);
@@ -2444,6 +2481,12 @@ static MemTxResult smmu_readl(SMMUv3State *s, hwaddr 
offset,
 
         *data = bank->eventq_irq_cfg2;
         return MEMTX_OK;
+    case A_S_INIT - SMMU_SECURE_REG_START:
+        if (reg_sec_sid != SMMU_SEC_SID_S) {
+            goto unhandled;
+        }
+        *data = 0;
+        return MEMTX_OK;
     default:
     unhandled:
         *data = 0;
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index 7cd4eb38578..ac9f737a5e6 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -67,6 +67,7 @@ smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
 smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu 
mr=%s"
 smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu 
mr=%s"
 smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, 
uint8_t tg, uint64_t num_pages, int stage) "iommu mr=%s asid=%d vmid=%d 
iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" stage=%d"
+smmuv3_invalidate_all_caches(void) "Invalidate all SMMU caches and TLBs"
 smmu_reset_exit(void) ""
 
 #smmuv3-accel.c
-- 
2.34.1


Reply via email to