target/arm: Implement HCR_EL2.TIDCP

Perform the check for EL2 enabled in the security space and the
TIDCP bit in an out-of-line helper.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20230831232441.66020-4-richard.henderson@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2023-08-31 16:24:39 -07:00 committed by Peter Maydell
parent e3d45c0a89
commit 27920d3d1d
4 changed files with 55 additions and 2 deletions

View File

@ -81,6 +81,7 @@ DEF_HELPER_FLAGS_2(check_bxj_trap, TCG_CALL_NO_WG, void, env, i32)
DEF_HELPER_4(access_check_cp_reg, cptr, env, i32, i32, i32) DEF_HELPER_4(access_check_cp_reg, cptr, env, i32, i32, i32)
DEF_HELPER_FLAGS_2(lookup_cp_reg, TCG_CALL_NO_RWG_SE, cptr, env, i32) DEF_HELPER_FLAGS_2(lookup_cp_reg, TCG_CALL_NO_RWG_SE, cptr, env, i32)
DEF_HELPER_FLAGS_2(tidcp_el1, TCG_CALL_NO_WG, void, env, i32)
DEF_HELPER_3(set_cp_reg, void, env, cptr, i32) DEF_HELPER_3(set_cp_reg, void, env, cptr, i32)
DEF_HELPER_2(get_cp_reg, i32, env, cptr) DEF_HELPER_2(get_cp_reg, i32, env, cptr)
DEF_HELPER_3(set_cp_reg64, void, env, cptr, i64) DEF_HELPER_3(set_cp_reg64, void, env, cptr, i64)

View File

@ -764,6 +764,19 @@ const void *HELPER(lookup_cp_reg)(CPUARMState *env, uint32_t key)
return ri; return ri;
} }
/*
* Test for HCR_EL2.TIDCP at EL1.
* Since implementation defined registers are rare, and within QEMU
* most of them are no-op, do not waste HFLAGS space for this and
* always use a helper.
*/
void HELPER(tidcp_el1)(CPUARMState *env, uint32_t syndrome)
{
if (arm_hcr_el2_eff(env) & HCR_TIDCP) {
raise_exception_ra(env, EXCP_UDEF, syndrome, 2, GETPC());
}
}
void HELPER(set_cp_reg)(CPUARMState *env, const void *rip, uint32_t value) void HELPER(set_cp_reg)(CPUARMState *env, const void *rip, uint32_t value)
{ {
const ARMCPRegInfo *ri = rip; const ARMCPRegInfo *ri = rip;

View File

@ -2154,6 +2154,20 @@ static void handle_sys(DisasContext *s, bool isread,
bool need_exit_tb = false; bool need_exit_tb = false;
TCGv_ptr tcg_ri = NULL; TCGv_ptr tcg_ri = NULL;
TCGv_i64 tcg_rt; TCGv_i64 tcg_rt;
uint32_t syndrome;
if (crn == 11 || crn == 15) {
/*
* Check for TIDCP trap, which must take precedence over
* the UNDEF for "no such register" etc.
*/
syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
switch (s->current_el) {
case 1:
gen_helper_tidcp_el1(cpu_env, tcg_constant_i32(syndrome));
break;
}
}
if (!ri) { if (!ri) {
/* Unknown register; this might be a guest error or a QEMU /* Unknown register; this might be a guest error or a QEMU
@ -2176,8 +2190,6 @@ static void handle_sys(DisasContext *s, bool isread,
/* Emit code to perform further access permissions checks at /* Emit code to perform further access permissions checks at
* runtime; this may result in an exception. * runtime; this may result in an exception.
*/ */
uint32_t syndrome;
syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
gen_a64_update_pc(s, 0); gen_a64_update_pc(s, 0);
tcg_ri = tcg_temp_new_ptr(); tcg_ri = tcg_temp_new_ptr();

View File

@ -4538,6 +4538,20 @@ void gen_gvec_uaba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
} }
static bool aa32_cpreg_encoding_in_impdef_space(uint8_t crn, uint8_t crm)
{
static const uint16_t mask[3] = {
0b0000000111100111, /* crn == 9, crm == {c0-c2, c5-c8} */
0b0000000100010011, /* crn == 10, crm == {c0, c1, c4, c8} */
0b1000000111111111, /* crn == 11, crm == {c0-c8, c15} */
};
if (crn >= 9 && crn <= 11) {
return (mask[crn - 9] >> crm) & 1;
}
return false;
}
static void do_coproc_insn(DisasContext *s, int cpnum, int is64, static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
int opc1, int crn, int crm, int opc2, int opc1, int crn, int crm, int opc2,
bool isread, int rt, int rt2) bool isread, int rt, int rt2)
@ -4619,6 +4633,19 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
} }
} }
if (cpnum == 15 && aa32_cpreg_encoding_in_impdef_space(crn, crm)) {
/*
* Check for TIDCP trap, which must take precedence over the UNDEF
* for "no such register" etc. It shares precedence with HSTR,
* but raises the same exception, so order doesn't matter.
*/
switch (s->current_el) {
case 1:
gen_helper_tidcp_el1(cpu_env, tcg_constant_i32(syndrome));
break;
}
}
if (!ri) { if (!ri) {
/* /*
* Unknown register; this might be a guest error or a QEMU * Unknown register; this might be a guest error or a QEMU