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>
This commit is contained in:
Rémi Denis-Courmont 2021-01-12 12:45:00 +02:00 committed by Peter Maydell
parent 6c85f90626
commit b6ad6062f1
5 changed files with 123 additions and 57 deletions

View File

@ -29,6 +29,6 @@
# define TARGET_PAGE_BITS_MIN 10 # define TARGET_PAGE_BITS_MIN 10
#endif #endif
#define NB_MMU_MODES 11 #define NB_MMU_MODES 15
#endif #endif

View File

@ -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_NOTLB 0x20 /* does not have a TLB */
#define ARM_MMU_IDX_M 0x40 /* M profile */ #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 */ /* Meanings of the bits for M profile mmu idx values */
#define ARM_MMU_IDX_M_PRIV 0x1 #define ARM_MMU_IDX_M_PRIV 0x1
#define ARM_MMU_IDX_M_NEGPRI 0x2 #define ARM_MMU_IDX_M_NEGPRI 0x2
@ -3062,20 +3065,22 @@ typedef enum ARMMMUIdx {
/* /*
* A-profile. * A-profile.
*/ */
ARMMMUIdx_E10_0 = 0 | ARM_MMU_IDX_A, ARMMMUIdx_SE10_0 = 0 | ARM_MMU_IDX_A,
ARMMMUIdx_E20_0 = 1 | 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_1 = 2 | ARM_MMU_IDX_A, ARMMMUIdx_E10_0 = ARMMMUIdx_SE10_0 | ARM_MMU_IDX_A_NS,
ARMMMUIdx_E10_1_PAN = 3 | ARM_MMU_IDX_A, ARMMMUIdx_E20_0 = ARMMMUIdx_SE20_0 | ARM_MMU_IDX_A_NS,
ARMMMUIdx_E10_1 = ARMMMUIdx_SE10_1 | ARM_MMU_IDX_A_NS,
ARMMMUIdx_E2 = 4 | ARM_MMU_IDX_A, ARMMMUIdx_E20_2 = ARMMMUIdx_SE20_2 | ARM_MMU_IDX_A_NS,
ARMMMUIdx_E20_2 = 5 | ARM_MMU_IDX_A, ARMMMUIdx_E10_1_PAN = ARMMMUIdx_SE10_1_PAN | ARM_MMU_IDX_A_NS,
ARMMMUIdx_E20_2_PAN = 6 | ARM_MMU_IDX_A, ARMMMUIdx_E20_2_PAN = ARMMMUIdx_SE20_2_PAN | ARM_MMU_IDX_A_NS,
ARMMMUIdx_E2 = ARMMMUIdx_SE2 | ARM_MMU_IDX_A_NS,
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,
/* /*
* These are not allocated TLBs and are used only for AT system * 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),
TO_CORE_BIT(E20_2_PAN), TO_CORE_BIT(E20_2_PAN),
TO_CORE_BIT(SE10_0), TO_CORE_BIT(SE10_0),
TO_CORE_BIT(SE20_0),
TO_CORE_BIT(SE10_1), TO_CORE_BIT(SE10_1),
TO_CORE_BIT(SE20_2),
TO_CORE_BIT(SE10_1_PAN), TO_CORE_BIT(SE10_1_PAN),
TO_CORE_BIT(SE20_2_PAN),
TO_CORE_BIT(SE2),
TO_CORE_BIT(SE3), TO_CORE_BIT(SE3),
TO_CORE_BIT(MUser), TO_CORE_BIT(MUser),

View File

@ -2862,6 +2862,9 @@ static int gt_phys_redir_timeridx(CPUARMState *env)
case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_0:
case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_SE20_0:
case ARMMMUIdx_SE20_2:
case ARMMMUIdx_SE20_2_PAN:
return GTIMER_HYP; return GTIMER_HYP;
default: default:
return GTIMER_PHYS; return GTIMER_PHYS;
@ -2874,6 +2877,9 @@ static int gt_virt_redir_timeridx(CPUARMState *env)
case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_0:
case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_SE20_0:
case ARMMMUIdx_SE20_2:
case ARMMMUIdx_SE20_2_PAN:
return GTIMER_HYPVIRT; return GTIMER_HYPVIRT;
default: default:
return GTIMER_VIRT; return GTIMER_VIRT;
@ -3577,7 +3583,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
mmu_idx = ARMMMUIdx_SE3; mmu_idx = ARMMMUIdx_SE3;
break; break;
case 2: case 2:
g_assert(!secure); /* TODO: ARMv8.4-SecEL2 */ g_assert(!secure); /* ARMv8.4-SecEL2 is 64-bit only */
/* fall through */ /* fall through */
case 1: case 1:
if (ri->crm == 9 && (env->uncached_cpsr & CPSR_PAN)) { if (ri->crm == 9 && (env->uncached_cpsr & CPSR_PAN)) {
@ -3673,7 +3679,7 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
} }
break; break;
case 4: /* AT S1E2R, AT S1E2W */ case 4: /* AT S1E2R, AT S1E2W */
mmu_idx = ARMMMUIdx_E2; mmu_idx = secure ? ARMMMUIdx_SE2 : ARMMMUIdx_E2;
break; break;
case 6: /* AT S1E3R, AT S1E3W */ case 6: /* AT S1E3R, AT S1E3W */
mmu_idx = ARMMMUIdx_SE3; 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) && if (extract64(raw_read(env, ri) ^ value, 48, 16) &&
(arm_hcr_el2_eff(env) & HCR_E2H)) { (arm_hcr_el2_eff(env) & HCR_E2H)) {
tlb_flush_by_mmuidx(env_cpu(env), uint16_t mask = ARMMMUIdxBit_E20_2 |
ARMMMUIdxBit_E20_2 | ARMMMUIdxBit_E20_2_PAN |
ARMMMUIdxBit_E20_2_PAN | ARMMMUIdxBit_E20_0;
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); raw_write(env, ri, value);
} }
@ -4442,9 +4453,15 @@ static int vae1_tlbmask(CPUARMState *env)
uint64_t hcr = arm_hcr_el2_eff(env); uint64_t hcr = arm_hcr_el2_eff(env);
if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
return ARMMMUIdxBit_E20_2 | uint16_t mask = ARMMMUIdxBit_E20_2 |
ARMMMUIdxBit_E20_2_PAN | ARMMMUIdxBit_E20_2_PAN |
ARMMMUIdxBit_E20_0; 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)) { } else if (arm_is_secure_below_el3(env)) {
return ARMMMUIdxBit_SE10_1 | return ARMMMUIdxBit_SE10_1 |
ARMMMUIdxBit_SE10_1_PAN | 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) static int vae1_tlbbits(CPUARMState *env, uint64_t addr)
{ {
uint64_t hcr = arm_hcr_el2_eff(env);
ARMMMUIdx mmu_idx; ARMMMUIdx mmu_idx;
/* Only the regime of the mmu_idx below is significant. */ /* Only the regime of the mmu_idx below is significant. */
if (arm_is_secure_below_el3(env)) { if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
mmu_idx = ARMMMUIdx_SE10_0;
} else if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE))
== (HCR_E2H | HCR_TGE)) {
mmu_idx = ARMMMUIdx_E20_0; mmu_idx = ARMMMUIdx_E20_0;
} else { } else {
mmu_idx = ARMMMUIdx_E10_0; 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); return tlbbits_for_regime(env, mmu_idx, addr);
} }
@ -4525,11 +4545,17 @@ static int alle1_tlbmask(CPUARMState *env)
static int e2_tlbmask(CPUARMState *env) static int e2_tlbmask(CPUARMState *env)
{ {
/* TODO: ARMv8.4-SecEL2 */ if (arm_is_secure_below_el3(env)) {
return ARMMMUIdxBit_E20_0 | return ARMMMUIdxBit_SE20_0 |
ARMMMUIdxBit_E20_2 | ARMMMUIdxBit_SE20_2 |
ARMMMUIdxBit_E20_2_PAN | ARMMMUIdxBit_SE20_2_PAN |
ARMMMUIdxBit_E2; 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, 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); CPUState *cs = env_cpu(env);
uint64_t pageaddr = sextract64(value << 12, 0, 56); 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, tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
ARMMMUIdxBit_E2, bits);
} }
static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri, 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. */ /* Only EL0 needs to be adjusted for EL1&0 or EL2&0. */
if (el == 0) { if (el == 0) {
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 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]; return env->cp15.sctlr_el[el];
} }
@ -10083,6 +10112,7 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx)
switch (mmu_idx) { switch (mmu_idx) {
case ARMMMUIdx_SE10_0: case ARMMMUIdx_SE10_0:
case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_0:
case ARMMMUIdx_SE20_0:
case ARMMMUIdx_Stage1_E0: case ARMMMUIdx_Stage1_E0:
case ARMMMUIdx_MUser: case ARMMMUIdx_MUser:
case ARMMMUIdx_MSUser: case ARMMMUIdx_MSUser:
@ -12676,6 +12706,7 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
case ARMMMUIdx_E10_0: case ARMMMUIdx_E10_0:
case ARMMMUIdx_E20_0: case ARMMMUIdx_E20_0:
case ARMMMUIdx_SE10_0: case ARMMMUIdx_SE10_0:
case ARMMMUIdx_SE20_0:
return 0; return 0;
case ARMMMUIdx_E10_1: case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN: case ARMMMUIdx_E10_1_PAN:
@ -12685,6 +12716,9 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
case ARMMMUIdx_E2: case ARMMMUIdx_E2:
case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_SE2:
case ARMMMUIdx_SE20_2:
case ARMMMUIdx_SE20_2_PAN:
return 2; return 2;
case ARMMMUIdx_SE3: case ARMMMUIdx_SE3:
return 3; 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 arm_mmu_idx_el(CPUARMState *env, int el)
{ {
ARMMMUIdx idx;
uint64_t hcr;
if (arm_feature(env, ARM_FEATURE_M)) { if (arm_feature(env, ARM_FEATURE_M)) {
return arm_v7m_mmu_idx_for_secstate(env, env->v7m.secure); 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. */ /* See ARM pseudo-function ELIsInHost. */
switch (el) { switch (el) {
case 0: case 0:
if (arm_is_secure_below_el3(env)) { hcr = arm_hcr_el2_eff(env);
return ARMMMUIdx_SE10_0; if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
idx = ARMMMUIdx_E20_0;
} else {
idx = ARMMMUIdx_E10_0;
} }
if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE) break;
&& arm_el_is_aa64(env, 2)) {
return ARMMMUIdx_E20_0;
}
return ARMMMUIdx_E10_0;
case 1: 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) { 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: case 2:
/* TODO: ARMv8.4-SecEL2 */
/* Note that TGE does not apply at EL2. */ /* 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) { 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: case 3:
return ARMMMUIdx_SE3; return ARMMMUIdx_SE3;
default: default:
g_assert_not_reached(); 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) ARMMMUIdx arm_mmu_idx(CPUARMState *env)
@ -12907,7 +12947,8 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
break; break;
case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN: 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 * 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. * gated by HCR_EL2.<E2H,TGE> == '11', and so is LDTR.

View File

@ -860,6 +860,9 @@ static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx)
case ARMMMUIdx_SE10_0: case ARMMMUIdx_SE10_0:
case ARMMMUIdx_SE10_1: case ARMMMUIdx_SE10_1:
case ARMMMUIdx_SE10_1_PAN: case ARMMMUIdx_SE10_1_PAN:
case ARMMMUIdx_SE20_0:
case ARMMMUIdx_SE20_2:
case ARMMMUIdx_SE20_2_PAN:
return true; return true;
default: default:
return false; return false;
@ -890,6 +893,10 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
case ARMMMUIdx_SE10_0: case ARMMMUIdx_SE10_0:
case ARMMMUIdx_SE10_1: case ARMMMUIdx_SE10_1:
case ARMMMUIdx_SE10_1_PAN: 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_MSPrivNegPri:
case ARMMMUIdx_MSUserNegPri: case ARMMMUIdx_MSUserNegPri:
case ARMMMUIdx_MSPriv: 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_E10_1_PAN:
case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_SE10_1_PAN: case ARMMMUIdx_SE10_1_PAN:
case ARMMMUIdx_SE20_2_PAN:
return true; return true;
default: default:
return false; 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) static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
{ {
switch (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_0:
case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN: case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_Stage2: case ARMMMUIdx_Stage2:
case ARMMMUIdx_SE2:
case ARMMMUIdx_E2: case ARMMMUIdx_E2:
return 2; return 2;
case ARMMMUIdx_SE3: case ARMMMUIdx_SE3:

View File

@ -118,6 +118,10 @@ static int get_a64_user_mem_index(DisasContext *s)
case ARMMMUIdx_SE10_1_PAN: case ARMMMUIdx_SE10_1_PAN:
useridx = ARMMMUIdx_SE10_0; useridx = ARMMMUIdx_SE10_0;
break; break;
case ARMMMUIdx_SE20_2:
case ARMMMUIdx_SE20_2_PAN:
useridx = ARMMMUIdx_SE20_0;
break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }