diff --git a/qemu/aarch64.h b/qemu/aarch64.h index f87f62d3..9e6d9a45 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_aarch64 #define swap_commutative2 swap_commutative2_aarch64 #define switch_mode switch_mode_aarch64 -#define switch_v7m_sp switch_v7m_sp_aarch64 #define syn_aa32_bkpt syn_aa32_bkpt_aarch64 #define syn_aa32_hvc syn_aa32_hvc_aarch64 #define syn_aa32_smc syn_aa32_smc_aarch64 @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_aarch64 #define write_list_to_cpustate write_list_to_cpustate_aarch64 #define write_raw_cp_reg write_raw_cp_reg_aarch64 +#define write_v7m_exception write_v7m_exception_aarch64 #define x86_ldl_phys x86_ldl_phys_aarch64 #define x86_ldq_phys x86_ldq_phys_aarch64 #define x86_ldub_phys x86_ldub_phys_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index 0a974604..d0cf6f84 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_aarch64eb #define swap_commutative2 swap_commutative2_aarch64eb #define switch_mode switch_mode_aarch64eb -#define switch_v7m_sp switch_v7m_sp_aarch64eb #define syn_aa32_bkpt syn_aa32_bkpt_aarch64eb #define syn_aa32_hvc syn_aa32_hvc_aarch64eb #define syn_aa32_smc syn_aa32_smc_aarch64eb @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_aarch64eb #define write_list_to_cpustate write_list_to_cpustate_aarch64eb #define write_raw_cp_reg write_raw_cp_reg_aarch64eb +#define write_v7m_exception write_v7m_exception_aarch64eb #define x86_ldl_phys x86_ldl_phys_aarch64eb #define x86_ldq_phys x86_ldq_phys_aarch64eb #define x86_ldub_phys x86_ldub_phys_aarch64eb diff --git a/qemu/arm.h b/qemu/arm.h index 7087f7f5..4abb1f23 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_arm #define swap_commutative2 swap_commutative2_arm #define switch_mode switch_mode_arm -#define switch_v7m_sp switch_v7m_sp_arm #define syn_aa32_bkpt syn_aa32_bkpt_arm #define syn_aa32_hvc syn_aa32_hvc_arm #define syn_aa32_smc syn_aa32_smc_arm @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_arm #define write_list_to_cpustate write_list_to_cpustate_arm #define write_raw_cp_reg write_raw_cp_reg_arm +#define write_v7m_exception write_v7m_exception_arm #define x86_ldl_phys x86_ldl_phys_arm #define x86_ldq_phys x86_ldq_phys_arm #define x86_ldub_phys x86_ldub_phys_arm diff --git a/qemu/armeb.h b/qemu/armeb.h index 651d646f..d2667e1d 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_armeb #define swap_commutative2 swap_commutative2_armeb #define switch_mode switch_mode_armeb -#define switch_v7m_sp switch_v7m_sp_armeb #define syn_aa32_bkpt syn_aa32_bkpt_armeb #define syn_aa32_hvc syn_aa32_hvc_armeb #define syn_aa32_smc syn_aa32_smc_armeb @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_armeb #define write_list_to_cpustate write_list_to_cpustate_armeb #define write_raw_cp_reg write_raw_cp_reg_armeb +#define write_v7m_exception write_v7m_exception_armeb #define x86_ldl_phys x86_ldl_phys_armeb #define x86_ldq_phys x86_ldq_phys_armeb #define x86_ldub_phys x86_ldub_phys_armeb diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 69783968..65464905 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -2911,7 +2911,6 @@ symbols = ( 'swap_commutative', 'swap_commutative2', 'switch_mode', - 'switch_v7m_sp', 'syn_aa32_bkpt', 'syn_aa32_hvc', 'syn_aa32_smc', @@ -3428,6 +3427,7 @@ symbols = ( 'write_cpustate_to_list', 'write_list_to_cpustate', 'write_raw_cp_reg', + 'write_v7m_exception', 'x86_ldl_phys', 'x86_ldq_phys', 'x86_ldub_phys', diff --git a/qemu/m68k.h b/qemu/m68k.h index 47e64b4f..8b2102f3 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_m68k #define swap_commutative2 swap_commutative2_m68k #define switch_mode switch_mode_m68k -#define switch_v7m_sp switch_v7m_sp_m68k #define syn_aa32_bkpt syn_aa32_bkpt_m68k #define syn_aa32_hvc syn_aa32_hvc_m68k #define syn_aa32_smc syn_aa32_smc_m68k @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_m68k #define write_list_to_cpustate write_list_to_cpustate_m68k #define write_raw_cp_reg write_raw_cp_reg_m68k +#define write_v7m_exception write_v7m_exception_m68k #define x86_ldl_phys x86_ldl_phys_m68k #define x86_ldq_phys x86_ldq_phys_m68k #define x86_ldub_phys x86_ldub_phys_m68k diff --git a/qemu/mips.h b/qemu/mips.h index 778c1e71..86d3f3a3 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_mips #define swap_commutative2 swap_commutative2_mips #define switch_mode switch_mode_mips -#define switch_v7m_sp switch_v7m_sp_mips #define syn_aa32_bkpt syn_aa32_bkpt_mips #define syn_aa32_hvc syn_aa32_hvc_mips #define syn_aa32_smc syn_aa32_smc_mips @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_mips #define write_list_to_cpustate write_list_to_cpustate_mips #define write_raw_cp_reg write_raw_cp_reg_mips +#define write_v7m_exception write_v7m_exception_mips #define x86_ldl_phys x86_ldl_phys_mips #define x86_ldq_phys x86_ldq_phys_mips #define x86_ldub_phys x86_ldub_phys_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 08b31594..b2c8614f 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_mips64 #define swap_commutative2 swap_commutative2_mips64 #define switch_mode switch_mode_mips64 -#define switch_v7m_sp switch_v7m_sp_mips64 #define syn_aa32_bkpt syn_aa32_bkpt_mips64 #define syn_aa32_hvc syn_aa32_hvc_mips64 #define syn_aa32_smc syn_aa32_smc_mips64 @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_mips64 #define write_list_to_cpustate write_list_to_cpustate_mips64 #define write_raw_cp_reg write_raw_cp_reg_mips64 +#define write_v7m_exception write_v7m_exception_mips64 #define x86_ldl_phys x86_ldl_phys_mips64 #define x86_ldq_phys x86_ldq_phys_mips64 #define x86_ldub_phys x86_ldub_phys_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index e75a7be2..a34d095e 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_mips64el #define swap_commutative2 swap_commutative2_mips64el #define switch_mode switch_mode_mips64el -#define switch_v7m_sp switch_v7m_sp_mips64el #define syn_aa32_bkpt syn_aa32_bkpt_mips64el #define syn_aa32_hvc syn_aa32_hvc_mips64el #define syn_aa32_smc syn_aa32_smc_mips64el @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_mips64el #define write_list_to_cpustate write_list_to_cpustate_mips64el #define write_raw_cp_reg write_raw_cp_reg_mips64el +#define write_v7m_exception write_v7m_exception_mips64el #define x86_ldl_phys x86_ldl_phys_mips64el #define x86_ldq_phys x86_ldq_phys_mips64el #define x86_ldub_phys x86_ldub_phys_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index f5f8d672..31b75565 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_mipsel #define swap_commutative2 swap_commutative2_mipsel #define switch_mode switch_mode_mipsel -#define switch_v7m_sp switch_v7m_sp_mipsel #define syn_aa32_bkpt syn_aa32_bkpt_mipsel #define syn_aa32_hvc syn_aa32_hvc_mipsel #define syn_aa32_smc syn_aa32_smc_mipsel @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_mipsel #define write_list_to_cpustate write_list_to_cpustate_mipsel #define write_raw_cp_reg write_raw_cp_reg_mipsel +#define write_v7m_exception write_v7m_exception_mipsel #define x86_ldl_phys x86_ldl_phys_mipsel #define x86_ldq_phys x86_ldq_phys_mipsel #define x86_ldub_phys x86_ldub_phys_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 7388cf91..516caf7f 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_powerpc #define swap_commutative2 swap_commutative2_powerpc #define switch_mode switch_mode_powerpc -#define switch_v7m_sp switch_v7m_sp_powerpc #define syn_aa32_bkpt syn_aa32_bkpt_powerpc #define syn_aa32_hvc syn_aa32_hvc_powerpc #define syn_aa32_smc syn_aa32_smc_powerpc @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_powerpc #define write_list_to_cpustate write_list_to_cpustate_powerpc #define write_raw_cp_reg write_raw_cp_reg_powerpc +#define write_v7m_exception write_v7m_exception_powerpc #define x86_ldl_phys x86_ldl_phys_powerpc #define x86_ldq_phys x86_ldq_phys_powerpc #define x86_ldub_phys x86_ldub_phys_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index b7d7f092..6e2da815 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_sparc #define swap_commutative2 swap_commutative2_sparc #define switch_mode switch_mode_sparc -#define switch_v7m_sp switch_v7m_sp_sparc #define syn_aa32_bkpt syn_aa32_bkpt_sparc #define syn_aa32_hvc syn_aa32_hvc_sparc #define syn_aa32_smc syn_aa32_smc_sparc @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_sparc #define write_list_to_cpustate write_list_to_cpustate_sparc #define write_raw_cp_reg write_raw_cp_reg_sparc +#define write_v7m_exception write_v7m_exception_sparc #define x86_ldl_phys x86_ldl_phys_sparc #define x86_ldq_phys x86_ldq_phys_sparc #define x86_ldub_phys x86_ldub_phys_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 2798b263..3f936e95 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_sparc64 #define swap_commutative2 swap_commutative2_sparc64 #define switch_mode switch_mode_sparc64 -#define switch_v7m_sp switch_v7m_sp_sparc64 #define syn_aa32_bkpt syn_aa32_bkpt_sparc64 #define syn_aa32_hvc syn_aa32_hvc_sparc64 #define syn_aa32_smc syn_aa32_smc_sparc64 @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_sparc64 #define write_list_to_cpustate write_list_to_cpustate_sparc64 #define write_raw_cp_reg write_raw_cp_reg_sparc64 +#define write_v7m_exception write_v7m_exception_sparc64 #define x86_ldl_phys x86_ldl_phys_sparc64 #define x86_ldq_phys x86_ldq_phys_sparc64 #define x86_ldub_phys x86_ldub_phys_sparc64 diff --git a/qemu/target/arm/cpu.h b/qemu/target/arm/cpu.h index 686bcabf..2a7a4231 100644 --- a/qemu/target/arm/cpu.h +++ b/qemu/target/arm/cpu.h @@ -963,6 +963,11 @@ void pmccntr_sync(CPUARMState *env); #define PSTATE_MODE_EL1t 4 #define PSTATE_MODE_EL0t 0 +/* Write a new value to v7m.exception, thus transitioning into or out + * of Handler mode; this may result in a change of active stack pointer. + */ +void write_v7m_exception(CPUARMState *env, uint32_t new_exc); + /* Map EL and handler into a PSTATE_MODE. */ static inline unsigned int aarch64_pstate_mode(unsigned int el, bool handler) { @@ -1043,7 +1048,8 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) env->condexec_bits |= (val >> 8) & 0xfc; } if (mask & XPSR_EXCP) { - env->v7m.exception = val & XPSR_EXCP; + /* Note that this only happens on exception exit */ + write_v7m_exception(env, val & XPSR_EXCP); } } diff --git a/qemu/target/arm/helper.c b/qemu/target/arm/helper.c index 134e78fa..f9d949d3 100644 --- a/qemu/target/arm/helper.c +++ b/qemu/target/arm/helper.c @@ -5318,20 +5318,44 @@ static bool v7m_using_psp(CPUARMState *env) env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK; } -/* Switch to V7M main or process stack pointer. */ -static void switch_v7m_sp(CPUARMState *env, bool new_spsel) +/* Write to v7M CONTROL.SPSEL bit. This may change the current + * stack pointer between Main and Process stack pointers. + */ +static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel) { uint32_t tmp; - uint32_t old_control = env->v7m.control[env->v7m.secure]; - bool old_spsel = old_control & R_V7M_CONTROL_SPSEL_MASK; + bool new_is_psp, old_is_psp = v7m_using_psp(env); - if (old_spsel != new_spsel) { + env->v7m.control[env->v7m.secure] = + deposit32(env->v7m.control[env->v7m.secure], + R_V7M_CONTROL_SPSEL_SHIFT, + R_V7M_CONTROL_SPSEL_LENGTH, new_spsel); + + new_is_psp = v7m_using_psp(env); + + if (old_is_psp != new_is_psp) { + tmp = env->v7m.other_sp; + env->v7m.other_sp = env->regs[13]; + env->regs[13] = tmp; + } +} + +void write_v7m_exception(CPUARMState *env, uint32_t new_exc) +{ + /* Write a new value to v7m.exception, thus transitioning into or out + * of Handler mode; this may result in a change of active stack pointer. + */ + bool new_is_psp, old_is_psp = v7m_using_psp(env); + uint32_t tmp; + + env->v7m.exception = new_exc; + + new_is_psp = v7m_using_psp(env); + + if (old_is_psp != new_is_psp) { tmp = env->v7m.other_sp; env->v7m.other_sp = env->regs[13]; env->regs[13] = tmp; - env->v7m.control[env->v7m.secure] = deposit32(old_control, - R_V7M_CONTROL_SPSEL_SHIFT, - R_V7M_CONTROL_SPSEL_LENGTH, new_spsel); } } @@ -5417,13 +5441,11 @@ static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode, bool want_psp = threadmode && spsel; if (secure == env->v7m.secure) { - /* Currently switch_v7m_sp switches SP as it updates SPSEL, - * so the SP we want is always in regs[13]. - * When we decouple SPSEL from the actually selected SP - * we need to check want_psp against v7m_using_psp() - * to see whether we need regs[13] or v7m.other_sp. - */ - return &env->regs[13]; + if (want_psp == v7m_using_psp(env)) { + return &env->regs[13]; + } else { + return &env->v7m.other_sp; + } } else { if (want_psp) { return &env->v7m.other_ss_psp; @@ -5467,7 +5489,7 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr) // Unicorn: commented out //armv7m_nvic_acknowledge_irq(env->nvic); - switch_v7m_sp(env, 0); + write_v7m_control_spsel(env, 0); arm_clear_exclusive(env); /* Clear IT bits */ env->condexec_bits = 0; @@ -5617,11 +5639,12 @@ static void do_v7m_exception_exit(ARMCPU *cpu) return; } - /* Set CONTROL.SPSEL from excret.SPSEL. For QEMU this currently - * causes us to switch the active SP, but we will change this - * later to not do that so we can support v8M. + /* Set CONTROL.SPSEL from excret.SPSEL. Since we're still in + * Handler mode (and will be until we write the new XPSR.Interrupt + * field) this does not switch around the current stack pointer. */ - switch_v7m_sp(env, return_to_sp_process); + write_v7m_control_spsel(env, return_to_sp_process); + { /* The stack pointer we should be reading the exception frame from * depends on bits in the magic exception return type value (and @@ -8447,11 +8470,11 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) case 20: /* CONTROL */ /* Writing to the SPSEL bit only has an effect if we are in * thread mode; other bits can be updated by any privileged code. - * switch_v7m_sp() deals with updating the SPSEL bit in + * write_v7m_control_spsel() deals with updating the SPSEL bit in * env->v7m.control, so we only need update the others. */ if (!arm_v7m_is_handler_mode(env)) { - switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0); + write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0); } env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK; env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK; diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 3fb3a989..1a80a72d 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -2905,7 +2905,6 @@ #define swap_commutative swap_commutative_x86_64 #define swap_commutative2 swap_commutative2_x86_64 #define switch_mode switch_mode_x86_64 -#define switch_v7m_sp switch_v7m_sp_x86_64 #define syn_aa32_bkpt syn_aa32_bkpt_x86_64 #define syn_aa32_hvc syn_aa32_hvc_x86_64 #define syn_aa32_smc syn_aa32_smc_x86_64 @@ -3422,6 +3421,7 @@ #define write_cpustate_to_list write_cpustate_to_list_x86_64 #define write_list_to_cpustate write_list_to_cpustate_x86_64 #define write_raw_cp_reg write_raw_cp_reg_x86_64 +#define write_v7m_exception write_v7m_exception_x86_64 #define x86_ldl_phys x86_ldl_phys_x86_64 #define x86_ldq_phys x86_ldq_phys_x86_64 #define x86_ldub_phys x86_ldub_phys_x86_64