diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 4b1e98284c812a125ac876333fb01ef4d0606627..cadec09ac4e5de96c07518866b1a9ad59c29636e 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2057,8 +2057,9 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, * of the AT/ATS operations. * The values used are carefully arranged to make mmu_idx => EL lookup easy. */ -#define ARM_MMU_IDX_A 0x10 /* A profile (and M profile, for the moment) */ +#define ARM_MMU_IDX_A 0x10 /* A profile */ #define ARM_MMU_IDX_NOTLB 0x20 /* does not have a TLB */ +#define ARM_MMU_IDX_M 0x40 /* M profile */ #define ARM_MMU_IDX_TYPE_MASK (~0x7) #define ARM_MMU_IDX_COREIDX_MASK 0x7 @@ -2071,6 +2072,8 @@ typedef enum ARMMMUIdx { ARMMMUIdx_S1SE0 = 4 | ARM_MMU_IDX_A, ARMMMUIdx_S1SE1 = 5 | ARM_MMU_IDX_A, ARMMMUIdx_S2NS = 6 | ARM_MMU_IDX_A, + ARMMMUIdx_MUser = 0 | ARM_MMU_IDX_M, + ARMMMUIdx_MPriv = 1 | ARM_MMU_IDX_M, /* Indexes below here don't have TLBs and are used only for AT system * instructions or for the first stage of an S12 page table walk. */ @@ -2089,6 +2092,8 @@ typedef enum ARMMMUIdxBit { ARMMMUIdxBit_S1SE0 = 1 << 4, ARMMMUIdxBit_S1SE1 = 1 << 5, ARMMMUIdxBit_S2NS = 1 << 6, + ARMMMUIdxBit_MUser = 1 << 0, + ARMMMUIdxBit_MPriv = 1 << 1, } ARMMMUIdxBit; #define MMU_USER_IDX 0 @@ -2100,7 +2105,11 @@ static inline int arm_to_core_mmu_idx(ARMMMUIdx mmu_idx) static inline ARMMMUIdx core_to_arm_mmu_idx(CPUARMState *env, int mmu_idx) { - return mmu_idx | ARM_MMU_IDX_A; + if (arm_feature(env, ARM_FEATURE_M)) { + return mmu_idx | ARM_MMU_IDX_M; + } else { + return mmu_idx | ARM_MMU_IDX_A; + } } /* Return the exception level we're running at if this is our mmu_idx */ @@ -2109,6 +2118,8 @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx) switch (mmu_idx & ARM_MMU_IDX_TYPE_MASK) { case ARM_MMU_IDX_A: return mmu_idx & 3; + case ARM_MMU_IDX_M: + return mmu_idx & 1; default: g_assert_not_reached(); } @@ -2119,6 +2130,12 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch) { int el = arm_current_el(env); + if (arm_feature(env, ARM_FEATURE_M)) { + ARMMMUIdx mmu_idx = el == 0 ? ARMMMUIdx_MUser : ARMMMUIdx_MPriv; + + return arm_to_core_mmu_idx(mmu_idx); + } + if (el < 2 && arm_is_secure_below_el3(env)) { return arm_to_core_mmu_idx(ARMMMUIdx_S1SE0 + el); } diff --git a/target/arm/helper.c b/target/arm/helper.c index 520adccd75302aacca3fa6af497708305d7c5ac8..791332cb86f14dc258aa1d5a676b2c02a56b2c42 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6992,6 +6992,8 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1SE1: case ARMMMUIdx_S1NSE0: case ARMMMUIdx_S1NSE1: + case ARMMMUIdx_MPriv: + case ARMMMUIdx_MUser: return 1; default: g_assert_not_reached(); @@ -7008,6 +7010,8 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1NSE1: case ARMMMUIdx_S1E2: case ARMMMUIdx_S2NS: + case ARMMMUIdx_MPriv: + case ARMMMUIdx_MUser: return false; case ARMMMUIdx_S1E3: case ARMMMUIdx_S1SE0: @@ -7146,6 +7150,7 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) switch (mmu_idx) { case ARMMMUIdx_S1SE0: case ARMMMUIdx_S1NSE0: + case ARMMMUIdx_MUser: return true; default: return false; diff --git a/target/arm/translate.c b/target/arm/translate.c index 8d509a292988655d37ccb6ffb3b3779eb5da3339..ac905dd8f4d3a39920b8bfd4b89e73f9b4656722 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -161,6 +161,9 @@ static inline int get_a32_user_mem_index(DisasContext *s) case ARMMMUIdx_S1SE0: case ARMMMUIdx_S1SE1: return arm_to_core_mmu_idx(ARMMMUIdx_S1SE0); + case ARMMMUIdx_MUser: + case ARMMMUIdx_MPriv: + return arm_to_core_mmu_idx(ARMMMUIdx_MUser); case ARMMMUIdx_S2NS: default: g_assert_not_reached();