target/arm: Support EL0 v7m msr/mrs for CONFIG_USER_ONLY

Simply moving the non-stub helper_v7m_mrs/msr outside of
!CONFIG_USER_ONLY is not an option, because of all of the
other system-mode helpers that are called.

But we can split out a few subroutines to handle the few
EL0 accessible registers without duplicating code.

Reported-by: Christophe Lyon <christophe.lyon@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20191118194916.3670-1-richard.henderson@linaro.org
[PMM: deleted now-redundant comment; added a default case
 to switch in v7m_msr helper]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2019-11-19 13:20:28 +00:00 committed by Peter Maydell
parent d46ad79efa
commit 04c9c81b8f
2 changed files with 73 additions and 43 deletions

View File

@ -1314,6 +1314,7 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
if (mask & XPSR_GE) {
env->GE = (val & XPSR_GE) >> 16;
}
#ifndef CONFIG_USER_ONLY
if (mask & XPSR_T) {
env->thumb = ((val & XPSR_T) != 0);
}
@ -1329,6 +1330,7 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
/* Note that this only happens on exception exit */
write_v7m_exception(env, val & XPSR_EXCP);
}
#endif
}
#define HCR_VM (1ULL << 0)

View File

@ -33,22 +33,82 @@
#include "exec/cpu_ldst.h"
#endif
static void v7m_msr_xpsr(CPUARMState *env, uint32_t mask,
uint32_t reg, uint32_t val)
{
/* Only APSR is actually writable */
if (!(reg & 4)) {
uint32_t apsrmask = 0;
if (mask & 8) {
apsrmask |= XPSR_NZCV | XPSR_Q;
}
if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
apsrmask |= XPSR_GE;
}
xpsr_write(env, val, apsrmask);
}
}
static uint32_t v7m_mrs_xpsr(CPUARMState *env, uint32_t reg, unsigned el)
{
uint32_t mask = 0;
if ((reg & 1) && el) {
mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
}
if (!(reg & 4)) {
mask |= XPSR_NZCV | XPSR_Q; /* APSR */
if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
mask |= XPSR_GE;
}
}
/* EPSR reads as zero */
return xpsr_read(env) & mask;
}
static uint32_t v7m_mrs_control(CPUARMState *env, uint32_t secure)
{
uint32_t value = env->v7m.control[secure];
if (!secure) {
/* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank */
value |= env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK;
}
return value;
}
#ifdef CONFIG_USER_ONLY
/* These should probably raise undefined insn exceptions. */
void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
{
ARMCPU *cpu = env_archcpu(env);
uint32_t mask = extract32(maskreg, 8, 4);
uint32_t reg = extract32(maskreg, 0, 8);
cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
switch (reg) {
case 0 ... 7: /* xPSR sub-fields */
v7m_msr_xpsr(env, mask, reg, val);
break;
case 20: /* CONTROL */
/* There are no sub-fields that are actually writable from EL0. */
break;
default:
/* Unprivileged writes to other registers are ignored */
break;
}
}
uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
{
ARMCPU *cpu = env_archcpu(env);
cpu_abort(CPU(cpu), "v7m_mrs %d\n", reg);
return 0;
switch (reg) {
case 0 ... 7: /* xPSR sub-fields */
return v7m_mrs_xpsr(env, reg, 0);
case 20: /* CONTROL */
return v7m_mrs_control(env, 0);
default:
/* Unprivileged reads others as zero. */
return 0;
}
}
void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
@ -2196,35 +2256,14 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
{
uint32_t mask;
unsigned el = arm_current_el(env);
/* First handle registers which unprivileged can read */
switch (reg) {
case 0 ... 7: /* xPSR sub-fields */
mask = 0;
if ((reg & 1) && el) {
mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
}
if (!(reg & 4)) {
mask |= XPSR_NZCV | XPSR_Q; /* APSR */
if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
mask |= XPSR_GE;
}
}
/* EPSR reads as zero */
return xpsr_read(env) & mask;
break;
return v7m_mrs_xpsr(env, reg, el);
case 20: /* CONTROL */
{
uint32_t value = env->v7m.control[env->v7m.secure];
if (!env->v7m.secure) {
/* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank */
value |= env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK;
}
return value;
}
return v7m_mrs_control(env, env->v7m.secure);
case 0x94: /* CONTROL_NS */
/*
* We have to handle this here because unprivileged Secure code
@ -2454,18 +2493,7 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
switch (reg) {
case 0 ... 7: /* xPSR sub-fields */
/* only APSR is actually writable */
if (!(reg & 4)) {
uint32_t apsrmask = 0;
if (mask & 8) {
apsrmask |= XPSR_NZCV | XPSR_Q;
}
if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
apsrmask |= XPSR_GE;
}
xpsr_write(env, val, apsrmask);
}
v7m_msr_xpsr(env, mask, reg, val);
break;
case 8: /* MSP */
if (v7m_using_psp(env)) {