aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-arm/cpu.h6
-rw-r--r--target-arm/op_helper.c15
2 files changed, 19 insertions, 2 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 9119a94..e431372 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1252,7 +1252,8 @@ typedef enum CPAccessResult {
/* Access fails due to a configurable trap or enable which would
* result in a categorized exception syndrome giving information about
* the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6,
- * 0xc or 0x18).
+ * 0xc or 0x18). The exception is taken to the usual target EL (EL1 or
+ * PL1 if in EL0, otherwise to the current EL).
*/
CP_ACCESS_TRAP = 1,
/* Access fails and results in an exception syndrome 0x0 ("uncategorized").
@@ -1260,6 +1261,9 @@ typedef enum CPAccessResult {
* result in this failure is specifically defined by the architecture.
*/
CP_ACCESS_TRAP_UNCATEGORIZED = 2,
+ /* As CP_ACCESS_TRAP, but for traps directly to EL2 or EL3 */
+ CP_ACCESS_TRAP_EL2 = 3,
+ CP_ACCESS_TRAP_EL3 = 4,
} CPAccessResult;
/* Access functions for coprocessor registers. These cannot fail and
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index a4507df..79e7d10 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -335,6 +335,7 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
{
const ARMCPRegInfo *ri = rip;
+ int target_el;
if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14
&& extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) {
@@ -349,15 +350,27 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
case CP_ACCESS_OK:
return;
case CP_ACCESS_TRAP:
+ target_el = exception_target_el(env);
+ break;
+ case CP_ACCESS_TRAP_EL2:
+ /* Requesting a trap to EL2 when we're in EL3 or S-EL0/1 is
+ * a bug in the access function.
+ */
+ assert(!arm_is_secure(env) && !arm_current_el(env) == 3);
+ target_el = 2;
+ break;
+ case CP_ACCESS_TRAP_EL3:
+ target_el = 3;
break;
case CP_ACCESS_TRAP_UNCATEGORIZED:
+ target_el = exception_target_el(env);
syndrome = syn_uncategorized();
break;
default:
g_assert_not_reached();
}
- raise_exception(env, EXCP_UDEF, syndrome, exception_target_el(env));
+ raise_exception(env, EXCP_UDEF, syndrome, target_el);
}
void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)