From 78798d10eb6d6787d29bf8b693cc043a2af86a5e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Dec 2018 04:26:25 -0500 Subject: [PATCH] target/arm: Introduce arm_hcr_el2_eff Replace arm_hcr_el2_{fmo,imo,amo} with a more general routine that also takes SCR_EL3.NS (aka arm_is_secure_below_el3) into account, as documented for the plethora of bits in HCR_EL2. Backports commit f77784446045231f7dfa46c9b872091241fa1557 from qemu --- qemu/aarch64.h | 1 + qemu/aarch64eb.h | 1 + qemu/arm.h | 1 + qemu/armeb.h | 1 + qemu/header_gen.py | 2 ++ qemu/target/arm/cpu.h | 8 +++++ qemu/target/arm/helper.c | 66 ++++++++++++++++++++++++++++++++++------ 7 files changed, 71 insertions(+), 9 deletions(-) diff --git a/qemu/aarch64.h b/qemu/aarch64.h index bb413ca4..a7c32cea 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -3280,6 +3280,7 @@ #define arm64_reg_reset arm64_reg_reset_aarch64 #define arm64_reg_write arm64_reg_write_aarch64 #define arm64_release arm64_release_aarch64 +#define arm_hcr_el2_eff arm_hcr_el2_eff_aarch64 #define arm_regime_tbi0 arm_regime_tbi0_aarch64 #define arm_regime_tbi1 arm_regime_tbi1_aarch64 #define arm_register_pre_el_change_hook arm_register_pre_el_change_hook_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index 304bdff6..eb34d13f 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -3280,6 +3280,7 @@ #define arm64_reg_reset arm64_reg_reset_aarch64eb #define arm64_reg_write arm64_reg_write_aarch64eb #define arm64_release arm64_release_aarch64eb +#define arm_hcr_el2_eff arm_hcr_el2_eff_aarch64eb #define arm_regime_tbi0 arm_regime_tbi0_aarch64eb #define arm_regime_tbi1 arm_regime_tbi1_aarch64eb #define arm_register_pre_el_change_hook arm_register_pre_el_change_hook_aarch64eb diff --git a/qemu/arm.h b/qemu/arm.h index 64c494e3..5e300615 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -3272,6 +3272,7 @@ #define xscale_cpar_write xscale_cpar_write_arm #define aarch64_translator_ops aarch64_translator_ops_arm #define ARM_REGS_STORAGE_SIZE ARM_REGS_STORAGE_SIZE_arm +#define arm_hcr_el2_eff arm_hcr_el2_eff_arm #define arm_regime_tbi0 arm_regime_tbi0_arm #define arm_regime_tbi1 arm_regime_tbi1_arm #define arm_register_pre_el_change_hook arm_register_pre_el_change_hook_arm diff --git a/qemu/armeb.h b/qemu/armeb.h index 435734ff..1bcd685d 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -3272,6 +3272,7 @@ #define xscale_cpar_write xscale_cpar_write_armeb #define aarch64_translator_ops aarch64_translator_ops_armeb #define ARM_REGS_STORAGE_SIZE ARM_REGS_STORAGE_SIZE_armeb +#define arm_hcr_el2_eff arm_hcr_el2_eff_armeb #define arm_regime_tbi0 arm_regime_tbi0_armeb #define arm_regime_tbi1 arm_regime_tbi1_armeb #define arm_register_pre_el_change_hook arm_register_pre_el_change_hook_armeb diff --git a/qemu/header_gen.py b/qemu/header_gen.py index b06231c7..6c27dba2 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -3281,6 +3281,7 @@ symbols = ( arm_symbols = ( 'aarch64_translator_ops', 'ARM_REGS_STORAGE_SIZE', + 'arm_hcr_el2_eff', 'arm_regime_tbi0', 'arm_regime_tbi1', 'arm_register_pre_el_change_hook', @@ -3313,6 +3314,7 @@ aarch64_symbols = ( 'arm64_reg_reset', 'arm64_reg_write', 'arm64_release', + 'arm_hcr_el2_eff', 'arm_regime_tbi0', 'arm_regime_tbi1', 'arm_register_pre_el_change_hook', diff --git a/qemu/target/arm/cpu.h b/qemu/target/arm/cpu.h index 2b6f40ab..2485b001 100644 --- a/qemu/target/arm/cpu.h +++ b/qemu/target/arm/cpu.h @@ -1673,6 +1673,14 @@ static inline bool arm_is_secure(CPUARMState *env) } #endif +/** + * arm_hcr_el2_eff(): Return the effective value of HCR_EL2. + * E.g. when in secure state, fields in HCR_EL2 are suppressed, + * "for all purposes other than a direct read or write access of HCR_EL2." + * Not included here is HCR_RW. + */ +uint64_t arm_hcr_el2_eff(CPUARMState *env); + /* Return true if the specified exception level is running in AArch64 state. */ static inline bool arm_el_is_aa64(CPUARMState *env, int el) { diff --git a/qemu/target/arm/helper.c b/qemu/target/arm/helper.c index 73216c2f..1f4fe43d 100644 --- a/qemu/target/arm/helper.c +++ b/qemu/target/arm/helper.c @@ -1195,9 +1195,10 @@ static void csselr_write(CPUARMState *env, const ARMCPRegInfo *ri, static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri) { CPUState *cs = ENV_GET_CPU(env); + uint64_t hcr_el2 = arm_hcr_el2_eff(env); uint64_t ret = 0; - if (arm_hcr_el2_imo(env)) { + if (hcr_el2 & HCR_IMO) { if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) { ret |= CPSR_I; } @@ -1207,7 +1208,7 @@ static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri) } } - if (arm_hcr_el2_fmo(env)) { + if (hcr_el2 & HCR_FMO) { if (cs->interrupt_request & CPU_INTERRUPT_VFIQ) { ret |= CPSR_F; } @@ -3563,6 +3564,51 @@ static void hcr_writelow(CPUARMState *env, const ARMCPRegInfo *ri, hcr_write(env, NULL, value); } +/* + * Return the effective value of HCR_EL2. + * Bits that are not included here: + * RW (read from SCR_EL3.RW as needed) + */ +uint64_t arm_hcr_el2_eff(CPUARMState *env) +{ + uint64_t ret = env->cp15.hcr_el2; + + if (arm_is_secure_below_el3(env)) { + /* + * "This register has no effect if EL2 is not enabled in the + * current Security state". This is ARMv8.4-SecEL2 speak for + * !(SCR_EL3.NS==1 || SCR_EL3.EEL2==1). + * + * Prior to that, the language was "In an implementation that + * includes EL3, when the value of SCR_EL3.NS is 0 the PE behaves + * as if this field is 0 for all purposes other than a direct + * read or write access of HCR_EL2". With lots of enumeration + * on a per-field basis. In current QEMU, this is condition + * is arm_is_secure_below_el3. + * + * Since the v8.4 language applies to the entire register, and + * appears to be backward compatible, use that. + */ + ret = 0; + } else if (ret & HCR_TGE) { + /* These bits are up-to-date as of ARMv8.4. */ + if (ret & HCR_E2H) { + ret &= ~(HCR_VM | HCR_FMO | HCR_IMO | HCR_AMO | + HCR_BSU_MASK | HCR_DC | HCR_TWI | HCR_TWE | + HCR_TID0 | HCR_TID2 | HCR_TPCP | HCR_TPU | + HCR_TDZ | HCR_CD | HCR_ID | HCR_MIOCNCE); + } else { + ret |= HCR_FMO | HCR_IMO | HCR_AMO; + } + ret &= ~(HCR_SWIO | HCR_PTW | HCR_VF | HCR_VI | HCR_VSE | + HCR_FB | HCR_TID1 | HCR_TID3 | HCR_TSC | HCR_TACR | + HCR_TSW | HCR_TTLB | HCR_TVM | HCR_HCD | HCR_TRVM | + HCR_TLOR); + } + + return ret; +} + static const ARMCPRegInfo el2_cp_reginfo[] = { { "HCR_EL2", 0,1,1, 3,4,0, ARM_CP_STATE_AA64, ARM_CP_IO, PL2_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.hcr_el2), {0, 0}, @@ -5708,12 +5754,13 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, uint32_t cur_el, bool secure) { CPUARMState *env = cs->env_ptr; - int rw; - int scr; - int hcr; + bool rw; + bool scr; + bool hcr; int target_el; /* Is the highest EL AArch64? */ - int is64 = arm_feature(env, ARM_FEATURE_AARCH64); + bool is64 = arm_feature(env, ARM_FEATURE_AARCH64); + uint64_t hcr_el2; if (arm_feature(env, ARM_FEATURE_EL3)) { rw = ((env->cp15.scr_el3 & SCR_RW) == SCR_RW); @@ -5725,18 +5772,19 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, rw = is64; } + hcr_el2 = arm_hcr_el2_eff(env); switch (excp_idx) { case EXCP_IRQ: scr = ((env->cp15.scr_el3 & SCR_IRQ) == SCR_IRQ); - hcr = arm_hcr_el2_imo(env); + hcr = hcr_el2 & HCR_IMO; break; case EXCP_FIQ: scr = ((env->cp15.scr_el3 & SCR_FIQ) == SCR_FIQ); - hcr = arm_hcr_el2_fmo(env); + hcr = hcr_el2 & HCR_FMO; break; default: scr = ((env->cp15.scr_el3 & SCR_EA) == SCR_EA); - hcr = arm_hcr_el2_amo(env); + hcr = hcr_el2 & HCR_AMO; break; };