target/arm: Implement support for taking exceptions to Hyp mode

Implement the necessary support code for taking exceptions
to Hyp mode in AArch32.

Backports commit b9bc21ff9f9bb2d841adf1dc7f6f8ddfb9ab8b5e from qemu
This commit is contained in:
Peter Maydell 2018-08-25 04:25:52 -04:00 committed by Lioncash
parent 4c445c2300
commit 16477f908e
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -7271,6 +7271,83 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
env->regs[15] = newpc;
}
static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
{
/*
* Handle exception entry to Hyp mode; this is sufficiently
* different to entry to other AArch32 modes that we handle it
* separately here.
*
* The vector table entry used is always the 0x14 Hyp mode entry point,
* unless this is an UNDEF/HVC/abort taken from Hyp to Hyp.
* The offset applied to the preferred return address is always zero
* (see DDI0487C.a section G1.12.3).
* PSTATE A/I/F masks are set based only on the SCR.EA/IRQ/FIQ values.
*/
uint32_t addr, mask;
ARMCPU *cpu = ARM_CPU(cs->uc, cs);
CPUARMState *env = &cpu->env;
switch (cs->exception_index) {
case EXCP_UDEF:
addr = 0x04;
break;
case EXCP_SWI:
addr = 0x14;
break;
case EXCP_BKPT:
/* Fall through to prefetch abort. */
case EXCP_PREFETCH_ABORT:
env->cp15.ifar_s = env->exception.vaddress;
qemu_log_mask(CPU_LOG_INT, "...with HIFAR 0x%x\n",
(uint32_t)env->exception.vaddress);
addr = 0x0c;
break;
case EXCP_DATA_ABORT:
env->cp15.dfar_s = env->exception.vaddress;
qemu_log_mask(CPU_LOG_INT, "...with HDFAR 0x%x\n",
(uint32_t)env->exception.vaddress);
addr = 0x10;
break;
case EXCP_IRQ:
addr = 0x18;
break;
case EXCP_FIQ:
addr = 0x1c;
break;
case EXCP_HVC:
addr = 0x08;
break;
case EXCP_HYP_TRAP:
addr = 0x14;
default:
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
}
if (cs->exception_index != EXCP_IRQ && cs->exception_index != EXCP_FIQ) {
env->cp15.esr_el[2] = env->exception.syndrome;
}
if (arm_current_el(env) != 2 && addr < 0x14) {
addr = 0x14;
}
mask = 0;
if (!(env->cp15.scr_el3 & SCR_EA)) {
mask |= CPSR_A;
}
if (!(env->cp15.scr_el3 & SCR_IRQ)) {
mask |= CPSR_I;
}
if (!(env->cp15.scr_el3 & SCR_FIQ)) {
mask |= CPSR_F;
}
addr += env->cp15.hvbar;
take_aarch32_exception(env, ARM_CPU_MODE_HYP, mask, 0, addr);
}
// Unicorn: underscore appended to prevent silly clashing with defines
static void arm_cpu_do_interrupt_aarch32_(CPUState *cs)
{
@ -7306,6 +7383,11 @@ static void arm_cpu_do_interrupt_aarch32_(CPUState *cs)
env->cp15.mdscr_el1 = deposit64(env->cp15.mdscr_el1, 2, 4, moe);
}
if (env->exception.target_el == 2) {
arm_cpu_do_interrupt_aarch32_hyp(cs);
return;
}
/* TODO: Vectored interrupt controller. */
switch (cs->exception_index) {
case EXCP_UDEF: