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:
parent
e3d45c0a89
commit
27920d3d1d
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user