From 67d68df40176fde08ab3a73bfde12a6f44d4fda1 Mon Sep 17 00:00:00 2001 From: Greg Bellows Date: Sun, 11 Feb 2018 17:42:00 -0500 Subject: [PATCH] target-arm: add async excp target_el function Adds a dedicated function and a lookup table for determining the target exception level of IRQ and FIQ exceptions. The lookup table is taken from the ARMv7 and ARMv8 specification exception routing tables. Backports commit 0eeb17d618361a0f4faddc160e33598b23da6dd5 from qemu --- qemu/aarch64.h | 1 + qemu/aarch64eb.h | 1 + qemu/arm.h | 1 + qemu/armeb.h | 1 + qemu/header_gen.py | 3 +- qemu/m68k.h | 1 + qemu/mips.h | 1 + qemu/mips64.h | 1 + qemu/mips64el.h | 1 + qemu/mipsel.h | 1 + qemu/powerpc.h | 1 + qemu/sparc.h | 1 + qemu/sparc64.h | 1 + qemu/target-arm/helper.c | 116 ++++++++++++++++++++++++++++++++------- qemu/x86_64.h | 1 + 15 files changed, 112 insertions(+), 20 deletions(-) diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 5342c6f0..626c6646 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -3083,6 +3083,7 @@ #define xpsr_write xpsr_write_aarch64 #define xscale_cpar_write xscale_cpar_write_aarch64 #define xscale_cp_reginfo xscale_cp_reginfo_aarch64 +#define target_el_table target_el_table_aarch64 #define ARM64_REGS_STORAGE_SIZE ARM64_REGS_STORAGE_SIZE_aarch64 #define arm64_release arm64_release_aarch64 #define arm64_reg_reset arm64_reg_reset_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index e57b1bdb..a0bda2c8 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -3083,6 +3083,7 @@ #define xpsr_write xpsr_write_aarch64eb #define xscale_cpar_write xscale_cpar_write_aarch64eb #define xscale_cp_reginfo xscale_cp_reginfo_aarch64eb +#define target_el_table target_el_table_aarch64eb #define ARM64_REGS_STORAGE_SIZE ARM64_REGS_STORAGE_SIZE_aarch64eb #define arm64_release arm64_release_aarch64eb #define arm64_reg_reset arm64_reg_reset_aarch64eb diff --git a/qemu/arm.h b/qemu/arm.h index d0c0d388..be842f8e 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -3083,5 +3083,6 @@ #define xpsr_write xpsr_write_arm #define xscale_cpar_write xscale_cpar_write_arm #define xscale_cp_reginfo xscale_cp_reginfo_arm +#define target_el_table target_el_table_arm #define ARM_REGS_STORAGE_SIZE ARM_REGS_STORAGE_SIZE_arm #endif diff --git a/qemu/armeb.h b/qemu/armeb.h index 09ab3d10..7c6ef47a 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -3083,5 +3083,6 @@ #define xpsr_write xpsr_write_armeb #define xscale_cpar_write xscale_cpar_write_armeb #define xscale_cp_reginfo xscale_cp_reginfo_armeb +#define target_el_table target_el_table_armeb #define ARM_REGS_STORAGE_SIZE ARM_REGS_STORAGE_SIZE_armeb #endif diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 10532b56..c3a51bea 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -2648,6 +2648,7 @@ symbols = ( 'system_bus_info', 't2ee_cp_reginfo', 'table_logic_cc', + 'target_el_table', 'target_parse_constraint', 'target_words_bigendian', 'tb_add_jump', @@ -3088,7 +3089,7 @@ symbols = ( 'xpsr_read', 'xpsr_write', 'xscale_cpar_write', - 'xscale_cp_reginfo' + 'xscale_cp_reginfo', ) arm_symbols = ( diff --git a/qemu/m68k.h b/qemu/m68k.h index 31063074..6868b7d4 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -3083,4 +3083,5 @@ #define xpsr_write xpsr_write_m68k #define xscale_cpar_write xscale_cpar_write_m68k #define xscale_cp_reginfo xscale_cp_reginfo_m68k +#define target_el_table target_el_table_m68k #endif diff --git a/qemu/mips.h b/qemu/mips.h index ef77a2d0..dac493cf 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -3083,6 +3083,7 @@ #define xpsr_write xpsr_write_mips #define xscale_cpar_write xscale_cpar_write_mips #define xscale_cp_reginfo xscale_cp_reginfo_mips +#define target_el_table target_el_table_mips #define cpu_mips_exec cpu_mips_exec_mips #define cpu_mips_get_random cpu_mips_get_random_mips #define cpu_mips_get_count cpu_mips_get_count_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 8676be2e..85d1b0f4 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -3083,6 +3083,7 @@ #define xpsr_write xpsr_write_mips64 #define xscale_cpar_write xscale_cpar_write_mips64 #define xscale_cp_reginfo xscale_cp_reginfo_mips64 +#define target_el_table target_el_table_mips64 #define cpu_mips_exec cpu_mips_exec_mips64 #define cpu_mips_get_random cpu_mips_get_random_mips64 #define cpu_mips_get_count cpu_mips_get_count_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 2ca995e9..a6cbb683 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -3083,6 +3083,7 @@ #define xpsr_write xpsr_write_mips64el #define xscale_cpar_write xscale_cpar_write_mips64el #define xscale_cp_reginfo xscale_cp_reginfo_mips64el +#define target_el_table target_el_table_mips64el #define cpu_mips_exec cpu_mips_exec_mips64el #define cpu_mips_get_random cpu_mips_get_random_mips64el #define cpu_mips_get_count cpu_mips_get_count_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 6b3d29d0..ff91a1a3 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -3083,6 +3083,7 @@ #define xpsr_write xpsr_write_mipsel #define xscale_cpar_write xscale_cpar_write_mipsel #define xscale_cp_reginfo xscale_cp_reginfo_mipsel +#define target_el_table target_el_table_mipsel #define cpu_mips_exec cpu_mips_exec_mipsel #define cpu_mips_get_random cpu_mips_get_random_mipsel #define cpu_mips_get_count cpu_mips_get_count_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 5996ddba..590c86c4 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -3083,4 +3083,5 @@ #define xpsr_write xpsr_write_powerpc #define xscale_cpar_write xscale_cpar_write_powerpc #define xscale_cp_reginfo xscale_cp_reginfo_powerpc +#define target_el_table target_el_table_powerpc #endif diff --git a/qemu/sparc.h b/qemu/sparc.h index fcfc7bcc..476c7539 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -3083,6 +3083,7 @@ #define xpsr_write xpsr_write_sparc #define xscale_cpar_write xscale_cpar_write_sparc #define xscale_cp_reginfo xscale_cp_reginfo_sparc +#define target_el_table target_el_table_sparc #define cpu_sparc_exec cpu_sparc_exec_sparc #define helper_compute_psr helper_compute_psr_sparc #define helper_compute_C_icc helper_compute_C_icc_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index b78a72ae..de7dee94 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -3083,6 +3083,7 @@ #define xpsr_write xpsr_write_sparc64 #define xscale_cpar_write xscale_cpar_write_sparc64 #define xscale_cp_reginfo xscale_cp_reginfo_sparc64 +#define target_el_table target_el_table_sparc64 #define cpu_sparc_exec cpu_sparc_exec_sparc64 #define helper_compute_psr helper_compute_psr_sparc64 #define helper_compute_C_icc helper_compute_C_icc_sparc64 diff --git a/qemu/target-arm/helper.c b/qemu/target-arm/helper.c index e35656a4..bd028876 100644 --- a/qemu/target-arm/helper.c +++ b/qemu/target-arm/helper.c @@ -3267,6 +3267,101 @@ void switch_mode(CPUARMState *env, int mode) env->spsr = env->banked_spsr[i]; } +/* Physical Interrupt Target EL Lookup Table + * + * [ From ARM ARM section G1.13.4 (Table G1-15) ] + * + * The below multi-dimensional table is used for looking up the target + * exception level given numerous condition criteria. Specifically, the + * target EL is based on SCR and HCR routing controls as well as the + * currently executing EL and secure state. + * + * Dimensions: + * target_el_table[2][2][2][2][2][4] + * | | | | | +--- Current EL + * | | | | +------ Non-secure(0)/Secure(1) + * | | | +--------- HCR mask override + * | | +------------ SCR exec state control + * | +--------------- SCR mask override + * +------------------ 32-bit(0)/64-bit(1) EL3 + * + * The table values are as such: + * 0-3 = EL0-EL3 + * -1 = Cannot occur + * + * The ARM ARM target EL table includes entries indicating that an "exception + * is not taken". The two cases where this is applicable are: + * 1) An exception is taken from EL3 but the SCR does not have the exception + * routed to EL3. + * 2) An exception is taken from EL2 but the HCR does not have the exception + * routed to EL2. + * In these two cases, the below table contain a target of EL1. This value is + * returned as it is expected that the consumer of the table data will check + * for "target EL >= current EL" to ensure the exception is not taken. + * + * SCR HCR + * 64 EA AMO From + * BIT IRQ IMO Non-secure Secure + * EL3 FIQ RW FMO EL0 EL1 EL2 EL3 EL0 EL1 EL2 EL3 + */ +const int8_t target_el_table[2][2][2][2][2][4] = { + {{{{/* 0 0 0 0 */{ 1, 1, 2, -1 },{ 3, -1, -1, 3 },}, + {/* 0 0 0 1 */{ 2, 2, 2, -1 },{ 3, -1, -1, 3 },},}, + {{/* 0 0 1 0 */{ 1, 1, 2, -1 },{ 3, -1, -1, 3 },}, + {/* 0 0 1 1 */{ 2, 2, 2, -1 },{ 3, -1, -1, 3 },},},}, + {{{/* 0 1 0 0 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },}, + {/* 0 1 0 1 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },},}, + {{/* 0 1 1 0 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },}, + {/* 0 1 1 1 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },},},},}, + {{{{/* 1 0 0 0 */{ 1, 1, 2, -1 },{ 1, 1, -1, 1 },}, + {/* 1 0 0 1 */{ 2, 2, 2, -1 },{ 1, 1, -1, 1 },},}, + {{/* 1 0 1 0 */{ 1, 1, 1, -1 },{ 1, 1, -1, 1 },}, + {/* 1 0 1 1 */{ 2, 2, 2, -1 },{ 1, 1, -1, 1 },},},}, + {{{/* 1 1 0 0 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },}, + {/* 1 1 0 1 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },},}, + {{/* 1 1 1 0 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },}, + {/* 1 1 1 1 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },},},},}, +}; + +/* + * Determine the target EL for physical exceptions + */ +static inline 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 = ((env->cp15.scr_el3 & SCR_RW) == SCR_RW); + int scr; + int hcr; + int target_el; + int is64 = arm_el_is_aa64(env, 3); + + switch (excp_idx) { + case EXCP_IRQ: + scr = ((env->cp15.scr_el3 & SCR_IRQ) == SCR_IRQ); + hcr = ((env->cp15.hcr_el2 & HCR_IMO) == HCR_IMO); + break; + case EXCP_FIQ: + scr = ((env->cp15.scr_el3 & SCR_FIQ) == SCR_FIQ); + hcr = ((env->cp15.hcr_el2 & HCR_FMO) == HCR_FMO); + break; + default: + scr = ((env->cp15.scr_el3 & SCR_EA) == SCR_EA); + hcr = ((env->cp15.hcr_el2 & HCR_AMO) == HCR_AMO); + break; + }; + + /* If HCR.TGE is set then HCR is treated as being 1 */ + hcr |= ((env->cp15.hcr_el2 & HCR_TGE) == HCR_TGE); + + /* Perform a table-lookup for the target EL given the current state */ + target_el = target_el_table[is64][scr][rw][hcr][secure][cur_el]; + + assert(target_el > 0); + + return target_el; +} + /* * Determine the target EL for a given exception type. */ @@ -3275,13 +3370,7 @@ unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx) CPUARMState *env = cs->env_ptr; unsigned int cur_el = arm_current_el(env); unsigned int target_el; - /* FIXME: Use actual secure state. */ - bool secure = false; - - if (!env->aarch64) { - /* TODO: Add EL2 and 3 exception handling for AArch32. */ - return 1; - } + bool secure = arm_is_secure(env); switch (excp_idx) { case EXCP_HVC: @@ -3293,19 +3382,8 @@ unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx) break; case EXCP_FIQ: case EXCP_IRQ: - { - const uint64_t hcr_mask = excp_idx == EXCP_FIQ ? HCR_FMO : HCR_IMO; - const uint32_t scr_mask = excp_idx == EXCP_FIQ ? SCR_FIQ : SCR_IRQ; - - target_el = 1; - if (!secure && (env->cp15.hcr_el2 & hcr_mask)) { - target_el = 2; - } - if (env->cp15.scr_el3 & scr_mask) { - target_el = 3; - } + target_el = arm_phys_excp_target_el(cs, excp_idx, cur_el, secure); break; - } case EXCP_VIRQ: case EXCP_VFIQ: target_el = 1; diff --git a/qemu/x86_64.h b/qemu/x86_64.h index a37857b0..6b5afb4c 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -3083,4 +3083,5 @@ #define xpsr_write xpsr_write_x86_64 #define xscale_cpar_write xscale_cpar_write_x86_64 #define xscale_cp_reginfo xscale_cp_reginfo_x86_64 +#define target_el_table target_el_table_x86_64 #endif