diff options
author | Rémi Denis-Courmont <remi.denis.courmont@huawei.com> | 2021-01-12 12:45:00 +0200 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-01-19 14:38:51 +0000 |
commit | b6ad6062f1e55bd5b9407ce89e55e3a08b83827c (patch) | |
tree | d15eeb1e9e455c1cf82c80cde7e62267237b5a9a | |
parent | 6c85f906261226e87211506bd9f787fd48a09f17 (diff) | |
download | qemu-b6ad6062f1e55bd5b9407ce89e55e3a08b83827c.zip qemu-b6ad6062f1e55bd5b9407ce89e55e3a08b83827c.tar.gz qemu-b6ad6062f1e55bd5b9407ce89e55e3a08b83827c.tar.bz2 |
target/arm: add MMU stage 1 for Secure EL2
This adds the MMU indices for EL2 stage 1 in secure state.
To keep code contained, which is largelly identical between secure and
non-secure modes, the MMU indices are reassigned. The new assignments
provide a systematic pattern with a non-secure bit.
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20210112104511.36576-8-remi.denis.courmont@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | target/arm/cpu-param.h | 2 | ||||
-rw-r--r-- | target/arm/cpu.h | 37 | ||||
-rw-r--r-- | target/arm/helper.c | 127 | ||||
-rw-r--r-- | target/arm/internals.h | 12 | ||||
-rw-r--r-- | target/arm/translate-a64.c | 4 |
5 files changed, 124 insertions, 58 deletions
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index 6321385..00e7d9e 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -29,6 +29,6 @@ # define TARGET_PAGE_BITS_MIN 10 #endif -#define NB_MMU_MODES 11 +#define NB_MMU_MODES 15 #endif diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 22a3c8a..cc1ea58 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3049,6 +3049,9 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync); #define ARM_MMU_IDX_NOTLB 0x20 /* does not have a TLB */ #define ARM_MMU_IDX_M 0x40 /* M profile */ +/* Meanings of the bits for A profile mmu idx values */ +#define ARM_MMU_IDX_A_NS 0x8 + /* Meanings of the bits for M profile mmu idx values */ #define ARM_MMU_IDX_M_PRIV 0x1 #define ARM_MMU_IDX_M_NEGPRI 0x2 @@ -3062,20 +3065,22 @@ typedef enum ARMMMUIdx { /* * A-profile. */ - ARMMMUIdx_E10_0 = 0 | ARM_MMU_IDX_A, - ARMMMUIdx_E20_0 = 1 | ARM_MMU_IDX_A, - - ARMMMUIdx_E10_1 = 2 | ARM_MMU_IDX_A, - ARMMMUIdx_E10_1_PAN = 3 | ARM_MMU_IDX_A, - - ARMMMUIdx_E2 = 4 | ARM_MMU_IDX_A, - ARMMMUIdx_E20_2 = 5 | ARM_MMU_IDX_A, - ARMMMUIdx_E20_2_PAN = 6 | ARM_MMU_IDX_A, - - ARMMMUIdx_SE10_0 = 7 | ARM_MMU_IDX_A, - ARMMMUIdx_SE10_1 = 8 | ARM_MMU_IDX_A, - ARMMMUIdx_SE10_1_PAN = 9 | ARM_MMU_IDX_A, - ARMMMUIdx_SE3 = 10 | ARM_MMU_IDX_A, + ARMMMUIdx_SE10_0 = 0 | ARM_MMU_IDX_A, + ARMMMUIdx_SE20_0 = 1 | ARM_MMU_IDX_A, + ARMMMUIdx_SE10_1 = 2 | ARM_MMU_IDX_A, + ARMMMUIdx_SE20_2 = 3 | ARM_MMU_IDX_A, + ARMMMUIdx_SE10_1_PAN = 4 | ARM_MMU_IDX_A, + ARMMMUIdx_SE20_2_PAN = 5 | ARM_MMU_IDX_A, + ARMMMUIdx_SE2 = 6 | ARM_MMU_IDX_A, + ARMMMUIdx_SE3 = 7 | ARM_MMU_IDX_A, + + ARMMMUIdx_E10_0 = ARMMMUIdx_SE10_0 | ARM_MMU_IDX_A_NS, + ARMMMUIdx_E20_0 = ARMMMUIdx_SE20_0 | ARM_MMU_IDX_A_NS, + ARMMMUIdx_E10_1 = ARMMMUIdx_SE10_1 | ARM_MMU_IDX_A_NS, + ARMMMUIdx_E20_2 = ARMMMUIdx_SE20_2 | ARM_MMU_IDX_A_NS, + ARMMMUIdx_E10_1_PAN = ARMMMUIdx_SE10_1_PAN | ARM_MMU_IDX_A_NS, + ARMMMUIdx_E20_2_PAN = ARMMMUIdx_SE20_2_PAN | ARM_MMU_IDX_A_NS, + ARMMMUIdx_E2 = ARMMMUIdx_SE2 | ARM_MMU_IDX_A_NS, /* * These are not allocated TLBs and are used only for AT system @@ -3122,8 +3127,12 @@ typedef enum ARMMMUIdxBit { TO_CORE_BIT(E20_2), TO_CORE_BIT(E20_2_PAN), TO_CORE_BIT(SE10_0), + TO_CORE_BIT(SE20_0), TO_CORE_BIT(SE10_1), + TO_CORE_BIT(SE20_2), TO_CORE_BIT(SE10_1_PAN), + TO_CORE_BIT(SE20_2_PAN), + TO_CORE_BIT(SE2), TO_CORE_BIT(SE3), TO_CORE_BIT(MUser), diff --git a/target/arm/helper.c b/target/arm/helper.c index 47f37b8..a11a76a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2862,6 +2862,9 @@ static int gt_phys_redir_timeridx(CPUARMState *env) case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: + case ARMMMUIdx_SE20_0: + case ARMMMUIdx_SE20_2: + case ARMMMUIdx_SE20_2_PAN: return GTIMER_HYP; default: return GTIMER_PHYS; @@ -2874,6 +2877,9 @@ static int gt_virt_redir_timeridx(CPUARMState *env) case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: + case ARMMMUIdx_SE20_0: + case ARMMMUIdx_SE20_2: + case ARMMMUIdx_SE20_2_PAN: return GTIMER_HYPVIRT; default: return GTIMER_VIRT; @@ -3577,7 +3583,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) mmu_idx = ARMMMUIdx_SE3; break; case 2: - g_assert(!secure); /* TODO: ARMv8.4-SecEL2 */ + g_assert(!secure); /* ARMv8.4-SecEL2 is 64-bit only */ /* fall through */ case 1: if (ri->crm == 9 && (env->uncached_cpsr & CPSR_PAN)) { @@ -3673,7 +3679,7 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri, } break; case 4: /* AT S1E2R, AT S1E2W */ - mmu_idx = ARMMMUIdx_E2; + mmu_idx = secure ? ARMMMUIdx_SE2 : ARMMMUIdx_E2; break; case 6: /* AT S1E3R, AT S1E3W */ mmu_idx = ARMMMUIdx_SE3; @@ -3988,10 +3994,15 @@ static void vmsa_tcr_ttbr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, */ if (extract64(raw_read(env, ri) ^ value, 48, 16) && (arm_hcr_el2_eff(env) & HCR_E2H)) { - tlb_flush_by_mmuidx(env_cpu(env), - ARMMMUIdxBit_E20_2 | - ARMMMUIdxBit_E20_2_PAN | - ARMMMUIdxBit_E20_0); + uint16_t mask = ARMMMUIdxBit_E20_2 | + ARMMMUIdxBit_E20_2_PAN | + ARMMMUIdxBit_E20_0; + + if (arm_is_secure_below_el3(env)) { + mask >>= ARM_MMU_IDX_A_NS; + } + + tlb_flush_by_mmuidx(env_cpu(env), mask); } raw_write(env, ri, value); } @@ -4442,9 +4453,15 @@ static int vae1_tlbmask(CPUARMState *env) uint64_t hcr = arm_hcr_el2_eff(env); if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { - return ARMMMUIdxBit_E20_2 | - ARMMMUIdxBit_E20_2_PAN | - ARMMMUIdxBit_E20_0; + uint16_t mask = ARMMMUIdxBit_E20_2 | + ARMMMUIdxBit_E20_2_PAN | + ARMMMUIdxBit_E20_0; + + if (arm_is_secure_below_el3(env)) { + mask >>= ARM_MMU_IDX_A_NS; + } + + return mask; } else if (arm_is_secure_below_el3(env)) { return ARMMMUIdxBit_SE10_1 | ARMMMUIdxBit_SE10_1_PAN | @@ -4469,17 +4486,20 @@ static int tlbbits_for_regime(CPUARMState *env, ARMMMUIdx mmu_idx, static int vae1_tlbbits(CPUARMState *env, uint64_t addr) { + uint64_t hcr = arm_hcr_el2_eff(env); ARMMMUIdx mmu_idx; /* Only the regime of the mmu_idx below is significant. */ - if (arm_is_secure_below_el3(env)) { - mmu_idx = ARMMMUIdx_SE10_0; - } else if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE)) - == (HCR_E2H | HCR_TGE)) { + if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { mmu_idx = ARMMMUIdx_E20_0; } else { mmu_idx = ARMMMUIdx_E10_0; } + + if (arm_is_secure_below_el3(env)) { + mmu_idx &= ~ARM_MMU_IDX_A_NS; + } + return tlbbits_for_regime(env, mmu_idx, addr); } @@ -4525,11 +4545,17 @@ static int alle1_tlbmask(CPUARMState *env) static int e2_tlbmask(CPUARMState *env) { - /* TODO: ARMv8.4-SecEL2 */ - return ARMMMUIdxBit_E20_0 | - ARMMMUIdxBit_E20_2 | - ARMMMUIdxBit_E20_2_PAN | - ARMMMUIdxBit_E2; + if (arm_is_secure_below_el3(env)) { + return ARMMMUIdxBit_SE20_0 | + ARMMMUIdxBit_SE20_2 | + ARMMMUIdxBit_SE20_2_PAN | + ARMMMUIdxBit_SE2; + } else { + return ARMMMUIdxBit_E20_0 | + ARMMMUIdxBit_E20_2 | + ARMMMUIdxBit_E20_2_PAN | + ARMMMUIdxBit_E2; + } } static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -4649,10 +4675,12 @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri, { CPUState *cs = env_cpu(env); uint64_t pageaddr = sextract64(value << 12, 0, 56); - int bits = tlbbits_for_regime(env, ARMMMUIdx_E2, pageaddr); + bool secure = arm_is_secure_below_el3(env); + int mask = secure ? ARMMMUIdxBit_SE2 : ARMMMUIdxBit_E2; + int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_E2 : ARMMMUIdx_SE2, + pageaddr); - tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, - ARMMMUIdxBit_E2, bits); + tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits); } static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -9954,7 +9982,8 @@ uint64_t arm_sctlr(CPUARMState *env, int el) /* Only EL0 needs to be adjusted for EL1&0 or EL2&0. */ if (el == 0) { ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0); - el = (mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1); + el = (mmu_idx == ARMMMUIdx_E20_0 || mmu_idx == ARMMMUIdx_SE20_0) + ? 2 : 1; } return env->cp15.sctlr_el[el]; } @@ -10083,6 +10112,7 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) switch (mmu_idx) { case ARMMMUIdx_SE10_0: case ARMMMUIdx_E20_0: + case ARMMMUIdx_SE20_0: case ARMMMUIdx_Stage1_E0: case ARMMMUIdx_MUser: case ARMMMUIdx_MSUser: @@ -12676,6 +12706,7 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx) case ARMMMUIdx_E10_0: case ARMMMUIdx_E20_0: case ARMMMUIdx_SE10_0: + case ARMMMUIdx_SE20_0: return 0; case ARMMMUIdx_E10_1: case ARMMMUIdx_E10_1_PAN: @@ -12685,6 +12716,9 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx) case ARMMMUIdx_E2: case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: + case ARMMMUIdx_SE2: + case ARMMMUIdx_SE20_2: + case ARMMMUIdx_SE20_2_PAN: return 2; case ARMMMUIdx_SE3: return 3; @@ -12702,6 +12736,9 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el) { + ARMMMUIdx idx; + uint64_t hcr; + if (arm_feature(env, ARM_FEATURE_M)) { return arm_v7m_mmu_idx_for_secstate(env, env->v7m.secure); } @@ -12709,40 +12746,43 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el) /* See ARM pseudo-function ELIsInHost. */ switch (el) { case 0: - if (arm_is_secure_below_el3(env)) { - return ARMMMUIdx_SE10_0; - } - if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE) - && arm_el_is_aa64(env, 2)) { - return ARMMMUIdx_E20_0; + hcr = arm_hcr_el2_eff(env); + if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { + idx = ARMMMUIdx_E20_0; + } else { + idx = ARMMMUIdx_E10_0; } - return ARMMMUIdx_E10_0; + break; case 1: - if (arm_is_secure_below_el3(env)) { - if (env->pstate & PSTATE_PAN) { - return ARMMMUIdx_SE10_1_PAN; - } - return ARMMMUIdx_SE10_1; - } if (env->pstate & PSTATE_PAN) { - return ARMMMUIdx_E10_1_PAN; + idx = ARMMMUIdx_E10_1_PAN; + } else { + idx = ARMMMUIdx_E10_1; } - return ARMMMUIdx_E10_1; + break; case 2: - /* TODO: ARMv8.4-SecEL2 */ /* Note that TGE does not apply at EL2. */ - if ((env->cp15.hcr_el2 & HCR_E2H) && arm_el_is_aa64(env, 2)) { + if (arm_hcr_el2_eff(env) & HCR_E2H) { if (env->pstate & PSTATE_PAN) { - return ARMMMUIdx_E20_2_PAN; + idx = ARMMMUIdx_E20_2_PAN; + } else { + idx = ARMMMUIdx_E20_2; } - return ARMMMUIdx_E20_2; + } else { + idx = ARMMMUIdx_E2; } - return ARMMMUIdx_E2; + break; case 3: return ARMMMUIdx_SE3; default: g_assert_not_reached(); } + + if (arm_is_secure_below_el3(env)) { + idx &= ~ARM_MMU_IDX_A_NS; + } + + return idx; } ARMMMUIdx arm_mmu_idx(CPUARMState *env) @@ -12907,7 +12947,8 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, break; case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: - /* TODO: ARMv8.4-SecEL2 */ + case ARMMMUIdx_SE20_2: + case ARMMMUIdx_SE20_2_PAN: /* * Note that EL20_2 is gated by HCR_EL2.E2H == 1, but EL20_0 is * gated by HCR_EL2.<E2H,TGE> == '11', and so is LDTR. diff --git a/target/arm/internals.h b/target/arm/internals.h index 5460678..e4e6afe 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -860,6 +860,9 @@ static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx) case ARMMMUIdx_SE10_0: case ARMMMUIdx_SE10_1: case ARMMMUIdx_SE10_1_PAN: + case ARMMMUIdx_SE20_0: + case ARMMMUIdx_SE20_2: + case ARMMMUIdx_SE20_2_PAN: return true; default: return false; @@ -890,6 +893,10 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_SE10_0: case ARMMMUIdx_SE10_1: case ARMMMUIdx_SE10_1_PAN: + case ARMMMUIdx_SE20_0: + case ARMMMUIdx_SE20_2: + case ARMMMUIdx_SE20_2_PAN: + case ARMMMUIdx_SE2: case ARMMMUIdx_MSPrivNegPri: case ARMMMUIdx_MSUserNegPri: case ARMMMUIdx_MSPriv: @@ -907,6 +914,7 @@ static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_E10_1_PAN: case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_SE10_1_PAN: + case ARMMMUIdx_SE20_2_PAN: return true; default: return false; @@ -917,10 +925,14 @@ static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx) static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) { switch (mmu_idx) { + case ARMMMUIdx_SE20_0: + case ARMMMUIdx_SE20_2: + case ARMMMUIdx_SE20_2_PAN: case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_Stage2: + case ARMMMUIdx_SE2: case ARMMMUIdx_E2: return 2; case ARMMMUIdx_SE3: diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index ef63edf..ffc060e 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -118,6 +118,10 @@ static int get_a64_user_mem_index(DisasContext *s) case ARMMMUIdx_SE10_1_PAN: useridx = ARMMMUIdx_SE10_0; break; + case ARMMMUIdx_SE20_2: + case ARMMMUIdx_SE20_2_PAN: + useridx = ARMMMUIdx_SE20_0; + break; default: g_assert_not_reached(); } |