target/arm: Implement SG instruction
Implement the SG instruction, which we emulate 'by hand' in the exception handling code path. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 1507556919-24992-3-git-send-email-peter.maydell@linaro.org
This commit is contained in:
parent
b9f587d62c
commit
333e10c51e
@ -41,6 +41,10 @@ typedef struct V8M_SAttributes {
|
||||
bool irvalid;
|
||||
} V8M_SAttributes;
|
||||
|
||||
static void v8m_security_lookup(CPUARMState *env, uint32_t address,
|
||||
MMUAccessType access_type, ARMMMUIdx mmu_idx,
|
||||
V8M_SAttributes *sattrs);
|
||||
|
||||
/* Definitions for the PMCCNTR and PMCR registers */
|
||||
#define PMCRD 0x8
|
||||
#define PMCRC 0x4
|
||||
@ -6736,6 +6740,126 @@ static void arm_log_exception(int idx)
|
||||
}
|
||||
}
|
||||
|
||||
static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
|
||||
uint32_t addr, uint16_t *insn)
|
||||
{
|
||||
/* Load a 16-bit portion of a v7M instruction, returning true on success,
|
||||
* or false on failure (in which case we will have pended the appropriate
|
||||
* exception).
|
||||
* We need to do the instruction fetch's MPU and SAU checks
|
||||
* like this because there is no MMU index that would allow
|
||||
* doing the load with a single function call. Instead we must
|
||||
* first check that the security attributes permit the load
|
||||
* and that they don't mismatch on the two halves of the instruction,
|
||||
* and then we do the load as a secure load (ie using the security
|
||||
* attributes of the address, not the CPU, as architecturally required).
|
||||
*/
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUARMState *env = &cpu->env;
|
||||
V8M_SAttributes sattrs = {};
|
||||
MemTxAttrs attrs = {};
|
||||
ARMMMUFaultInfo fi = {};
|
||||
MemTxResult txres;
|
||||
target_ulong page_size;
|
||||
hwaddr physaddr;
|
||||
int prot;
|
||||
uint32_t fsr;
|
||||
|
||||
v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs);
|
||||
if (!sattrs.nsc || sattrs.ns) {
|
||||
/* This must be the second half of the insn, and it straddles a
|
||||
* region boundary with the second half not being S&NSC.
|
||||
*/
|
||||
env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...really SecureFault with SFSR.INVEP\n");
|
||||
return false;
|
||||
}
|
||||
if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx,
|
||||
&physaddr, &attrs, &prot, &page_size, &fsr, &fi)) {
|
||||
/* the MPU lookup failed */
|
||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure);
|
||||
qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL\n");
|
||||
return false;
|
||||
}
|
||||
*insn = address_space_lduw_le(arm_addressspace(cs, attrs), physaddr,
|
||||
attrs, &txres);
|
||||
if (txres != MEMTX_OK) {
|
||||
env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_IBUSERR_MASK;
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
|
||||
qemu_log_mask(CPU_LOG_INT, "...really BusFault with CFSR.IBUSERR\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool v7m_handle_execute_nsc(ARMCPU *cpu)
|
||||
{
|
||||
/* Check whether this attempt to execute code in a Secure & NS-Callable
|
||||
* memory region is for an SG instruction; if so, then emulate the
|
||||
* effect of the SG instruction and return true. Otherwise pend
|
||||
* the correct kind of exception and return false.
|
||||
*/
|
||||
CPUARMState *env = &cpu->env;
|
||||
ARMMMUIdx mmu_idx;
|
||||
uint16_t insn;
|
||||
|
||||
/* We should never get here unless get_phys_addr_pmsav8() caused
|
||||
* an exception for NS executing in S&NSC memory.
|
||||
*/
|
||||
assert(!env->v7m.secure);
|
||||
assert(arm_feature(env, ARM_FEATURE_M_SECURITY));
|
||||
|
||||
/* We want to do the MPU lookup as secure; work out what mmu_idx that is */
|
||||
mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);
|
||||
|
||||
if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15], &insn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!env->thumb) {
|
||||
goto gen_invep;
|
||||
}
|
||||
|
||||
if (insn != 0xe97f) {
|
||||
/* Not an SG instruction first half (we choose the IMPDEF
|
||||
* early-SG-check option).
|
||||
*/
|
||||
goto gen_invep;
|
||||
}
|
||||
|
||||
if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15] + 2, &insn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (insn != 0xe97f) {
|
||||
/* Not an SG instruction second half (yes, both halves of the SG
|
||||
* insn have the same hex value)
|
||||
*/
|
||||
goto gen_invep;
|
||||
}
|
||||
|
||||
/* OK, we have confirmed that we really have an SG instruction.
|
||||
* We know we're NS in S memory so don't need to repeat those checks.
|
||||
*/
|
||||
qemu_log_mask(CPU_LOG_INT, "...really an SG instruction at 0x%08" PRIx32
|
||||
", executing it\n", env->regs[15]);
|
||||
env->regs[14] &= ~1;
|
||||
switch_v7m_security_state(env, true);
|
||||
xpsr_write(env, 0, XPSR_IT);
|
||||
env->regs[15] += 4;
|
||||
return true;
|
||||
|
||||
gen_invep:
|
||||
env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...really SecureFault with SFSR.INVEP\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
@ -6778,12 +6902,10 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||
* the SG instruction have the same security attributes.)
|
||||
* Everything else must generate an INVEP SecureFault, so we
|
||||
* emulate the SG instruction here.
|
||||
* TODO: actually emulate SG.
|
||||
*/
|
||||
env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...really SecureFault with SFSR.INVEP\n");
|
||||
if (v7m_handle_execute_nsc(cpu)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case M_FAKE_FSR_SFAULT:
|
||||
/* Various flavours of SecureFault for attempts to execute or
|
||||
|
Loading…
Reference in New Issue
Block a user