aboutsummaryrefslogtreecommitdiff
path: root/target/arm/tcg/translate-a64.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/tcg/translate-a64.c')
-rw-r--r--target/arm/tcg/translate-a64.c49
1 files changed, 39 insertions, 10 deletions
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 5975fc4793..f5377dbaf2 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2132,16 +2132,17 @@ static void handle_sys(DisasContext *s, bool isread,
crn, crm, op0, op1, op2);
const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
bool need_exit_tb = false;
+ bool nv_trap_to_el2 = false;
+ bool skip_fp_access_checks = false;
TCGv_ptr tcg_ri = NULL;
TCGv_i64 tcg_rt;
- uint32_t syndrome;
+ uint32_t syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
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 0:
if (dc_isar_feature(aa64_tidcp1, s)) {
@@ -2167,15 +2168,35 @@ static void handle_sys(DisasContext *s, bool isread,
/* Check access permissions */
if (!cp_access_ok(s->current_el, ri, isread)) {
- gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt);
- return;
+ /*
+ * FEAT_NV/NV2 handling does not do the usual FP access checks
+ * for registers only accessible at EL2 (though it *does* do them
+ * for registers accessible at EL1).
+ */
+ skip_fp_access_checks = true;
+ if (s->nv && arm_cpreg_traps_in_nv(ri)) {
+ /*
+ * This register / instruction exists and is an EL2 register, so
+ * we must trap to EL2 if accessed in nested virtualization EL1
+ * instead of UNDEFing. We'll do that after the usual access checks.
+ * (This makes a difference only for a couple of registers like
+ * VSTTBR_EL2 where the "UNDEF if NonSecure" should take priority
+ * over the trap-to-EL2. Most trapped-by-FEAT_NV registers have
+ * an accessfn which does nothing when called from EL1, because
+ * the trap-to-EL3 controls which would apply to that register
+ * at EL2 don't take priority over the FEAT_NV trap-to-EL2.)
+ */
+ nv_trap_to_el2 = true;
+ } else {
+ gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt);
+ return;
+ }
}
if (ri->accessfn || (ri->fgt && s->fgt_active)) {
/* Emit code to perform further access permissions checks at
* runtime; this may result in an exception.
*/
- syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
gen_a64_update_pc(s, 0);
tcg_ri = tcg_temp_new_ptr();
gen_helper_access_check_cp_reg(tcg_ri, tcg_env,
@@ -2190,11 +2211,18 @@ static void handle_sys(DisasContext *s, bool isread,
gen_a64_update_pc(s, 0);
}
- if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) {
- return;
- } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) {
- return;
- } else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) {
+ if (!skip_fp_access_checks) {
+ if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) {
+ return;
+ } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) {
+ return;
+ } else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) {
+ return;
+ }
+ }
+
+ if (nv_trap_to_el2) {
+ gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2);
return;
}
@@ -13998,6 +14026,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
dc->pstate_za = EX_TBFLAG_A64(tb_flags, PSTATE_ZA);
dc->sme_trap_nonstreaming = EX_TBFLAG_A64(tb_flags, SME_TRAP_NONSTREAMING);
dc->naa = EX_TBFLAG_A64(tb_flags, NAA);
+ dc->nv = EX_TBFLAG_A64(tb_flags, NV);
dc->vec_len = 0;
dc->vec_stride = 0;
dc->cp_regs = arm_cpu->cp_regs;