From: gilles grimaud <[email protected]>

Cortex-M0+ implementations may provide an Armv6 PMSA MPU with eight regions. 
QEMU already marks M-profile CPUs as PMSA, but only exposes and allocates the 
existing region model for Armv7 CPUs. This prevents a Cortex-M0+ board from 
enabling its optional MPU.

Use QEMU's PMSAv7 state and translation path for the compatible Armv6-M MPU 
register layout. Permit CONTROL.nPRIV changes when the optional MPU is present 
and clear the region state on reset.

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

diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index a7651f831e..3140599ac1 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -1626,6 +1626,9 @@ static void nvic_writel(NVICState *s, uint32_t offset, 
uint32_t value,
         break;
     case 0xd08: /* Vector Table Offset.  */
         cpu->env.v7m.vecbase[attrs.secure] = value & 0xffffff80;
+        if (!arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) {
+            cpu->env.v7m.vecbase[!attrs.secure] = value & 0xffffff80;
+        }
         break;
     case 0xd0c: /* Application Interrupt/Reset Control (AIRCR) */
         if ((value >> R_V7M_AIRCR_VECTKEY_SHIFT) == 0x05fa) {
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/ptw.c b/target/arm/ptw.c
index a29de0385f..b366a8d3dd 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -3901,7 +3901,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);
diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c
index f4ba93b291..667b2a3cbd 100644
--- a/target/arm/tcg/m_helper.c
+++ b/target/arm/tcg/m_helper.c
@@ -16,6 +16,7 @@
 #include "qemu/bitops.h"
 #include "qemu/log.h"
 #include "exec/page-protection.h"
+#include "exec/cputlb.h"
 #ifdef CONFIG_TCG
 #include "accel/tcg/cpu-ldst-common.h"
 #include "semihosting/common-semi.h"
@@ -2775,9 +2776,16 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, 
uint32_t val)
                            !arm_v7m_is_handler_mode(env))) {
             write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 
0);
         }
-        if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
+        if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_M_MAIN) ||
+                           env_archcpu(env)->has_mpu)) {
+            uint32_t old_control = env->v7m.control[env->v7m.secure];
+
             env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
             env->v7m.control[env->v7m.secure] |= val & 
R_V7M_CONTROL_NPRIV_MASK;
+            if ((old_control ^ env->v7m.control[env->v7m.secure]) &
+                R_V7M_CONTROL_NPRIV_MASK) {
+                tlb_flush(env_cpu(env));
+            }
         }
         if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
             /*
-- 
2.55.0


Reply via email to