mirror of https://github.com/xemu-project/xemu.git
target-arm: Separate out M profile cpu_exec_interrupt handling
The M profile cpu_exec_interrupt handling is fairly simple but does include an M profile specific oddity (disabling interrupts for certain PC values). A/R profile handling on the other hand is getting rapidly more complicated with the support for EL2 and EL3. Split the M profile code out into its own implementation of cpu_exec_interrupt to keep these two things out of each others' way. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Message-id: 1414684132-23971-2-git-send-email-peter.maydell@linaro.org
This commit is contained in:
parent
f4df22102a
commit
b5c633c5bd
|
@ -203,15 +203,6 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||||
cc->do_interrupt(cs);
|
cc->do_interrupt(cs);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
/* ARMv7-M interrupt return works by loading a magic value
|
|
||||||
into the PC. On real hardware the load causes the
|
|
||||||
return to occur. The qemu implementation performs the
|
|
||||||
jump normally, then does the exception return when the
|
|
||||||
CPU tries to execute code at the magic address.
|
|
||||||
This will cause the magic PC value to be pushed to
|
|
||||||
the stack if an interrupt occurred at the wrong time.
|
|
||||||
We avoid this by disabling interrupts when
|
|
||||||
pc contains a magic address. */
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
if (interrupt_request & CPU_INTERRUPT_HARD
|
||||||
&& arm_excp_unmasked(cs, EXCP_IRQ)) {
|
&& arm_excp_unmasked(cs, EXCP_IRQ)) {
|
||||||
cs->exception_index = EXCP_IRQ;
|
cs->exception_index = EXCP_IRQ;
|
||||||
|
@ -234,6 +225,42 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
|
||||||
|
static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||||
|
{
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cs);
|
||||||
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
|
CPUARMState *env = &cpu->env;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
|
||||||
|
if (interrupt_request & CPU_INTERRUPT_FIQ
|
||||||
|
&& !(env->daif & PSTATE_F)) {
|
||||||
|
cs->exception_index = EXCP_FIQ;
|
||||||
|
cc->do_interrupt(cs);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
/* ARMv7-M interrupt return works by loading a magic value
|
||||||
|
* into the PC. On real hardware the load causes the
|
||||||
|
* return to occur. The qemu implementation performs the
|
||||||
|
* jump normally, then does the exception return when the
|
||||||
|
* CPU tries to execute code at the magic address.
|
||||||
|
* This will cause the magic PC value to be pushed to
|
||||||
|
* the stack if an interrupt occurred at the wrong time.
|
||||||
|
* We avoid this by disabling interrupts when
|
||||||
|
* pc contains a magic address.
|
||||||
|
*/
|
||||||
|
if (interrupt_request & CPU_INTERRUPT_HARD
|
||||||
|
&& !(env->daif & PSTATE_I)
|
||||||
|
&& (env->regs[15] < 0xfffffff0)) {
|
||||||
|
cs->exception_index = EXCP_IRQ;
|
||||||
|
cc->do_interrupt(cs);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
static void arm_cpu_set_irq(void *opaque, int irq, int level)
|
static void arm_cpu_set_irq(void *opaque, int irq, int level)
|
||||||
{
|
{
|
||||||
|
@ -670,11 +697,13 @@ static void cortex_m3_initfn(Object *obj)
|
||||||
|
|
||||||
static void arm_v7m_class_init(ObjectClass *oc, void *data)
|
static void arm_v7m_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
CPUClass *cc = CPU_CLASS(oc);
|
CPUClass *cc = CPU_CLASS(oc);
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->do_interrupt = arm_v7m_cpu_do_interrupt;
|
cc->do_interrupt = arm_v7m_cpu_do_interrupt;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
cc->cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
|
static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
|
||||||
|
|
|
@ -1251,18 +1251,6 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx)
|
||||||
bool secure = false;
|
bool secure = false;
|
||||||
/* If in EL1/0, Physical IRQ routing to EL2 only happens from NS state. */
|
/* If in EL1/0, Physical IRQ routing to EL2 only happens from NS state. */
|
||||||
bool irq_can_hyp = !secure && cur_el < 2 && target_el == 2;
|
bool irq_can_hyp = !secure && cur_el < 2 && target_el == 2;
|
||||||
/* ARMv7-M interrupt return works by loading a magic value
|
|
||||||
* into the PC. On real hardware the load causes the
|
|
||||||
* return to occur. The qemu implementation performs the
|
|
||||||
* jump normally, then does the exception return when the
|
|
||||||
* CPU tries to execute code at the magic address.
|
|
||||||
* This will cause the magic PC value to be pushed to
|
|
||||||
* the stack if an interrupt occurred at the wrong time.
|
|
||||||
* We avoid this by disabling interrupts when
|
|
||||||
* pc contains a magic address.
|
|
||||||
*/
|
|
||||||
bool irq_unmasked = !(env->daif & PSTATE_I)
|
|
||||||
&& (!IS_M(env) || env->regs[15] < 0xfffffff0);
|
|
||||||
|
|
||||||
/* Don't take exceptions if they target a lower EL. */
|
/* Don't take exceptions if they target a lower EL. */
|
||||||
if (cur_el > target_el) {
|
if (cur_el > target_el) {
|
||||||
|
@ -1279,7 +1267,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx)
|
||||||
if (irq_can_hyp && (env->cp15.hcr_el2 & HCR_IMO)) {
|
if (irq_can_hyp && (env->cp15.hcr_el2 & HCR_IMO)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return irq_unmasked;
|
return !(env->daif & PSTATE_I);
|
||||||
case EXCP_VFIQ:
|
case EXCP_VFIQ:
|
||||||
if (!secure && !(env->cp15.hcr_el2 & HCR_FMO)) {
|
if (!secure && !(env->cp15.hcr_el2 & HCR_FMO)) {
|
||||||
/* VFIQs are only taken when hypervized and non-secure. */
|
/* VFIQs are only taken when hypervized and non-secure. */
|
||||||
|
@ -1291,7 +1279,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx)
|
||||||
/* VIRQs are only taken when hypervized and non-secure. */
|
/* VIRQs are only taken when hypervized and non-secure. */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return irq_unmasked;
|
return !(env->daif & PSTATE_I);
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue