target/arm: Reorg CPAccessResult and access_check_cp_reg

Rearrange the values of the enumerators of CPAccessResult
so that we may directly extract the target el. For the two
special cases in access_check_cp_reg, use CPAccessResult.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20220501055028.646596-3-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2022-04-30 22:49:44 -07:00 committed by Peter Maydell
parent cf7c6d1004
commit 330477eae9
2 changed files with 44 additions and 38 deletions

View File

@ -167,26 +167,32 @@ static inline bool cptype_valid(int cptype)
typedef enum CPAccessResult { typedef enum CPAccessResult {
/* Access is permitted */ /* Access is permitted */
CP_ACCESS_OK = 0, 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 * Access fails due to a configurable trap or enable which would
* result in a categorized exception syndrome giving information about * result in a categorized exception syndrome giving information about
* the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6, * the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6,
* 0xc or 0x18). The exception is taken to the usual target EL (EL1 or * 0xc or 0x18).
* PL1 if in EL0, otherwise to the current EL).
*/ */
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"). * 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 * 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. * result in this failure is specifically defined by the architecture.
*/ */
CP_ACCESS_TRAP_UNCATEGORIZED = 2, CP_ACCESS_TRAP_UNCATEGORIZED = (2 << 2),
/* As CP_ACCESS_TRAP, but for traps directly to EL2 or EL3 */ CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = CP_ACCESS_TRAP_UNCATEGORIZED | 2,
CP_ACCESS_TRAP_EL2 = 3, CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = CP_ACCESS_TRAP_UNCATEGORIZED | 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,
} CPAccessResult; } CPAccessResult;
typedef struct ARMCPRegInfo ARMCPRegInfo; typedef struct ARMCPRegInfo ARMCPRegInfo;

View File

@ -632,11 +632,13 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
uint32_t isread) uint32_t isread)
{ {
const ARMCPRegInfo *ri = rip; const ARMCPRegInfo *ri = rip;
CPAccessResult res = CP_ACCESS_OK;
int target_el; int target_el;
if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14 if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14
&& extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) { && 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)); mask &= ~((1 << 4) | (1 << 14));
if (env->cp15.hstr_el2 & mask) { if (env->cp15.hstr_el2 & mask) {
target_el = 2; res = CP_ACCESS_TRAP_EL2;
goto exept; goto fail;
} }
} }
if (!ri->accessfn) { if (ri->accessfn) {
res = ri->accessfn(env, ri, isread);
}
if (likely(res == CP_ACCESS_OK)) {
return; return;
} }
switch (ri->accessfn(env, ri, isread)) { fail:
case CP_ACCESS_OK: switch (res & ~CP_ACCESS_EL_MASK) {
return;
case CP_ACCESS_TRAP: 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; break;
case CP_ACCESS_TRAP_UNCATEGORIZED: 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(); syndrome = syn_uncategorized();
break; break;
default: default:
g_assert_not_reached(); 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); raise_exception(env, EXCP_UDEF, syndrome, target_el);
} }