diff options
Diffstat (limited to 'target/arm/helper.c')
| -rw-r--r-- | target/arm/helper.c | 118 |
1 files changed, 80 insertions, 38 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c index 6dd241fbef..b5f80988c9 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6154,43 +6154,67 @@ int sve_exception_el(CPUARMState *env, int el) uint64_t hcr_el2 = arm_hcr_el2_eff(env); if (el <= 1 && (hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { - bool disabled = false; - - /* The CPACR.ZEN controls traps to EL1: - * 0, 2 : trap EL0 and EL1 accesses - * 1 : trap only EL0 accesses - * 3 : trap no accesses - */ - if (!extract32(env->cp15.cpacr_el1, 16, 1)) { - disabled = true; - } else if (!extract32(env->cp15.cpacr_el1, 17, 1)) { - disabled = el == 0; - } - if (disabled) { + /* Check CPACR.ZEN. */ + switch (extract32(env->cp15.cpacr_el1, 16, 2)) { + case 1: + if (el != 0) { + break; + } + /* fall through */ + case 0: + case 2: /* route_to_el2 */ return hcr_el2 & HCR_TGE ? 2 : 1; } /* Check CPACR.FPEN. */ - if (!extract32(env->cp15.cpacr_el1, 20, 1)) { - disabled = true; - } else if (!extract32(env->cp15.cpacr_el1, 21, 1)) { - disabled = el == 0; - } - if (disabled) { + switch (extract32(env->cp15.cpacr_el1, 20, 2)) { + case 1: + if (el != 0) { + break; + } + /* fall through */ + case 0: + case 2: return 0; } } - /* CPTR_EL2. Since TZ and TFP are positive, - * they will be zero when EL2 is not present. + /* + * CPTR_EL2 changes format with HCR_EL2.E2H (regardless of TGE). */ - if (el <= 2 && arm_is_el2_enabled(env)) { - if (env->cp15.cptr_el[2] & CPTR_TZ) { - return 2; - } - if (env->cp15.cptr_el[2] & CPTR_TFP) { - return 0; + if (el <= 2) { + if (hcr_el2 & HCR_E2H) { + /* Check CPTR_EL2.ZEN. */ + switch (extract32(env->cp15.cptr_el[2], 16, 2)) { + case 1: + if (el != 0 || !(hcr_el2 & HCR_TGE)) { + break; + } + /* fall through */ + case 0: + case 2: + return 2; + } + + /* Check CPTR_EL2.FPEN. */ + switch (extract32(env->cp15.cptr_el[2], 20, 2)) { + case 1: + if (el == 2 || !(hcr_el2 & HCR_TGE)) { + break; + } + /* fall through */ + case 0: + case 2: + return 0; + } + } else if (arm_is_el2_enabled(env)) { + if (env->cp15.cptr_el[2] & CPTR_TZ) { + return 2; + } + if (env->cp15.cptr_el[2] & CPTR_TFP) { + return 0; + } } } @@ -6225,7 +6249,8 @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el) ARMCPU *cpu = env_archcpu(env); uint32_t zcr_len = cpu->sve_max_vq - 1; - if (el <= 1) { + if (el <= 1 && + (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]); } if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) { @@ -12913,6 +12938,8 @@ uint32_t HELPER(crc32c)(uint32_t acc, uint32_t val, uint32_t bytes) int fp_exception_el(CPUARMState *env, int cur_el) { #ifndef CONFIG_USER_ONLY + uint64_t hcr_el2; + /* CPACR and the CPTR registers don't exist before v6, so FP is * always accessible */ @@ -12936,13 +12963,15 @@ int fp_exception_el(CPUARMState *env, int cur_el) return 0; } + hcr_el2 = arm_hcr_el2_eff(env); + /* The CPACR controls traps to EL1, or PL1 if we're 32 bit: * 0, 2 : trap EL0 and EL1/PL1 accesses * 1 : trap only EL0 accesses * 3 : trap no accesses * This register is ignored if E2H+TGE are both set. */ - if ((arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { + if ((hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { int fpen = extract32(env->cp15.cpacr_el1, 20, 2); switch (fpen) { @@ -12983,19 +13012,32 @@ int fp_exception_el(CPUARMState *env, int cur_el) } } - /* For the CPTR registers we don't need to guard with an ARM_FEATURE - * check because zero bits in the registers mean "don't trap". + /* + * CPTR_EL2 is present in v7VE or v8, and changes format + * with HCR_EL2.E2H (regardless of TGE). */ - - /* CPTR_EL2 : present in v7VE or v8 */ - if (cur_el <= 2 && extract32(env->cp15.cptr_el[2], 10, 1) - && arm_is_el2_enabled(env)) { - /* Trap FP ops at EL2, NS-EL1 or NS-EL0 to EL2 */ - return 2; + if (cur_el <= 2) { + if (hcr_el2 & HCR_E2H) { + /* Check CPTR_EL2.FPEN. */ + switch (extract32(env->cp15.cptr_el[2], 20, 2)) { + case 1: + if (cur_el != 0 || !(hcr_el2 & HCR_TGE)) { + break; + } + /* fall through */ + case 0: + case 2: + return 2; + } + } else if (arm_is_el2_enabled(env)) { + if (env->cp15.cptr_el[2] & CPTR_TFP) { + return 2; + } + } } /* CPTR_EL3 : present in v8 */ - if (extract32(env->cp15.cptr_el[3], 10, 1)) { + if (env->cp15.cptr_el[3] & CPTR_TFP) { /* Trap all FP ops to EL3 */ return 3; } |