diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2024-01-09 14:43:54 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2024-01-09 14:44:45 +0000 |
commit | 674e5345275d42581ed859acfb1ef14ebf98f9d6 (patch) | |
tree | 3776d376dd2c748aa82d83570421cb740c5cb5b7 /target/arm/tcg | |
parent | daf9b4a00fd19dcab8df9091080367889befa4c2 (diff) |
target/arm: Report VNCR_EL2 based faults correctly
If FEAT_NV2 redirects a system register access to a memory offset
from VNCR_EL2, that access might fault. In this case we need to
report the correct syndrome information:
* Data Abort, from same-EL
* no ISS information
* the VNCR bit (bit 13) is set
and the exception must be taken to EL2.
Save an appropriate syndrome template when generating code; we can
then use that to:
* select the right target EL
* reconstitute a correct final syndrome for the data abort
* report the right syndrome if we take a FEAT_RME granule protection
fault on the VNCR-based write
Note that because VNCR is bit 13, we must start keeping bit 13 in
template syndromes, by adjusting ARM_INSN_START_WORD2_SHIFT.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Tested-by: Miguel Luis <miguel.luis@oracle.com>
Diffstat (limited to 'target/arm/tcg')
-rw-r--r-- | target/arm/tcg/tlb_helper.c | 27 | ||||
-rw-r--r-- | target/arm/tcg/translate-a64.c | 4 |
2 files changed, 29 insertions, 2 deletions
diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c index 4fdd85359e..dd5de74ffb 100644 --- a/target/arm/tcg/tlb_helper.c +++ b/target/arm/tcg/tlb_helper.c @@ -50,7 +50,15 @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn, * ST64BV, or ST64BV0 insns report syndrome info even for stage-1 * faults and regardless of the target EL. */ - if (!(template_syn & ARM_EL_ISV) || target_el != 2 + if (template_syn & ARM_EL_VNCR) { + /* + * FEAT_NV2 faults on accesses via VNCR_EL2 are a special case: + * they are always reported as "same EL", even though we are going + * from EL1 to EL2. + */ + assert(!fi->stage2); + syn = syn_data_abort_vncr(fi->ea, is_write, fsc); + } else if (!(template_syn & ARM_EL_ISV) || target_el != 2 || fi->s1ptw || !fi->stage2) { syn = syn_data_abort_no_iss(same_el, 0, fi->ea, 0, fi->s1ptw, is_write, fsc); @@ -169,6 +177,20 @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, int current_el = arm_current_el(env); bool same_el; uint32_t syn, exc, fsr, fsc; + /* + * We know this must be a data or insn abort, and that + * env->exception.syndrome contains the template syndrome set + * up at translate time. So we can check only the VNCR bit + * (and indeed syndrome does not have the EC field in it, + * because we masked that out in disas_set_insn_syndrome()) + */ + bool is_vncr = (mmu_idx != MMU_INST_FETCH) && + (env->exception.syndrome & ARM_EL_VNCR); + + if (is_vncr) { + /* FEAT_NV2 faults on accesses via VNCR_EL2 go to EL2 */ + target_el = 2; + } if (report_as_gpc_exception(cpu, current_el, fi)) { target_el = 3; @@ -177,7 +199,8 @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, syn = syn_gpc(fi->stage2 && fi->type == ARMFault_GPCFOnWalk, access_type == MMU_INST_FETCH, - encode_gpcsc(fi), 0, fi->s1ptw, + encode_gpcsc(fi), is_vncr, + 0, fi->s1ptw, access_type == MMU_DATA_STORE, fsc); env->cp15.mfar_el3 = fi->paddr; diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 2938397d52..27335e8540 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -2294,6 +2294,7 @@ static void handle_sys(DisasContext *s, bool isread, MemOp mop = MO_64 | MO_ALIGN | MO_ATOM_IFALIGN; ARMMMUIdx armmemidx = s->nv2_mem_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_E2; int memidx = arm_to_core_mmu_idx(armmemidx); + uint32_t syn; mop |= (s->nv2_mem_be ? MO_BE : MO_LE); @@ -2301,6 +2302,9 @@ static void handle_sys(DisasContext *s, bool isread, tcg_gen_addi_i64(ptr, ptr, (ri->nv2_redirect_offset & ~NV2_REDIR_FLAG_MASK)); tcg_rt = cpu_reg(s, rt); + + syn = syn_data_abort_vncr(0, !isread, 0); + disas_set_insn_syndrome(s, syn); if (isread) { tcg_gen_qemu_ld_i64(tcg_rt, ptr, memidx, mop); } else { |