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
