@@ -167,26 +167,32 @@ static inline bool cptype_valid(int cptype)
typedef enum CPAccessResult {
/* Access is permitted */
CP_ACCESS_OK = 0,
+
+ /*
+ * Combined with one of the following, the low 2 bits indicate the
+ * target exception level. If 0, the exception is taken to the usual
+ * target EL (EL1 or PL1 if in EL0, otherwise to the current EL).
+ */
+ CP_ACCESS_EL_MASK = 3,
+
/*
* 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). The exception is taken to the usual target EL (EL1 or
- * PL1 if in EL0, otherwise to the current EL).
+ * 0xc or 0x18).
*/
- CP_ACCESS_TRAP = 1,
+ CP_ACCESS_TRAP = (1 << 2),
+ CP_ACCESS_TRAP_EL2 = CP_ACCESS_TRAP | 2,
+ CP_ACCESS_TRAP_EL3 = CP_ACCESS_TRAP | 3,
+
/*
* Access fails and results in an exception syndrome 0x0 ("uncategorized").
* Note that this is not a catch-all case -- the set of cases which may
* 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,
- /* As CP_ACCESS_UNCATEGORIZED, but for traps directly to EL2 or EL3 */
- CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = 5,
- CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = 6,
+ CP_ACCESS_TRAP_UNCATEGORIZED = (2 << 2),
+ CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = CP_ACCESS_TRAP_UNCATEGORIZED | 2,
+ CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = CP_ACCESS_TRAP_UNCATEGORIZED | 3,
} CPAccessResult;
typedef struct ARMCPRegInfo ARMCPRegInfo;
@@ -632,11 +632,13 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
uint32_t isread)
{
const ARMCPRegInfo *ri = rip;
+ CPAccessResult res = CP_ACCESS_OK;
int target_el;
if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14
&& extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) {
- raise_exception(env, EXCP_UDEF, syndrome, exception_target_el(env));
+ res = CP_ACCESS_TRAP;
+ goto fail;
}
/*
@@ -655,48 +657,46 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
mask &= ~((1 << 4) | (1 << 14));
if (env->cp15.hstr_el2 & mask) {
- target_el = 2;
- goto exept;
+ res = CP_ACCESS_TRAP_EL2;
+ goto fail;
}
}
- if (!ri->accessfn) {
+ if (ri->accessfn) {
+ res = ri->accessfn(env, ri, isread);
+ }
+ if (likely(res == CP_ACCESS_OK)) {
return;
}
- switch (ri->accessfn(env, ri, isread)) {
- case CP_ACCESS_OK:
- return;
+ fail:
+ switch (res & ~CP_ACCESS_EL_MASK) {
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 is
- * a bug in the access function.
- */
- assert(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;
- case CP_ACCESS_TRAP_UNCATEGORIZED_EL2:
- target_el = 2;
- syndrome = syn_uncategorized();
- break;
- case CP_ACCESS_TRAP_UNCATEGORIZED_EL3:
- target_el = 3;
syndrome = syn_uncategorized();
break;
default:
g_assert_not_reached();
}
-exept:
+ target_el = res & CP_ACCESS_EL_MASK;
+ switch (target_el) {
+ case 0:
+ target_el = exception_target_el(env);
+ break;
+ case 2:
+ assert(arm_current_el(env) != 3);
+ assert(arm_is_el2_enabled(env));
+ break;
+ case 3:
+ 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);
}