Richard Henderson <richard.hender...@linaro.org> writes:
> To implement PAN, we will want to swap, for short periods > of time, to a different privileged mmu_idx. In addition, > we cannot do this with flushing alone, because the AT* > instructions have both PAN and PAN-less versions. > > Add the ARMMMUIdx*_PAN constants where necessary next to > the corresponding ARMMMUIdx* constant. > > Reviewed-by: Peter Maydell <peter.mayd...@linaro.org> > Signed-off-by: Richard Henderson <richard.hender...@linaro.org> Reviewed-by: Alex Bennée <alex.ben...@linaro.org> > --- > target/arm/cpu-param.h | 2 +- > target/arm/cpu.h | 33 ++++++++++++++------- > target/arm/internals.h | 9 ++++++ > target/arm/helper.c | 60 +++++++++++++++++++++++++++++++------- > target/arm/translate-a64.c | 3 ++ > target/arm/translate.c | 2 ++ > 6 files changed, 87 insertions(+), 22 deletions(-) > > diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h > index 18ac562346..d593b60b28 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 9 > +#define NB_MMU_MODES 12 > > #endif > diff --git a/target/arm/cpu.h b/target/arm/cpu.h > index 0b3036c484..c63bceaaa5 100644 > --- a/target/arm/cpu.h > +++ b/target/arm/cpu.h > @@ -2751,20 +2751,24 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool > kvm_sync); > * 5. we want to be able to use the TLB for accesses done as part of a > * stage1 page table walk, rather than having to walk the stage2 page > * table over and over. > + * 6. we need separate EL1/EL2 mmu_idx for handling the Privileged Access > + * Never (PAN) bit within PSTATE. > * > * This gives us the following list of cases: > * > * NS EL0 EL1&0 stage 1+2 (aka NS PL0) > * NS EL1 EL1&0 stage 1+2 (aka NS PL1) > + * NS EL1 EL1&0 stage 1+2 +PAN > * NS EL0 EL2&0 > - * NS EL2 EL2&0 > + * NS EL2 EL2&0 +PAN > * NS EL2 (aka NS PL2) > * S EL0 EL1&0 (aka S PL0) > * S EL1 EL1&0 (not used if EL3 is 32 bit) > + * S EL1 EL1&0 +PAN > * S EL3 (aka S PL1) > * NS EL1&0 stage 2 > * > - * for a total of 9 different mmu_idx. > + * for a total of 12 different mmu_idx. > * > * R profile CPUs have an MPU, but can use the same set of MMU indexes > * as A profile. They only need to distinguish NS EL0 and NS EL1 (and > @@ -2819,19 +2823,22 @@ typedef enum ARMMMUIdx { > /* > * A-profile. > */ > - ARMMMUIdx_E10_0 = 0 | ARM_MMU_IDX_A, > - ARMMMUIdx_E20_0 = 1 | ARM_MMU_IDX_A, > + 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 = 2 | ARM_MMU_IDX_A, > + ARMMMUIdx_E10_1_PAN = 3 | ARM_MMU_IDX_A, > > - ARMMMUIdx_E2 = 3 | ARM_MMU_IDX_A, > - ARMMMUIdx_E20_2 = 4 | 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 = 5 | ARM_MMU_IDX_A, > - ARMMMUIdx_SE10_1 = 6 | ARM_MMU_IDX_A, > - ARMMMUIdx_SE3 = 7 | 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_Stage2 = 8 | ARM_MMU_IDX_A, > + ARMMMUIdx_Stage2 = 11 | ARM_MMU_IDX_A, > > /* > * These are not allocated TLBs and are used only for AT system > @@ -2839,6 +2846,7 @@ typedef enum ARMMMUIdx { > */ > ARMMMUIdx_Stage1_E0 = 0 | ARM_MMU_IDX_NOTLB, > ARMMMUIdx_Stage1_E1 = 1 | ARM_MMU_IDX_NOTLB, > + ARMMMUIdx_Stage1_E1_PAN = 2 | ARM_MMU_IDX_NOTLB, > > /* > * M-profile. > @@ -2864,10 +2872,13 @@ typedef enum ARMMMUIdxBit { > TO_CORE_BIT(E10_0), > TO_CORE_BIT(E20_0), > TO_CORE_BIT(E10_1), > + TO_CORE_BIT(E10_1_PAN), > TO_CORE_BIT(E2), > TO_CORE_BIT(E20_2), > + TO_CORE_BIT(E20_2_PAN), > TO_CORE_BIT(SE10_0), > TO_CORE_BIT(SE10_1), > + TO_CORE_BIT(SE10_1_PAN), > TO_CORE_BIT(SE3), > TO_CORE_BIT(Stage2), > > diff --git a/target/arm/internals.h b/target/arm/internals.h > index 1f8ee5f573..6be8b2d1a9 100644 > --- a/target/arm/internals.h > +++ b/target/arm/internals.h > @@ -843,12 +843,16 @@ static inline bool regime_has_2_ranges(ARMMMUIdx > mmu_idx) > switch (mmu_idx) { > case ARMMMUIdx_Stage1_E0: > case ARMMMUIdx_Stage1_E1: > + case ARMMMUIdx_Stage1_E1_PAN: > case ARMMMUIdx_E10_0: > case ARMMMUIdx_E10_1: > + case ARMMMUIdx_E10_1_PAN: > case ARMMMUIdx_E20_0: > case ARMMMUIdx_E20_2: > + case ARMMMUIdx_E20_2_PAN: > case ARMMMUIdx_SE10_0: > case ARMMMUIdx_SE10_1: > + case ARMMMUIdx_SE10_1_PAN: > return true; > default: > return false; > @@ -861,10 +865,13 @@ static inline bool regime_is_secure(CPUARMState *env, > ARMMMUIdx mmu_idx) > switch (mmu_idx) { > case ARMMMUIdx_E10_0: > case ARMMMUIdx_E10_1: > + case ARMMMUIdx_E10_1_PAN: > case ARMMMUIdx_E20_0: > case ARMMMUIdx_E20_2: > + case ARMMMUIdx_E20_2_PAN: > case ARMMMUIdx_Stage1_E0: > case ARMMMUIdx_Stage1_E1: > + case ARMMMUIdx_Stage1_E1_PAN: > case ARMMMUIdx_E2: > case ARMMMUIdx_Stage2: > case ARMMMUIdx_MPrivNegPri: > @@ -875,6 +882,7 @@ static inline bool regime_is_secure(CPUARMState *env, > ARMMMUIdx mmu_idx) > case ARMMMUIdx_SE3: > case ARMMMUIdx_SE10_0: > case ARMMMUIdx_SE10_1: > + case ARMMMUIdx_SE10_1_PAN: > case ARMMMUIdx_MSPrivNegPri: > case ARMMMUIdx_MSUserNegPri: > case ARMMMUIdx_MSPriv: > @@ -1046,6 +1054,7 @@ static inline bool arm_mmu_idx_is_stage1_of_2(ARMMMUIdx > mmu_idx) > switch (mmu_idx) { > case ARMMMUIdx_Stage1_E0: > case ARMMMUIdx_Stage1_E1: > + case ARMMMUIdx_Stage1_E1_PAN: > return true; > default: > return false; > diff --git a/target/arm/helper.c b/target/arm/helper.c > index 852fd71dcc..739d2d4cc5 100644 > --- a/target/arm/helper.c > +++ b/target/arm/helper.c > @@ -671,6 +671,7 @@ static void tlbiall_nsnh_write(CPUARMState *env, const > ARMCPRegInfo *ri, > > tlb_flush_by_mmuidx(cs, > ARMMMUIdxBit_E10_1 | > + ARMMMUIdxBit_E10_1_PAN | > ARMMMUIdxBit_E10_0 | > ARMMMUIdxBit_Stage2); > } > @@ -682,6 +683,7 @@ static void tlbiall_nsnh_is_write(CPUARMState *env, const > ARMCPRegInfo *ri, > > tlb_flush_by_mmuidx_all_cpus_synced(cs, > ARMMMUIdxBit_E10_1 | > + ARMMMUIdxBit_E10_1_PAN | > ARMMMUIdxBit_E10_0 | > ARMMMUIdxBit_Stage2); > } > @@ -2700,6 +2702,7 @@ static int gt_phys_redir_timeridx(CPUARMState *env) > switch (arm_mmu_idx(env)) { > case ARMMMUIdx_E20_0: > case ARMMMUIdx_E20_2: > + case ARMMMUIdx_E20_2_PAN: > return GTIMER_HYP; > default: > return GTIMER_PHYS; > @@ -2711,6 +2714,7 @@ static int gt_virt_redir_timeridx(CPUARMState *env) > switch (arm_mmu_idx(env)) { > case ARMMMUIdx_E20_0: > case ARMMMUIdx_E20_2: > + case ARMMMUIdx_E20_2_PAN: > return GTIMER_HYPVIRT; > default: > return GTIMER_VIRT; > @@ -3337,7 +3341,9 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t > value, > format64 = arm_s1_regime_using_lpae_format(env, mmu_idx); > > if (arm_feature(env, ARM_FEATURE_EL2)) { > - if (mmu_idx == ARMMMUIdx_E10_0 || mmu_idx == ARMMMUIdx_E10_1) { > + if (mmu_idx == ARMMMUIdx_E10_0 || > + mmu_idx == ARMMMUIdx_E10_1 || > + mmu_idx == ARMMMUIdx_E10_1_PAN) { > format64 |= env->cp15.hcr_el2 & (HCR_VM | HCR_DC); > } else { > format64 |= arm_current_el(env) == 2; > @@ -3797,7 +3803,9 @@ 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_0); > + ARMMMUIdxBit_E20_2 | > + ARMMMUIdxBit_E20_2_PAN | > + ARMMMUIdxBit_E20_0); > } > raw_write(env, ri, value); > } > @@ -3815,6 +3823,7 @@ static void vttbr_write(CPUARMState *env, const > ARMCPRegInfo *ri, > if (raw_read(env, ri) != value) { > tlb_flush_by_mmuidx(cs, > ARMMMUIdxBit_E10_1 | > + ARMMMUIdxBit_E10_1_PAN | > ARMMMUIdxBit_E10_0 | > ARMMMUIdxBit_Stage2); > raw_write(env, ri, value); > @@ -4175,12 +4184,18 @@ static int vae1_tlbmask(CPUARMState *env) > { > /* Since we exclude secure first, we may read HCR_EL2 directly. */ > if (arm_is_secure_below_el3(env)) { > - return ARMMMUIdxBit_SE10_1 | ARMMMUIdxBit_SE10_0; > + return ARMMMUIdxBit_SE10_1 | > + ARMMMUIdxBit_SE10_1_PAN | > + ARMMMUIdxBit_SE10_0; > } else if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE)) > == (HCR_E2H | HCR_TGE)) { > - return ARMMMUIdxBit_E20_2 | ARMMMUIdxBit_E20_0; > + return ARMMMUIdxBit_E20_2 | > + ARMMMUIdxBit_E20_2_PAN | > + ARMMMUIdxBit_E20_0; > } else { > - return ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_0; > + return ARMMMUIdxBit_E10_1 | > + ARMMMUIdxBit_E10_1_PAN | > + ARMMMUIdxBit_E10_0; > } > } > > @@ -4214,18 +4229,28 @@ static int alle1_tlbmask(CPUARMState *env) > * stage 1 translations. > */ > if (arm_is_secure_below_el3(env)) { > - return ARMMMUIdxBit_SE10_1 | ARMMMUIdxBit_SE10_0; > + return ARMMMUIdxBit_SE10_1 | > + ARMMMUIdxBit_SE10_1_PAN | > + ARMMMUIdxBit_SE10_0; > } else if (arm_feature(env, ARM_FEATURE_EL2)) { > - return ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_0 | ARMMMUIdxBit_Stage2; > + return ARMMMUIdxBit_E10_1 | > + ARMMMUIdxBit_E10_1_PAN | > + ARMMMUIdxBit_E10_0 | > + ARMMMUIdxBit_Stage2; > } else { > - return ARMMMUIdxBit_E10_1 | ARMMMUIdxBit_E10_0; > + return ARMMMUIdxBit_E10_1 | > + ARMMMUIdxBit_E10_1_PAN | > + ARMMMUIdxBit_E10_0; > } > } > > static int alle2_tlbmask(CPUARMState *env) > { > /* TODO: ARMv8.4-SecEL2 */ > - return ARMMMUIdxBit_E20_0 | ARMMMUIdxBit_E20_2 | ARMMMUIdxBit_E2; > + return ARMMMUIdxBit_E20_0 | > + ARMMMUIdxBit_E20_2 | > + ARMMMUIdxBit_E20_2_PAN | > + ARMMMUIdxBit_E2; > } > > static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri, > @@ -9215,6 +9240,7 @@ static uint32_t regime_el(CPUARMState *env, ARMMMUIdx > mmu_idx) > switch (mmu_idx) { > case ARMMMUIdx_E20_0: > case ARMMMUIdx_E20_2: > + case ARMMMUIdx_E20_2_PAN: > case ARMMMUIdx_Stage2: > case ARMMMUIdx_E2: > return 2; > @@ -9223,10 +9249,13 @@ static uint32_t regime_el(CPUARMState *env, ARMMMUIdx > mmu_idx) > case ARMMMUIdx_SE10_0: > return arm_el_is_aa64(env, 3) ? 1 : 3; > case ARMMMUIdx_SE10_1: > + case ARMMMUIdx_SE10_1_PAN: > case ARMMMUIdx_Stage1_E0: > case ARMMMUIdx_Stage1_E1: > + case ARMMMUIdx_Stage1_E1_PAN: > case ARMMMUIdx_E10_0: > case ARMMMUIdx_E10_1: > + case ARMMMUIdx_E10_1_PAN: > case ARMMMUIdx_MPrivNegPri: > case ARMMMUIdx_MUserNegPri: > case ARMMMUIdx_MPriv: > @@ -9342,6 +9371,8 @@ static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx > mmu_idx) > return ARMMMUIdx_Stage1_E0; > case ARMMMUIdx_E10_1: > return ARMMMUIdx_Stage1_E1; > + case ARMMMUIdx_E10_1_PAN: > + return ARMMMUIdx_Stage1_E1_PAN; > default: > return mmu_idx; > } > @@ -9388,6 +9419,7 @@ static inline bool regime_is_user(CPUARMState *env, > ARMMMUIdx mmu_idx) > return false; > case ARMMMUIdx_E10_0: > case ARMMMUIdx_E10_1: > + case ARMMMUIdx_E10_1_PAN: > g_assert_not_reached(); > } > } > @@ -11280,7 +11312,9 @@ bool get_phys_addr(CPUARMState *env, target_ulong > address, > target_ulong *page_size, > ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) > { > - if (mmu_idx == ARMMMUIdx_E10_0 || mmu_idx == ARMMMUIdx_E10_1) { > + if (mmu_idx == ARMMMUIdx_E10_0 || > + mmu_idx == ARMMMUIdx_E10_1 || > + mmu_idx == ARMMMUIdx_E10_1_PAN) { > /* Call ourselves recursively to do the stage 1 and then stage 2 > * translations. > */ > @@ -11807,10 +11841,13 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx) > case ARMMMUIdx_SE10_0: > return 0; > case ARMMMUIdx_E10_1: > + case ARMMMUIdx_E10_1_PAN: > case ARMMMUIdx_SE10_1: > + case ARMMMUIdx_SE10_1_PAN: > return 1; > case ARMMMUIdx_E2: > case ARMMMUIdx_E20_2: > + case ARMMMUIdx_E20_2_PAN: > return 2; > case ARMMMUIdx_SE3: > return 3; > @@ -12027,11 +12064,14 @@ static uint32_t rebuild_hflags_a64(CPUARMState > *env, int el, int fp_el, > /* TODO: ARMv8.2-UAO */ > switch (mmu_idx) { > case ARMMMUIdx_E10_1: > + case ARMMMUIdx_E10_1_PAN: > case ARMMMUIdx_SE10_1: > + case ARMMMUIdx_SE10_1_PAN: > /* TODO: ARMv8.3-NV */ > flags = FIELD_DP32(flags, TBFLAG_A64, UNPRIV, 1); > break; > case ARMMMUIdx_E20_2: > + case ARMMMUIdx_E20_2_PAN: > /* TODO: ARMv8.4-SecEL2 */ > /* > * Note that E20_2 is gated by HCR_EL2.E2H == 1, but E20_0 is > diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c > index 6e82486884..49631c2340 100644 > --- a/target/arm/translate-a64.c > +++ b/target/arm/translate-a64.c > @@ -124,12 +124,15 @@ static int get_a64_user_mem_index(DisasContext *s) > */ > switch (useridx) { > case ARMMMUIdx_E10_1: > + case ARMMMUIdx_E10_1_PAN: > useridx = ARMMMUIdx_E10_0; > break; > case ARMMMUIdx_E20_2: > + case ARMMMUIdx_E20_2_PAN: > useridx = ARMMMUIdx_E20_0; > break; > case ARMMMUIdx_SE10_1: > + case ARMMMUIdx_SE10_1_PAN: > useridx = ARMMMUIdx_SE10_0; > break; > default: > diff --git a/target/arm/translate.c b/target/arm/translate.c > index e11a5871d0..d58c328e08 100644 > --- a/target/arm/translate.c > +++ b/target/arm/translate.c > @@ -155,10 +155,12 @@ static inline int get_a32_user_mem_index(DisasContext > *s) > case ARMMMUIdx_E2: /* this one is UNPREDICTABLE */ > case ARMMMUIdx_E10_0: > case ARMMMUIdx_E10_1: > + case ARMMMUIdx_E10_1_PAN: > return arm_to_core_mmu_idx(ARMMMUIdx_E10_0); > case ARMMMUIdx_SE3: > case ARMMMUIdx_SE10_0: > case ARMMMUIdx_SE10_1: > + case ARMMMUIdx_SE10_1_PAN: > return arm_to_core_mmu_idx(ARMMMUIdx_SE10_0); > case ARMMMUIdx_MUser: > case ARMMMUIdx_MPriv: -- Alex Bennée