aboutsummaryrefslogtreecommitdiff
path: root/target/arm/tcg/op_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/tcg/op_helper.c')
-rw-r--r--target/arm/tcg/op_helper.c111
1 files changed, 77 insertions, 34 deletions
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index c083e5c..575e566 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -20,10 +20,11 @@
#include "qemu/main-loop.h"
#include "cpu.h"
#include "exec/helper-proto.h"
+#include "exec/target_page.h"
#include "internals.h"
#include "cpu-features.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
+#include "accel/tcg/cpu-ldst.h"
+#include "accel/tcg/probe.h"
#include "cpregs.h"
#define SIGNBIT (uint32_t)0x80000000
@@ -313,15 +314,19 @@ void HELPER(check_bxj_trap)(CPUARMState *env, uint32_t rm)
}
#ifndef CONFIG_USER_ONLY
-/* Function checks whether WFx (WFI/WFE) instructions are set up to be trapped.
+/*
+ * Function checks whether WFx (WFI/WFE) instructions are set up to be trapped.
* The function returns the target EL (1-3) if the instruction is to be trapped;
* otherwise it returns 0 indicating it is not trapped.
+ * For a trap, *excp is updated with the EXCP_* trap type to use.
*/
-static inline int check_wfx_trap(CPUARMState *env, bool is_wfe)
+static inline int check_wfx_trap(CPUARMState *env, bool is_wfe, uint32_t *excp)
{
int cur_el = arm_current_el(env);
uint64_t mask;
+ *excp = EXCP_UDEF;
+
if (arm_feature(env, ARM_FEATURE_M)) {
/* M profile cores can never trap WFI/WFE. */
return 0;
@@ -331,18 +336,9 @@ static inline int check_wfx_trap(CPUARMState *env, bool is_wfe)
* WFx instructions being trapped to EL1. These trap bits don't exist in v7.
*/
if (cur_el < 1 && arm_feature(env, ARM_FEATURE_V8)) {
- int target_el;
-
mask = is_wfe ? SCTLR_nTWE : SCTLR_nTWI;
- if (arm_is_secure_below_el3(env) && !arm_el_is_aa64(env, 3)) {
- /* Secure EL0 and Secure PL1 is at EL3 */
- target_el = 3;
- } else {
- target_el = 1;
- }
-
- if (!(env->cp15.sctlr_el[target_el] & mask)) {
- return target_el;
+ if (!(arm_sctlr(env, cur_el) & mask)) {
+ return exception_target_el(env);
}
}
@@ -358,9 +354,12 @@ static inline int check_wfx_trap(CPUARMState *env, bool is_wfe)
}
/* We are not trapping to EL1 or EL2; trap to EL3 if SCR_EL3 requires it */
- if (cur_el < 3) {
+ if (arm_feature(env, ARM_FEATURE_V8) && !arm_is_el3_or_mon(env)) {
mask = (is_wfe) ? SCR_TWE : SCR_TWI;
if (env->cp15.scr_el3 & mask) {
+ if (!arm_el_is_aa64(env, 3)) {
+ *excp = EXCP_MON_TRAP;
+ }
return 3;
}
}
@@ -383,7 +382,8 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
return;
#else
CPUState *cs = env_cpu(env);
- int target_el = check_wfx_trap(env, false);
+ uint32_t excp;
+ int target_el = check_wfx_trap(env, false, &excp);
if (cpu_has_work(cs)) {
/* Don't bother to go into our "low power state" if
@@ -399,7 +399,7 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
env->regs[15] -= insn_len;
}
- raise_exception(env, EXCP_UDEF, syn_wfx(1, 0xe, 0, insn_len == 2),
+ raise_exception(env, excp, syn_wfx(1, 0xe, 0, insn_len == 2),
target_el);
}
@@ -424,10 +424,17 @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout)
#else
ARMCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
- int target_el = check_wfx_trap(env, false);
+ uint32_t excp;
+ int target_el = check_wfx_trap(env, false, &excp);
/* The WFIT should time out when CNTVCT_EL0 >= the specified value. */
uint64_t cntval = gt_get_countervalue(env);
- uint64_t offset = gt_virt_cnt_offset(env);
+ /*
+ * We want the value that we would get if we read CNTVCT_EL0 from
+ * the current exception level, so the direct_access offset, not
+ * the indirect_access one. Compare the pseudocode LocalTimeoutEvent(),
+ * which calls VirtualCounterTimer().
+ */
+ uint64_t offset = gt_direct_access_timer_offset(env, GTIMER_VIRT);
uint64_t cntvct = cntval - offset;
uint64_t nexttick;
@@ -441,8 +448,7 @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout)
if (target_el) {
env->pc -= 4;
- raise_exception(env, EXCP_UDEF, syn_wfx(1, 0xe, 0, false),
- target_el);
+ raise_exception(env, excp, syn_wfx(1, 0xe, 0, false), target_el);
}
if (uadd64_overflow(timeout, offset, &nexttick)) {
@@ -758,12 +764,13 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, key);
CPAccessResult res = CP_ACCESS_OK;
int target_el;
+ uint32_t excp;
assert(ri != NULL);
if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14
&& extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) {
- res = CP_ACCESS_TRAP;
+ res = CP_ACCESS_UNDEFINED;
goto fail;
}
@@ -780,7 +787,7 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
* the other trap takes priority. So we take the "check HSTR_EL2" path
* for all of those cases.)
*/
- if (res != CP_ACCESS_OK && ((res & CP_ACCESS_EL_MASK) == 0) &&
+ if (res != CP_ACCESS_OK && ((res & CP_ACCESS_EL_MASK) < 2) &&
arm_current_el(env) == 0) {
goto fail;
}
@@ -817,6 +824,7 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
unsigned int idx = FIELD_EX32(ri->fgt, FGT, IDX);
unsigned int bitpos = FIELD_EX32(ri->fgt, FGT, BITPOS);
bool rev = FIELD_EX32(ri->fgt, FGT, REV);
+ bool nxs = FIELD_EX32(ri->fgt, FGT, NXS);
bool trapbit;
if (ri->fgt & FGT_EXEC) {
@@ -830,7 +838,15 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
trapword = env->cp15.fgt_write[idx];
}
- trapbit = extract64(trapword, bitpos, 1);
+ if (nxs && (arm_hcrx_el2_eff(env) & HCRX_FGTNXS)) {
+ /*
+ * If HCRX_EL2.FGTnXS is 1 then the fine-grained trap for
+ * TLBI maintenance insns does *not* apply to the nXS variant.
+ */
+ trapbit = 0;
+ } else {
+ trapbit = extract64(trapword, bitpos, 1);
+ }
if (trapbit != rev) {
res = CP_ACCESS_TRAP_EL2;
goto fail;
@@ -842,12 +858,25 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
}
fail:
- switch (res & ~CP_ACCESS_EL_MASK) {
- case CP_ACCESS_TRAP:
+ excp = EXCP_UDEF;
+ switch (res) {
+ /* CP_ACCESS_TRAP* traps are always direct to a specified EL */
+ case CP_ACCESS_TRAP_EL3:
+ /*
+ * If EL3 is AArch32 then there's no syndrome register; the cases
+ * where we would raise a SystemAccessTrap to AArch64 EL3 all become
+ * raising a Monitor trap exception. (Because there's no visible
+ * syndrome it doesn't matter what we pass to raise_exception().)
+ */
+ if (!arm_el_is_aa64(env, 3)) {
+ excp = EXCP_MON_TRAP;
+ }
break;
- case CP_ACCESS_TRAP_UNCATEGORIZED:
- /* Only CP_ACCESS_TRAP traps are direct to a specified EL */
- assert((res & CP_ACCESS_EL_MASK) == 0);
+ case CP_ACCESS_TRAP_EL2:
+ case CP_ACCESS_TRAP_EL1:
+ break;
+ case CP_ACCESS_UNDEFINED:
+ /* CP_ACCESS_UNDEFINED is never direct to a specified EL */
if (cpu_isar_feature(aa64_ids, cpu) && isread &&
arm_cpreg_in_idspace(ri)) {
/*
@@ -867,6 +896,9 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
case 0:
target_el = exception_target_el(env);
break;
+ case 1:
+ assert(arm_current_el(env) < 2);
+ break;
case 2:
assert(arm_current_el(env) != 3);
assert(arm_is_el2_enabled(env));
@@ -875,11 +907,10 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
assert(arm_feature(env, ARM_FEATURE_EL3));
break;
default:
- /* No "direct" traps to EL1 */
g_assert_not_reached();
}
- raise_exception(env, EXCP_UDEF, syndrome, target_el);
+ raise_exception(env, excp, syndrome, target_el);
}
const void *HELPER(lookup_cp_reg)(CPUARMState *env, uint32_t key)
@@ -912,7 +943,19 @@ void HELPER(tidcp_el0)(CPUARMState *env, uint32_t syndrome)
{
/* See arm_sctlr(), but we also need the sctlr el. */
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0);
- int target_el = mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1;
+ int target_el;
+
+ switch (mmu_idx) {
+ case ARMMMUIdx_E20_0:
+ target_el = 2;
+ break;
+ case ARMMMUIdx_E30_0:
+ target_el = 3;
+ break;
+ default:
+ target_el = 1;
+ break;
+ }
/*
* The bit is not valid unless the target el is aa64, but since the
@@ -1179,7 +1222,7 @@ uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
}
}
-void HELPER(probe_access)(CPUARMState *env, target_ulong ptr,
+void HELPER(probe_access)(CPUARMState *env, vaddr ptr,
uint32_t access_type, uint32_t mmu_idx,
uint32_t size)
{