aboutsummaryrefslogtreecommitdiff
path: root/target/arm/tcg
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2024-01-09 14:43:54 +0000
committerPeter Maydell <peter.maydell@linaro.org>2024-01-09 14:44:45 +0000
commit674e5345275d42581ed859acfb1ef14ebf98f9d6 (patch)
tree3776d376dd2c748aa82d83570421cb740c5cb5b7 /target/arm/tcg
parentdaf9b4a00fd19dcab8df9091080367889befa4c2 (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.c27
-rw-r--r--target/arm/tcg/translate-a64.c4
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 {