mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-01-22 19:10:57 +00:00
target/arm: Handle floating point registers in exception return
Handle floating point registers in exception return. This corresponds to pseudocode functions ValidateExceptionReturn(), ExceptionReturn(), PopStack() and ConsumeExcStackFrame(). Backports commit 6808c4d2d2826920087533f517472c09edc7b0d2 from qemu
This commit is contained in:
parent
2244bb085a
commit
86776d451e
|
@ -8252,6 +8252,8 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
bool rettobase = false;
|
||||
bool exc_secure = false;
|
||||
bool return_to_secure;
|
||||
bool ftype;
|
||||
bool restore_s16_s31;
|
||||
|
||||
/* If we're not in Handler mode then jumps to magic exception-exit
|
||||
* addresses don't have magic behaviour. However for the v8M
|
||||
|
@ -8289,6 +8291,16 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
excret);
|
||||
}
|
||||
|
||||
ftype = excret & R_V7M_EXCRET_FTYPE_MASK;
|
||||
|
||||
if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception "
|
||||
"exit PC value 0x%" PRIx32 " is UNPREDICTABLE "
|
||||
"if FPU not present\n",
|
||||
excret);
|
||||
ftype = true;
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
/* EXC_RETURN.ES validation check (R_SMFL). We must do this before
|
||||
* we pick which FAULTMASK to clear.
|
||||
|
@ -8393,6 +8405,30 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
*/
|
||||
write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_secure);
|
||||
|
||||
/*
|
||||
* Clear scratch FP values left in caller saved registers; this
|
||||
* must happen before any kind of tail chaining.
|
||||
*/
|
||||
if ((env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_CLRONRET_MASK) &&
|
||||
(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
|
||||
if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
|
||||
env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
|
||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
|
||||
qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
|
||||
"stackframe: error during lazy state deactivation\n");
|
||||
v7m_exception_taken(cpu, excret, true, false);
|
||||
return;
|
||||
} else {
|
||||
/* Clear s0..s15 and FPSCR */
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i += 2) {
|
||||
*aa32_vfp_dreg(env, i / 2) = 0;
|
||||
}
|
||||
vfp_set_fpscr(env, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (sfault) {
|
||||
env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;
|
||||
// Unicorn: commented out
|
||||
|
@ -8559,8 +8595,105 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
if (!ftype) {
|
||||
/* FP present and we need to handle it */
|
||||
if (!return_to_secure &&
|
||||
(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK)) {
|
||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
|
||||
env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...taking SecureFault on existing stackframe: "
|
||||
"Secure LSPACT set but exception return is "
|
||||
"not to secure state\n");
|
||||
v7m_exception_taken(cpu, excret, true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
restore_s16_s31 = return_to_secure &&
|
||||
(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
|
||||
|
||||
if (env->v7m.fpccr[return_to_secure] & R_V7M_FPCCR_LSPACT_MASK) {
|
||||
/* State in FPU is still valid, just clear LSPACT */
|
||||
env->v7m.fpccr[return_to_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
|
||||
} else {
|
||||
int i;
|
||||
uint32_t fpscr;
|
||||
bool cpacr_pass, nsacr_pass;
|
||||
|
||||
cpacr_pass = v7m_cpacr_pass(env, return_to_secure,
|
||||
return_to_priv);
|
||||
nsacr_pass = return_to_secure ||
|
||||
extract32(env->v7m.nsacr, 10, 1);
|
||||
|
||||
if (!cpacr_pass) {
|
||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
|
||||
// return_to_secure);
|
||||
env->v7m.cfsr[return_to_secure] |= R_V7M_CFSR_NOCP_MASK;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...taking UsageFault on existing "
|
||||
"stackframe: CPACR.CP10 prevents unstacking "
|
||||
"FP regs\n");
|
||||
v7m_exception_taken(cpu, excret, true, false);
|
||||
return;
|
||||
} else if (!nsacr_pass) {
|
||||
//armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, true);
|
||||
env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_INVPC_MASK;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...taking Secure UsageFault on existing "
|
||||
"stackframe: NSACR.CP10 prevents unstacking "
|
||||
"FP regs\n");
|
||||
v7m_exception_taken(cpu, excret, true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
|
||||
uint32_t slo, shi;
|
||||
uint64_t dn;
|
||||
uint32_t faddr = frameptr + 0x20 + 4 * i;
|
||||
|
||||
if (i >= 16) {
|
||||
faddr += 8; /* Skip the slot for the FPSCR */
|
||||
}
|
||||
|
||||
pop_ok = pop_ok &&
|
||||
v7m_stack_read(cpu, &slo, faddr, mmu_idx) &&
|
||||
v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx);
|
||||
|
||||
if (!pop_ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
dn = (uint64_t)shi << 32 | slo;
|
||||
*aa32_vfp_dreg(env, i / 2) = dn;
|
||||
}
|
||||
pop_ok = pop_ok &&
|
||||
v7m_stack_read(cpu, &fpscr, frameptr + 0x60, mmu_idx);
|
||||
if (pop_ok) {
|
||||
vfp_set_fpscr(env, fpscr);
|
||||
}
|
||||
if (!pop_ok) {
|
||||
/*
|
||||
* These regs are 0 if security extension present;
|
||||
* otherwise merely UNKNOWN. We zero always.
|
||||
*/
|
||||
for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
|
||||
*aa32_vfp_dreg(env, i / 2) = 0;
|
||||
}
|
||||
vfp_set_fpscr(env, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
|
||||
V7M_CONTROL, FPCA, !ftype);
|
||||
|
||||
/* Commit to consuming the stack frame */
|
||||
frameptr += 0x20;
|
||||
if (!ftype) {
|
||||
frameptr += 0x48;
|
||||
if (restore_s16_s31) {
|
||||
frameptr += 0x40;
|
||||
}
|
||||
}
|
||||
/* Undo stack alignment (the SPREALIGN bit indicates that the original
|
||||
* pre-exception SP was not 8-aligned and we added a padding word to
|
||||
* align it, so we undo this by ORing in the bit that increases it
|
||||
|
@ -8573,7 +8706,14 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
|
|||
*frame_sp_p = frameptr;
|
||||
}
|
||||
/* This xpsr_write() will invalidate frame_sp_p as it may switch stack */
|
||||
xpsr_write(env, xpsr, ~XPSR_SPREALIGN);
|
||||
xpsr_write(env, xpsr, ~(XPSR_SPREALIGN | XPSR_SFPA));
|
||||
|
||||
if (env->v7m.secure) {
|
||||
bool sfpa = xpsr & XPSR_SFPA;
|
||||
|
||||
env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
|
||||
V7M_CONTROL, SFPA, sfpa);
|
||||
}
|
||||
|
||||
/* The restored xPSR exception field will be zero if we're
|
||||
* resuming in Thread mode. If that doesn't match what the
|
||||
|
|
Loading…
Reference in a new issue