From f02045f5f5abbaa49d2308529dec7a4d08be31e2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 3 Mar 2021 18:57:50 -0500 Subject: [PATCH] target/arm: Implement new v8.1M NOCP check for exception return In v8.1M a new exception return check is added which may cause a NOCP UsageFault (see rule R_XLTP): before we clear s0..s15 and the FPSCR we must check whether access to CP10 from the Security state of the returning exception is disabled; if it is then we must take a fault. (Note that for our implementation CPPWR is always RAZ/WI and so can never cause CP10 accesses to fail.) The other v8.1M change to this register-clearing code is that if MVE is implemented VPR must also be cleared, so add a TODO comment to that effect. Backports 3423fbf10427db7680d3237d4f62d8370052fca0 --- qemu/target/arm/m_helper.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/qemu/target/arm/m_helper.c b/qemu/target/arm/m_helper.c index 08652c39..b75c982e 100644 --- a/qemu/target/arm/m_helper.c +++ b/qemu/target/arm/m_helper.c @@ -1438,7 +1438,27 @@ static void do_v7m_exception_exit(ARMCPU *cpu) v7m_exception_taken(cpu, excret, true, false); return; } else { - /* Clear s0..s15 and FPSCR */ + if (arm_feature(env, ARM_FEATURE_V8_1M)) { + /* v8.1M adds this NOCP check */ + bool nsacr_pass = exc_secure || + extract32(env->v7m.nsacr, 10, 1); + bool cpacr_pass = v7m_cpacr_pass(env, exc_secure, true); + if (!nsacr_pass) { + //armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, true); + env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK; + qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing " + "stackframe: NSACR prevents clearing FPU registers\n"); + v7m_exception_taken(cpu, excret, true, false); + } else if (!cpacr_pass) { + //armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, + // exc_secure); + env->v7m.cfsr[exc_secure] |= R_V7M_CFSR_NOCP_MASK; + qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing " + "stackframe: CPACR prevents clearing FPU registers\n"); + v7m_exception_taken(cpu, excret, true, false); + } + } + /* Clear s0..s15 and FPSCR; TODO also VPR when MVE is implemented */ int i; for (i = 0; i < 16; i += 2) {