mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-01-11 01:45:31 +00:00
target/arm: Implement v7m_update_fpccr()
Implement the code which updates the FPCCR register on an exception entry where we are going to use lazy FP stacking. We have to defer to the NVIC to determine whether the various exceptions are currently ready or not. Backports commit b593c2b81287040ab6f452afec6281e2f7ee487b from qemu
This commit is contained in:
parent
065e60503f
commit
c7f5633cfe
|
@ -1917,7 +1917,11 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
|
|||
|
||||
/* Interface between CPU and Interrupt controller. */
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
bool armv7m_nvic_can_take_pending_exception(void *opaque);
|
||||
static inline bool armv7m_nvic_can_take_pending_exception(void *opaque)
|
||||
{
|
||||
// Unicorn: We return true here as well
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
static inline bool armv7m_nvic_can_take_pending_exception(void *opaque)
|
||||
{
|
||||
|
@ -1986,6 +1990,25 @@ void armv7m_nvic_acknowledge_irq(void *opaque);
|
|||
* (Ignoring -1, this is the same as the RETTOBASE value before completion.)
|
||||
*/
|
||||
int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure);
|
||||
/**
|
||||
* armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure)
|
||||
* @opaque: the NVIC
|
||||
* @irq: the exception number to mark pending
|
||||
* @secure: false for non-banked exceptions or for the nonsecure
|
||||
* version of a banked exception, true for the secure version of a banked
|
||||
* exception.
|
||||
*
|
||||
* Return whether an exception is "ready", i.e. whether the exception is
|
||||
* enabled and is configured at a priority which would allow it to
|
||||
* interrupt the current execution priority. This controls whether the
|
||||
* RDY bit for it in the FPCCR is set.
|
||||
*/
|
||||
static inline bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure)
|
||||
{
|
||||
// Unicorn: We always return as ready.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* armv7m_nvic_raw_execution_priority: return the raw execution priority
|
||||
* @opaque: the NVIC
|
||||
|
@ -2004,7 +2027,11 @@ int armv7m_nvic_raw_execution_priority(void *opaque);
|
|||
* This corresponds to the pseudocode IsReqExecPriNeg().
|
||||
*/
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure);
|
||||
static inline bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
|
||||
{
|
||||
// Unicorn: We also return false here
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
static inline bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
|
||||
{
|
||||
|
|
|
@ -7982,6 +7982,71 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
|
|||
env->thumb = addr & 1;
|
||||
}
|
||||
|
||||
static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr,
|
||||
bool apply_splim)
|
||||
{
|
||||
/*
|
||||
* Like the pseudocode UpdateFPCCR: save state in FPCAR and FPCCR
|
||||
* that we will need later in order to do lazy FP reg stacking.
|
||||
*/
|
||||
bool is_secure = env->v7m.secure;
|
||||
void *nvic = env->nvic;
|
||||
/*
|
||||
* Some bits are unbanked and live always in fpccr[M_REG_S]; some bits
|
||||
* are banked and we want to update the bit in the bank for the
|
||||
* current security state; and in one case we want to specifically
|
||||
* update the NS banked version of a bit even if we are secure.
|
||||
*/
|
||||
uint32_t *fpccr_s = &env->v7m.fpccr[M_REG_S];
|
||||
uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS];
|
||||
uint32_t *fpccr = &env->v7m.fpccr[is_secure];
|
||||
bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy;
|
||||
|
||||
env->v7m.fpcar[is_secure] = frameptr & ~0x7;
|
||||
|
||||
if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) {
|
||||
bool splimviol;
|
||||
uint32_t splim = v7m_sp_limit(env);
|
||||
bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) &&
|
||||
(env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK);
|
||||
|
||||
splimviol = !ign && frameptr < splim;
|
||||
*fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol);
|
||||
}
|
||||
|
||||
*fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1);
|
||||
|
||||
*fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure);
|
||||
|
||||
*fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0);
|
||||
|
||||
*fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD,
|
||||
!arm_v7m_is_handler_mode(env));
|
||||
|
||||
hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false);
|
||||
*fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
|
||||
|
||||
bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false);
|
||||
*fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
|
||||
|
||||
mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure);
|
||||
*fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy);
|
||||
|
||||
ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false);
|
||||
*fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy);
|
||||
|
||||
monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false);
|
||||
*fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy);
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true);
|
||||
*fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy);
|
||||
|
||||
sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false);
|
||||
*fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, SFRDY, sfrdy);
|
||||
}
|
||||
}
|
||||
|
||||
static bool v7m_push_stack(ARMCPU *cpu)
|
||||
{
|
||||
/* Do the "set up stack frame" part of exception entry,
|
||||
|
@ -8129,7 +8194,7 @@ static bool v7m_push_stack(ARMCPU *cpu)
|
|||
}
|
||||
} else {
|
||||
/* Lazy stacking enabled, save necessary info to stack later */
|
||||
/* TODO : equivalent of UpdateFPCCR() pseudocode */
|
||||
v7m_update_fpccr(env, frameptr + 0x20, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue