Cortex-M0+ implementations may provide an Armv6-M PMSA MPU with eight
regions. QEMU uses its historical v7m/PMSAv7 naming for M-profile code
shared by v6-M and v7-M, but currently exposes, allocates and migrates the
existing region model only when ARM_FEATURE_V7 is set. This prevents a
Cortex-M0+ board from enabling its optional MPU.

Allow non-v8 M-profile CPUs to use the existing PMSAv7 state, migration
state and translation path. Restrict the shared register model to the v6-M
layout: do not expose the v7-M alias registers or TEX bits, and reject
region sizes below the v6-M minimum of 256 bytes.

The dedicated PMSAv8 path remains selected first for v8-M CPUs. Expose the
pmsav7-dregion property and clear region state on reset.

Signed-off-by: gilles grimaud <[email protected]>
---
 hw/intc/armv7m_nvic.c | 27 ++++++++++++++++++++++++++-
 target/arm/cpu.c      | 12 +++++++++---
 target/arm/machine.c  |  3 ++-
 target/arm/ptw.c      | 10 +++++++---
 4 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index c1ceb7450f..a702bd0c38 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -1405,6 +1405,11 @@ static uint32_t nvic_readl(NVICState *s, uint32_t 
offset, MemTxAttrs attrs)
             return cpu->env.pmsav8.rbar[attrs.secure][region];
         }
 
+        if (offset != 0xd9c &&
+            !arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            goto bad_offset;
+        }
+
         if (region >= cpu->pmsav7_dregion) {
             return 0;
         }
@@ -1432,6 +1437,11 @@ static uint32_t nvic_readl(NVICState *s, uint32_t 
offset, MemTxAttrs attrs)
             return cpu->env.pmsav8.rlar[attrs.secure][region];
         }
 
+        if (offset != 0xda0 &&
+            !arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            goto bad_offset;
+        }
+
         if (region >= cpu->pmsav7_dregion) {
             return 0;
         }
@@ -1919,6 +1929,11 @@ static void nvic_writel(NVICState *s, uint32_t offset, 
uint32_t value,
             return;
         }
 
+        if (offset != 0xd9c &&
+            !arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            goto bad_offset;
+        }
+
         if (value & (1 << 4)) {
             /* VALID bit means use the region number specified in this
              * value and also update MPU_RNR.REGION with that value.
@@ -1969,12 +1984,22 @@ static void nvic_writel(NVICState *s, uint32_t offset, 
uint32_t value,
             return;
         }
 
+        if (offset != 0xda0 &&
+            !arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            goto bad_offset;
+        }
+
         if (region >= cpu->pmsav7_dregion) {
             return;
         }
 
         cpu->env.pmsav7.drsr[region] = value & 0xff3f;
-        cpu->env.pmsav7.dracr[region] = (value >> 16) & 0x173f;
+        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+            cpu->env.pmsav7.dracr[region] = (value >> 16) & 0x173f;
+        } else {
+            /* Armv6-M has XN, AP, S, C and B, but no TEX field. */
+            cpu->env.pmsav7.dracr[region] = (value >> 16) & 0x1707;
+        }
         tlb_flush(CPU(cpu));
         break;
     }
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 77aa78f00e..f58a1db843 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -617,7 +617,8 @@ static void arm_cpu_reset_hold(Object *obj, ResetType type)
                            sizeof(*env->pmsav8.rlar[M_REG_S])
                            * cpu->pmsav7_dregion);
                 }
-            } else if (arm_feature(env, ARM_FEATURE_V7)) {
+            } else if (arm_feature(env, ARM_FEATURE_V7) ||
+                       arm_feature(env, ARM_FEATURE_M)) {
                 memset(env->pmsav7.drbar, 0,
                        sizeof(*env->pmsav7.drbar) * cpu->pmsav7_dregion);
                 memset(env->pmsav7.drsr, 0,
@@ -1656,7 +1657,11 @@ static void arm_cpu_post_init(Object *obj)
 #ifndef CONFIG_USER_ONLY
     if (arm_feature(&cpu->env, ARM_FEATURE_PMSA)) {
         qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property);
-        if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
+        /*
+         * QEMU's PMSAv7 state also models the Armv6-M MPU register layout.
+         */
+        if (arm_feature(&cpu->env, ARM_FEATURE_V7) ||
+            arm_feature(&cpu->env, ARM_FEATURE_M)) {
             qdev_property_add_static(DEVICE(obj),
                                      &arm_cpu_pmsav7_dregion_property);
         }
@@ -2332,7 +2337,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error 
**errp)
     }
 
     if (arm_feature(env, ARM_FEATURE_PMSA) &&
-        arm_feature(env, ARM_FEATURE_V7)) {
+        (arm_feature(env, ARM_FEATURE_V7) ||
+         arm_feature(env, ARM_FEATURE_M))) {
         uint32_t nr = cpu->pmsav7_dregion;
 
         if (nr > 0xff) {
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 7005f4e5d7..53a2734d25 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -584,7 +584,8 @@ static bool pmsav7_needed(void *opaque)
     CPUARMState *env = &cpu->env;
 
     return arm_feature(env, ARM_FEATURE_PMSA) &&
-           arm_feature(env, ARM_FEATURE_V7) &&
+           (arm_feature(env, ARM_FEATURE_V7) ||
+            arm_feature(env, ARM_FEATURE_M)) &&
            !arm_feature(env, ARM_FEATURE_V8);
 }
 
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index a29de0385f..6cb8a8394a 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -2748,9 +2748,12 @@ static bool get_phys_addr_pmsav7(CPUARMState *env,
                 continue;
             }
 
-            if (!rsize) {
+            if (!rsize ||
+                (arm_feature(env, ARM_FEATURE_M) &&
+                 !arm_feature(env, ARM_FEATURE_V7) && rsize < 7)) {
                 qemu_log_mask(LOG_GUEST_ERROR,
-                              "DRSR[%d]: Rsize field cannot be 0\n", n);
+                              "DRSR[%d]: invalid Rsize field 0x%x\n",
+                              n, rsize);
                 continue;
             }
             rsize++;
@@ -3901,7 +3904,8 @@ static bool get_phys_addr_nogpc(CPUARMState *env, 
S1Translate *ptw,
             /* PMSAv8 */
             ret = get_phys_addr_pmsav8(env, ptw, address, access_type,
                                        result, fi);
-        } else if (arm_feature(env, ARM_FEATURE_V7)) {
+        } else if (arm_feature(env, ARM_FEATURE_V7) ||
+                   arm_feature(env, ARM_FEATURE_M)) {
             /* PMSAv7 */
             ret = get_phys_addr_pmsav7(env, ptw, address, access_type,
                                        result, fi);
-- 
2.55.0


Reply via email to