mirror of https://github.com/xemu-project/xemu.git
armv7m: MRS/MSR: handle unprivileged access
The MRS and MSR instruction handling has a number of flaws: * unprivileged accesses should only be able to read CONTROL and the xPSR subfields, and only write APSR (others RAZ/WI) * privileged access should not be able to write xPSR subfields other than APSR * accesses to unimplemented registers should log as guest errors, not abort QEMU Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1484937883-1068-2-git-send-email-peter.maydell@linaro.org [PMM: rewrote commit message] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
ac2810defa
commit
58117c9bb4
|
@ -8243,23 +8243,32 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
|
||||||
|
|
||||||
uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
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 |= 0x000001ff; /* IPSR (unpriv. reads as zero) */
|
||||||
|
}
|
||||||
|
if (!(reg & 4)) {
|
||||||
|
mask |= 0xf8000000; /* APSR */
|
||||||
|
}
|
||||||
|
/* EPSR reads as zero */
|
||||||
|
return xpsr_read(env) & mask;
|
||||||
|
break;
|
||||||
|
case 20: /* CONTROL */
|
||||||
|
return env->v7m.control;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el == 0) {
|
||||||
|
return 0; /* unprivileged reads others as zero */
|
||||||
|
}
|
||||||
|
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case 0: /* APSR */
|
|
||||||
return xpsr_read(env) & 0xf8000000;
|
|
||||||
case 1: /* IAPSR */
|
|
||||||
return xpsr_read(env) & 0xf80001ff;
|
|
||||||
case 2: /* EAPSR */
|
|
||||||
return xpsr_read(env) & 0xff00fc00;
|
|
||||||
case 3: /* xPSR */
|
|
||||||
return xpsr_read(env) & 0xff00fdff;
|
|
||||||
case 5: /* IPSR */
|
|
||||||
return xpsr_read(env) & 0x000001ff;
|
|
||||||
case 6: /* EPSR */
|
|
||||||
return xpsr_read(env) & 0x0700fc00;
|
|
||||||
case 7: /* IEPSR */
|
|
||||||
return xpsr_read(env) & 0x0700edff;
|
|
||||||
case 8: /* MSP */
|
case 8: /* MSP */
|
||||||
return env->v7m.current_sp ? env->v7m.other_sp : env->regs[13];
|
return env->v7m.current_sp ? env->v7m.other_sp : env->regs[13];
|
||||||
case 9: /* PSP */
|
case 9: /* PSP */
|
||||||
|
@ -8271,40 +8280,26 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
||||||
return env->v7m.basepri;
|
return env->v7m.basepri;
|
||||||
case 19: /* FAULTMASK */
|
case 19: /* FAULTMASK */
|
||||||
return (env->daif & PSTATE_F) != 0;
|
return (env->daif & PSTATE_F) != 0;
|
||||||
case 20: /* CONTROL */
|
|
||||||
return env->v7m.control;
|
|
||||||
default:
|
default:
|
||||||
/* ??? For debugging only. */
|
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
|
||||||
cpu_abort(CPU(cpu), "Unimplemented system register read (%d)\n", reg);
|
" register %d\n", reg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
|
void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
if (arm_current_el(env) == 0 && reg > 7) {
|
||||||
|
/* only xPSR sub-fields may be written by unprivileged */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case 0: /* APSR */
|
case 0 ... 7: /* xPSR sub-fields */
|
||||||
xpsr_write(env, val, 0xf8000000);
|
/* only APSR is actually writable */
|
||||||
break;
|
if (reg & 4) {
|
||||||
case 1: /* IAPSR */
|
xpsr_write(env, val, 0xf8000000); /* APSR */
|
||||||
xpsr_write(env, val, 0xf8000000);
|
}
|
||||||
break;
|
|
||||||
case 2: /* EAPSR */
|
|
||||||
xpsr_write(env, val, 0xfe00fc00);
|
|
||||||
break;
|
|
||||||
case 3: /* xPSR */
|
|
||||||
xpsr_write(env, val, 0xfe00fc00);
|
|
||||||
break;
|
|
||||||
case 5: /* IPSR */
|
|
||||||
/* IPSR bits are readonly. */
|
|
||||||
break;
|
|
||||||
case 6: /* EPSR */
|
|
||||||
xpsr_write(env, val, 0x0600fc00);
|
|
||||||
break;
|
|
||||||
case 7: /* IEPSR */
|
|
||||||
xpsr_write(env, val, 0x0600fc00);
|
|
||||||
break;
|
break;
|
||||||
case 8: /* MSP */
|
case 8: /* MSP */
|
||||||
if (env->v7m.current_sp)
|
if (env->v7m.current_sp)
|
||||||
|
@ -8345,8 +8340,8 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
|
||||||
switch_v7m_sp(env, (val & 2) != 0);
|
switch_v7m_sp(env, (val & 2) != 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* ??? For debugging only. */
|
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"
|
||||||
cpu_abort(CPU(cpu), "Unimplemented system register write (%d)\n", reg);
|
" register %d\n", reg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue