qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/35] target/arm: Implement emulation of nested virtualization
@ 2023-12-18 11:32 Peter Maydell
  2023-12-18 11:32 ` [PATCH 01/35] target/arm: Don't implement *32_EL2 registers when EL1 is AArch64 only Peter Maydell
                   ` (35 more replies)
  0 siblings, 36 replies; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

This patchset adds support for emulating the Arm architectural features
FEAT_NV and FEAT_NV2 which allow nested virtualization, i.e. where a
hypervisor can run a guest which thinks it is running at EL2.

Nominally FEAT_NV is sufficient for this and FEAT_NV2 merely improves
the performance in the nested-virt setup, but in practice hypervisors
such as KVM are going to require FEAT_NV2 and not bother to support
the FEAT_NV-only case, so I have implemented them one after the other
in this single patchset.

The feature is essentially a collection of changes that allow the
hypervisor to lie to the guest so that it thinks it is running in EL2
when it's really at EL1. The best summary of what all the changes are
is in section D8.11 "Nested virtualization" in the Arm ARM, but the
short summary is:
 * EL2 system registers etc trap to EL2 rather than UNDEFing
 * ERET traps to EL2
 * the CurrentEL register reports "EL2" when NV is enabled
 * on exception entry, SPSR_EL1.M may report "EL2" as the EL the
   exception was taken from
 * when HCR_EL1.NV1 is also set, then there are some extra tweaks
   (NV1 == 1 means "guest thinks it is running with HCR_EL2.E2H == 0")
 * some AT S1 address translation insns can be trapped to EL2
and FEAT_NV2 adds:
 * accesses to some system registers are transformed into memory
   accesses instead of trapping to EL2
 * accesses to a few EL2 system registers are redirected to the
   equivalent EL1 registers

This patchset is sufficient that you can run an L0 guest kernel that
has support for FEAT_NV/FEAT_NV2 in its KVM code, and then
inside that start a nested L1 guest that thinks it has EL2 access,
and then run an inner-nested L2 guest under that that can get
to running userspace code. To do that you'll need some not-yet-upstream
patches for both Linux and kvmtool:

https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/nv-6.8-nv2-only
https://gitlab.arm.com/linux-arm/kvmtool/-/commits/nv-v6.6

You'll also want to turn off SVE and SME emulation in QEMU
(-cpu max,sve=off,sme=off) because at the moment the KVM patchset
doesn't handle SVE and nested-virt together (the other option
is to hack kvmtool to make it not ask for both at once, but this
is easier).

(kvmtool is needed here to run the L1 because QEMU itself as a VMM
doesn't yet support asking KVM for an EL2 guest.)

The first three patches in the series aren't strictly part of FEAT_NV:
 * patch 1 is already reviewed; I put it here to avoid having
   to deal with textual conflicts between it and this series
 * patch 2 sets CTR_EL0.{IDC,DIC} for '-cpu max', which is a good
   idea anyway and also works around what Marc Z and I think is
   a KVM bug that otherwise causes boot of the L2 kernel to hang
 * patch 3 is a GIC bug which is not FEAT_NV specific but for
   some reason only manifests when booting an L1 kernel under NV

thanks
-- PMM

Peter Maydell (35):
  target/arm: Don't implement *32_EL2 registers when EL1 is AArch64 only
  target/arm: Set CTR_EL0.{IDC,DIC} for the 'max' CPU
  hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers
  target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV
  target/arm: Implement HCR_EL2.AT handling
  target/arm: Enable trapping of ERET for FEAT_NV
  target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set
  target/arm: Allow use of upper 32 bits of TBFLAG_A64
  target/arm: Record correct opcode fields in cpreg for E2H aliases
  target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0
  target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses
  target/arm: Move FPU/SVE/SME access checks up above
    ARM_CP_SPECIAL_MASK check
  target/arm: Trap sysreg accesses for FEAT_NV
  target/arm: Make NV reads of CurrentEL return EL2
  target/arm: Set SPSR_EL1.M correctly when nested virt is enabled
  target/arm: Trap registers when HCR_EL2.{NV,NV1} == {1,1}
  target/arm: Always use arm_pan_enabled() when checking if PAN is
    enabled
  target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV,NV1} == {1,1}
  target/arm: Treat LDTR* and STTR* as LDR/STR when NV,NV1 is 1,1
  target/arm: Handle FEAT_NV page table attribute changes
  target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs
  target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits
  target/arm: Implement VNCR_EL2 register
  target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2
  target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2,
    FAR_EL2
  target/arm: Implement FEAT_NV2 redirection of sysregs to RAM
  target/arm: Report VNCR_EL2 based faults correctly
  target/arm: Mark up VNCR offsets (offsets 0x0..0xff)
  target/arm: Mark up VNCR offsets (offsets 0x100..0x160)
  target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8)
  target/arm: Mark up VNCR offsets (offsets >= 0x200, except GIC)
  hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers
  target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps
  target/arm: Enhance CPU_LOG_INT to show SPSR on AArch64
    exception-entry
  target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs

 docs/system/arm/emulation.rst  |   2 +
 target/arm/cpregs.h            |  54 ++++-
 target/arm/cpu-features.h      |  10 +
 target/arm/cpu.h               |  24 ++-
 target/arm/syndrome.h          |  20 +-
 target/arm/tcg/translate.h     |  16 +-
 hw/intc/arm_gicv3_cpuif.c      |  28 ++-
 target/arm/cpu.c               |   8 +-
 target/arm/debug_helper.c      |  34 +++-
 target/arm/helper.c            | 360 ++++++++++++++++++++++++++++-----
 target/arm/ptw.c               |  21 ++
 target/arm/tcg/cpu64.c         |  11 +
 target/arm/tcg/hflags.c        |  30 ++-
 target/arm/tcg/op_helper.c     |  16 +-
 target/arm/tcg/tlb_helper.c    |  27 ++-
 target/arm/tcg/translate-a64.c | 162 +++++++++++++--
 16 files changed, 725 insertions(+), 98 deletions(-)

-- 
2.34.1



^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 01/35] target/arm: Don't implement *32_EL2 registers when EL1 is AArch64 only
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-18 11:32 ` [PATCH 02/35] target/arm: Set CTR_EL0.{IDC,DIC} for the 'max' CPU Peter Maydell
                   ` (34 subsequent siblings)
  35 siblings, 0 replies; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

The system registers DBGVCR32_EL2, FPEXC32_EL2, DACR32_EL2 and
IFSR32_EL2 are present only to allow an AArch64 EL2 or EL3 to read
and write the contents of an AArch32-only system register.  The
architecture requires that they are present only when EL1 can be
AArch32, but we implement them unconditionally. This was OK when
all our CPUs supported AArch32 EL1, but we have quite a lot of
CPU models now which only support AArch64 at EL1:
 a64fx
 cortex-a76
 cortex-a710
 neoverse-n1
 neoverse-n2
 neoverse-v1

Only define these registers for CPUs which allow AArch32 EL1.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/debug_helper.c | 23 +++++++++++++++--------
 target/arm/helper.c       | 35 +++++++++++++++++++++--------------
 2 files changed, 36 insertions(+), 22 deletions(-)

diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
index cbfba532f50..83d2619080f 100644
--- a/target/arm/debug_helper.c
+++ b/target/arm/debug_helper.c
@@ -1026,14 +1026,6 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
       .cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tda,
       .type = ARM_CP_NOP },
-    /*
-     * Dummy DBGVCR32_EL2 (which is only for a 64-bit hypervisor
-     * to save and restore a 32-bit guest's DBGVCR)
-     */
-    { .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64,
-      .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0,
-      .access = PL2_RW, .accessfn = access_tda,
-      .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP },
     /*
      * Dummy MDCCINT_EL1, since we don't implement the Debug Communications
      * Channel but Linux may try to access this register. The 32-bit
@@ -1062,6 +1054,18 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
       .fieldoffset = offsetof(CPUARMState, cp15.dbgclaim) },
 };
 
+/* These are present only when EL1 supports AArch32 */
+static const ARMCPRegInfo debug_aa32_el1_reginfo[] = {
+    /*
+     * Dummy DBGVCR32_EL2 (which is only for a 64-bit hypervisor
+     * to save and restore a 32-bit guest's DBGVCR)
+     */
+    { .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64,
+      .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0,
+      .access = PL2_RW, .accessfn = access_tda,
+      .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP },
+};
+
 static const ARMCPRegInfo debug_lpae_cp_reginfo[] = {
     /* 64 bit access versions of the (dummy) debug registers */
     { .name = "DBGDRAR", .cp = 14, .crm = 1, .opc1 = 0,
@@ -1207,6 +1211,9 @@ void define_debug_regs(ARMCPU *cpu)
     assert(ctx_cmps <= brps);
 
     define_arm_cp_regs(cpu, debug_cp_reginfo);
+    if (cpu_isar_feature(aa64_aa32_el1, cpu)) {
+        define_arm_cp_regs(cpu, debug_aa32_el1_reginfo);
+    }
 
     if (arm_feature(&cpu->env, ARM_FEATURE_LPAE)) {
         define_arm_cp_regs(cpu, debug_lpae_cp_reginfo);
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 2746d3fdac8..39830c7f948 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5698,20 +5698,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 0,
       .type = ARM_CP_NO_RAW,
       .access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write },
-    { .name = "FPEXC32_EL2", .state = ARM_CP_STATE_AA64,
-      .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 3, .opc2 = 0,
-      .access = PL2_RW,
-      .type = ARM_CP_ALIAS | ARM_CP_FPU | ARM_CP_EL3_NO_EL2_KEEP,
-      .fieldoffset = offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPEXC]) },
-    { .name = "DACR32_EL2", .state = ARM_CP_STATE_AA64,
-      .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 0, .opc2 = 0,
-      .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP,
-      .writefn = dacr_write, .raw_writefn = raw_write,
-      .fieldoffset = offsetof(CPUARMState, cp15.dacr32_el2) },
-    { .name = "IFSR32_EL2", .state = ARM_CP_STATE_AA64,
-      .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 0, .opc2 = 1,
-      .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP,
-      .fieldoffset = offsetof(CPUARMState, cp15.ifsr32_el2) },
     { .name = "SPSR_IRQ", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_ALIAS,
       .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 3, .opc2 = 0,
@@ -5746,6 +5732,24 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .fieldoffset = offsetoflow32(CPUARMState, cp15.mdcr_el3) },
 };
 
+/* These are present only when EL1 supports AArch32 */
+static const ARMCPRegInfo v8_aa32_el1_reginfo[] = {
+    { .name = "FPEXC32_EL2", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 3, .opc2 = 0,
+      .access = PL2_RW,
+      .type = ARM_CP_ALIAS | ARM_CP_FPU | ARM_CP_EL3_NO_EL2_KEEP,
+      .fieldoffset = offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPEXC]) },
+    { .name = "DACR32_EL2", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 0, .opc2 = 0,
+      .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP,
+      .writefn = dacr_write, .raw_writefn = raw_write,
+      .fieldoffset = offsetof(CPUARMState, cp15.dacr32_el2) },
+    { .name = "IFSR32_EL2", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 0, .opc2 = 1,
+      .access = PL2_RW, .resetvalue = 0, .type = ARM_CP_EL3_NO_EL2_KEEP,
+      .fieldoffset = offsetof(CPUARMState, cp15.ifsr32_el2) },
+};
+
 static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask)
 {
     ARMCPU *cpu = env_archcpu(env);
@@ -8716,6 +8720,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
         }
         define_arm_cp_regs(cpu, v8_idregs);
         define_arm_cp_regs(cpu, v8_cp_reginfo);
+        if (cpu_isar_feature(aa64_aa32_el1, cpu)) {
+            define_arm_cp_regs(cpu, v8_aa32_el1_reginfo);
+        }
 
         for (i = 4; i < 16; i++) {
             /*
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 02/35] target/arm: Set CTR_EL0.{IDC,DIC} for the 'max' CPU
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
  2023-12-18 11:32 ` [PATCH 01/35] target/arm: Don't implement *32_EL2 registers when EL1 is AArch64 only Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 21:08   ` [PATCH 02/35] target/arm: Set CTR_EL0.{IDC, DIC} " Richard Henderson
  2023-12-18 11:32 ` [PATCH 03/35] hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers Peter Maydell
                   ` (33 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

The CTR_EL0 register has some bits which allow the implementation to
tell the guest that it does not need to do cache maintenance for
data-to-instruction coherence and instruction-to-data coherence.
QEMU doesn't emulate caches and so our cache maintenance insns are
all NOPs.

We already have some models of specific CPUs where we set these bits
(e.g.  the Neoverse V1), but the 'max' CPU still uses the settings it
inherits from Cortex-A57.  Set the bits for 'max' as well, so the
guest doesn't need to do unnecessary work.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
This is worthwhile anyway; it also works around what Marc Z
and I think is a KVM bug where booting the L2 guest hangs
if L0 thinks it needs to do cache maintenance ops, when
running all this under QEMU's FEAT_NV/FEAT_NV2 emulation.
---
 target/arm/tcg/cpu64.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index fcda99e1583..40e7a45166f 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1105,6 +1105,16 @@ void aarch64_max_tcg_initfn(Object *obj)
     u = FIELD_DP32(u, CLIDR_EL1, LOUU, 0);
     cpu->clidr = u;
 
+    /*
+     * Set CTR_EL0.DIC and IDC to tell the guest it doesnt' need to
+     * do any cache maintenance for data-to-instruction or
+     * instruction-to-guest coherence. (Our cache ops are nops.)
+     */
+    t = cpu->ctr;
+    t = FIELD_DP64(t, CTR_EL0, IDC, 1);
+    t = FIELD_DP64(t, CTR_EL0, DIC, 1);
+    cpu->ctr = t;
+
     t = cpu->isar.id_aa64isar0;
     t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2);      /* FEAT_PMULL */
     t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1);     /* FEAT_SHA1 */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 03/35] hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
  2023-12-18 11:32 ` [PATCH 01/35] target/arm: Don't implement *32_EL2 registers when EL1 is AArch64 only Peter Maydell
  2023-12-18 11:32 ` [PATCH 02/35] target/arm: Set CTR_EL0.{IDC,DIC} for the 'max' CPU Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 21:11   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 04/35] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV Peter Maydell
                   ` (32 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

The hypervisor can deliver (virtual) LPIs to a guest by setting up a
list register to have an intid which is an LPI.  The GIC has to treat
these a little differently to standard interrupt IDs, because LPIs
have no Active state, and so the guest will only EOI them, it will
not also deactivate them.  So icv_eoir_write() must do two things:

 * if the LPI ID is not in any list register, we drop the
   priority but do not increment the EOI count
 * if the LPI ID is in a list register, we immediately deactivate
   it, regardless of the split-drop-and-deactivate control

This can be seen in the VirtualWriteEOIR0() and VirtualWriteEOIR1()
pseudocode in the GICv3 architecture specification.

Without this fix, potentially a hypervisor guest might stall because
LPIs get stuck in a bogus Active+Pending state.

Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
Weirdly, I only saw this being a problem when the hypervisor guest
was an EL2-enabled one under my FEAT_NV/FEAT_NV2 implementation.
But there's nothing FEAT_NV specific about the bug.
---
 hw/intc/arm_gicv3_cpuif.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index ab1a00508e6..258dee1b808 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -1434,16 +1434,25 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
     idx = icv_find_active(cs, irq);
 
     if (idx < 0) {
-        /* No valid list register corresponding to EOI ID */
-        icv_increment_eoicount(cs);
+        /*
+         * No valid list register corresponding to EOI ID; if this is a vLPI
+         * not in the list regs then do nothing; otherwise increment EOI count
+         */
+        if (irq < GICV3_LPI_INTID_START) {
+            icv_increment_eoicount(cs);
+        }
     } else {
         uint64_t lr = cs->ich_lr_el2[idx];
         int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
         int lr_gprio = ich_lr_prio(lr) & icv_gprio_mask(cs, grp);
 
         if (thisgrp == grp && lr_gprio == dropprio) {
-            if (!icv_eoi_split(env, cs)) {
-                /* Priority drop and deactivate not split: deactivate irq now */
+            if (!icv_eoi_split(env, cs) || irq >= GICV3_LPI_INTID_START) {
+                /*
+                 * Priority drop and deactivate not split: deactivate irq now.
+                 * LPIs always get their active state cleared immediately
+                 * because no separate deactivate is expected.
+                 */
                 icv_deactivate_irq(cs, idx);
             }
         }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 04/35] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (2 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 03/35] hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 21:42   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 05/35] target/arm: Implement HCR_EL2.AT handling Peter Maydell
                   ` (31 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

FEAT_NV defines three new bits in HCR_EL2: NV, NV1 and AT.  When the
feature is enabled, allow these bits to be written, and flush the
TLBs for the bits which affect page table interpretation.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu-features.h | 5 +++++
 target/arm/helper.c       | 6 +++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index 954d3582685..3a43c328d9e 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -839,6 +839,11 @@ static inline bool isar_feature_aa64_e0pd(const ARMISARegisters *id)
     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, E0PD) != 0;
 }
 
+static inline bool isar_feature_aa64_nv(const ARMISARegisters *id)
+{
+    return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) != 0;
+}
+
 static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id)
 {
     return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 &&
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 39830c7f948..ca8de414bdb 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5799,6 +5799,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask)
         if (cpu_isar_feature(aa64_rme, cpu)) {
             valid_mask |= HCR_GPF;
         }
+        if (cpu_isar_feature(aa64_nv, cpu)) {
+            valid_mask |= HCR_NV | HCR_NV1 | HCR_AT;
+        }
     }
 
     if (cpu_isar_feature(any_evt, cpu)) {
@@ -5817,9 +5820,10 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask)
      * HCR_DC disables stage1 and enables stage2 translation
      * HCR_DCT enables tagging on (disabled) stage1 translation
      * HCR_FWB changes the interpretation of stage2 descriptor bits
+     * HCR_NV and HCR_NV1 affect interpretation of descriptor bits
      */
     if ((env->cp15.hcr_el2 ^ value) &
-        (HCR_VM | HCR_PTW | HCR_DC | HCR_DCT | HCR_FWB)) {
+        (HCR_VM | HCR_PTW | HCR_DC | HCR_DCT | HCR_FWB | HCR_NV | HCR_NV1)) {
         tlb_flush(CPU(cpu));
     }
     env->cp15.hcr_el2 = value;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 05/35] target/arm: Implement HCR_EL2.AT handling
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (3 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 04/35] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:01   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 06/35] target/arm: Enable trapping of ERET for FEAT_NV Peter Maydell
                   ` (30 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

The FEAT_NV HCR_EL2.AT bit enables trapping of some address
translation instructions from EL1 to EL2.  Implement this behaviour.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index ca8de414bdb..f1c7fbf319c 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3687,6 +3687,15 @@ static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri,
     return at_e012_access(env, ri, isread);
 }
 
+static CPAccessResult at_s1e01_access(CPUARMState *env, const ARMCPRegInfo *ri,
+                                      bool isread)
+{
+    if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_AT)) {
+        return CP_ACCESS_TRAP_EL2;
+    }
+    return at_e012_access(env, ri, isread);
+}
+
 static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
                         uint64_t value)
 {
@@ -5552,22 +5561,22 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 0,
       .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
       .fgt = FGT_ATS1E1R,
-      .accessfn = at_e012_access, .writefn = ats_write64 },
+      .accessfn = at_s1e01_access, .writefn = ats_write64 },
     { .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64,
       .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 1,
       .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
       .fgt = FGT_ATS1E1W,
-      .accessfn = at_e012_access, .writefn = ats_write64 },
+      .accessfn = at_s1e01_access, .writefn = ats_write64 },
     { .name = "AT_S1E0R", .state = ARM_CP_STATE_AA64,
       .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 2,
       .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
       .fgt = FGT_ATS1E0R,
-      .accessfn = at_e012_access, .writefn = ats_write64 },
+      .accessfn = at_s1e01_access, .writefn = ats_write64 },
     { .name = "AT_S1E0W", .state = ARM_CP_STATE_AA64,
       .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3,
       .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
       .fgt = FGT_ATS1E0W,
-      .accessfn = at_e012_access, .writefn = ats_write64 },
+      .accessfn = at_s1e01_access, .writefn = ats_write64 },
     { .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64,
       .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4,
       .access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
@@ -8145,12 +8154,12 @@ static const ARMCPRegInfo ats1e1_reginfo[] = {
       .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 0,
       .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
       .fgt = FGT_ATS1E1RP,
-      .accessfn = at_e012_access, .writefn = ats_write64 },
+      .accessfn = at_s1e01_access, .writefn = ats_write64 },
     { .name = "AT_S1E1WP", .state = ARM_CP_STATE_AA64,
       .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1,
       .access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
       .fgt = FGT_ATS1E1WP,
-      .accessfn = at_e012_access, .writefn = ats_write64 },
+      .accessfn = at_s1e01_access, .writefn = ats_write64 },
 };
 
 static const ARMCPRegInfo ats1cp_reginfo[] = {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 06/35] target/arm: Enable trapping of ERET for FEAT_NV
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (4 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 05/35] target/arm: Implement HCR_EL2.AT handling Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:06   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 07/35] target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set Peter Maydell
                   ` (29 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

When FEAT_NV is turned on via the HCR_EL2.NV bit, ERET instructions
are trapped, with the same syndrome information as for the existing
FEAT_FGT fine-grained trap (in the pseudocode this is handled in
AArch64.CheckForEretTrap()).

Rename the DisasContext and tbflag bits to reflect that they are
no longer exclusively for FGT traps, and set the tbflag bit when
FEAT_NV is enabled as well as when the FGT is enabled.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu.h               |  2 +-
 target/arm/tcg/translate.h     |  4 ++--
 target/arm/tcg/hflags.c        | 11 ++++++++++-
 target/arm/tcg/translate-a64.c |  6 +++---
 4 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index a0282e0d281..167b3759ac9 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3235,7 +3235,7 @@ FIELD(TBFLAG_A64, PSTATE_ZA, 23, 1)
 FIELD(TBFLAG_A64, SVL, 24, 4)
 /* Indicates that SME Streaming mode is active, and SMCR_ELx.FA64 is not. */
 FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1)
-FIELD(TBFLAG_A64, FGT_ERET, 29, 1)
+FIELD(TBFLAG_A64, TRAP_ERET, 29, 1)
 FIELD(TBFLAG_A64, NAA, 30, 1)
 FIELD(TBFLAG_A64, ATA0, 31, 1)
 
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 3c3bb3431ad..8c84377003c 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -138,10 +138,10 @@ typedef struct DisasContext {
     bool mve_no_pred;
     /* True if fine-grained traps are active */
     bool fgt_active;
-    /* True if fine-grained trap on ERET is enabled */
-    bool fgt_eret;
     /* True if fine-grained trap on SVC is enabled */
     bool fgt_svc;
+    /* True if a trap on ERET is enabled (FGT or NV) */
+    bool trap_eret;
     /* True if FEAT_LSE2 SCTLR_ELx.nAA is set */
     bool naa;
     /*
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index a6ebd7571a3..560fb7964ab 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -169,6 +169,7 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
     CPUARMTBFlags flags = {};
     ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx);
     uint64_t tcr = regime_tcr(env, mmu_idx);
+    uint64_t hcr = arm_hcr_el2_eff(env);
     uint64_t sctlr;
     int tbii, tbid;
 
@@ -285,13 +286,21 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
     if (arm_fgt_active(env, el)) {
         DP_TBFLAG_ANY(flags, FGT_ACTIVE, 1);
         if (FIELD_EX64(env->cp15.fgt_exec[FGTREG_HFGITR], HFGITR_EL2, ERET)) {
-            DP_TBFLAG_A64(flags, FGT_ERET, 1);
+            DP_TBFLAG_A64(flags, TRAP_ERET, 1);
         }
         if (fgt_svc(env, el)) {
             DP_TBFLAG_ANY(flags, FGT_SVC, 1);
         }
     }
 
+    /*
+     * ERET can also be trapped for FEAT_NV. arm_hcr_el2_eff() takes care
+     * of "is EL2 enabled" and the NV bit can only be set if FEAT_NV is present.
+     */
+    if (el == 1 && (hcr & HCR_NV)) {
+        DP_TBFLAG_A64(flags, TRAP_ERET, 1);
+    }
+
     if (cpu_isar_feature(aa64_mte, env_archcpu(env))) {
         /*
          * Set MTE_ACTIVE if any access may be Checked, and leave clear
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index a2e49c39f9f..00d12e148ca 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -1605,7 +1605,7 @@ static bool trans_ERET(DisasContext *s, arg_ERET *a)
     if (s->current_el == 0) {
         return false;
     }
-    if (s->fgt_eret) {
+    if (s->trap_eret) {
         gen_exception_insn_el(s, 0, EXCP_UDEF, syn_erettrap(0), 2);
         return true;
     }
@@ -1632,7 +1632,7 @@ static bool trans_ERETA(DisasContext *s, arg_reta *a)
         return false;
     }
     /* The FGT trap takes precedence over an auth trap. */
-    if (s->fgt_eret) {
+    if (s->trap_eret) {
         gen_exception_insn_el(s, 0, EXCP_UDEF, syn_erettrap(a->m ? 3 : 2), 2);
         return true;
     }
@@ -13979,7 +13979,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
     dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
     dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE);
     dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC);
-    dc->fgt_eret = EX_TBFLAG_A64(tb_flags, FGT_ERET);
+    dc->trap_eret = EX_TBFLAG_A64(tb_flags, TRAP_ERET);
     dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL);
     dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL);
     dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 07/35] target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (5 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 06/35] target/arm: Enable trapping of ERET for FEAT_NV Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:18   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 08/35] target/arm: Allow use of upper 32 bits of TBFLAG_A64 Peter Maydell
                   ` (28 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

The HCR_EL2.TSC trap for trapping EL1 execution of SMC instructions
has a behaviour change for FEAT_NV when EL3 is not implemented:

 * in older architecture versions TSC was required to have no
   effect (i.e. the SMC insn UNDEFs)
 * with FEAT_NV, when HCR_EL2.NV == 1 the trap must apply
   (i.e. SMC traps to EL2, as it already does in all cases when
   EL3 is implemented)
 * in newer architecture versions, the behaviour either without
   FEAT_NV or with FEAT_NV and HCR_EL2.NV == 0 is relaxed to
   an IMPDEF choice between UNDEF and trap-to-EL2 (i.e. it is
   permitted to always honour HCR_EL2.TSC) for AArch64 only

Add the condition to honour the trap bit when HCR_EL2.NV == 1.  We
leave the HCR_EL2.NV == 0 case with the existing (UNDEF) behaviour,
as our IMPDEF choice (both because it avoids a behaviour change
for older CPU models and because we'd have to distinguish AArch32
from AArch64 if we opted to trap to EL2).

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/tcg/op_helper.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index ea08936a852..ae158200c00 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -930,7 +930,14 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
      *
      *  Conduit SMC, valid call  Trap to EL2         PSCI Call
      *  Conduit SMC, inval call  Trap to EL2         Undef insn
-     *  Conduit not SMC          Undef insn          Undef insn
+     *  Conduit not SMC          Undef or trap[1]    Undef insn
+     *
+     * [1] In this case:
+     *  - if HCR_EL2.NV == 1 we must trap to EL2
+     *  - if HCR_EL2.NV == 0 then newer architecture revisions permit
+     *    AArch64 (but not AArch32) to trap to EL2 as an IMPDEF choice
+     *  - otherwise we must UNDEF
+     * We take the IMPDEF choice to always UNDEF if HCR_EL2.NV == 0.
      */
 
     /* On ARMv8 with EL3 AArch64, SMD applies to both S and NS state.
@@ -944,9 +951,12 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
                                                      : smd_flag && !secure;
 
     if (!arm_feature(env, ARM_FEATURE_EL3) &&
+        !(arm_hcr_el2_eff(env) & HCR_NV) &&
         cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
-        /* If we have no EL3 then SMC always UNDEFs and can't be
-         * trapped to EL2. PSCI-via-SMC is a sort of ersatz EL3
+        /*
+         * If we have no EL3 then traditionally SMC always UNDEFs and can't be
+         * trapped to EL2. For nested virtualization, SMC can be trapped to
+         * the outer hypervisor. PSCI-via-SMC is a sort of ersatz EL3
          * firmware within QEMU, and we want an EL2 guest to be able
          * to forbid its EL1 from making PSCI calls into QEMU's
          * "firmware" via HCR.TSC, so for these purposes treat
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 08/35] target/arm: Allow use of upper 32 bits of TBFLAG_A64
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (6 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 07/35] target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:20   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 09/35] target/arm: Record correct opcode fields in cpreg for E2H aliases Peter Maydell
                   ` (27 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

The TBFLAG_A64 TB flag bits go in flags2, which for AArch64 guests
we know is 64 bits. However at the moment we use FIELD_EX32() and
FIELD_DP32() to read and write these bits, which only works for
bits 0 to 31. Since we're about to add a flag that uses bit 32,
switch to FIELD_EX64() and FIELD_DP64() so that this will work.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu.h | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 167b3759ac9..91157db85ae 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3240,12 +3240,14 @@ FIELD(TBFLAG_A64, NAA, 30, 1)
 FIELD(TBFLAG_A64, ATA0, 31, 1)
 
 /*
- * Helpers for using the above.
+ * Helpers for using the above. Note that only the A64 accessors use
+ * FIELD_DP64() and FIELD_EX64(), because in the other cases the flags
+ * word either is or might be 32 bits only.
  */
 #define DP_TBFLAG_ANY(DST, WHICH, VAL) \
     (DST.flags = FIELD_DP32(DST.flags, TBFLAG_ANY, WHICH, VAL))
 #define DP_TBFLAG_A64(DST, WHICH, VAL) \
-    (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A64, WHICH, VAL))
+    (DST.flags2 = FIELD_DP64(DST.flags2, TBFLAG_A64, WHICH, VAL))
 #define DP_TBFLAG_A32(DST, WHICH, VAL) \
     (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A32, WHICH, VAL))
 #define DP_TBFLAG_M32(DST, WHICH, VAL) \
@@ -3254,7 +3256,7 @@ FIELD(TBFLAG_A64, ATA0, 31, 1)
     (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_AM32, WHICH, VAL))
 
 #define EX_TBFLAG_ANY(IN, WHICH)   FIELD_EX32(IN.flags, TBFLAG_ANY, WHICH)
-#define EX_TBFLAG_A64(IN, WHICH)   FIELD_EX32(IN.flags2, TBFLAG_A64, WHICH)
+#define EX_TBFLAG_A64(IN, WHICH)   FIELD_EX64(IN.flags2, TBFLAG_A64, WHICH)
 #define EX_TBFLAG_A32(IN, WHICH)   FIELD_EX32(IN.flags2, TBFLAG_A32, WHICH)
 #define EX_TBFLAG_M32(IN, WHICH)   FIELD_EX32(IN.flags2, TBFLAG_M32, WHICH)
 #define EX_TBFLAG_AM32(IN, WHICH)  FIELD_EX32(IN.flags2, TBFLAG_AM32, WHICH)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 09/35] target/arm: Record correct opcode fields in cpreg for E2H aliases
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (7 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 08/35] target/arm: Allow use of upper 32 bits of TBFLAG_A64 Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:23   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 10/35] target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0 Peter Maydell
                   ` (26 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

For FEAT_VHE, we define a set of register aliases, so that for instance:
 * the SCTLR_EL1 either accesses the real SCTLR_EL1, or (if E2H is 1)
   SCTLR_EL2
 * a new SCTLR_EL12 register accesses SCTLR_EL1 if E2H is 1

However when we create the 'new_reg' cpreg struct for the SCTLR_EL12
register, we duplicate the information in the SCTLR_EL1 cpreg, which
means the opcode fields are those of SCTLR_EL1, not SCTLR_EL12.  This
is a problem for code which looks at the cpreg opcode fields to
determine behaviour (e.g.  in access_check_cp_reg()). In practice
the current checks we do there don't intersect with the *_EL12
registers, but for FEAT_NV this will become a problem.

Write the correct values from the encoding into the new_reg struct.
This restores the invariant that the cpreg that you get back
from the hashtable has opcode fields that match the key you used
to retrieve it.

When we call the readfn or writefn for the target register, we
pass it the cpreg struct for that target register, not the one
for the alias, in case the readfn/writefn want to look at the
opcode fields to determine behaviour. This means we need to
interpose custom read/writefns for the e12 aliases.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index f1c7fbf319c..c6f069b74cd 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6506,6 +6506,19 @@ static void el2_e2h_write(CPUARMState *env, const ARMCPRegInfo *ri,
     writefn(env, ri, value);
 }
 
+static uint64_t el2_e2h_e12_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    /* Pass the EL1 register accessor its ri, not the EL12 alias ri */
+    return ri->orig_readfn(env, ri->opaque);
+}
+
+static void el2_e2h_e12_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                              uint64_t value)
+{
+    /* Pass the EL1 register accessor its ri, not the EL12 alias ri */
+    return ri->orig_writefn(env, ri->opaque, value);
+}
+
 static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
 {
     struct E2HAlias {
@@ -6605,6 +6618,28 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
         new_reg->type |= ARM_CP_ALIAS;
         /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place.  */
         new_reg->access &= PL2_RW | PL3_RW;
+        /* The new_reg op fields are as per new_key, not the target reg */
+        new_reg->crn = (a->new_key & CP_REG_ARM64_SYSREG_CRN_MASK)
+            >> CP_REG_ARM64_SYSREG_CRN_SHIFT;
+        new_reg->crm = (a->new_key & CP_REG_ARM64_SYSREG_CRM_MASK)
+            >> CP_REG_ARM64_SYSREG_CRM_SHIFT;
+        new_reg->opc0 = (a->new_key & CP_REG_ARM64_SYSREG_OP0_MASK)
+            >> CP_REG_ARM64_SYSREG_OP0_SHIFT;
+        new_reg->opc1 = (a->new_key & CP_REG_ARM64_SYSREG_OP1_MASK)
+            >> CP_REG_ARM64_SYSREG_OP1_SHIFT;
+        new_reg->opc2 = (a->new_key & CP_REG_ARM64_SYSREG_OP2_MASK)
+            >> CP_REG_ARM64_SYSREG_OP2_SHIFT;
+        new_reg->opaque = src_reg;
+        new_reg->orig_readfn = src_reg->readfn ?: raw_read;
+        new_reg->orig_writefn = src_reg->writefn ?: raw_write;
+        if (!new_reg->raw_readfn) {
+            new_reg->raw_readfn = raw_read;
+        }
+        if (!new_reg->raw_writefn) {
+            new_reg->raw_writefn = raw_write;
+        }
+        new_reg->readfn = el2_e2h_e12_read;
+        new_reg->writefn = el2_e2h_e12_write;
 
         ok = g_hash_table_insert(cpu->cp_regs,
                                  (gpointer)(uintptr_t)a->new_key, new_reg);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 10/35] target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (8 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 09/35] target/arm: Record correct opcode fields in cpreg for E2H aliases Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:25   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 11/35] target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses Peter Maydell
                   ` (25 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

The alias registers like SCTLR_EL12 only exist when HCR_EL2.E2H
is 1; they should UNDEF otherwise. We weren't implementing this.
Add an intercept of the accessfn for these aliases, and implement
the UNDEF check.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpregs.h |  3 ++-
 target/arm/helper.c | 16 ++++++++++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index f1293d16c07..e748d184cb6 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -937,7 +937,7 @@ struct ARMCPRegInfo {
     CPResetFn *resetfn;
 
     /*
-     * "Original" writefn and readfn.
+     * "Original" readfn, writefn, accessfn.
      * For ARMv8.1-VHE register aliases, we overwrite the read/write
      * accessor functions of various EL1/EL0 to perform the runtime
      * check for which sysreg should actually be modified, and then
@@ -948,6 +948,7 @@ struct ARMCPRegInfo {
      */
     CPReadFn *orig_readfn;
     CPWriteFn *orig_writefn;
+    CPAccessFn *orig_accessfn;
 };
 
 /*
diff --git a/target/arm/helper.c b/target/arm/helper.c
index c6f069b74cd..e90eb5e16f3 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6519,6 +6519,20 @@ static void el2_e2h_e12_write(CPUARMState *env, const ARMCPRegInfo *ri,
     return ri->orig_writefn(env, ri->opaque, value);
 }
 
+static CPAccessResult el2_e2h_e12_access(CPUARMState *env,
+                                         const ARMCPRegInfo *ri,
+                                         bool isread)
+{
+    /* FOO_EL12 aliases only exist when E2H is 1; otherwise they UNDEF */
+    if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
+        return CP_ACCESS_TRAP_UNCATEGORIZED;
+    }
+    if (ri->orig_accessfn) {
+        return ri->orig_accessfn(env, ri->opaque, isread);
+    }
+    return CP_ACCESS_OK;
+}
+
 static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
 {
     struct E2HAlias {
@@ -6632,6 +6646,7 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
         new_reg->opaque = src_reg;
         new_reg->orig_readfn = src_reg->readfn ?: raw_read;
         new_reg->orig_writefn = src_reg->writefn ?: raw_write;
+        new_reg->orig_accessfn = src_reg->accessfn;
         if (!new_reg->raw_readfn) {
             new_reg->raw_readfn = raw_read;
         }
@@ -6640,6 +6655,7 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
         }
         new_reg->readfn = el2_e2h_e12_read;
         new_reg->writefn = el2_e2h_e12_write;
+        new_reg->accessfn = el2_e2h_e12_access;
 
         ok = g_hash_table_insert(cpu->cp_regs,
                                  (gpointer)(uintptr_t)a->new_key, new_reg);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 11/35] target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (9 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 10/35] target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0 Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:31   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 12/35] target/arm: Move FPU/SVE/SME access checks up above ARM_CP_SPECIAL_MASK check Peter Maydell
                   ` (24 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

FEAT_NV and FEAT_NV2 will allow EL1 to attempt to access cpregs that
only exist at EL2. This means we're going to want to run their
accessfns when the CPU is at EL1. In almost all cases, the behaviour
we want is "the accessfn returns OK if at EL1".

Mostly the accessfn already does the right thing; in a few cases we
need to explicitly check that the EL is not 1 before applying various
trap controls, or split out an accessfn used both for an _EL1 and an
_EL2 register into two so we can handle the FEAT_NV case correctly
for the _EL2 register.

There are two registers where we want the accessfn to trap for
a FEAT_NV EL1 access: VSTTBR_EL2 and VSTCR_EL2 should UNDEF
an access from NonSecure EL1, not trap to EL2 under FEAT_NV.
The way we have written sel2_access() already results in this
behaviour.

We can identify the registers we care about here because they
all have opc1 == 4 or 5.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/debug_helper.c | 12 +++++++-
 target/arm/helper.c       | 65 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 69 insertions(+), 8 deletions(-)

diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
index 83d2619080f..b39144d5b93 100644
--- a/target/arm/debug_helper.c
+++ b/target/arm/debug_helper.c
@@ -844,6 +844,16 @@ static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
     return CP_ACCESS_OK;
 }
 
+static CPAccessResult access_dbgvcr32(CPUARMState *env, const ARMCPRegInfo *ri,
+                                      bool isread)
+{
+    /* MCDR_EL3.TDMA doesn't apply for FEAT_NV traps */
+    if (arm_current_el(env) == 2 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
+        return CP_ACCESS_TRAP_EL3;
+    }
+    return CP_ACCESS_OK;
+}
+
 /*
  * Check for traps to Debug Comms Channel registers. If FEAT_FGT
  * is implemented then these are controlled by MDCR_EL2.TDCC for
@@ -1062,7 +1072,7 @@ static const ARMCPRegInfo debug_aa32_el1_reginfo[] = {
      */
     { .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0,
-      .access = PL2_RW, .accessfn = access_tda,
+      .access = PL2_RW, .accessfn = access_dbgvcr32,
       .type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP },
 };
 
diff --git a/target/arm/helper.c b/target/arm/helper.c
index e90eb5e16f3..44005665d12 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3308,6 +3308,11 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
 static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri,
                                  bool isread)
 {
+    if (arm_current_el(env) == 1) {
+        /* This must be a FEAT_NV access */
+        /* TODO: FEAT_ECV will need to check CNTHCTL_EL2 here */
+        return CP_ACCESS_OK;
+    }
     if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
         return CP_ACCESS_TRAP;
     }
@@ -5998,7 +6003,7 @@ static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri,
 static CPAccessResult access_hxen(CPUARMState *env, const ARMCPRegInfo *ri,
                                   bool isread)
 {
-    if (arm_current_el(env) < 3
+    if (arm_current_el(env) == 2
         && arm_feature(env, ARM_FEATURE_EL3)
         && !(env->cp15.scr_el3 & SCR_HXEN)) {
         return CP_ACCESS_TRAP_EL3;
@@ -6523,6 +6528,15 @@ static CPAccessResult el2_e2h_e12_access(CPUARMState *env,
                                          const ARMCPRegInfo *ri,
                                          bool isread)
 {
+    if (arm_current_el(env) == 1) {
+        /*
+         * This must be a FEAT_NV access (will either trap or redirect
+         * to memory). None of the registers with _EL12 aliases want to
+         * apply their trap controls for this kind of access, so don't
+         * call the orig_accessfn or do the "UNDEF when E2H is 0" check.
+         */
+        return CP_ACCESS_OK;
+    }
     /* FOO_EL12 aliases only exist when E2H is 1; otherwise they UNDEF */
     if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
         return CP_ACCESS_TRAP_UNCATEGORIZED;
@@ -6999,10 +7013,21 @@ static CPAccessResult access_tpidr2(CPUARMState *env, const ARMCPRegInfo *ri,
     return CP_ACCESS_OK;
 }
 
-static CPAccessResult access_esm(CPUARMState *env, const ARMCPRegInfo *ri,
-                                 bool isread)
+static CPAccessResult access_smprimap(CPUARMState *env, const ARMCPRegInfo *ri,
+                                      bool isread)
+{
+    /* If EL1 this is a FEAT_NV access and CPTR_EL3.ESM doesn't apply */
+    if (arm_current_el(env) == 2
+        && arm_feature(env, ARM_FEATURE_EL3)
+        && !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, ESM)) {
+        return CP_ACCESS_TRAP_EL3;
+    }
+    return CP_ACCESS_OK;
+}
+
+static CPAccessResult access_smpri(CPUARMState *env, const ARMCPRegInfo *ri,
+                                   bool isread)
 {
-    /* TODO: FEAT_FGT for SMPRI_EL1 but not SMPRIMAP_EL2 */
     if (arm_current_el(env) < 3
         && arm_feature(env, ARM_FEATURE_EL3)
         && !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, ESM)) {
@@ -7121,12 +7146,12 @@ static const ARMCPRegInfo sme_reginfo[] = {
      */
     { .name = "SMPRI_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 4,
-      .access = PL1_RW, .accessfn = access_esm,
+      .access = PL1_RW, .accessfn = access_smpri,
       .fgt = FGT_NSMPRI_EL1,
       .type = ARM_CP_CONST, .resetvalue = 0 },
     { .name = "SMPRIMAP_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 5,
-      .access = PL2_RW, .accessfn = access_esm,
+      .access = PL2_RW, .accessfn = access_smprimap,
       .type = ARM_CP_CONST, .resetvalue = 0 },
 };
 
@@ -7769,7 +7794,33 @@ static CPAccessResult access_mte(CPUARMState *env, const ARMCPRegInfo *ri,
                                  bool isread)
 {
     int el = arm_current_el(env);
+    if (el < 2 && arm_is_el2_enabled(env)) {
+        uint64_t hcr = arm_hcr_el2_eff(env);
+        if (!(hcr & HCR_ATA) && (!(hcr & HCR_E2H) || !(hcr & HCR_TGE))) {
+            return CP_ACCESS_TRAP_EL2;
+        }
+    }
+    if (el < 3 &&
+        arm_feature(env, ARM_FEATURE_EL3) &&
+        !(env->cp15.scr_el3 & SCR_ATA)) {
+        return CP_ACCESS_TRAP_EL3;
+    }
+    return CP_ACCESS_OK;
+}
 
+static CPAccessResult access_tfsr_el2(CPUARMState *env, const ARMCPRegInfo *ri,
+                                      bool isread)
+{
+    /*
+     * TFSR_EL2: similar to generic access_mte(), but we need to
+     * account for FEAT_NV. At EL1 this must be a FEAT_NV access;
+     * we will trap to EL2 and the HCR/SCR traps do not apply.
+     */
+    int el = arm_current_el(env);
+
+    if (el == 1) {
+        return CP_ACCESS_OK;
+    }
     if (el < 2 && arm_is_el2_enabled(env)) {
         uint64_t hcr = arm_hcr_el2_eff(env);
         if (!(hcr & HCR_ATA) && (!(hcr & HCR_E2H) || !(hcr & HCR_TGE))) {
@@ -7805,7 +7856,7 @@ static const ARMCPRegInfo mte_reginfo[] = {
       .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) },
     { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 6, .opc2 = 0,
-      .access = PL2_RW, .accessfn = access_mte,
+      .access = PL2_RW, .accessfn = access_tfsr_el2,
       .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[2]) },
     { .name = "TFSR_EL3", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 6, .crn = 5, .crm = 6, .opc2 = 0,
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 12/35] target/arm: Move FPU/SVE/SME access checks up above ARM_CP_SPECIAL_MASK check
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (10 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 11/35] target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:32   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 13/35] target/arm: Trap sysreg accesses for FEAT_NV Peter Maydell
                   ` (23 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

In handle_sys() we don't do the check for whether the register is
marked as needing an FPU/SVE/SME access check until after we've
handled the special cases covered by ARM_CP_SPECIAL_MASK.  This is
conceptually the wrong way around, because if for example we happen
to implement an FPU-access-checked register as ARM_CP_NOP, we should
do the access check first.

Move the access checks up so they are with all the other access
checks, not sandwiched between the special-case read/write handling
and the normal-case read/write handling. This doesn't change
behaviour at the moment, because we happen not to define any
cpregs with both ARM_CPU_{FPU,SVE,SME} and one of the cases
dealt with by ARM_CP_SPECIAL_MASK.

Moving this code also means we have the correct place to put the
FEAT_NV/FEAT_NV2 access handling, which should come after the access
checks and before we try to do any read/write action.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/tcg/translate-a64.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 00d12e148ca..2d26cb6210f 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2189,6 +2189,14 @@ 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)) {
+        return;
+    }
+
     /* Handle special cases first */
     switch (ri->type & ARM_CP_SPECIAL_MASK) {
     case 0:
@@ -2267,13 +2275,6 @@ static void handle_sys(DisasContext *s, bool isread,
     default:
         g_assert_not_reached();
     }
-    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 (ri->type & ARM_CP_IO) {
         /* I/O operations must end the TB here (whether read or write) */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 13/35] target/arm: Trap sysreg accesses for FEAT_NV
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (11 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 12/35] target/arm: Move FPU/SVE/SME access checks up above ARM_CP_SPECIAL_MASK check Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:40   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 14/35] target/arm: Make NV reads of CurrentEL return EL2 Peter Maydell
                   ` (22 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

For FEAT_NV, accesses to system registers and instructions from EL1
which would normally UNDEF there but which work in EL2 need to
instead be trapped to EL2. Detect this both for "we know this will
UNDEF at translate time" and "we found this UNDEFs at runtime", and
make the affected registers trap to EL2 instead.

The Arm ARM defines the set of registers that should trap in terms
of their names; for our implementation this would be both awkward
and inefficent as a test, so we instead trap based on the opc1
field of the sysreg. The regularity of the architectural choice
of encodings for sysregs means that in practice this captures
exactly the correct set of registers.

Regardless of how we try to define the registers this trapping
applies to, there's going to be a certain possibility of breakage
if new architectural features introduce new registers that don't
follow the current rules (FEAT_MEC is one example already visible
in the released sysreg XML, though not yet in the Arm ARM). This
approach seems to me to be straightforward and likely to require
a minimum of manual overrides.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpregs.h            | 34 +++++++++++++++++++++++
 target/arm/cpu.h               |  1 +
 target/arm/tcg/translate.h     |  2 ++
 target/arm/tcg/hflags.c        |  1 +
 target/arm/tcg/translate-a64.c | 49 +++++++++++++++++++++++++++-------
 5 files changed, 77 insertions(+), 10 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index e748d184cb6..3c5f1b48879 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -1080,4 +1080,38 @@ void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu);
 
 CPAccessResult access_tvm_trvm(CPUARMState *, const ARMCPRegInfo *, bool);
 
+/**
+ * arm_cpreg_trap_in_nv: Return true if cpreg traps in nested virtualization
+ *
+ * Return true if this cpreg is one which should be trapped to EL2 if
+ * it is executed at EL1 when nested virtualization is enabled via HCR_EL2.NV.
+ */
+static inline bool arm_cpreg_traps_in_nv(const ARMCPRegInfo *ri)
+{
+    /*
+     * The Arm ARM defines the registers to be trapped in terms of
+     * their names (I_TZTZL). However the underlying principle is "if
+     * it would UNDEF at EL1 but work at EL2 then it should trap", and
+     * the way the encoding of sysregs and system instructions is done
+     * means that the right set of registers is exactly those where
+     * the opc1 field is 4 or 5. (You can see this also in the assert
+     * we do that the opc1 field and the permissions mask line up in
+     * define_one_arm_cp_reg_with_opaque().)
+     * Checking the opc1 field is easier for us and avoids the problem
+     * that we do not consistently use the right architectural names
+     * for all sysregs, since we treat the name field as largely for debug.
+     *
+     * However we do this check, it is going to be at least potentially
+     * fragile to future new sysregs, but this seems the least likely
+     * to break.
+     *
+     * In particular, note that the released sysreg XML defines that
+     * the FEAT_MEC sysregs and instructions do not follow this FEAT_NV
+     * trapping rule, so we will need to add an ARM_CP_* flag to indicate
+     * "register does not trap on NV" to handle those if/when we implement
+     * FEAT_MEC.
+     */
+    return ri->opc1 == 4 || ri->opc1 == 5;
+}
+
 #endif /* TARGET_ARM_CPREGS_H */
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 91157db85ae..0ec67847181 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3238,6 +3238,7 @@ FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1)
 FIELD(TBFLAG_A64, TRAP_ERET, 29, 1)
 FIELD(TBFLAG_A64, NAA, 30, 1)
 FIELD(TBFLAG_A64, ATA0, 31, 1)
+FIELD(TBFLAG_A64, NV, 32, 1)
 
 /*
  * Helpers for using the above. Note that only the A64 accessors use
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 8c84377003c..63e075bce3a 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -144,6 +144,8 @@ typedef struct DisasContext {
     bool trap_eret;
     /* True if FEAT_LSE2 SCTLR_ELx.nAA is set */
     bool naa;
+    /* True if FEAT_NV HCR_EL2.NV is enabled */
+    bool nv;
     /*
      * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
      *  < 0, set by the current instruction.
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index 560fb7964ab..f33c0a12741 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -299,6 +299,7 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
      */
     if (el == 1 && (hcr & HCR_NV)) {
         DP_TBFLAG_A64(flags, TRAP_ERET, 1);
+        DP_TBFLAG_A64(flags, NV, 1);
     }
 
     if (cpu_isar_feature(aa64_mte, env_archcpu(env))) {
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 2d26cb6210f..d060e24356d 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2131,16 +2131,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)) {
@@ -2166,15 +2167,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 likee
+             * 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,
@@ -2189,11 +2210,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;
     }
 
@@ -13997,6 +14025,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;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 14/35] target/arm: Make NV reads of CurrentEL return EL2
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (12 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 13/35] target/arm: Trap sysreg accesses for FEAT_NV Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:42   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 15/35] target/arm: Set SPSR_EL1.M correctly when nested virt is enabled Peter Maydell
                   ` (21 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

FEAT_NV requires that when HCR_EL2.NV is set reads of the CurrentEL
register from EL1 always report EL2 rather than the real EL.
Implement this.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/tcg/translate-a64.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index d060e24356d..6bfc39d8ea7 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2240,12 +2240,17 @@ static void handle_sys(DisasContext *s, bool isread,
         }
         return;
     case ARM_CP_CURRENTEL:
-        /* Reads as current EL value from pstate, which is
+    {
+        /*
+         * Reads as current EL value from pstate, which is
          * guaranteed to be constant by the tb flags.
+         * For nested virt we should report EL2.
          */
+        int el = s->nv ? 2 : s->current_el;
         tcg_rt = cpu_reg(s, rt);
-        tcg_gen_movi_i64(tcg_rt, s->current_el << 2);
+        tcg_gen_movi_i64(tcg_rt, el << 2);
         return;
+    }
     case ARM_CP_DC_ZVA:
         /* Writes clear the aligned block of memory which rt points into. */
         if (s->mte_active[0]) {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 15/35] target/arm: Set SPSR_EL1.M correctly when nested virt is enabled
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (13 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 14/35] target/arm: Make NV reads of CurrentEL return EL2 Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:43   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 16/35] target/arm: Trap registers when HCR_EL2.{NV, NV1} == {1, 1} Peter Maydell
                   ` (20 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

FEAT_NV requires that when HCR_EL2.{NV,NV1} == {1,0} and an exception
is taken from EL1 to EL1 then the reported EL in SPSR_EL1.M should be
EL2, not EL1.  Implement this behaviour.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 44005665d12..220ee64df0d 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11327,6 +11327,12 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
         old_mode = pstate_read(env);
         aarch64_save_sp(env, arm_current_el(env));
         env->elr_el[new_el] = env->pc;
+
+        if (cur_el == 1 && new_el == 1 &&
+            ((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == HCR_NV)) {
+            /* I_ZJRNN: report EL2 in the SPSR by setting M[3:2] to 0b10 */
+            old_mode = deposit32(old_mode, 2, 2, 2);
+        }
     } else {
         old_mode = cpsr_read_for_spsr_elx(env);
         env->elr_el[new_el] = env->regs[15];
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 16/35] target/arm: Trap registers when HCR_EL2.{NV, NV1} == {1, 1}
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (14 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 15/35] target/arm: Set SPSR_EL1.M correctly when nested virt is enabled Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:47   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 17/35] target/arm: Always use arm_pan_enabled() when checking if PAN is enabled Peter Maydell
                   ` (19 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

When HCR_EL2.{NV,NV1} is {1,1} we must trap five extra registers to
EL2: VBAR_EL1, ELR_EL1, SPSR_EL1, SCXTNUM_EL1 and TFSR_EL1.
Implement these traps.

This trap does not apply when FEAT_NV2 is implemented and enabled;
include the check that HCR_EL2.NV2 is 0 here, to save us having
to come back and add it later.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
I have mostly implemented FEAT_NV2 after FEAT_NV, but in
this particular case it seemed cleaner to include the NV2
bit check from the start.
---
 target/arm/helper.c | 44 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 40 insertions(+), 4 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 220ee64df0d..3270fb11049 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5339,6 +5339,19 @@ static void mdcr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
     }
 }
 
+static CPAccessResult access_nv1(CPUARMState *env, const ARMCPRegInfo *ri,
+                                 bool isread)
+{
+    if (arm_current_el(env) == 1) {
+        uint64_t hcr_nv = arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1 | HCR_NV2);
+
+        if (hcr_nv == (HCR_NV | HCR_NV1)) {
+            return CP_ACCESS_TRAP_EL2;
+        }
+    }
+    return CP_ACCESS_OK;
+}
+
 #ifdef CONFIG_USER_ONLY
 /*
  * `IC IVAU` is handled to improve compatibility with JITs that dual-map their
@@ -5687,12 +5700,12 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
     { .name = "ELR_EL1", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_ALIAS,
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
-      .access = PL1_RW,
+      .access = PL1_RW, .accessfn = access_nv1,
       .fieldoffset = offsetof(CPUARMState, elr_el[1]) },
     { .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_ALIAS,
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0,
-      .access = PL1_RW,
+      .access = PL1_RW, .accessfn = access_nv1,
       .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_SVC]) },
     /*
      * We rely on the access checks not allowing the guest to write to the
@@ -7807,6 +7820,16 @@ static CPAccessResult access_mte(CPUARMState *env, const ARMCPRegInfo *ri,
     }
     return CP_ACCESS_OK;
 }
+static CPAccessResult access_tfsr_el1(CPUARMState *env, const ARMCPRegInfo *ri,
+                                      bool isread)
+{
+    CPAccessResult nv1 = access_nv1(env, ri, isread);
+
+    if (nv1 != CP_ACCESS_OK) {
+        return nv1;
+    }
+    return access_mte(env, ri, isread);
+}
 
 static CPAccessResult access_tfsr_el2(CPUARMState *env, const ARMCPRegInfo *ri,
                                       bool isread)
@@ -7852,7 +7875,7 @@ static const ARMCPRegInfo mte_reginfo[] = {
       .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[0]) },
     { .name = "TFSR_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 6, .opc2 = 0,
-      .access = PL1_RW, .accessfn = access_mte,
+      .access = PL1_RW, .accessfn = access_tfsr_el1,
       .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) },
     { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 6, .opc2 = 0,
@@ -8004,6 +8027,18 @@ static CPAccessResult access_scxtnum(CPUARMState *env, const ARMCPRegInfo *ri,
     return CP_ACCESS_OK;
 }
 
+static CPAccessResult access_scxtnum_el1(CPUARMState *env,
+                                         const ARMCPRegInfo *ri,
+                                         bool isread)
+{
+    CPAccessResult nv1 = access_nv1(env, ri, isread);
+
+    if (nv1 != CP_ACCESS_OK) {
+        return nv1;
+    }
+    return access_scxtnum(env, ri, isread);
+}
+
 static const ARMCPRegInfo scxtnum_reginfo[] = {
     { .name = "SCXTNUM_EL0", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 3, .crn = 13, .crm = 0, .opc2 = 7,
@@ -8012,7 +8047,7 @@ static const ARMCPRegInfo scxtnum_reginfo[] = {
       .fieldoffset = offsetof(CPUARMState, scxtnum_el[0]) },
     { .name = "SCXTNUM_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7,
-      .access = PL1_RW, .accessfn = access_scxtnum,
+      .access = PL1_RW, .accessfn = access_scxtnum_el1,
       .fgt = FGT_SCXTNUM_EL1,
       .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) },
     { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64,
@@ -9394,6 +9429,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
               .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
               .access = PL1_RW, .writefn = vbar_write,
+              .accessfn = access_nv1,
               .fgt = FGT_VBAR_EL1,
               .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s),
                                      offsetof(CPUARMState, cp15.vbar_ns) },
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 17/35] target/arm: Always use arm_pan_enabled() when checking if PAN is enabled
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (15 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 16/35] target/arm: Trap registers when HCR_EL2.{NV, NV1} == {1, 1} Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:50   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 18/35] target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV, NV1} == {1, 1} Peter Maydell
                   ` (18 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

Currently the code in target/arm/helper.c mostly checks the PAN bits
in env->pstate or env->uncached_cpsr directly when it wants to know
if PAN is enabled, because in most callsites we know whether we are
in AArch64 or AArch32. We do have an arm_pan_enabled() function, but
we only use it in a few places where the code might run in either an
AArch32 or AArch64 context.

For FEAT_NV, when HCR_EL2.{NV,NV1} is {1,1} PAN is always disabled
even when the PSTATE.PAN bit is set, the "is PAN enabled" test
becomes more complicated. Make all places that check for PAN use
arm_pan_enabled(), so we have a place to put the FEAT_NV test.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3270fb11049..4b0e46cfaae 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -263,6 +263,15 @@ void init_cpreg_list(ARMCPU *cpu)
     g_list_free(keys);
 }
 
+static bool arm_pan_enabled(CPUARMState *env)
+{
+    if (is_a64(env)) {
+        return env->pstate & PSTATE_PAN;
+    } else {
+        return env->uncached_cpsr & CPSR_PAN;
+    }
+}
+
 /*
  * Some registers are not accessible from AArch32 EL3 if SCR.NS == 0.
  */
@@ -3598,7 +3607,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
             g_assert(ss != ARMSS_Secure);  /* ARMv8.4-SecEL2 is 64-bit only */
             /* fall through */
         case 1:
-            if (ri->crm == 9 && (env->uncached_cpsr & CPSR_PAN)) {
+            if (ri->crm == 9 && arm_pan_enabled(env)) {
                 mmu_idx = ARMMMUIdx_Stage1_E1_PAN;
             } else {
                 mmu_idx = ARMMMUIdx_Stage1_E1;
@@ -3714,7 +3723,7 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
     case 0:
         switch (ri->opc1) {
         case 0: /* AT S1E1R, AT S1E1W, AT S1E1RP, AT S1E1WP */
-            if (ri->crm == 9 && (env->pstate & PSTATE_PAN)) {
+            if (ri->crm == 9 && arm_pan_enabled(env)) {
                 mmu_idx = regime_e20 ?
                           ARMMMUIdx_E20_2_PAN : ARMMMUIdx_Stage1_E1_PAN;
             } else {
@@ -12222,15 +12231,6 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
 }
 #endif
 
-static bool arm_pan_enabled(CPUARMState *env)
-{
-    if (is_a64(env)) {
-        return env->pstate & PSTATE_PAN;
-    } else {
-        return env->uncached_cpsr & CPSR_PAN;
-    }
-}
-
 ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
 {
     ARMMMUIdx idx;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 18/35] target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV, NV1} == {1, 1}
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (16 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 17/35] target/arm: Always use arm_pan_enabled() when checking if PAN is enabled Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:52   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 19/35] target/arm: Treat LDTR* and STTR* as LDR/STR when NV, NV1 is 1, 1 Peter Maydell
                   ` (17 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

For FEAT_NV, when HCR_EL2.{NV,NV1} is {1,1} PAN is always disabled
even when the PSTATE.PAN bit is set. Implement this by having
arm_pan_enabled() return false in this situation.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 4b0e46cfaae..28448624c36 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -266,6 +266,9 @@ void init_cpreg_list(ARMCPU *cpu)
 static bool arm_pan_enabled(CPUARMState *env)
 {
     if (is_a64(env)) {
+        if ((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == (HCR_NV | HCR_NV1)) {
+            return false;
+        }
         return env->pstate & PSTATE_PAN;
     } else {
         return env->uncached_cpsr & CPSR_PAN;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 19/35] target/arm: Treat LDTR* and STTR* as LDR/STR when NV, NV1 is 1, 1
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (17 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 18/35] target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV, NV1} == {1, 1} Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:53   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 20/35] target/arm: Handle FEAT_NV page table attribute changes Peter Maydell
                   ` (16 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

FEAT_NV requires (per I_JKLJK) that when HCR_EL2.{NV,NV1} is {1,1} the
unprivileged-access instructions LDTR, STTR etc behave as normal
loads and stores. Implement the check that handles this.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/tcg/hflags.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index f33c0a12741..8f254bf9ccb 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -261,8 +261,10 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
         switch (mmu_idx) {
         case ARMMMUIdx_E10_1:
         case ARMMMUIdx_E10_1_PAN:
-            /* TODO: ARMv8.3-NV */
-            DP_TBFLAG_A64(flags, UNPRIV, 1);
+            /* FEAT_NV: NV,NV1 == 1,1 means we don't do UNPRIV accesses */
+            if ((hcr & (HCR_NV | HCR_NV1)) != (HCR_NV | HCR_NV1)) {
+                DP_TBFLAG_A64(flags, UNPRIV, 1);
+            }
             break;
         case ARMMMUIdx_E20_2:
         case ARMMMUIdx_E20_2_PAN:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 20/35] target/arm: Handle FEAT_NV page table attribute changes
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (18 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 19/35] target/arm: Treat LDTR* and STTR* as LDR/STR when NV, NV1 is 1, 1 Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:57   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 21/35] target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs Peter Maydell
                   ` (15 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

FEAT_NV requires that when HCR_EL2.{NV,NV1} == {1,1} the handling
of some of the page table attribute bits changes for the EL1&0
translation regime:

 * for block and page descriptors:
  - bit [54] holds PXN, not UXN
  - bit [53] is RES0, and the effective value of UXN is 0
  - bit [6], AP[1], is treated as 0
 * for table descriptors, when hierarchical permissions are enabled:
  - bit [60] holds PXNTable, not UXNTable
  - bit [59] is RES0
  - bit [61], APTable[0] is treated as 0

Implement these changes to the page table attribute handling.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/ptw.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 1762b058aec..cab30f0bf46 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -1581,6 +1581,12 @@ static bool lpae_block_desc_valid(ARMCPU *cpu, bool ds,
     }
 }
 
+static bool nv_nv1_enabled(CPUARMState *env, S1Translate *ptw)
+{
+    uint64_t hcr = arm_hcr_el2_eff_secstate(env, ptw->in_space);
+    return (hcr & (HCR_NV | HCR_NV1)) == (HCR_NV | HCR_NV1);
+}
+
 /**
  * get_phys_addr_lpae: perform one stage of page table walk, LPAE format
  *
@@ -1989,6 +1995,21 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
         xn = extract64(attrs, 54, 1);
         pxn = extract64(attrs, 53, 1);
 
+        if (el == 1 && nv_nv1_enabled(env, ptw)) {
+            /*
+             * With FEAT_NV, when HCR_EL2.{NV,NV1} == {1,1}, the block/page
+             * descriptor bit 54 holds PXN, 53 is RES0, and the effective value
+             * of UXN is 0. Similarly for bits 59 and 60 in table descriptors
+             * (which we have already folded into bits 53 and 54 of attrs).
+             * AP[1] (descriptor bit 6, our ap bit 0) is treated as 0.
+             * Similarly, APTable[0] from the table descriptor is treated as 0;
+             * we already folded this into AP[1] and squashing that to 0 does
+             * the right thing.
+             */
+            pxn = xn;
+            xn = 0;
+            ap &= ~1;
+        }
         /*
          * Note that we modified ptw->in_space earlier for NSTable, but
          * result->f.attrs retains a copy of the original security space.
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 21/35] target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (19 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 20/35] target/arm: Handle FEAT_NV page table attribute changes Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:59   ` Richard Henderson
  2023-12-29 11:37   ` Marcin Juszkiewicz
  2023-12-18 11:32 ` [PATCH 22/35] target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits Peter Maydell
                   ` (14 subsequent siblings)
  35 siblings, 2 replies; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

Enable FEAT_NV on the 'max' CPU, and stop filtering it out for the
Neoverse N2 and Neoverse V1 CPUs.  We continue to downgrade FEAT_NV2
support to FEAT_NV for the latter two CPU types.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 docs/system/arm/emulation.rst | 1 +
 target/arm/cpu.c              | 8 +++++---
 target/arm/tcg/cpu64.c        | 1 +
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index 0b604f90059..d827b42de79 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -63,6 +63,7 @@ the following architecture extensions:
 - FEAT_MTE (Memory Tagging Extension)
 - FEAT_MTE2 (Memory Tagging Extension)
 - FEAT_MTE3 (MTE Asymmetric Fault Handling)
+- FEAT_NV (Nested Virtualization)
 - FEAT_PACIMP (Pointer authentication - IMPLEMENTATION DEFINED algorithm)
 - FEAT_PACQARMA3 (Pointer authentication - QARMA3 algorithm)
 - FEAT_PACQARMA5 (Pointer authentication - QARMA5 algorithm)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index efb22a87f9e..da0c02f850b 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2238,9 +2238,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         /* FEAT_MPAM (Memory Partitioning and Monitoring Extension) */
         cpu->isar.id_aa64pfr0 =
             FIELD_DP64(cpu->isar.id_aa64pfr0, ID_AA64PFR0, MPAM, 0);
-        /* FEAT_NV (Nested Virtualization) */
-        cpu->isar.id_aa64mmfr2 =
-            FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 0);
+        /* FEAT_NV2 (Enhanced Nested Virtualization support) */
+        if (FIELD_EX64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV) > 1) {
+            cpu->isar.id_aa64mmfr2 =
+                FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 1);
+        }
     }
 
     /* MPU can be configured out of a PMSA CPU either by setting has-mpu
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 40e7a45166f..93f040e6e96 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1204,6 +1204,7 @@ void aarch64_max_tcg_initfn(Object *obj)
     t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);      /* FEAT_UAO */
     t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1);     /* FEAT_IESB */
     t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1);  /* FEAT_LVA */
+    t = FIELD_DP64(t, ID_AA64MMFR2, NV, 1);       /* FEAT_NV */
     t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1);       /* FEAT_TTST */
     t = FIELD_DP64(t, ID_AA64MMFR2, AT, 1);       /* FEAT_LSE2 */
     t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1);      /* FEAT_IDST */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 22/35] target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (20 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 21/35] target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 22:59   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 23/35] target/arm: Implement VNCR_EL2 register Peter Maydell
                   ` (13 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

FEAT_NV2 defines another new bit in HCR_EL2: NV2. When the
feature is enabled, allow this bit to be written in HCR_EL2.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu-features.h | 5 +++++
 target/arm/helper.c       | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index 3a43c328d9e..7a590c824cf 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -844,6 +844,11 @@ static inline bool isar_feature_aa64_nv(const ARMISARegisters *id)
     return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) != 0;
 }
 
+static inline bool isar_feature_aa64_nv2(const ARMISARegisters *id)
+{
+    return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) >= 2;
+}
+
 static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id)
 {
     return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 &&
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 28448624c36..afed58b6f7f 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5841,6 +5841,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask)
         if (cpu_isar_feature(aa64_nv, cpu)) {
             valid_mask |= HCR_NV | HCR_NV1 | HCR_AT;
         }
+        if (cpu_isar_feature(aa64_nv2, cpu)) {
+            valid_mask |= HCR_NV2;
+        }
     }
 
     if (cpu_isar_feature(any_evt, cpu)) {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 23/35] target/arm: Implement VNCR_EL2 register
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (21 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 22/35] target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 23:01   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 24/35] target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2 Peter Maydell
                   ` (12 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

For FEAT_NV2, a new system register VNCR_EL2 holds the base
address of the memory which nested-guest system register
accesses are redirected to. Implement this register.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu.h    |  3 +++
 target/arm/helper.c | 26 ++++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 0ec67847181..9df8fc08d79 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -547,6 +547,9 @@ typedef struct CPUArchState {
         uint64_t gpccr_el3;
         uint64_t gptbr_el3;
         uint64_t mfar_el3;
+
+        /* NV2 register */
+        uint64_t vncr_el2;
     } cp15;
 
     struct {
diff --git a/target/arm/helper.c b/target/arm/helper.c
index afed58b6f7f..45444360f95 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8107,6 +8107,28 @@ static const ARMCPRegInfo fgt_reginfo[] = {
       .access = PL2_RW, .accessfn = access_fgt,
       .fieldoffset = offsetof(CPUARMState, cp15.fgt_exec[FGTREG_HFGITR]) },
 };
+
+static void vncr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                       uint64_t value)
+{
+    /*
+     * Clear the RES0 bottom 12 bits; this means at runtime we can guarantee
+     * that VNCR_EL2 + offset is 64-bit aligned. We don't need to do anything
+     * about the RESS bits at the top -- we choose the "generate an EL2
+     * translation abort on use" CONSTRAINED UNPREDICTABLE option (i.e. let
+     * the ptw.c code detect the resulting invalid address).
+     */
+    env->cp15.vncr_el2 = value & ~0xfffULL;
+}
+
+static const ARMCPRegInfo nv2_reginfo[] = {
+    { .name = "VNCR_EL2", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 2, .opc2 = 0,
+      .access = PL2_RW,
+      .writefn = vncr_write,
+      .fieldoffset = offsetof(CPUARMState, cp15.vncr_el2) },
+};
+
 #endif /* TARGET_AARCH64 */
 
 static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -9590,6 +9612,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             define_arm_cp_regs(cpu, rme_mte_reginfo);
         }
     }
+
+    if (cpu_isar_feature(aa64_nv2, cpu)) {
+        define_arm_cp_regs(cpu, nv2_reginfo);
+    }
 #endif
 
     if (cpu_isar_feature(any_predinv, cpu)) {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 24/35] target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (22 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 23/35] target/arm: Implement VNCR_EL2 register Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 23:06   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 25/35] target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2 Peter Maydell
                   ` (11 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

With FEAT_NV2, the condition for when SPSR_EL1.M should report that
an exception was taken from EL2 changes.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 45444360f95..38e16c2f8a5 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11405,10 +11405,18 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
         aarch64_save_sp(env, arm_current_el(env));
         env->elr_el[new_el] = env->pc;
 
-        if (cur_el == 1 && new_el == 1 &&
-            ((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == HCR_NV)) {
-            /* I_ZJRNN: report EL2 in the SPSR by setting M[3:2] to 0b10 */
-            old_mode = deposit32(old_mode, 2, 2, 2);
+        if (cur_el == 1 && new_el == 1) {
+            uint64_t hcr = arm_hcr_el2_eff(env);
+            if ((hcr & (HCR_NV | HCR_NV1 | HCR_NV2)) == HCR_NV ||
+                (hcr & (HCR_NV | HCR_NV2)) == (HCR_NV | HCR_NV2)) {
+                /*
+                 * FEAT_NV, FEAT_NV2 may need to report EL2 in the SPSR
+                 * by setting M[3:2] to 0b10.
+                 * If NV2 is disabled, change SPSR when NV,NV1 == 1,0 (I_ZJRNN)
+                 * If NV2 is enabled, change SPSR when NV is 1 (I_DBTLM)
+                 */
+                old_mode = deposit32(old_mode, 2, 2, 2);
+            }
         }
     } else {
         old_mode = cpsr_read_for_spsr_elx(env);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 25/35] target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (23 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 24/35] target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2 Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 23:11   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 26/35] target/arm: Implement FEAT_NV2 redirection of sysregs to RAM Peter Maydell
                   ` (10 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

Under FEAT_NV2, when HCR_EL2.{NV,NV2} == 0b11 at EL1, accesses to the
registers SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2 and TFSR_EL2 (which
would UNDEF without FEAT_NV or FEAT_NV2) should instead access the
equivalent EL1 registers SPSR_EL1, ELR_EL1, ESR_EL1, FAR_EL1 and
TFSR_EL1.

Because there are only five registers involved and the encoding for
the EL1 register is identical to that of the EL2 register except
that opc1 is 0, we handle this by finding the EL1 register in the
hash table and using it instead.

Note that traps that apply to direct accesses to the EL1 register,
such as active fine-grained traps or other trap bits, do not trigger
when it is accessed via the EL2 encoding in this way.  However, some
traps that are defined by the EL2 register may apply.  We therefore
call the EL2 register's accessfn first.  The only one of the five
which has such traps is TFSR_EL2: make sure its accessfn correctly
handles both FEAT_NV (where we trap to EL2 without checking ATA bits)
and FEAT_NV2 (where we check ATA bits and then redirect to TFSR_EL1).

(We don't need the NV1 tbflag bit until the next patch, but we
introduce it here to avoid putting the NV, NV1, NV2 bits in an
odd order.)

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpregs.h            |  5 +++++
 target/arm/cpu.h               |  2 ++
 target/arm/tcg/translate.h     |  4 ++++
 target/arm/helper.c            | 13 +++++++++----
 target/arm/tcg/hflags.c        |  6 ++++++
 target/arm/tcg/translate-a64.c | 33 ++++++++++++++++++++++++++++++++-
 6 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 3c5f1b48879..cb795bed75b 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -118,6 +118,11 @@ enum {
      * ARM pseudocode function CheckSMEAccess().
      */
     ARM_CP_SME                   = 1 << 19,
+    /*
+     * Flag: one of the four EL2 registers which redirect to the
+     * equivalent EL1 register when FEAT_NV2 is enabled.
+     */
+    ARM_CP_NV2_REDIRECT          = 1 << 20,
 };
 
 /*
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 9df8fc08d79..e60b4f34fe4 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3242,6 +3242,8 @@ FIELD(TBFLAG_A64, TRAP_ERET, 29, 1)
 FIELD(TBFLAG_A64, NAA, 30, 1)
 FIELD(TBFLAG_A64, ATA0, 31, 1)
 FIELD(TBFLAG_A64, NV, 32, 1)
+FIELD(TBFLAG_A64, NV1, 33, 1)
+FIELD(TBFLAG_A64, NV2, 34, 1)
 
 /*
  * Helpers for using the above. Note that only the A64 accessors use
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 63e075bce3a..9e13c4ef7b6 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -146,6 +146,10 @@ typedef struct DisasContext {
     bool naa;
     /* True if FEAT_NV HCR_EL2.NV is enabled */
     bool nv;
+    /* True if NV enabled and HCR_EL2.NV1 is set */
+    bool nv1;
+    /* True if NV enabled and HCR_EL2.NV2 is set */
+    bool nv2;
     /*
      * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
      *  < 0, set by the current instruction.
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 38e16c2f8a5..61aac61bcc4 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6119,14 +6119,16 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 7,
       .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
     { .name = "ELR_EL2", .state = ARM_CP_STATE_AA64,
-      .type = ARM_CP_ALIAS,
+      .type = ARM_CP_ALIAS | ARM_CP_NV2_REDIRECT,
       .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1,
       .access = PL2_RW,
       .fieldoffset = offsetof(CPUARMState, elr_el[2]) },
     { .name = "ESR_EL2", .state = ARM_CP_STATE_BOTH,
+      .type = ARM_CP_NV2_REDIRECT,
       .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0,
       .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[2]) },
     { .name = "FAR_EL2", .state = ARM_CP_STATE_BOTH,
+      .type = ARM_CP_NV2_REDIRECT,
       .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0,
       .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[2]) },
     { .name = "HIFAR", .state = ARM_CP_STATE_AA32,
@@ -6135,7 +6137,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
       .access = PL2_RW,
       .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[2]) },
     { .name = "SPSR_EL2", .state = ARM_CP_STATE_AA64,
-      .type = ARM_CP_ALIAS,
+      .type = ARM_CP_ALIAS | ARM_CP_NV2_REDIRECT,
       .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 0,
       .access = PL2_RW,
       .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_HYP]) },
@@ -7852,11 +7854,13 @@ static CPAccessResult access_tfsr_el2(CPUARMState *env, const ARMCPRegInfo *ri,
     /*
      * TFSR_EL2: similar to generic access_mte(), but we need to
      * account for FEAT_NV. At EL1 this must be a FEAT_NV access;
-     * we will trap to EL2 and the HCR/SCR traps do not apply.
+     * if NV2 is enabled then we will redirect this to TFSR_EL1
+     * after doing the HCR and SCR ATA traps; otherwise this will
+     * be a trap to EL2 and the HCR/SCR traps do not apply.
      */
     int el = arm_current_el(env);
 
-    if (el == 1) {
+    if (el == 1 && (arm_hcr_el2_eff(env) & HCR_NV2)) {
         return CP_ACCESS_OK;
     }
     if (el < 2 && arm_is_el2_enabled(env)) {
@@ -7893,6 +7897,7 @@ static const ARMCPRegInfo mte_reginfo[] = {
       .access = PL1_RW, .accessfn = access_tfsr_el1,
       .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) },
     { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64,
+      .type = ARM_CP_NV2_REDIRECT,
       .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 6, .opc2 = 0,
       .access = PL2_RW, .accessfn = access_tfsr_el2,
       .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[2]) },
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index 8f254bf9ccb..d2b352663e8 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -302,6 +302,12 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
     if (el == 1 && (hcr & HCR_NV)) {
         DP_TBFLAG_A64(flags, TRAP_ERET, 1);
         DP_TBFLAG_A64(flags, NV, 1);
+        if (hcr & HCR_NV1) {
+            DP_TBFLAG_A64(flags, NV1, 1);
+        }
+        if (hcr & HCR_NV2) {
+            DP_TBFLAG_A64(flags, NV2, 1);
+        }
     }
 
     if (cpu_isar_feature(aa64_mte, env_archcpu(env))) {
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 6bfc39d8ea7..6909c9df30d 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2132,6 +2132,7 @@ static void handle_sys(DisasContext *s, bool isread,
     const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
     bool need_exit_tb = false;
     bool nv_trap_to_el2 = false;
+    bool nv_redirect_reg = false;
     bool skip_fp_access_checks = false;
     TCGv_ptr tcg_ri = NULL;
     TCGv_i64 tcg_rt;
@@ -2173,7 +2174,14 @@ static void handle_sys(DisasContext *s, bool isread,
          * for registers accessible at EL1).
          */
         skip_fp_access_checks = true;
-        if (s->nv && arm_cpreg_traps_in_nv(ri)) {
+        if (s->nv && s->nv2 && (ri->type & ARM_CP_NV2_REDIRECT)) {
+            /*
+             * This is one of the few EL2 registers which should redirect
+             * to the equivalent EL1 register. We do that after running
+             * the EL2 register's accessfn.
+             */
+            nv_redirect_reg = true;
+        } else 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
@@ -2225,6 +2233,27 @@ static void handle_sys(DisasContext *s, bool isread,
         return;
     }
 
+    if (nv_redirect_reg) {
+        /*
+         * FEAT_NV2 redirection of an EL2 register to an EL1 register.
+         * Conveniently in all cases the encoding of the EL1 register is
+         * identical to the EL2 register except that opc1 is 0.
+         * Get the reginfo for the EL1 register to use for the actual access.
+         * We don't use the EL1 register's access function, and
+         * fine-grained-traps on EL1 also do not apply here.
+         */
+        key = ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
+                                 crn, crm, op0, 0, op2);
+        ri = get_arm_cp_reginfo(s->cp_regs, key);
+        assert(ri);
+        assert(cp_access_ok(s->current_el, ri, isread));
+        /*
+         * We might not have done an update_pc earlier, so check we don't
+         * need it. We could support this in future if necessary.
+         */
+        assert(!(ri->type & ARM_CP_RAISES_EXC));
+    }
+
     /* Handle special cases first */
     switch (ri->type & ARM_CP_SPECIAL_MASK) {
     case 0:
@@ -14031,6 +14060,8 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
     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->nv1 = EX_TBFLAG_A64(tb_flags, NV1);
+    dc->nv2 = EX_TBFLAG_A64(tb_flags, NV2);
     dc->vec_len = 0;
     dc->vec_stride = 0;
     dc->cp_regs = arm_cpu->cp_regs;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 26/35] target/arm: Implement FEAT_NV2 redirection of sysregs to RAM
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (24 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 25/35] target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2 Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-27 23:55   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly Peter Maydell
                   ` (9 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

FEAT_NV2 requires that when HCR_EL2.{NV,NV2} == 0b11 then accesses by
EL1 to certain system registers are redirected to RAM.  The full list
of affected registers is in the table in rule R_CSRPQ in the Arm ARM.
The registers may be normally accessible at EL1 (like ACTLR_EL1), or
normally UNDEF at EL1 (like HCR_EL2).  Some registers redirect to RAM
only when HCR_EL2.NV1 is 0, and some only when HCR_EL2.NV1 is 1;
others trap in both cases.

Add the infrastructure for identifying which registers should be
redirected and turning them into memory accesses.

This code does not set the correct syndrome or arrange for the
exception to be taken to the correct target EL if the access via
VNCR_EL2 faults; we will do that in the next commit.

Subsequent commits will mark up the relevant regdefs to set their
nv2_redirect_offset, and if relevant one of the two flags which
indicates that the redirect happens only for a particular value of
HCR_EL2.NV1.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpregs.h            | 12 +++++++
 target/arm/cpu.h               |  4 +++
 target/arm/tcg/translate.h     |  6 ++++
 target/arm/tcg/hflags.c        |  6 ++++
 target/arm/tcg/translate-a64.c | 58 ++++++++++++++++++++++++++++++++++
 5 files changed, 86 insertions(+)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index cb795bed75b..b6fdd0f3eb4 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -826,6 +826,11 @@ typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
 
 #define CP_ANY 0xff
 
+/* Flags in the high bits of nv2_redirect_offset */
+#define NV2_REDIR_NV1 0x4000 /* Only redirect when HCR_EL2.NV1 == 1 */
+#define NV2_REDIR_NO_NV1 0x8000 /* Only redirect when HCR_EL2.NV1 == 0 */
+#define NV2_REDIR_FLAG_MASK 0xc000
+
 /* Definition of an ARM coprocessor register */
 struct ARMCPRegInfo {
     /* Name of register (useful mainly for debugging, need not be unique) */
@@ -867,6 +872,13 @@ struct ARMCPRegInfo {
      * value encodes both the trap register and bit within it.
      */
     FGTBit fgt;
+
+    /*
+     * Offset from VNCR_EL2 when FEAT_NV2 redirects access to memory;
+     * may include an NV2_REDIR_* flag.
+     */
+    uint32_t nv2_redirect_offset;
+
     /*
      * The opaque pointer passed to define_arm_cp_regs_with_opaque() when
      * this register was defined: can be used to hand data through to the
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index e60b4f34fe4..bc4fa95ea35 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3244,6 +3244,10 @@ FIELD(TBFLAG_A64, ATA0, 31, 1)
 FIELD(TBFLAG_A64, NV, 32, 1)
 FIELD(TBFLAG_A64, NV1, 33, 1)
 FIELD(TBFLAG_A64, NV2, 34, 1)
+/* Set if FEAT_NV2 RAM accesses use the EL2&0 translation regime */
+FIELD(TBFLAG_A64, NV2_MEM_E20, 35, 1)
+/* Set if FEAT_NV2 RAM accesses are big-endian */
+FIELD(TBFLAG_A64, NV2_MEM_BE, 36, 1)
 
 /*
  * Helpers for using the above. Note that only the A64 accessors use
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 9e13c4ef7b6..93be745cf33 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -150,6 +150,10 @@ typedef struct DisasContext {
     bool nv1;
     /* True if NV enabled and HCR_EL2.NV2 is set */
     bool nv2;
+    /* True if NV2 enabled and NV2 RAM accesses use EL2&0 translation regime */
+    bool nv2_mem_e20;
+    /* True if NV2 enabled and NV2 RAM accesses are big-endian */
+    bool nv2_mem_be;
     /*
      * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
      *  < 0, set by the current instruction.
@@ -165,6 +169,8 @@ typedef struct DisasContext {
     int c15_cpar;
     /* TCG op of the current insn_start.  */
     TCGOp *insn_start;
+    /* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */
+    uint32_t nv2_redirect_offset;
 } DisasContext;
 
 typedef struct DisasCompare {
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index d2b352663e8..8e5d35d9227 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -307,6 +307,12 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
         }
         if (hcr & HCR_NV2) {
             DP_TBFLAG_A64(flags, NV2, 1);
+            if (hcr & HCR_E2H) {
+                DP_TBFLAG_A64(flags, NV2_MEM_E20, 1);
+            }
+            if (env->cp15.sctlr_el[2] & SCTLR_EE) {
+                DP_TBFLAG_A64(flags, NV2_MEM_BE, 1);
+            }
         }
     }
 
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 6909c9df30d..128bff4b445 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2134,6 +2134,7 @@ static void handle_sys(DisasContext *s, bool isread,
     bool nv_trap_to_el2 = false;
     bool nv_redirect_reg = false;
     bool skip_fp_access_checks = false;
+    bool nv2_mem_redirect = false;
     TCGv_ptr tcg_ri = NULL;
     TCGv_i64 tcg_rt;
     uint32_t syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
@@ -2166,6 +2167,21 @@ static void handle_sys(DisasContext *s, bool isread,
         return;
     }
 
+    if (s->nv && s->nv2 && ri->nv2_redirect_offset) {
+        /*
+         * Some registers always redirect to memory; some only do so if
+         * HCR_EL2.NV1 is 0, and some only if NV1 is 1 (these come in
+         * pairs which share an offset; see the table in R_CSRPQ).
+         */
+        if (ri->nv2_redirect_offset & NV2_REDIR_NV1) {
+            nv2_mem_redirect = s->nv1;
+        } else if (ri->nv2_redirect_offset & NV2_REDIR_NO_NV1) {
+            nv2_mem_redirect = !s->nv1;
+        } else {
+            nv2_mem_redirect = true;
+        }
+    }
+
     /* Check access permissions */
     if (!cp_access_ok(s->current_el, ri, isread)) {
         /*
@@ -2181,6 +2197,12 @@ static void handle_sys(DisasContext *s, bool isread,
              * the EL2 register's accessfn.
              */
             nv_redirect_reg = true;
+            assert(!nv2_mem_redirect);
+        } else if (nv2_mem_redirect) {
+            /*
+             * NV2 redirect-to-memory takes precedence over trap to EL2 or
+             * UNDEF to EL1.
+             */
         } else if (s->nv && arm_cpreg_traps_in_nv(ri)) {
             /*
              * This register / instruction exists and is an EL2 register, so
@@ -2254,6 +2276,40 @@ static void handle_sys(DisasContext *s, bool isread,
         assert(!(ri->type & ARM_CP_RAISES_EXC));
     }
 
+    if (nv2_mem_redirect) {
+        /*
+         * This system register is being redirected into an EL2 memory access.
+         * This means it is not an IO operation, doesn't change hflags,
+         * and need not end the TB, because it has no side effects.
+         *
+         * The access is 64-bit single copy atomic, guaranteed aligned because
+         * of the definition of VCNR_EL2. Its endianness depends on
+         * SCTLR_EL2.EE, not on the data endianness of EL1.
+         * It is done under either the EL2 translation regime or the EL2&0
+         * translation regime, depending on HCR_EL2.E2H. It behaves as if
+         * PSTATE.PAN is 0.
+         */
+        TCGv_i64 ptr = tcg_temp_new_i64();
+        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);
+
+        if (s->nv2_mem_be) {
+            mop |= MO_BE;
+        }
+
+        tcg_gen_ld_i64(ptr, tcg_env, offsetof(CPUARMState, cp15.vncr_el2));
+        tcg_gen_addi_i64(ptr, ptr,
+                         (ri->nv2_redirect_offset & ~NV2_REDIR_FLAG_MASK));
+        tcg_rt = cpu_reg(s, rt);
+        if (isread) {
+            tcg_gen_qemu_ld_i64(tcg_rt, ptr, memidx, mop);
+        } else {
+            tcg_gen_qemu_st_i64(tcg_rt, ptr, memidx, mop);
+        }
+        return;
+    }
+
     /* Handle special cases first */
     switch (ri->type & ARM_CP_SPECIAL_MASK) {
     case 0:
@@ -14062,6 +14118,8 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
     dc->nv = EX_TBFLAG_A64(tb_flags, NV);
     dc->nv1 = EX_TBFLAG_A64(tb_flags, NV1);
     dc->nv2 = EX_TBFLAG_A64(tb_flags, NV2);
+    dc->nv2_mem_e20 = EX_TBFLAG_A64(tb_flags, NV2_MEM_E20);
+    dc->nv2_mem_be = EX_TBFLAG_A64(tb_flags, NV2_MEM_BE);
     dc->vec_len = 0;
     dc->vec_stride = 0;
     dc->cp_regs = arm_cpu->cp_regs;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (25 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 26/35] target/arm: Implement FEAT_NV2 redirection of sysregs to RAM Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-28  0:03   ` Richard Henderson
  2024-01-16 13:09   ` Jonathan Cameron via
  2023-12-18 11:32 ` [PATCH 28/35] target/arm: Mark up VNCR offsets (offsets 0x0..0xff) Peter Maydell
                   ` (8 subsequent siblings)
  35 siblings, 2 replies; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

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>
---
 target/arm/cpu.h               |  4 ++--
 target/arm/syndrome.h          | 20 ++++++++++++++++----
 target/arm/tcg/tlb_helper.c    | 27 +++++++++++++++++++++++++--
 target/arm/tcg/translate-a64.c |  4 ++++
 4 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index bc4fa95ea35..da640949518 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -120,12 +120,12 @@ enum {
 #define TARGET_INSN_START_EXTRA_WORDS 2
 
 /* The 2nd extra word holding syndrome info for data aborts does not use
- * the upper 6 bits nor the lower 14 bits. We mask and shift it down to
+ * the upper 6 bits nor the lower 13 bits. We mask and shift it down to
  * help the sleb128 encoder do a better job.
  * When restoring the CPU state, we shift it back up.
  */
 #define ARM_INSN_START_WORD2_MASK ((1 << 26) - 1)
-#define ARM_INSN_START_WORD2_SHIFT 14
+#define ARM_INSN_START_WORD2_SHIFT 13
 
 /* We currently assume float and double are IEEE single and double
    precision respectively.
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index 95454b5b3bb..1a49767479f 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -86,6 +86,9 @@ typedef enum {
 #define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
 #define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT)
 
+/* In the Data Abort syndrome */
+#define ARM_EL_VNCR (1 << 13)
+
 static inline uint32_t syn_get_ec(uint32_t syn)
 {
     return syn >> ARM_EL_EC_SHIFT;
@@ -256,13 +259,12 @@ static inline uint32_t syn_bxjtrap(int cv, int cond, int rm)
         (cv << 24) | (cond << 20) | rm;
 }
 
-static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc,
+static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr,
                                int cm, int s1ptw, int wnr, int fsc)
 {
-    /* TODO: FEAT_NV2 adds VNCR */
     return (EC_GPC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (s2ptw << 21)
-            | (ind << 20) | (gpcsc << 14) | (cm << 8) | (s1ptw << 7)
-            | (wnr << 6) | fsc;
+        | (ind << 20) | (gpcsc << 14) | (vncr << 13) | (cm << 8)
+        | (s1ptw << 7) | (wnr << 6) | fsc;
 }
 
 static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
@@ -295,6 +297,16 @@ static inline uint32_t syn_data_abort_with_iss(int same_el,
            | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
 }
 
+/*
+ * Faults due to FEAT_NV2 VNCR_EL2-based accesses report as same-EL
+ * Data Aborts with the VNCR bit set.
+ */
+static inline uint32_t syn_data_abort_vncr(int ea, int wnr, int fsc)
+{
+    return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (1 << ARM_EL_EC_SHIFT)
+        | ARM_EL_IL | ARM_EL_VNCR | (wnr << 6) | fsc;
+}
+
 static inline uint32_t syn_swstep(int same_el, int isv, int ex)
 {
     return (EC_SOFTWARESTEP << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c
index 4fdd85359e1..dd5de74ffb7 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 128bff4b445..8f905ed9645 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2293,6 +2293,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;
 
         if (s->nv2_mem_be) {
             mop |= MO_BE;
@@ -2302,6 +2303,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 {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 28/35] target/arm: Mark up VNCR offsets (offsets 0x0..0xff)
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (26 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-28  0:35   ` Richard Henderson
  2023-12-18 11:32 ` [PATCH 29/35] target/arm: Mark up VNCR offsets (offsets 0x100..0x160) Peter Maydell
                   ` (7 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

Mark up the cpreginfo structs to indicate offsets for system
registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
the Arm ARM. This commit covers offsets below 0x100; all of these
registers are redirected to memory regardless of the value of
HCR_EL2.NV1.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 61aac61bcc4..ff7f90fa4af 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6043,6 +6043,7 @@ static const ARMCPRegInfo hcrx_el2_reginfo = {
     .name = "HCRX_EL2", .state = ARM_CP_STATE_AA64,
     .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 2,
     .access = PL2_RW, .writefn = hcrx_write, .accessfn = access_hxen,
+    .nv2_redirect_offset = 0xa0,
     .fieldoffset = offsetof(CPUARMState, cp15.hcrx_el2),
 };
 
@@ -6109,6 +6110,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
       .type = ARM_CP_IO,
       .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
       .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2),
+      .nv2_redirect_offset = 0x78,
       .writefn = hcr_write, .raw_writefn = raw_write },
     { .name = "HCR", .state = ARM_CP_STATE_AA32,
       .type = ARM_CP_ALIAS | ARM_CP_IO,
@@ -6193,6 +6195,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
     { .name = "VTCR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2,
       .access = PL2_RW,
+      .nv2_redirect_offset = 0x40,
       /* no .writefn needed as this can't cause an ASID change */
       .fieldoffset = offsetof(CPUARMState, cp15.vtcr_el2) },
     { .name = "VTTBR", .state = ARM_CP_STATE_AA32,
@@ -6204,6 +6207,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
     { .name = "VTTBR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 0,
       .access = PL2_RW, .writefn = vttbr_write, .raw_writefn = raw_write,
+      .nv2_redirect_offset = 0x20,
       .fieldoffset = offsetof(CPUARMState, cp15.vttbr_el2) },
     { .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0,
@@ -6212,6 +6216,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
     { .name = "TPIDR_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 2,
       .access = PL2_RW, .resetvalue = 0,
+      .nv2_redirect_offset = 0x90,
       .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[2]) },
     { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0,
@@ -6307,6 +6312,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
       .access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 0,
       .writefn = gt_cntvoff_write,
+      .nv2_redirect_offset = 0x60,
       .fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) },
     { .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14,
       .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS | ARM_CP_IO,
@@ -6345,6 +6351,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
     { .name = "HSTR_EL2", .state = ARM_CP_STATE_BOTH,
       .cp = 15, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3,
       .access = PL2_RW,
+      .nv2_redirect_offset = 0x80,
       .fieldoffset = offsetof(CPUARMState, cp15.hstr_el2) },
 };
 
@@ -6370,10 +6377,12 @@ static const ARMCPRegInfo el2_sec_cp_reginfo[] = {
     { .name = "VSTTBR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 0,
       .access = PL2_RW, .accessfn = sel2_access,
+      .nv2_redirect_offset = 0x30,
       .fieldoffset = offsetof(CPUARMState, cp15.vsttbr_el2) },
     { .name = "VSTCR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 2,
       .access = PL2_RW, .accessfn = sel2_access,
+      .nv2_redirect_offset = 0x48,
       .fieldoffset = offsetof(CPUARMState, cp15.vstcr_el2) },
 };
 
@@ -8131,6 +8140,7 @@ static const ARMCPRegInfo nv2_reginfo[] = {
       .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 2, .opc2 = 0,
       .access = PL2_RW,
       .writefn = vncr_write,
+      .nv2_redirect_offset = 0xb0,
       .fieldoffset = offsetof(CPUARMState, cp15.vncr_el2) },
 };
 
@@ -8962,6 +8972,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
               .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 0,
               .access = PL2_RW, .resetvalue = cpu->midr,
               .type = ARM_CP_EL3_NO_EL2_C_NZ,
+              .nv2_redirect_offset = 0x88,
               .fieldoffset = offsetof(CPUARMState, cp15.vpidr_el2) },
             { .name = "VMPIDR", .state = ARM_CP_STATE_AA32,
               .cp = 15, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5,
@@ -8973,6 +8984,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
               .opc0 = 3, .opc1 = 4, .crn = 0, .crm = 0, .opc2 = 5,
               .access = PL2_RW, .resetvalue = vmpidr_def,
               .type = ARM_CP_EL3_NO_EL2_C_NZ,
+              .nv2_redirect_offset = 0x50,
               .fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) },
         };
         /*
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 29/35] target/arm: Mark up VNCR offsets (offsets 0x100..0x160)
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (27 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 28/35] target/arm: Mark up VNCR offsets (offsets 0x0..0xff) Peter Maydell
@ 2023-12-18 11:32 ` Peter Maydell
  2023-12-28  0:42   ` Richard Henderson
  2023-12-18 11:33 ` [PATCH 30/35] target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8) Peter Maydell
                   ` (6 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:32 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

Mark up the cpreginfo structs to indicate offsets for system
registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
the Arm ARM.  This commit covers offsets 0x100 to 0x160.

Many (but not all) of the registers in this range have _EL12 aliases,
and the slot in memory is shared between the _EL12 version of the
register and the _EL1 version.  Where we programmatically generate
the regdef for the _EL12 register, arrange that its
nv2_redirect_offset is set up correctly to do this.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/debug_helper.c |  1 +
 target/arm/helper.c       | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
index b39144d5b93..7d856acddf2 100644
--- a/target/arm/debug_helper.c
+++ b/target/arm/debug_helper.c
@@ -960,6 +960,7 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
       .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
       .access = PL1_RW, .accessfn = access_tda,
       .fgt = FGT_MDSCR_EL1,
+      .nv2_redirect_offset = 0x158,
       .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
       .resetvalue = 0 },
     /*
diff --git a/target/arm/helper.c b/target/arm/helper.c
index ff7f90fa4af..78c3c3ebd8d 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -647,6 +647,7 @@ static const ARMCPRegInfo cp_reginfo[] = {
       .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_CONTEXTIDR_EL1,
+      .nv2_redirect_offset = 0x108 | NV2_REDIR_NV1,
       .secure = ARM_CP_SECSTATE_NS,
       .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[1]),
       .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, },
@@ -883,6 +884,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
     { .name = "CPACR", .state = ARM_CP_STATE_BOTH, .opc0 = 3,
       .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access,
       .fgt = FGT_CPACR_EL1,
+      .nv2_redirect_offset = 0x100 | NV2_REDIR_NV1,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.cpacr_el1),
       .resetfn = cpacr_reset, .writefn = cpacr_write, .readfn = cpacr_read },
 };
@@ -2234,11 +2236,13 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_AFSR0_EL1,
+      .nv2_redirect_offset = 0x128 | NV2_REDIR_NV1,
       .type = ARM_CP_CONST, .resetvalue = 0 },
     { .name = "AFSR1_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 1,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_AFSR1_EL1,
+      .nv2_redirect_offset = 0x130 | NV2_REDIR_NV1,
       .type = ARM_CP_CONST, .resetvalue = 0 },
     /*
      * MAIR can just read-as-written because we don't implement caches
@@ -2248,6 +2252,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_MAIR_EL1,
+      .nv2_redirect_offset = 0x140 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.mair_el[1]),
       .resetvalue = 0 },
     { .name = "MAIR_EL3", .state = ARM_CP_STATE_AA64,
@@ -4271,6 +4276,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_ESR_EL1,
+      .nv2_redirect_offset = 0x138 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, },
     { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0,
@@ -4290,6 +4296,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_TCR_EL1,
+      .nv2_redirect_offset = 0x120 | NV2_REDIR_NV1,
       .writefn = vmsa_tcr_el12_write,
       .raw_writefn = raw_write,
       .resetvalue = 0,
@@ -4529,6 +4536,7 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
       .opc0 = 3, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_AMAIR_EL1,
+      .nv2_redirect_offset = 0x148 | NV2_REDIR_NV1,
       .type = ARM_CP_CONST, .resetvalue = 0 },
     /* AMAIR1 is mapped to AMAIR_EL1[63:32] */
     { .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1,
@@ -5718,6 +5726,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .type = ARM_CP_ALIAS,
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_nv1,
+      .nv2_redirect_offset = 0x160 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_SVC]) },
     /*
      * We rely on the access checks not allowing the guest to write to the
@@ -6710,6 +6719,17 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
         new_reg->writefn = el2_e2h_e12_write;
         new_reg->accessfn = el2_e2h_e12_access;
 
+        /*
+         * If the _EL1 register is redirected to memory by FEAT_NV2,
+         * then it shares the offset with the _EL12 register,
+         * and which one is redirected depends on HCR_EL2.NV1.
+         */
+        if (new_reg->nv2_redirect_offset) {
+            assert(new_reg->nv2_redirect_offset & NV2_REDIR_NV1);
+            new_reg->nv2_redirect_offset &= ~NV2_REDIR_NV1;
+            new_reg->nv2_redirect_offset |= NV2_REDIR_NO_NV1;
+        }
+
         ok = g_hash_table_insert(cpu->cp_regs,
                                  (gpointer)(uintptr_t)a->new_key, new_reg);
         g_assert(ok);
@@ -9414,6 +9434,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             { .name = "ACTLR_EL1", .state = ARM_CP_STATE_BOTH,
               .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 1,
               .access = PL1_RW, .accessfn = access_tacr,
+              .nv2_redirect_offset = 0x118,
               .type = ARM_CP_CONST, .resetvalue = cpu->reset_auxcr },
             { .name = "ACTLR_EL2", .state = ARM_CP_STATE_BOTH,
               .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 1,
@@ -9499,6 +9520,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0,
             .access = PL1_RW, .accessfn = access_tvm_trvm,
             .fgt = FGT_SCTLR_EL1,
+            .nv2_redirect_offset = 0x110 | NV2_REDIR_NV1,
             .bank_fieldoffsets = { offsetof(CPUARMState, cp15.sctlr_s),
                                    offsetof(CPUARMState, cp15.sctlr_ns) },
             .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr,
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 30/35] target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8)
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (28 preceding siblings ...)
  2023-12-18 11:32 ` [PATCH 29/35] target/arm: Mark up VNCR offsets (offsets 0x100..0x160) Peter Maydell
@ 2023-12-18 11:33 ` Peter Maydell
  2023-12-28  0:45   ` Richard Henderson
  2023-12-18 11:33 ` [PATCH 31/35] target/arm: Mark up VNCR offsets (offsets >= 0x200, except GIC) Peter Maydell
                   ` (5 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:33 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

Mark up the cpreginfo structs to indicate offsets for system
registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
the Arm ARM.  This commit covers offsets 0x168 to 0x1f8.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 78c3c3ebd8d..6c33619d646 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3175,6 +3175,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 1,
       .type = ARM_CP_IO, .access = PL0_RW,
       .accessfn = gt_ptimer_access,
+      .nv2_redirect_offset = 0x180 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
       .resetvalue = 0,
       .readfn = gt_phys_redir_ctl_read, .raw_readfn = raw_read,
@@ -3192,6 +3193,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 1,
       .type = ARM_CP_IO, .access = PL0_RW,
       .accessfn = gt_vtimer_access,
+      .nv2_redirect_offset = 0x170 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
       .resetvalue = 0,
       .readfn = gt_virt_redir_ctl_read, .raw_readfn = raw_read,
@@ -3271,6 +3273,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 2,
       .access = PL0_RW,
       .type = ARM_CP_IO,
+      .nv2_redirect_offset = 0x178 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
       .resetvalue = 0, .accessfn = gt_ptimer_access,
       .readfn = gt_phys_redir_cval_read, .raw_readfn = raw_read,
@@ -3288,6 +3291,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 2,
       .access = PL0_RW,
       .type = ARM_CP_IO,
+      .nv2_redirect_offset = 0x168 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
       .resetvalue = 0, .accessfn = gt_vtimer_access,
       .readfn = gt_virt_redir_cval_read, .raw_readfn = raw_read,
@@ -7036,6 +7040,7 @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
 static const ARMCPRegInfo zcr_reginfo[] = {
     { .name = "ZCR_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 0,
+      .nv2_redirect_offset = 0x1e0 | NV2_REDIR_NV1,
       .access = PL1_RW, .type = ARM_CP_SVE,
       .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]),
       .writefn = zcr_write, .raw_writefn = raw_write },
@@ -7177,6 +7182,7 @@ static const ARMCPRegInfo sme_reginfo[] = {
       .writefn = svcr_write, .raw_writefn = raw_write },
     { .name = "SMCR_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 6,
+      .nv2_redirect_offset = 0x1f0 | NV2_REDIR_NV1,
       .access = PL1_RW, .type = ARM_CP_SME,
       .fieldoffset = offsetof(CPUARMState, vfp.smcr_el[1]),
       .writefn = smcr_write, .raw_writefn = raw_write },
@@ -7210,6 +7216,7 @@ static const ARMCPRegInfo sme_reginfo[] = {
       .type = ARM_CP_CONST, .resetvalue = 0 },
     { .name = "SMPRIMAP_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 5,
+      .nv2_redirect_offset = 0x1f8,
       .access = PL2_RW, .accessfn = access_smprimap,
       .type = ARM_CP_CONST, .resetvalue = 0 },
 };
@@ -7924,6 +7931,7 @@ static const ARMCPRegInfo mte_reginfo[] = {
     { .name = "TFSR_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 6, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tfsr_el1,
+      .nv2_redirect_offset = 0x190 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) },
     { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_NV2_REDIRECT,
@@ -8098,6 +8106,7 @@ static const ARMCPRegInfo scxtnum_reginfo[] = {
       .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7,
       .access = PL1_RW, .accessfn = access_scxtnum_el1,
       .fgt = FGT_SCXTNUM_EL1,
+      .nv2_redirect_offset = 0x188 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) },
     { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 7,
@@ -8122,22 +8131,27 @@ static CPAccessResult access_fgt(CPUARMState *env, const ARMCPRegInfo *ri,
 static const ARMCPRegInfo fgt_reginfo[] = {
     { .name = "HFGRTR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4,
+      .nv2_redirect_offset = 0x1b8,
       .access = PL2_RW, .accessfn = access_fgt,
       .fieldoffset = offsetof(CPUARMState, cp15.fgt_read[FGTREG_HFGRTR]) },
     { .name = "HFGWTR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 5,
+      .nv2_redirect_offset = 0x1c0,
       .access = PL2_RW, .accessfn = access_fgt,
       .fieldoffset = offsetof(CPUARMState, cp15.fgt_write[FGTREG_HFGWTR]) },
     { .name = "HDFGRTR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 1, .opc2 = 4,
+      .nv2_redirect_offset = 0x1d0,
       .access = PL2_RW, .accessfn = access_fgt,
       .fieldoffset = offsetof(CPUARMState, cp15.fgt_read[FGTREG_HDFGRTR]) },
     { .name = "HDFGWTR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 3, .crm = 1, .opc2 = 5,
+      .nv2_redirect_offset = 0x1d8,
       .access = PL2_RW, .accessfn = access_fgt,
       .fieldoffset = offsetof(CPUARMState, cp15.fgt_write[FGTREG_HDFGWTR]) },
     { .name = "HFGITR_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 6,
+      .nv2_redirect_offset = 0x1c8,
       .access = PL2_RW, .accessfn = access_fgt,
       .fieldoffset = offsetof(CPUARMState, cp15.fgt_exec[FGTREG_HFGITR]) },
 };
@@ -8324,12 +8338,14 @@ static const ARMCPRegInfo vhe_reginfo[] = {
       .opc0 = 3, .opc1 = 5, .crn = 14, .crm = 2, .opc2 = 1,
       .type = ARM_CP_IO | ARM_CP_ALIAS,
       .access = PL2_RW, .accessfn = e2h_access,
+      .nv2_redirect_offset = 0x180 | NV2_REDIR_NO_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
       .writefn = gt_phys_ctl_write, .raw_writefn = raw_write },
     { .name = "CNTV_CTL_EL02", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 5, .crn = 14, .crm = 3, .opc2 = 1,
       .type = ARM_CP_IO | ARM_CP_ALIAS,
       .access = PL2_RW, .accessfn = e2h_access,
+      .nv2_redirect_offset = 0x170 | NV2_REDIR_NO_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
       .writefn = gt_virt_ctl_write, .raw_writefn = raw_write },
     { .name = "CNTP_TVAL_EL02", .state = ARM_CP_STATE_AA64,
@@ -8346,11 +8362,13 @@ static const ARMCPRegInfo vhe_reginfo[] = {
       .opc0 = 3, .opc1 = 5, .crn = 14, .crm = 2, .opc2 = 2,
       .type = ARM_CP_IO | ARM_CP_ALIAS,
       .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
+      .nv2_redirect_offset = 0x178 | NV2_REDIR_NO_NV1,
       .access = PL2_RW, .accessfn = e2h_access,
       .writefn = gt_phys_cval_write, .raw_writefn = raw_write },
     { .name = "CNTV_CVAL_EL02", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 5, .crn = 14, .crm = 3, .opc2 = 2,
       .type = ARM_CP_IO | ARM_CP_ALIAS,
+      .nv2_redirect_offset = 0x168 | NV2_REDIR_NO_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
       .access = PL2_RW, .accessfn = e2h_access,
       .writefn = gt_virt_cval_write, .raw_writefn = raw_write },
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 31/35] target/arm: Mark up VNCR offsets (offsets >= 0x200, except GIC)
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (29 preceding siblings ...)
  2023-12-18 11:33 ` [PATCH 30/35] target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8) Peter Maydell
@ 2023-12-18 11:33 ` Peter Maydell
  2023-12-28  0:50   ` Richard Henderson
  2023-12-18 11:33 ` [PATCH 32/35] hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers Peter Maydell
                   ` (4 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:33 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

Mark up the cpreginfo structs to indicate offsets for system
registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
the Arm ARM.  This covers all the remaining offsets at 0x200 and
above, except for the GIC ICH_* registers.

(Note that because we don't implement FEAT_SPE, FEAT_TRF,
FEAT_MPAM, FEAT_BRBE or FEAT_AMUv1p1 we don't implement any
of the registers that use offsets at 0x800 and above.)

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 6c33619d646..c72ce4aee09 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4271,6 +4271,7 @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = {
       .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_FAR_EL1,
+      .nv2_redirect_offset = 0x220 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
       .resetvalue = 0, },
 };
@@ -4286,6 +4287,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_TTBR0_EL1,
+      .nv2_redirect_offset = 0x200 | NV2_REDIR_NV1,
       .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write,
       .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s),
                              offsetof(CPUARMState, cp15.ttbr0_ns) } },
@@ -4293,6 +4295,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_TTBR1_EL1,
+      .nv2_redirect_offset = 0x210 | NV2_REDIR_NV1,
       .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write,
       .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
                              offsetof(CPUARMState, cp15.ttbr1_ns) } },
@@ -5725,6 +5728,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .type = ARM_CP_ALIAS,
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
       .access = PL1_RW, .accessfn = access_nv1,
+      .nv2_redirect_offset = 0x230 | NV2_REDIR_NV1,
       .fieldoffset = offsetof(CPUARMState, elr_el[1]) },
     { .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_ALIAS,
@@ -5744,6 +5748,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .fieldoffset = offsetof(CPUARMState, sp_el[0]) },
     { .name = "SP_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 1, .opc2 = 0,
+      .nv2_redirect_offset = 0x240,
       .access = PL2_RW, .type = ARM_CP_ALIAS | ARM_CP_EL3_NO_EL2_KEEP,
       .fieldoffset = offsetof(CPUARMState, sp_el[1]) },
     { .name = "SPSel", .state = ARM_CP_STATE_AA64,
@@ -6866,9 +6871,11 @@ static const ARMCPRegInfo minimal_ras_reginfo[] = {
       .type = ARM_CP_CONST, .resetvalue = 0 },
     { .name = "VDISR_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 1, .opc2 = 1,
+      .nv2_redirect_offset = 0x500,
       .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vdisr_el2) },
     { .name = "VSESR_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 3,
+      .nv2_redirect_offset = 0x508,
       .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.vsesr_el2) },
 };
 
@@ -9524,6 +9531,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
               .access = PL1_RW, .writefn = vbar_write,
               .accessfn = access_nv1,
               .fgt = FGT_VBAR_EL1,
+              .nv2_redirect_offset = 0x250 | NV2_REDIR_NV1,
               .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s),
                                      offsetof(CPUARMState, cp15.vbar_ns) },
               .resetvalue = 0 },
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 32/35] hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (30 preceding siblings ...)
  2023-12-18 11:33 ` [PATCH 31/35] target/arm: Mark up VNCR offsets (offsets >= 0x200, except GIC) Peter Maydell
@ 2023-12-18 11:33 ` Peter Maydell
  2023-12-28  0:52   ` Richard Henderson
  2023-12-18 11:33 ` [PATCH 33/35] target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps Peter Maydell
                   ` (3 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:33 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

Mark up the cpreginfo structs for the GIC CPU registers to indicate
the offsets from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ
in the Arm ARM.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/arm_gicv3_cpuif.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 258dee1b808..96539cdbe9a 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -2684,6 +2684,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
     { .name = "ICH_AP0R0_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 0,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .nv2_redirect_offset = 0x480,
       .access = PL2_RW,
       .readfn = ich_ap_read,
       .writefn = ich_ap_write,
@@ -2691,6 +2692,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
     { .name = "ICH_AP1R0_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 0,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .nv2_redirect_offset = 0x4a0,
       .access = PL2_RW,
       .readfn = ich_ap_read,
       .writefn = ich_ap_write,
@@ -2698,6 +2700,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
     { .name = "ICH_HCR_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 0,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .nv2_redirect_offset = 0x4c0,
       .access = PL2_RW,
       .readfn = ich_hcr_read,
       .writefn = ich_hcr_write,
@@ -2729,6 +2732,7 @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
     { .name = "ICH_VMCR_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 11, .opc2 = 7,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .nv2_redirect_offset = 0x4c8,
       .access = PL2_RW,
       .readfn = ich_vmcr_read,
       .writefn = ich_vmcr_write,
@@ -2739,6 +2743,7 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = {
     { .name = "ICH_AP0R1_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 1,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .nv2_redirect_offset = 0x488,
       .access = PL2_RW,
       .readfn = ich_ap_read,
       .writefn = ich_ap_write,
@@ -2746,6 +2751,7 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = {
     { .name = "ICH_AP1R1_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 1,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .nv2_redirect_offset = 0x4a8,
       .access = PL2_RW,
       .readfn = ich_ap_read,
       .writefn = ich_ap_write,
@@ -2756,6 +2762,7 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
     { .name = "ICH_AP0R2_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 2,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .nv2_redirect_offset = 0x490,
       .access = PL2_RW,
       .readfn = ich_ap_read,
       .writefn = ich_ap_write,
@@ -2763,6 +2770,7 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
     { .name = "ICH_AP0R3_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 8, .opc2 = 3,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .nv2_redirect_offset = 0x498,
       .access = PL2_RW,
       .readfn = ich_ap_read,
       .writefn = ich_ap_write,
@@ -2770,6 +2778,7 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
     { .name = "ICH_AP1R2_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 2,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .nv2_redirect_offset = 0x4b0,
       .access = PL2_RW,
       .readfn = ich_ap_read,
       .writefn = ich_ap_write,
@@ -2777,6 +2786,7 @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
     { .name = "ICH_AP1R3_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 3,
       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+      .nv2_redirect_offset = 0x4b8,
       .access = PL2_RW,
       .readfn = ich_ap_read,
       .writefn = ich_ap_write,
@@ -2898,6 +2908,7 @@ void gicv3_init_cpuif(GICv3State *s)
                       .opc0 = 3, .opc1 = 4, .crn = 12,
                       .crm = 12 + (j >> 3), .opc2 = j & 7,
                       .type = ARM_CP_IO | ARM_CP_NO_RAW,
+                      .nv2_redirect_offset = 0x400 + 8 * j,
                       .access = PL2_RW,
                       .readfn = ich_lr_read,
                       .writefn = ich_lr_write,
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 33/35] target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (31 preceding siblings ...)
  2023-12-18 11:33 ` [PATCH 32/35] hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers Peter Maydell
@ 2023-12-18 11:33 ` Peter Maydell
  2023-12-28  0:54   ` Richard Henderson
  2023-12-18 11:33 ` [PATCH 34/35] target/arm: Enhance CPU_LOG_INT to show SPSR on AArch64 exception-entry Peter Maydell
                   ` (2 subsequent siblings)
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:33 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

When interpreting CPU dumps where FEAT_NV and FEAT_NV2 are in use,
it's helpful to include the values of HCR_EL2.{NV,NV1,NV2} in the CPU
dump format, as a way of distinguishing when we are in EL1 as part of
executing guest-EL2 and when we are just in normal EL1.

Add the bits to the end of the log line that shows PSTATE and similar
information:

PSTATE=000003c9 ---- EL2h  BTYPE=0 NV NV2

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index da0c02f850b..d1d592609eb 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1059,6 +1059,7 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
     uint32_t psr = pstate_read(env);
     int i, j;
     int el = arm_current_el(env);
+    uint64_t hcr = arm_hcr_el2_eff(env);
     const char *ns_status;
     bool sve;
 
@@ -1096,6 +1097,10 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
     if (cpu_isar_feature(aa64_bti, cpu)) {
         qemu_fprintf(f, "  BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
     }
+    qemu_fprintf(f, "%s%s%s",
+                 (hcr & HCR_NV) ? " NV" : "",
+                 (hcr & HCR_NV1) ? " NV1" : "",
+                 (hcr & HCR_NV2) ? " NV2" : "");
     if (!(flags & CPU_DUMP_FPU)) {
         qemu_fprintf(f, "\n");
         return;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 34/35] target/arm: Enhance CPU_LOG_INT to show SPSR on AArch64 exception-entry
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (32 preceding siblings ...)
  2023-12-18 11:33 ` [PATCH 33/35] target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps Peter Maydell
@ 2023-12-18 11:33 ` Peter Maydell
  2023-12-28  0:54   ` Richard Henderson
  2023-12-18 11:33 ` [PATCH 35/35] target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs Peter Maydell
  2023-12-22 14:23 ` [PATCH 00/35] target/arm: Implement emulation of nested virtualization Miguel Luis
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:33 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

We already print various lines of information when we take an
exception, including the ELR and (if relevant) the FAR. Now
that FEAT_NV means that we might report something other than
the old PSTATE to the guest as the SPSR, it's worth logging
this as well.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/helper.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index c72ce4aee09..b8604f39169 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11493,6 +11493,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
     }
     env->banked_spsr[aarch64_banked_spsr_index(new_el)] = old_mode;
 
+    qemu_log_mask(CPU_LOG_INT, "...with SPSR 0x%x\n", old_mode);
     qemu_log_mask(CPU_LOG_INT, "...with ELR 0x%" PRIx64 "\n",
                   env->elr_el[new_el]);
 
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 35/35] target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (33 preceding siblings ...)
  2023-12-18 11:33 ` [PATCH 34/35] target/arm: Enhance CPU_LOG_INT to show SPSR on AArch64 exception-entry Peter Maydell
@ 2023-12-18 11:33 ` Peter Maydell
  2023-12-28  0:58   ` Richard Henderson
  2023-12-22 14:23 ` [PATCH 00/35] target/arm: Implement emulation of nested virtualization Miguel Luis
  35 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2023-12-18 11:33 UTC (permalink / raw)
  To: qemu-arm, qemu-devel

Enable FEAT_NV2 on the 'max' CPU, and stop filtering it out for
the Neoverse N2 and Neoverse V1 CPUs.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 docs/system/arm/emulation.rst | 1 +
 target/arm/cpu.c              | 5 -----
 target/arm/tcg/cpu64.c        | 2 +-
 3 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index d827b42de79..f67aea2d836 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -64,6 +64,7 @@ the following architecture extensions:
 - FEAT_MTE2 (Memory Tagging Extension)
 - FEAT_MTE3 (MTE Asymmetric Fault Handling)
 - FEAT_NV (Nested Virtualization)
+- FEAT_NV2 (Enhanced nested virtualization support)
 - FEAT_PACIMP (Pointer authentication - IMPLEMENTATION DEFINED algorithm)
 - FEAT_PACQARMA3 (Pointer authentication - QARMA3 algorithm)
 - FEAT_PACQARMA5 (Pointer authentication - QARMA5 algorithm)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index d1d592609eb..65dc88ba864 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2243,11 +2243,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         /* FEAT_MPAM (Memory Partitioning and Monitoring Extension) */
         cpu->isar.id_aa64pfr0 =
             FIELD_DP64(cpu->isar.id_aa64pfr0, ID_AA64PFR0, MPAM, 0);
-        /* FEAT_NV2 (Enhanced Nested Virtualization support) */
-        if (FIELD_EX64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV) > 1) {
-            cpu->isar.id_aa64mmfr2 =
-                FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 1);
-        }
     }
 
     /* MPU can be configured out of a PMSA CPU either by setting has-mpu
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 93f040e6e96..5fba2c0f040 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1204,7 +1204,7 @@ void aarch64_max_tcg_initfn(Object *obj)
     t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);      /* FEAT_UAO */
     t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1);     /* FEAT_IESB */
     t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1);  /* FEAT_LVA */
-    t = FIELD_DP64(t, ID_AA64MMFR2, NV, 1);       /* FEAT_NV */
+    t = FIELD_DP64(t, ID_AA64MMFR2, NV, 2);       /* FEAT_NV2 */
     t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1);       /* FEAT_TTST */
     t = FIELD_DP64(t, ID_AA64MMFR2, AT, 1);       /* FEAT_LSE2 */
     t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1);      /* FEAT_IDST */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 84+ messages in thread

* Re: [PATCH 00/35] target/arm: Implement emulation of nested virtualization
  2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
                   ` (34 preceding siblings ...)
  2023-12-18 11:33 ` [PATCH 35/35] target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs Peter Maydell
@ 2023-12-22 14:23 ` Miguel Luis
  35 siblings, 0 replies; 84+ messages in thread
From: Miguel Luis @ 2023-12-22 14:23 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-arm@nongnu.org, qemu-devel@nongnu.org

Hi Peter,

> On 18 Dec 2023, at 10:32, Peter Maydell <peter.maydell@linaro.org> wrote:
> 
> This patchset adds support for emulating the Arm architectural features
> FEAT_NV and FEAT_NV2 which allow nested virtualization, i.e. where a
> hypervisor can run a guest which thinks it is running at EL2.
> 
> Nominally FEAT_NV is sufficient for this and FEAT_NV2 merely improves
> the performance in the nested-virt setup, but in practice hypervisors
> such as KVM are going to require FEAT_NV2 and not bother to support
> the FEAT_NV-only case, so I have implemented them one after the other
> in this single patchset.
> 
> The feature is essentially a collection of changes that allow the
> hypervisor to lie to the guest so that it thinks it is running in EL2
> when it's really at EL1. The best summary of what all the changes are
> is in section D8.11 "Nested virtualization" in the Arm ARM, but the
> short summary is:
> * EL2 system registers etc trap to EL2 rather than UNDEFing
> * ERET traps to EL2
> * the CurrentEL register reports "EL2" when NV is enabled
> * on exception entry, SPSR_EL1.M may report "EL2" as the EL the
>   exception was taken from
> * when HCR_EL1.NV1 is also set, then there are some extra tweaks
>   (NV1 == 1 means "guest thinks it is running with HCR_EL2.E2H == 0")
> * some AT S1 address translation insns can be trapped to EL2
> and FEAT_NV2 adds:
> * accesses to some system registers are transformed into memory
>   accesses instead of trapping to EL2
> * accesses to a few EL2 system registers are redirected to the
>   equivalent EL1 registers
> 
> This patchset is sufficient that you can run an L0 guest kernel that
> has support for FEAT_NV/FEAT_NV2 in its KVM code, and then
> inside that start a nested L1 guest that thinks it has EL2 access,
> and then run an inner-nested L2 guest under that that can get
> to running userspace code. To do that you'll need some not-yet-upstream
> patches for both Linux and kvmtool:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/nv-6.8-nv2-only
> https://gitlab.arm.com/linux-arm/kvmtool/-/commits/nv-v6.6
> 
> You'll also want to turn off SVE and SME emulation in QEMU
> (-cpu max,sve=off,sme=off) because at the moment the KVM patchset
> doesn't handle SVE and nested-virt together (the other option
> is to hack kvmtool to make it not ask for both at once, but this
> is easier).
> 
> (kvmtool is needed here to run the L1 because QEMU itself as a VMM
> doesn't yet support asking KVM for an EL2 guest.)
> 
> The first three patches in the series aren't strictly part of FEAT_NV:
> * patch 1 is already reviewed; I put it here to avoid having
>   to deal with textual conflicts between it and this series
> * patch 2 sets CTR_EL0.{IDC,DIC} for '-cpu max', which is a good
>   idea anyway and also works around what Marc Z and I think is
>   a KVM bug that otherwise causes boot of the L2 kernel to hang
> * patch 3 is a GIC bug which is not FEAT_NV specific but for
>   some reason only manifests when booting an L1 kernel under NV
> 

I've successfully replicated this setup and reached inner-nested L2 guest 
userspace.

FWIW, feel free to add

Tested-by: Miguel Luis <miguel.luis@oracle.com>

(I've been working on QEMU asking KVM for an EL2 guest on top of this series 
although there's been yet some debugging to do.)

Thank you!

Miguel

> thanks
> -- PMM
> 
> Peter Maydell (35):
>  target/arm: Don't implement *32_EL2 registers when EL1 is AArch64 only
>  target/arm: Set CTR_EL0.{IDC,DIC} for the 'max' CPU
>  hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers
>  target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV
>  target/arm: Implement HCR_EL2.AT handling
>  target/arm: Enable trapping of ERET for FEAT_NV
>  target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set
>  target/arm: Allow use of upper 32 bits of TBFLAG_A64
>  target/arm: Record correct opcode fields in cpreg for E2H aliases
>  target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0
>  target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses
>  target/arm: Move FPU/SVE/SME access checks up above
>    ARM_CP_SPECIAL_MASK check
>  target/arm: Trap sysreg accesses for FEAT_NV
>  target/arm: Make NV reads of CurrentEL return EL2
>  target/arm: Set SPSR_EL1.M correctly when nested virt is enabled
>  target/arm: Trap registers when HCR_EL2.{NV,NV1} == {1,1}
>  target/arm: Always use arm_pan_enabled() when checking if PAN is
>    enabled
>  target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV,NV1} == {1,1}
>  target/arm: Treat LDTR* and STTR* as LDR/STR when NV,NV1 is 1,1
>  target/arm: Handle FEAT_NV page table attribute changes
>  target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs
>  target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits
>  target/arm: Implement VNCR_EL2 register
>  target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2
>  target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2,
>    FAR_EL2
>  target/arm: Implement FEAT_NV2 redirection of sysregs to RAM
>  target/arm: Report VNCR_EL2 based faults correctly
>  target/arm: Mark up VNCR offsets (offsets 0x0..0xff)
>  target/arm: Mark up VNCR offsets (offsets 0x100..0x160)
>  target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8)
>  target/arm: Mark up VNCR offsets (offsets >= 0x200, except GIC)
>  hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers
>  target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps
>  target/arm: Enhance CPU_LOG_INT to show SPSR on AArch64
>    exception-entry
>  target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs
> 
> docs/system/arm/emulation.rst  |   2 +
> target/arm/cpregs.h            |  54 ++++-
> target/arm/cpu-features.h      |  10 +
> target/arm/cpu.h               |  24 ++-
> target/arm/syndrome.h          |  20 +-
> target/arm/tcg/translate.h     |  16 +-
> hw/intc/arm_gicv3_cpuif.c      |  28 ++-
> target/arm/cpu.c               |   8 +-
> target/arm/debug_helper.c      |  34 +++-
> target/arm/helper.c            | 360 ++++++++++++++++++++++++++++-----
> target/arm/ptw.c               |  21 ++
> target/arm/tcg/cpu64.c         |  11 +
> target/arm/tcg/hflags.c        |  30 ++-
> target/arm/tcg/op_helper.c     |  16 +-
> target/arm/tcg/tlb_helper.c    |  27 ++-
> target/arm/tcg/translate-a64.c | 162 +++++++++++++--
> 16 files changed, 725 insertions(+), 98 deletions(-)
> 
> -- 
> 2.34.1
> 
> 



^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 02/35] target/arm: Set CTR_EL0.{IDC, DIC} for the 'max' CPU
  2023-12-18 11:32 ` [PATCH 02/35] target/arm: Set CTR_EL0.{IDC,DIC} for the 'max' CPU Peter Maydell
@ 2023-12-27 21:08   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 21:08 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> The CTR_EL0 register has some bits which allow the implementation to
> tell the guest that it does not need to do cache maintenance for
> data-to-instruction coherence and instruction-to-data coherence.
> QEMU doesn't emulate caches and so our cache maintenance insns are
> all NOPs.
> 
> We already have some models of specific CPUs where we set these bits
> (e.g.  the Neoverse V1), but the 'max' CPU still uses the settings it
> inherits from Cortex-A57.  Set the bits for 'max' as well, so the
> guest doesn't need to do unnecessary work.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 03/35] hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers
  2023-12-18 11:32 ` [PATCH 03/35] hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers Peter Maydell
@ 2023-12-27 21:11   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 21:11 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> The hypervisor can deliver (virtual) LPIs to a guest by setting up a
> list register to have an intid which is an LPI.  The GIC has to treat
> these a little differently to standard interrupt IDs, because LPIs
> have no Active state, and so the guest will only EOI them, it will
> not also deactivate them.  So icv_eoir_write() must do two things:
> 
>   * if the LPI ID is not in any list register, we drop the
>     priority but do not increment the EOI count
>   * if the LPI ID is in a list register, we immediately deactivate
>     it, regardless of the split-drop-and-deactivate control
> 
> This can be seen in the VirtualWriteEOIR0() and VirtualWriteEOIR1()
> pseudocode in the GICv3 architecture specification.
> 
> Without this fix, potentially a hypervisor guest might stall because
> LPIs get stuck in a bogus Active+Pending state.
> 
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> Weirdly, I only saw this being a problem when the hypervisor guest
> was an EL2-enabled one under my FEAT_NV/FEAT_NV2 implementation.
> But there's nothing FEAT_NV specific about the bug.
> ---
>   hw/intc/arm_gicv3_cpuif.c | 17 +++++++++++++----
>   1 file changed, 13 insertions(+), 4 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 04/35] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV
  2023-12-18 11:32 ` [PATCH 04/35] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV Peter Maydell
@ 2023-12-27 21:42   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 21:42 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> FEAT_NV defines three new bits in HCR_EL2: NV, NV1 and AT.  When the
> feature is enabled, allow these bits to be written, and flush the
> TLBs for the bits which affect page table interpretation.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/cpu-features.h | 5 +++++
>   target/arm/helper.c       | 6 +++++-
>   2 files changed, 10 insertions(+), 1 deletion(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 05/35] target/arm: Implement HCR_EL2.AT handling
  2023-12-18 11:32 ` [PATCH 05/35] target/arm: Implement HCR_EL2.AT handling Peter Maydell
@ 2023-12-27 22:01   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:01 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> The FEAT_NV HCR_EL2.AT bit enables trapping of some address
> translation instructions from EL1 to EL2.  Implement this behaviour.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/helper.c | 21 +++++++++++++++------
>   1 file changed, 15 insertions(+), 6 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 06/35] target/arm: Enable trapping of ERET for FEAT_NV
  2023-12-18 11:32 ` [PATCH 06/35] target/arm: Enable trapping of ERET for FEAT_NV Peter Maydell
@ 2023-12-27 22:06   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:06 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> When FEAT_NV is turned on via the HCR_EL2.NV bit, ERET instructions
> are trapped, with the same syndrome information as for the existing
> FEAT_FGT fine-grained trap (in the pseudocode this is handled in
> AArch64.CheckForEretTrap()).
> 
> Rename the DisasContext and tbflag bits to reflect that they are
> no longer exclusively for FGT traps, and set the tbflag bit when
> FEAT_NV is enabled as well as when the FGT is enabled.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/cpu.h               |  2 +-
>   target/arm/tcg/translate.h     |  4 ++--
>   target/arm/tcg/hflags.c        | 11 ++++++++++-
>   target/arm/tcg/translate-a64.c |  6 +++---
>   4 files changed, 16 insertions(+), 7 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 07/35] target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set
  2023-12-18 11:32 ` [PATCH 07/35] target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set Peter Maydell
@ 2023-12-27 22:18   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:18 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> The HCR_EL2.TSC trap for trapping EL1 execution of SMC instructions
> has a behaviour change for FEAT_NV when EL3 is not implemented:
> 
>   * in older architecture versions TSC was required to have no
>     effect (i.e. the SMC insn UNDEFs)
>   * with FEAT_NV, when HCR_EL2.NV == 1 the trap must apply
>     (i.e. SMC traps to EL2, as it already does in all cases when
>     EL3 is implemented)
>   * in newer architecture versions, the behaviour either without
>     FEAT_NV or with FEAT_NV and HCR_EL2.NV == 0 is relaxed to
>     an IMPDEF choice between UNDEF and trap-to-EL2 (i.e. it is
>     permitted to always honour HCR_EL2.TSC) for AArch64 only
> 
> Add the condition to honour the trap bit when HCR_EL2.NV == 1.  We
> leave the HCR_EL2.NV == 0 case with the existing (UNDEF) behaviour,
> as our IMPDEF choice (both because it avoids a behaviour change
> for older CPU models and because we'd have to distinguish AArch32
> from AArch64 if we opted to trap to EL2).
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/tcg/op_helper.c | 16 +++++++++++++---
>   1 file changed, 13 insertions(+), 3 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 08/35] target/arm: Allow use of upper 32 bits of TBFLAG_A64
  2023-12-18 11:32 ` [PATCH 08/35] target/arm: Allow use of upper 32 bits of TBFLAG_A64 Peter Maydell
@ 2023-12-27 22:20   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:20 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> The TBFLAG_A64 TB flag bits go in flags2, which for AArch64 guests
> we know is 64 bits. However at the moment we use FIELD_EX32() and
> FIELD_DP32() to read and write these bits, which only works for
> bits 0 to 31. Since we're about to add a flag that uses bit 32,
> switch to FIELD_EX64() and FIELD_DP64() so that this will work.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>   target/arm/cpu.h | 8 +++++---
>   1 file changed, 5 insertions(+), 3 deletions(-)

Oops, I hadn't intended this to be 32-bit from the start.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~

> 
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index 167b3759ac9..91157db85ae 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -3240,12 +3240,14 @@ FIELD(TBFLAG_A64, NAA, 30, 1)
>   FIELD(TBFLAG_A64, ATA0, 31, 1)
>   
>   /*
> - * Helpers for using the above.
> + * Helpers for using the above. Note that only the A64 accessors use
> + * FIELD_DP64() and FIELD_EX64(), because in the other cases the flags
> + * word either is or might be 32 bits only.
>    */
>   #define DP_TBFLAG_ANY(DST, WHICH, VAL) \
>       (DST.flags = FIELD_DP32(DST.flags, TBFLAG_ANY, WHICH, VAL))
>   #define DP_TBFLAG_A64(DST, WHICH, VAL) \
> -    (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A64, WHICH, VAL))
> +    (DST.flags2 = FIELD_DP64(DST.flags2, TBFLAG_A64, WHICH, VAL))
>   #define DP_TBFLAG_A32(DST, WHICH, VAL) \
>       (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A32, WHICH, VAL))
>   #define DP_TBFLAG_M32(DST, WHICH, VAL) \
> @@ -3254,7 +3256,7 @@ FIELD(TBFLAG_A64, ATA0, 31, 1)
>       (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_AM32, WHICH, VAL))
>   
>   #define EX_TBFLAG_ANY(IN, WHICH)   FIELD_EX32(IN.flags, TBFLAG_ANY, WHICH)
> -#define EX_TBFLAG_A64(IN, WHICH)   FIELD_EX32(IN.flags2, TBFLAG_A64, WHICH)
> +#define EX_TBFLAG_A64(IN, WHICH)   FIELD_EX64(IN.flags2, TBFLAG_A64, WHICH)
>   #define EX_TBFLAG_A32(IN, WHICH)   FIELD_EX32(IN.flags2, TBFLAG_A32, WHICH)
>   #define EX_TBFLAG_M32(IN, WHICH)   FIELD_EX32(IN.flags2, TBFLAG_M32, WHICH)
>   #define EX_TBFLAG_AM32(IN, WHICH)  FIELD_EX32(IN.flags2, TBFLAG_AM32, WHICH)



^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 09/35] target/arm: Record correct opcode fields in cpreg for E2H aliases
  2023-12-18 11:32 ` [PATCH 09/35] target/arm: Record correct opcode fields in cpreg for E2H aliases Peter Maydell
@ 2023-12-27 22:23   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:23 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> For FEAT_VHE, we define a set of register aliases, so that for instance:
>   * the SCTLR_EL1 either accesses the real SCTLR_EL1, or (if E2H is 1)
>     SCTLR_EL2
>   * a new SCTLR_EL12 register accesses SCTLR_EL1 if E2H is 1
> 
> However when we create the 'new_reg' cpreg struct for the SCTLR_EL12
> register, we duplicate the information in the SCTLR_EL1 cpreg, which
> means the opcode fields are those of SCTLR_EL1, not SCTLR_EL12.  This
> is a problem for code which looks at the cpreg opcode fields to
> determine behaviour (e.g.  in access_check_cp_reg()). In practice
> the current checks we do there don't intersect with the *_EL12
> registers, but for FEAT_NV this will become a problem.
> 
> Write the correct values from the encoding into the new_reg struct.
> This restores the invariant that the cpreg that you get back
> from the hashtable has opcode fields that match the key you used
> to retrieve it.
> 
> When we call the readfn or writefn for the target register, we
> pass it the cpreg struct for that target register, not the one
> for the alias, in case the readfn/writefn want to look at the
> opcode fields to determine behaviour. This means we need to
> interpose custom read/writefns for the e12 aliases.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/helper.c | 35 +++++++++++++++++++++++++++++++++++
>   1 file changed, 35 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 10/35] target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0
  2023-12-18 11:32 ` [PATCH 10/35] target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0 Peter Maydell
@ 2023-12-27 22:25   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:25 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> The alias registers like SCTLR_EL12 only exist when HCR_EL2.E2H
> is 1; they should UNDEF otherwise. We weren't implementing this.
> Add an intercept of the accessfn for these aliases, and implement
> the UNDEF check.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/cpregs.h |  3 ++-
>   target/arm/helper.c | 16 ++++++++++++++++
>   2 files changed, 18 insertions(+), 1 deletion(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 11/35] target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses
  2023-12-18 11:32 ` [PATCH 11/35] target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses Peter Maydell
@ 2023-12-27 22:31   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:31 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> FEAT_NV and FEAT_NV2 will allow EL1 to attempt to access cpregs that
> only exist at EL2. This means we're going to want to run their
> accessfns when the CPU is at EL1. In almost all cases, the behaviour
> we want is "the accessfn returns OK if at EL1".
> 
> Mostly the accessfn already does the right thing; in a few cases we
> need to explicitly check that the EL is not 1 before applying various
> trap controls, or split out an accessfn used both for an _EL1 and an
> _EL2 register into two so we can handle the FEAT_NV case correctly
> for the _EL2 register.
> 
> There are two registers where we want the accessfn to trap for
> a FEAT_NV EL1 access: VSTTBR_EL2 and VSTCR_EL2 should UNDEF
> an access from NonSecure EL1, not trap to EL2 under FEAT_NV.
> The way we have written sel2_access() already results in this
> behaviour.
> 
> We can identify the registers we care about here because they
> all have opc1 == 4 or 5.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/debug_helper.c | 12 +++++++-
>   target/arm/helper.c       | 65 ++++++++++++++++++++++++++++++++++-----
>   2 files changed, 69 insertions(+), 8 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 12/35] target/arm: Move FPU/SVE/SME access checks up above ARM_CP_SPECIAL_MASK check
  2023-12-18 11:32 ` [PATCH 12/35] target/arm: Move FPU/SVE/SME access checks up above ARM_CP_SPECIAL_MASK check Peter Maydell
@ 2023-12-27 22:32   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:32 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> In handle_sys() we don't do the check for whether the register is
> marked as needing an FPU/SVE/SME access check until after we've
> handled the special cases covered by ARM_CP_SPECIAL_MASK.  This is
> conceptually the wrong way around, because if for example we happen
> to implement an FPU-access-checked register as ARM_CP_NOP, we should
> do the access check first.
> 
> Move the access checks up so they are with all the other access
> checks, not sandwiched between the special-case read/write handling
> and the normal-case read/write handling. This doesn't change
> behaviour at the moment, because we happen not to define any
> cpregs with both ARM_CPU_{FPU,SVE,SME} and one of the cases
> dealt with by ARM_CP_SPECIAL_MASK.
> 
> Moving this code also means we have the correct place to put the
> FEAT_NV/FEAT_NV2 access handling, which should come after the access
> checks and before we try to do any read/write action.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/tcg/translate-a64.c | 15 ++++++++-------
>   1 file changed, 8 insertions(+), 7 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 13/35] target/arm: Trap sysreg accesses for FEAT_NV
  2023-12-18 11:32 ` [PATCH 13/35] target/arm: Trap sysreg accesses for FEAT_NV Peter Maydell
@ 2023-12-27 22:40   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:40 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> For FEAT_NV, accesses to system registers and instructions from EL1
> which would normally UNDEF there but which work in EL2 need to
> instead be trapped to EL2. Detect this both for "we know this will
> UNDEF at translate time" and "we found this UNDEFs at runtime", and
> make the affected registers trap to EL2 instead.
> 
> The Arm ARM defines the set of registers that should trap in terms
> of their names; for our implementation this would be both awkward
> and inefficent as a test, so we instead trap based on the opc1
> field of the sysreg. The regularity of the architectural choice
> of encodings for sysregs means that in practice this captures
> exactly the correct set of registers.
> 
> Regardless of how we try to define the registers this trapping
> applies to, there's going to be a certain possibility of breakage
> if new architectural features introduce new registers that don't
> follow the current rules (FEAT_MEC is one example already visible
> in the released sysreg XML, though not yet in the Arm ARM). This
> approach seems to me to be straightforward and likely to require
> a minimum of manual overrides.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>   target/arm/cpregs.h            | 34 +++++++++++++++++++++++
>   target/arm/cpu.h               |  1 +
>   target/arm/tcg/translate.h     |  2 ++
>   target/arm/tcg/hflags.c        |  1 +
>   target/arm/tcg/translate-a64.c | 49 +++++++++++++++++++++++++++-------
>   5 files changed, 77 insertions(+), 10 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

> +             * (This makes a difference only for a couple of registers likee

like



r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 14/35] target/arm: Make NV reads of CurrentEL return EL2
  2023-12-18 11:32 ` [PATCH 14/35] target/arm: Make NV reads of CurrentEL return EL2 Peter Maydell
@ 2023-12-27 22:42   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:42 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> FEAT_NV requires that when HCR_EL2.NV is set reads of the CurrentEL
> register from EL1 always report EL2 rather than the real EL.
> Implement this.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/tcg/translate-a64.c | 9 +++++++--
>   1 file changed, 7 insertions(+), 2 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 15/35] target/arm: Set SPSR_EL1.M correctly when nested virt is enabled
  2023-12-18 11:32 ` [PATCH 15/35] target/arm: Set SPSR_EL1.M correctly when nested virt is enabled Peter Maydell
@ 2023-12-27 22:43   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:43 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> FEAT_NV requires that when HCR_EL2.{NV,NV1} == {1,0} and an exception
> is taken from EL1 to EL1 then the reported EL in SPSR_EL1.M should be
> EL2, not EL1.  Implement this behaviour.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>   target/arm/helper.c | 6 ++++++
>   1 file changed, 6 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 16/35] target/arm: Trap registers when HCR_EL2.{NV, NV1} == {1, 1}
  2023-12-18 11:32 ` [PATCH 16/35] target/arm: Trap registers when HCR_EL2.{NV, NV1} == {1, 1} Peter Maydell
@ 2023-12-27 22:47   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:47 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> When HCR_EL2.{NV,NV1} is {1,1} we must trap five extra registers to
> EL2: VBAR_EL1, ELR_EL1, SPSR_EL1, SCXTNUM_EL1 and TFSR_EL1.
> Implement these traps.
> 
> This trap does not apply when FEAT_NV2 is implemented and enabled;
> include the check that HCR_EL2.NV2 is 0 here, to save us having
> to come back and add it later.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> I have mostly implemented FEAT_NV2 after FEAT_NV, but in
> this particular case it seemed cleaner to include the NV2
> bit check from the start.
> ---
>   target/arm/helper.c | 44 ++++++++++++++++++++++++++++++++++++++++----
>   1 file changed, 40 insertions(+), 4 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


> @@ -7807,6 +7820,16 @@ static CPAccessResult access_mte(CPUARMState *env, const ARMCPRegInfo *ri,
>       }
>       return CP_ACCESS_OK;
>   }
> +static CPAccessResult access_tfsr_el1(CPUARMState *env, const ARMCPRegInfo *ri,

Spacing.


r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 17/35] target/arm: Always use arm_pan_enabled() when checking if PAN is enabled
  2023-12-18 11:32 ` [PATCH 17/35] target/arm: Always use arm_pan_enabled() when checking if PAN is enabled Peter Maydell
@ 2023-12-27 22:50   ` Richard Henderson
  2024-01-04 15:59     ` Peter Maydell
  0 siblings, 1 reply; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:50 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> Currently the code in target/arm/helper.c mostly checks the PAN bits
> in env->pstate or env->uncached_cpsr directly when it wants to know
> if PAN is enabled, because in most callsites we know whether we are
> in AArch64 or AArch32. We do have an arm_pan_enabled() function, but
> we only use it in a few places where the code might run in either an
> AArch32 or AArch64 context.
> 
> For FEAT_NV, when HCR_EL2.{NV,NV1} is {1,1} PAN is always disabled
> even when the PSTATE.PAN bit is set, the "is PAN enabled" test
> becomes more complicated. Make all places that check for PAN use
> arm_pan_enabled(), so we have a place to put the FEAT_NV test.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>   target/arm/helper.c | 22 +++++++++++-----------
>   1 file changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 3270fb11049..4b0e46cfaae 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -263,6 +263,15 @@ void init_cpreg_list(ARMCPU *cpu)
>       g_list_free(keys);
>   }
>   
> +static bool arm_pan_enabled(CPUARMState *env)
> +{
> +    if (is_a64(env)) {
> +        return env->pstate & PSTATE_PAN;
> +    } else {
> +        return env->uncached_cpsr & CPSR_PAN;
> +    }
> +}

Worth splitting out helpers aa{32,64}_pan_enabled to avoid the is_a64 check when context 
dictates?

Either way,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 18/35] target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV, NV1} == {1, 1}
  2023-12-18 11:32 ` [PATCH 18/35] target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV, NV1} == {1, 1} Peter Maydell
@ 2023-12-27 22:52   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:52 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> For FEAT_NV, when HCR_EL2.{NV,NV1} is {1,1} PAN is always disabled
> even when the PSTATE.PAN bit is set. Implement this by having
> arm_pan_enabled() return false in this situation.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/helper.c | 3 +++
>   1 file changed, 3 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 19/35] target/arm: Treat LDTR* and STTR* as LDR/STR when NV, NV1 is 1, 1
  2023-12-18 11:32 ` [PATCH 19/35] target/arm: Treat LDTR* and STTR* as LDR/STR when NV, NV1 is 1, 1 Peter Maydell
@ 2023-12-27 22:53   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:53 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> FEAT_NV requires (per I_JKLJK) that when HCR_EL2.{NV,NV1} is {1,1} the
> unprivileged-access instructions LDTR, STTR etc behave as normal
> loads and stores. Implement the check that handles this.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/tcg/hflags.c | 6 ++++--
>   1 file changed, 4 insertions(+), 2 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 20/35] target/arm: Handle FEAT_NV page table attribute changes
  2023-12-18 11:32 ` [PATCH 20/35] target/arm: Handle FEAT_NV page table attribute changes Peter Maydell
@ 2023-12-27 22:57   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:57 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> FEAT_NV requires that when HCR_EL2.{NV,NV1} == {1,1} the handling
> of some of the page table attribute bits changes for the EL1&0
> translation regime:
> 
>   * for block and page descriptors:
>    - bit [54] holds PXN, not UXN
>    - bit [53] is RES0, and the effective value of UXN is 0
>    - bit [6], AP[1], is treated as 0
>   * for table descriptors, when hierarchical permissions are enabled:
>    - bit [60] holds PXNTable, not UXNTable
>    - bit [59] is RES0
>    - bit [61], APTable[0] is treated as 0
> 
> Implement these changes to the page table attribute handling.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/ptw.c | 21 +++++++++++++++++++++
>   1 file changed, 21 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 21/35] target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs
  2023-12-18 11:32 ` [PATCH 21/35] target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs Peter Maydell
@ 2023-12-27 22:59   ` Richard Henderson
  2023-12-29 11:37   ` Marcin Juszkiewicz
  1 sibling, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:59 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> Enable FEAT_NV on the 'max' CPU, and stop filtering it out for the
> Neoverse N2 and Neoverse V1 CPUs.  We continue to downgrade FEAT_NV2
> support to FEAT_NV for the latter two CPU types.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   docs/system/arm/emulation.rst | 1 +
>   target/arm/cpu.c              | 8 +++++---
>   target/arm/tcg/cpu64.c        | 1 +
>   3 files changed, 7 insertions(+), 3 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 22/35] target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits
  2023-12-18 11:32 ` [PATCH 22/35] target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits Peter Maydell
@ 2023-12-27 22:59   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 22:59 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> FEAT_NV2 defines another new bit in HCR_EL2: NV2. When the
> feature is enabled, allow this bit to be written in HCR_EL2.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>   target/arm/cpu-features.h | 5 +++++
>   target/arm/helper.c       | 3 +++
>   2 files changed, 8 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 23/35] target/arm: Implement VNCR_EL2 register
  2023-12-18 11:32 ` [PATCH 23/35] target/arm: Implement VNCR_EL2 register Peter Maydell
@ 2023-12-27 23:01   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 23:01 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> For FEAT_NV2, a new system register VNCR_EL2 holds the base
> address of the memory which nested-guest system register
> accesses are redirected to. Implement this register.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/cpu.h    |  3 +++
>   target/arm/helper.c | 26 ++++++++++++++++++++++++++
>   2 files changed, 29 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 24/35] target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2
  2023-12-18 11:32 ` [PATCH 24/35] target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2 Peter Maydell
@ 2023-12-27 23:06   ` Richard Henderson
  2024-01-04 16:03     ` Peter Maydell
  0 siblings, 1 reply; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 23:06 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> With FEAT_NV2, the condition for when SPSR_EL1.M should report that
> an exception was taken from EL2 changes.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>   target/arm/helper.c | 16 ++++++++++++----
>   1 file changed, 12 insertions(+), 4 deletions(-)
> 
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 45444360f95..38e16c2f8a5 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -11405,10 +11405,18 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
>           aarch64_save_sp(env, arm_current_el(env));
>           env->elr_el[new_el] = env->pc;
>   
> -        if (cur_el == 1 && new_el == 1 &&
> -            ((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == HCR_NV)) {
> -            /* I_ZJRNN: report EL2 in the SPSR by setting M[3:2] to 0b10 */
> -            old_mode = deposit32(old_mode, 2, 2, 2);
> +        if (cur_el == 1 && new_el == 1) {
> +            uint64_t hcr = arm_hcr_el2_eff(env);
> +            if ((hcr & (HCR_NV | HCR_NV1 | HCR_NV2)) == HCR_NV ||
> +                (hcr & (HCR_NV | HCR_NV2)) == (HCR_NV | HCR_NV2)) {

Maybe clearer as

	if ((hcr & HCR_NV) && ((hcr & HCR_NV2) || !(hcr & HCR_NV1)))

?

Anyway,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~

> +                /*
> +                 * FEAT_NV, FEAT_NV2 may need to report EL2 in the SPSR
> +                 * by setting M[3:2] to 0b10.
> +                 * If NV2 is disabled, change SPSR when NV,NV1 == 1,0 (I_ZJRNN)
> +                 * If NV2 is enabled, change SPSR when NV is 1 (I_DBTLM)
> +                 */
> +                old_mode = deposit32(old_mode, 2, 2, 2);
> +            }
>           }
>       } else {
>           old_mode = cpsr_read_for_spsr_elx(env);



^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 25/35] target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2
  2023-12-18 11:32 ` [PATCH 25/35] target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2 Peter Maydell
@ 2023-12-27 23:11   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 23:11 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> @@ -2173,7 +2174,14 @@ static void handle_sys(DisasContext *s, bool isread,
>            * for registers accessible at EL1).
>            */
>           skip_fp_access_checks = true;
> -        if (s->nv && arm_cpreg_traps_in_nv(ri)) {
> +        if (s->nv && s->nv2 && (ri->type & ARM_CP_NV2_REDIRECT)) {

You've documented and implemented that nv2 is true iff nv, thus the nv test can be dropped.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 26/35] target/arm: Implement FEAT_NV2 redirection of sysregs to RAM
  2023-12-18 11:32 ` [PATCH 26/35] target/arm: Implement FEAT_NV2 redirection of sysregs to RAM Peter Maydell
@ 2023-12-27 23:55   ` Richard Henderson
  2024-01-04 16:23     ` Peter Maydell
  0 siblings, 1 reply; 84+ messages in thread
From: Richard Henderson @ 2023-12-27 23:55 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> +    if (s->nv && s->nv2 && ri->nv2_redirect_offset) {

Again, s->nv test is redundant.

> +        /*
> +         * Some registers always redirect to memory; some only do so if
> +         * HCR_EL2.NV1 is 0, and some only if NV1 is 1 (these come in
> +         * pairs which share an offset; see the table in R_CSRPQ).
> +         */
> +        if (ri->nv2_redirect_offset & NV2_REDIR_NV1) {
> +            nv2_mem_redirect = s->nv1;
> +        } else if (ri->nv2_redirect_offset & NV2_REDIR_NO_NV1) {
> +            nv2_mem_redirect = !s->nv1;
> +        } else {
> +            nv2_mem_redirect = true;
> +        }

I wondered if it would be clearer with the "both" case having both bits set.  While I see 
that the first defined offset is 0x20, offset 0x00 is still reserved and *could* be used. 
At which point ri->nv2_redirect_offset would need a non-zero value for a zero offset.

Maybe clearer as

     nv2_mem_redirect = (ri->nv2_redirect_offset &
                         (s->nv1 ? NV2_REDIR_NV1_1 : NV2_REDIR_NV1_0));

?

This is more verbose for the (common?) case of redirect regardless of nv1, so maybe not.

> +        if (s->nv2_mem_be) {
> +            mop |= MO_BE;
> +        }

MO_BSWAP is host dependent -- needs

     mop |= (s->nv2_mem_be ? MO_BE : MO_LE);


r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly
  2023-12-18 11:32 ` [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly Peter Maydell
@ 2023-12-28  0:03   ` Richard Henderson
  2024-01-16 13:09   ` Jonathan Cameron via
  1 sibling, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-28  0:03 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> 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>
> ---
>   target/arm/cpu.h               |  4 ++--
>   target/arm/syndrome.h          | 20 ++++++++++++++++----
>   target/arm/tcg/tlb_helper.c    | 27 +++++++++++++++++++++++++--
>   target/arm/tcg/translate-a64.c |  4 ++++
>   4 files changed, 47 insertions(+), 8 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 28/35] target/arm: Mark up VNCR offsets (offsets 0x0..0xff)
  2023-12-18 11:32 ` [PATCH 28/35] target/arm: Mark up VNCR offsets (offsets 0x0..0xff) Peter Maydell
@ 2023-12-28  0:35   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-28  0:35 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> Mark up the cpreginfo structs to indicate offsets for system
> registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
> the Arm ARM. This commit covers offsets below 0x100; all of these
> registers are redirected to memory regardless of the value of
> HCR_EL2.NV1.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/helper.c | 12 ++++++++++++
>   1 file changed, 12 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 29/35] target/arm: Mark up VNCR offsets (offsets 0x100..0x160)
  2023-12-18 11:32 ` [PATCH 29/35] target/arm: Mark up VNCR offsets (offsets 0x100..0x160) Peter Maydell
@ 2023-12-28  0:42   ` Richard Henderson
  2024-01-04 16:24     ` Peter Maydell
  0 siblings, 1 reply; 84+ messages in thread
From: Richard Henderson @ 2023-12-28  0:42 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:32, Peter Maydell wrote:
> Mark up the cpreginfo structs to indicate offsets for system
> registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
> the Arm ARM.  This commit covers offsets 0x100 to 0x160.
> 
> Many (but not all) of the registers in this range have _EL12 aliases,
> and the slot in memory is shared between the _EL12 version of the
> register and the _EL1 version.  Where we programmatically generate
> the regdef for the _EL12 register, arrange that its
> nv2_redirect_offset is set up correctly to do this.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>   target/arm/debug_helper.c |  1 +
>   target/arm/helper.c       | 22 ++++++++++++++++++++++
>   2 files changed, 23 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

> +        /*
> +         * If the _EL1 register is redirected to memory by FEAT_NV2,
> +         * then it shares the offset with the _EL12 register,
> +         * and which one is redirected depends on HCR_EL2.NV1.
> +         */
> +        if (new_reg->nv2_redirect_offset) {
> +            assert(new_reg->nv2_redirect_offset & NV2_REDIR_NV1);
> +            new_reg->nv2_redirect_offset &= ~NV2_REDIR_NV1;
> +            new_reg->nv2_redirect_offset |= NV2_REDIR_NO_NV1;
> +        }

Could use xor to flip both bits at once.


r~



^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 30/35] target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8)
  2023-12-18 11:33 ` [PATCH 30/35] target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8) Peter Maydell
@ 2023-12-28  0:45   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-28  0:45 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:33, Peter Maydell wrote:
> Mark up the cpreginfo structs to indicate offsets for system
> registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
> the Arm ARM.  This commit covers offsets 0x168 to 0x1f8.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/helper.c | 18 ++++++++++++++++++
>   1 file changed, 18 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 31/35] target/arm: Mark up VNCR offsets (offsets >= 0x200,  except GIC)
  2023-12-18 11:33 ` [PATCH 31/35] target/arm: Mark up VNCR offsets (offsets >= 0x200, except GIC) Peter Maydell
@ 2023-12-28  0:50   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-28  0:50 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:33, Peter Maydell wrote:
> Mark up the cpreginfo structs to indicate offsets for system
> registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
> the Arm ARM.  This covers all the remaining offsets at 0x200 and
> above, except for the GIC ICH_* registers.
> 
> (Note that because we don't implement FEAT_SPE, FEAT_TRF,
> FEAT_MPAM, FEAT_BRBE or FEAT_AMUv1p1 we don't implement any
> of the registers that use offsets at 0x800 and above.)
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/helper.c | 8 ++++++++
>   1 file changed, 8 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 32/35] hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers
  2023-12-18 11:33 ` [PATCH 32/35] hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers Peter Maydell
@ 2023-12-28  0:52   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-28  0:52 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:33, Peter Maydell wrote:
> Mark up the cpreginfo structs for the GIC CPU registers to indicate
> the offsets from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ
> in the Arm ARM.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   hw/intc/arm_gicv3_cpuif.c | 11 +++++++++++
>   1 file changed, 11 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 33/35] target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps
  2023-12-18 11:33 ` [PATCH 33/35] target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps Peter Maydell
@ 2023-12-28  0:54   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-28  0:54 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:33, Peter Maydell wrote:
> When interpreting CPU dumps where FEAT_NV and FEAT_NV2 are in use,
> it's helpful to include the values of HCR_EL2.{NV,NV1,NV2} in the CPU
> dump format, as a way of distinguishing when we are in EL1 as part of
> executing guest-EL2 and when we are just in normal EL1.
> 
> Add the bits to the end of the log line that shows PSTATE and similar
> information:
> 
> PSTATE=000003c9 ---- EL2h  BTYPE=0 NV NV2
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>   target/arm/cpu.c | 5 +++++
>   1 file changed, 5 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 34/35] target/arm: Enhance CPU_LOG_INT to show SPSR on AArch64 exception-entry
  2023-12-18 11:33 ` [PATCH 34/35] target/arm: Enhance CPU_LOG_INT to show SPSR on AArch64 exception-entry Peter Maydell
@ 2023-12-28  0:54   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-28  0:54 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:33, Peter Maydell wrote:
> We already print various lines of information when we take an
> exception, including the ELR and (if relevant) the FAR. Now
> that FEAT_NV means that we might report something other than
> the old PSTATE to the guest as the SPSR, it's worth logging
> this as well.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/helper.c | 1 +
>   1 file changed, 1 insertion(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 35/35] target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs
  2023-12-18 11:33 ` [PATCH 35/35] target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs Peter Maydell
@ 2023-12-28  0:58   ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2023-12-28  0:58 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 12/18/23 22:33, Peter Maydell wrote:
> Enable FEAT_NV2 on the 'max' CPU, and stop filtering it out for
> the Neoverse N2 and Neoverse V1 CPUs.
> 
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   docs/system/arm/emulation.rst | 1 +
>   target/arm/cpu.c              | 5 -----
>   target/arm/tcg/cpu64.c        | 2 +-
>   3 files changed, 2 insertions(+), 6 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 21/35] target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs
  2023-12-18 11:32 ` [PATCH 21/35] target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs Peter Maydell
  2023-12-27 22:59   ` Richard Henderson
@ 2023-12-29 11:37   ` Marcin Juszkiewicz
  2024-01-04 11:36     ` Peter Maydell
  1 sibling, 1 reply; 84+ messages in thread
From: Marcin Juszkiewicz @ 2023-12-29 11:37 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

W dniu 18.12.2023 o 12:32, Peter Maydell pisze:

> Enable FEAT_NV on the 'max' CPU, and stop filtering it out for the 
> Neoverse N2 and Neoverse V1 CPUs.  We continue to downgrade FEAT_NV2 
> support to FEAT_NV for the latter two CPU types.

According to Neoverse-V1 TRM r1p2 it has FEAT_NV2. Similar with Neoverse-N2.

You wrote already:

> in practice hypervisors such as KVM are going to require FEAT_NV2 
> and not bother to support the FEAT_NV-only case, so I have
> implemented them one after the other in this single patchset.
So maybe they both should be FEAT_NV2 and FEAT_NV will be left unused. 
Or enable FEAT_NV for V1 (as being older) and FEAT_NV2 on N2.

This way if someone wants to test nested virtualization then both 
versions will be available without use of 'max' cpu.


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 21/35] target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs
  2023-12-29 11:37   ` Marcin Juszkiewicz
@ 2024-01-04 11:36     ` Peter Maydell
  0 siblings, 0 replies; 84+ messages in thread
From: Peter Maydell @ 2024-01-04 11:36 UTC (permalink / raw)
  To: Marcin Juszkiewicz; +Cc: qemu-arm, qemu-devel

On Fri, 29 Dec 2023 at 11:37, Marcin Juszkiewicz
<marcin.juszkiewicz@linaro.org> wrote:
>
> W dniu 18.12.2023 o 12:32, Peter Maydell pisze:
>
> > Enable FEAT_NV on the 'max' CPU, and stop filtering it out for the
> > Neoverse N2 and Neoverse V1 CPUs.  We continue to downgrade FEAT_NV2
> > support to FEAT_NV for the latter two CPU types.
>
> According to Neoverse-V1 TRM r1p2 it has FEAT_NV2. Similar with Neoverse-N2.

I'm not sure what you're trying to say here ? Yes, the V1 has
NV2, that's why we have to downgrade it to FEAT_NV for the moment
when we're emulating, because at this point in the series we
don't have FEAT_NV2 emulation. At the end of the series this downgrade
goes away, because at that point we can emulate FEAT_NV2.

>
> You wrote already:
>
> > in practice hypervisors such as KVM are going to require FEAT_NV2
> > and not bother to support the FEAT_NV-only case, so I have
> > implemented them one after the other in this single patchset.
> So maybe they both should be FEAT_NV2 and FEAT_NV will be left unused.
> Or enable FEAT_NV for V1 (as being older) and FEAT_NV2 on N2.

As usual, we emulate what the actual hardware has, to the extent
that we are able to. For both of these CPUs that's both FEAT_NV
and FEAT_NV2, and we enable emulation of each at the point in the
series when we've implemented it.

> This way if someone wants to test nested virtualization then both
> versions will be available without use of 'max' cpu.

In theory it might be nice to be able to emulate a pure FEAT_NV
CPU, but in practice I don't expect anybody to want to do that.
If anybody has a real use case for it we can add a -cpu suboption
later.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 17/35] target/arm: Always use arm_pan_enabled() when checking if PAN is enabled
  2023-12-27 22:50   ` Richard Henderson
@ 2024-01-04 15:59     ` Peter Maydell
  0 siblings, 0 replies; 84+ messages in thread
From: Peter Maydell @ 2024-01-04 15:59 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-arm, qemu-devel

On Wed, 27 Dec 2023 at 22:50, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 12/18/23 22:32, Peter Maydell wrote:
> > Currently the code in target/arm/helper.c mostly checks the PAN bits
> > in env->pstate or env->uncached_cpsr directly when it wants to know
> > if PAN is enabled, because in most callsites we know whether we are
> > in AArch64 or AArch32. We do have an arm_pan_enabled() function, but
> > we only use it in a few places where the code might run in either an
> > AArch32 or AArch64 context.
> >
> > For FEAT_NV, when HCR_EL2.{NV,NV1} is {1,1} PAN is always disabled
> > even when the PSTATE.PAN bit is set, the "is PAN enabled" test
> > becomes more complicated. Make all places that check for PAN use
> > arm_pan_enabled(), so we have a place to put the FEAT_NV test.
> >
> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> > ---
> >   target/arm/helper.c | 22 +++++++++++-----------
> >   1 file changed, 11 insertions(+), 11 deletions(-)
> >
> > diff --git a/target/arm/helper.c b/target/arm/helper.c
> > index 3270fb11049..4b0e46cfaae 100644
> > --- a/target/arm/helper.c
> > +++ b/target/arm/helper.c
> > @@ -263,6 +263,15 @@ void init_cpreg_list(ARMCPU *cpu)
> >       g_list_free(keys);
> >   }
> >
> > +static bool arm_pan_enabled(CPUARMState *env)
> > +{
> > +    if (is_a64(env)) {
> > +        return env->pstate & PSTATE_PAN;
> > +    } else {
> > +        return env->uncached_cpsr & CPSR_PAN;
> > +    }
> > +}
>
> Worth splitting out helpers aa{32,64}_pan_enabled to avoid the is_a64 check when context
> dictates?

Doesn't really seem worthwhile to me -- we only know this
for a couple of subcases of AT instructions, which aren't
all that common in guest execution, and the cost of
is_a64() is going to be completely swamped by the cost
of actually doing the address translation...

thanks
-- PMM


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 24/35] target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2
  2023-12-27 23:06   ` Richard Henderson
@ 2024-01-04 16:03     ` Peter Maydell
  0 siblings, 0 replies; 84+ messages in thread
From: Peter Maydell @ 2024-01-04 16:03 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-arm, qemu-devel

On Wed, 27 Dec 2023 at 23:06, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 12/18/23 22:32, Peter Maydell wrote:
> > With FEAT_NV2, the condition for when SPSR_EL1.M should report that
> > an exception was taken from EL2 changes.
> >
> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> > ---
> >   target/arm/helper.c | 16 ++++++++++++----
> >   1 file changed, 12 insertions(+), 4 deletions(-)
> >
> > diff --git a/target/arm/helper.c b/target/arm/helper.c
> > index 45444360f95..38e16c2f8a5 100644
> > --- a/target/arm/helper.c
> > +++ b/target/arm/helper.c
> > @@ -11405,10 +11405,18 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
> >           aarch64_save_sp(env, arm_current_el(env));
> >           env->elr_el[new_el] = env->pc;
> >
> > -        if (cur_el == 1 && new_el == 1 &&
> > -            ((arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1)) == HCR_NV)) {
> > -            /* I_ZJRNN: report EL2 in the SPSR by setting M[3:2] to 0b10 */
> > -            old_mode = deposit32(old_mode, 2, 2, 2);
> > +        if (cur_el == 1 && new_el == 1) {
> > +            uint64_t hcr = arm_hcr_el2_eff(env);
> > +            if ((hcr & (HCR_NV | HCR_NV1 | HCR_NV2)) == HCR_NV ||
> > +                (hcr & (HCR_NV | HCR_NV2)) == (HCR_NV | HCR_NV2)) {
>
> Maybe clearer as
>
>         if ((hcr & HCR_NV) && ((hcr & HCR_NV2) || !(hcr & HCR_NV1)))
>
> ?

I dunno; I went back and forth a bit on how to write this, but
I think what I have is a little closer to how the Arm ARM
defines it (as separate FEAT_NV vs FEAT_NV2 conditions). At any rate,
I don't think your suggestion sufficiently better to do the
work to make the change :-)

-- PMM


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 26/35] target/arm: Implement FEAT_NV2 redirection of sysregs to RAM
  2023-12-27 23:55   ` Richard Henderson
@ 2024-01-04 16:23     ` Peter Maydell
  2024-01-09  8:40       ` Richard Henderson
  0 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2024-01-04 16:23 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-arm, qemu-devel

On Wed, 27 Dec 2023 at 23:55, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 12/18/23 22:32, Peter Maydell wrote:
> > +    if (s->nv && s->nv2 && ri->nv2_redirect_offset) {
>
> Again, s->nv test is redundant.

Fixed, thanks.

> > +        /*
> > +         * Some registers always redirect to memory; some only do so if
> > +         * HCR_EL2.NV1 is 0, and some only if NV1 is 1 (these come in
> > +         * pairs which share an offset; see the table in R_CSRPQ).
> > +         */
> > +        if (ri->nv2_redirect_offset & NV2_REDIR_NV1) {
> > +            nv2_mem_redirect = s->nv1;
> > +        } else if (ri->nv2_redirect_offset & NV2_REDIR_NO_NV1) {
> > +            nv2_mem_redirect = !s->nv1;
> > +        } else {
> > +            nv2_mem_redirect = true;
> > +        }
>
> I wondered if it would be clearer with the "both" case having both bits set.  While I see
> that the first defined offset is 0x20, offset 0x00 is still reserved and *could* be used.
> At which point ri->nv2_redirect_offset would need a non-zero value for a zero offset.
>
> Maybe clearer as
>
>      nv2_mem_redirect = (ri->nv2_redirect_offset &
>                          (s->nv1 ? NV2_REDIR_NV1_1 : NV2_REDIR_NV1_0));
>
> ?
>
> This is more verbose for the (common?) case of redirect regardless of nv1, so maybe not.

Yes, my motivation for the notation I used is that I wanted to
make the specification of the cpreg structs in the common case
simple and not too long-winded. If offset 0 does ever get
allocated, we'll have to come back and revisit this. But
new entries clearly seem to be being allocated at the other
end of the table, so I think our chances are good...

> > +        if (s->nv2_mem_be) {
> > +            mop |= MO_BE;
> > +        }
>
> MO_BSWAP is host dependent -- needs
>
>      mop |= (s->nv2_mem_be ? MO_BE : MO_LE);

Fixed.

With those two fixes, can I have a reviewed-by? This is the
only patch without one, and all the fixes seem to me like
very minor things not worth sending out a full v2 for.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 29/35] target/arm: Mark up VNCR offsets (offsets 0x100..0x160)
  2023-12-28  0:42   ` Richard Henderson
@ 2024-01-04 16:24     ` Peter Maydell
  0 siblings, 0 replies; 84+ messages in thread
From: Peter Maydell @ 2024-01-04 16:24 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-arm, qemu-devel

On Thu, 28 Dec 2023 at 00:42, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 12/18/23 22:32, Peter Maydell wrote:
> > Mark up the cpreginfo structs to indicate offsets for system
> > registers from VNCR_EL2, as defined in table D8-66 in rule R_CSRPQ in
> > the Arm ARM.  This commit covers offsets 0x100 to 0x160.
> >
> > Many (but not all) of the registers in this range have _EL12 aliases,
> > and the slot in memory is shared between the _EL12 version of the
> > register and the _EL1 version.  Where we programmatically generate
> > the regdef for the _EL12 register, arrange that its
> > nv2_redirect_offset is set up correctly to do this.
> >
> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> > ---
> >   target/arm/debug_helper.c |  1 +
> >   target/arm/helper.c       | 22 ++++++++++++++++++++++
> >   2 files changed, 23 insertions(+)
>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
>
> > +        /*
> > +         * If the _EL1 register is redirected to memory by FEAT_NV2,
> > +         * then it shares the offset with the _EL12 register,
> > +         * and which one is redirected depends on HCR_EL2.NV1.
> > +         */
> > +        if (new_reg->nv2_redirect_offset) {
> > +            assert(new_reg->nv2_redirect_offset & NV2_REDIR_NV1);
> > +            new_reg->nv2_redirect_offset &= ~NV2_REDIR_NV1;
> > +            new_reg->nv2_redirect_offset |= NV2_REDIR_NO_NV1;
> > +        }
>
> Could use xor to flip both bits at once.

Could do, but explicit clear-then-set seems a bit more
readable to me, and since this is only happening once at
startup there's no efficiency concern here.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 26/35] target/arm: Implement FEAT_NV2 redirection of sysregs to RAM
  2024-01-04 16:23     ` Peter Maydell
@ 2024-01-09  8:40       ` Richard Henderson
  0 siblings, 0 replies; 84+ messages in thread
From: Richard Henderson @ 2024-01-09  8:40 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-arm, qemu-devel

On 1/5/24 03:23, Peter Maydell wrote:
> On Wed, 27 Dec 2023 at 23:55, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> On 12/18/23 22:32, Peter Maydell wrote:
>>> +    if (s->nv && s->nv2 && ri->nv2_redirect_offset) {
>>
>> Again, s->nv test is redundant.
> 
> Fixed, thanks.
> 
>>> +        /*
>>> +         * Some registers always redirect to memory; some only do so if
>>> +         * HCR_EL2.NV1 is 0, and some only if NV1 is 1 (these come in
>>> +         * pairs which share an offset; see the table in R_CSRPQ).
>>> +         */
>>> +        if (ri->nv2_redirect_offset & NV2_REDIR_NV1) {
>>> +            nv2_mem_redirect = s->nv1;
>>> +        } else if (ri->nv2_redirect_offset & NV2_REDIR_NO_NV1) {
>>> +            nv2_mem_redirect = !s->nv1;
>>> +        } else {
>>> +            nv2_mem_redirect = true;
>>> +        }
>>
>> I wondered if it would be clearer with the "both" case having both bits set.  While I see
>> that the first defined offset is 0x20, offset 0x00 is still reserved and *could* be used.
>> At which point ri->nv2_redirect_offset would need a non-zero value for a zero offset.
>>
>> Maybe clearer as
>>
>>       nv2_mem_redirect = (ri->nv2_redirect_offset &
>>                           (s->nv1 ? NV2_REDIR_NV1_1 : NV2_REDIR_NV1_0));
>>
>> ?
>>
>> This is more verbose for the (common?) case of redirect regardless of nv1, so maybe not.
> 
> Yes, my motivation for the notation I used is that I wanted to
> make the specification of the cpreg structs in the common case
> simple and not too long-winded. If offset 0 does ever get
> allocated, we'll have to come back and revisit this. But
> new entries clearly seem to be being allocated at the other
> end of the table, so I think our chances are good...
> 
>>> +        if (s->nv2_mem_be) {
>>> +            mop |= MO_BE;
>>> +        }
>>
>> MO_BSWAP is host dependent -- needs
>>
>>       mop |= (s->nv2_mem_be ? MO_BE : MO_LE);
> 
> Fixed.
> 
> With those two fixes, can I have a reviewed-by? This is the
> only patch without one, and all the fixes seem to me like
> very minor things not worth sending out a full v2 for.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly
  2023-12-18 11:32 ` [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly Peter Maydell
  2023-12-28  0:03   ` Richard Henderson
@ 2024-01-16 13:09   ` Jonathan Cameron via
  2024-01-16 13:20     ` Peter Maydell
  1 sibling, 1 reply; 84+ messages in thread
From: Jonathan Cameron via @ 2024-01-16 13:09 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-arm, qemu-devel

On Mon, 18 Dec 2023 11:32:57 +0000
Peter Maydell <peter.maydell@linaro.org> wrote:

> 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>

Hi Peter,

I'm getting an unhelpful crash on calling init in a guest
running on top of an a76 emulated host with virtualization turned on.

Run /sbin/init as init process
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000007
CPU: 1 PID: 1 Comm: init Not tainted 6.7.0+ #1119
Hardware name: linux,dummy-virt (DT)
Call trace:
 dump_backtrace+0xa0/0x128
 show_stack+0x20/0x38
 dump_stack_lvl+0x48/0x60
 dump_stack+0x18/0x28
 panic+0x380/0x3c0
 do_exit+0x89c/0x9a0
 do_group_exit+0x3c/0xa0
 get_signal+0x968/0x970
 do_notify_resume+0x21c/0x1460
 el0_ia+0xa0/0xb0
 el0t_64_sync_handler+0xd0/0x130
 el0t_64_sync+0x190/0x198
SMP: stopping secondary CPUs
Kernel Offset: 0x2a8c93a00000 from 0xffff800080000000
PHYS_OFFSET: 0xffff82f980000000
CPU features: 0x0,00000001,7002014a,2101720b
Memory Limit: none
---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000007 ]---

Upstream kernel as of yesterday.  Nothing particular 'exciting' in the
configurations. Not attempting to use Nested virt.
-M virt,gic-version=3,virtualization=true
-cpu cortex-a76 (happens with max as well but switched to a76 for testing
to reduce possible sources of problems).

Doesn't happen if single cpu in the guest, or if using gic v2 in both.

Bisection points at this patch - so far no idea why but I've only
just started digging into this.
Having one of those weeks where I'm juggling several issues so
might not make progress on this for a while.

The VMM in the guest is also recent QEMU (yesterday's upstream I think)
so I suppose this might just be exposing a problem that will bisect
to a different patch in there.

Jonathan

> ---
>  target/arm/cpu.h               |  4 ++--
>  target/arm/syndrome.h          | 20 ++++++++++++++++----
>  target/arm/tcg/tlb_helper.c    | 27 +++++++++++++++++++++++++--
>  target/arm/tcg/translate-a64.c |  4 ++++
>  4 files changed, 47 insertions(+), 8 deletions(-)
> 
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index bc4fa95ea35..da640949518 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -120,12 +120,12 @@ enum {
>  #define TARGET_INSN_START_EXTRA_WORDS 2
>  
>  /* The 2nd extra word holding syndrome info for data aborts does not use
> - * the upper 6 bits nor the lower 14 bits. We mask and shift it down to
> + * the upper 6 bits nor the lower 13 bits. We mask and shift it down to
>   * help the sleb128 encoder do a better job.
>   * When restoring the CPU state, we shift it back up.
>   */
>  #define ARM_INSN_START_WORD2_MASK ((1 << 26) - 1)
> -#define ARM_INSN_START_WORD2_SHIFT 14
> +#define ARM_INSN_START_WORD2_SHIFT 13
>  
>  /* We currently assume float and double are IEEE single and double
>     precision respectively.
> diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
> index 95454b5b3bb..1a49767479f 100644
> --- a/target/arm/syndrome.h
> +++ b/target/arm/syndrome.h
> @@ -86,6 +86,9 @@ typedef enum {
>  #define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
>  #define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT)
>  
> +/* In the Data Abort syndrome */
> +#define ARM_EL_VNCR (1 << 13)
> +
>  static inline uint32_t syn_get_ec(uint32_t syn)
>  {
>      return syn >> ARM_EL_EC_SHIFT;
> @@ -256,13 +259,12 @@ static inline uint32_t syn_bxjtrap(int cv, int cond, int rm)
>          (cv << 24) | (cond << 20) | rm;
>  }
>  
> -static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc,
> +static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr,
>                                 int cm, int s1ptw, int wnr, int fsc)
>  {
> -    /* TODO: FEAT_NV2 adds VNCR */
>      return (EC_GPC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (s2ptw << 21)
> -            | (ind << 20) | (gpcsc << 14) | (cm << 8) | (s1ptw << 7)
> -            | (wnr << 6) | fsc;
> +        | (ind << 20) | (gpcsc << 14) | (vncr << 13) | (cm << 8)
> +        | (s1ptw << 7) | (wnr << 6) | fsc;
>  }
>  
>  static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
> @@ -295,6 +297,16 @@ static inline uint32_t syn_data_abort_with_iss(int same_el,
>             | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
>  }
>  
> +/*
> + * Faults due to FEAT_NV2 VNCR_EL2-based accesses report as same-EL
> + * Data Aborts with the VNCR bit set.
> + */
> +static inline uint32_t syn_data_abort_vncr(int ea, int wnr, int fsc)
> +{
> +    return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (1 << ARM_EL_EC_SHIFT)
> +        | ARM_EL_IL | ARM_EL_VNCR | (wnr << 6) | fsc;
> +}
> +
>  static inline uint32_t syn_swstep(int same_el, int isv, int ex)
>  {
>      return (EC_SOFTWARESTEP << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
> diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c
> index 4fdd85359e1..dd5de74ffb7 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 128bff4b445..8f905ed9645 100644
> --- a/target/arm/tcg/translate-a64.c
> +++ b/target/arm/tcg/translate-a64.c
> @@ -2293,6 +2293,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;
>  
>          if (s->nv2_mem_be) {
>              mop |= MO_BE;
> @@ -2302,6 +2303,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 {



^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly
  2024-01-16 13:09   ` Jonathan Cameron via
@ 2024-01-16 13:20     ` Peter Maydell
  2024-01-16 14:50       ` Jonathan Cameron via
  0 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2024-01-16 13:20 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: qemu-arm, qemu-devel

On Tue, 16 Jan 2024 at 13:09, Jonathan Cameron
<Jonathan.Cameron@huawei.com> wrote:
>
> On Mon, 18 Dec 2023 11:32:57 +0000
> Peter Maydell <peter.maydell@linaro.org> wrote:
>
> > 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>
>
> Hi Peter,
>
> I'm getting an unhelpful crash on calling init in a guest
> running on top of an a76 emulated host with virtualization turned on.
>
> Run /sbin/init as init process
> Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000007
> CPU: 1 PID: 1 Comm: init Not tainted 6.7.0+ #1119
> Hardware name: linux,dummy-virt (DT)
> Call trace:
>  dump_backtrace+0xa0/0x128
>  show_stack+0x20/0x38
>  dump_stack_lvl+0x48/0x60
>  dump_stack+0x18/0x28
>  panic+0x380/0x3c0
>  do_exit+0x89c/0x9a0
>  do_group_exit+0x3c/0xa0
>  get_signal+0x968/0x970
>  do_notify_resume+0x21c/0x1460
>  el0_ia+0xa0/0xb0
>  el0t_64_sync_handler+0xd0/0x130
>  el0t_64_sync+0x190/0x198
> SMP: stopping secondary CPUs
> Kernel Offset: 0x2a8c93a00000 from 0xffff800080000000
> PHYS_OFFSET: 0xffff82f980000000
> CPU features: 0x0,00000001,7002014a,2101720b
> Memory Limit: none
> ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000007 ]---
>
> Upstream kernel as of yesterday.  Nothing particular 'exciting' in the
> configurations. Not attempting to use Nested virt.
> -M virt,gic-version=3,virtualization=true
> -cpu cortex-a76 (happens with max as well but switched to a76 for testing
> to reduce possible sources of problems).
>
> Doesn't happen if single cpu in the guest, or if using gic v2 in both.
>
> Bisection points at this patch - so far no idea why but I've only
> just started digging into this.

Bisecting to this patch is a bit weird because at this point
in the series emulation of FEAT_NV2 should be disabled and
the code being added should never be used. You could put
an assert(0) into the code in translate-a64.c before the
call to syn_data_abort_vncr() and in arm_deliver_fault()
assert(!is_vncr) to confirm that we're not somehow getting
into this code for some non-FEAT_NV2 situation, I guess.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly
  2024-01-16 13:20     ` Peter Maydell
@ 2024-01-16 14:50       ` Jonathan Cameron via
  2024-01-16 14:59         ` Peter Maydell
  0 siblings, 1 reply; 84+ messages in thread
From: Jonathan Cameron via @ 2024-01-16 14:50 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-arm, qemu-devel

On Tue, 16 Jan 2024 13:20:33 +0000
Peter Maydell <peter.maydell@linaro.org> wrote:

> On Tue, 16 Jan 2024 at 13:09, Jonathan Cameron
> <Jonathan.Cameron@huawei.com> wrote:
> >
> > On Mon, 18 Dec 2023 11:32:57 +0000
> > Peter Maydell <peter.maydell@linaro.org> wrote:
> >  
> > > 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>  
> >
> > Hi Peter,
> >
> > I'm getting an unhelpful crash on calling init in a guest
> > running on top of an a76 emulated host with virtualization turned on.
> >
> > Run /sbin/init as init process
> > Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000007
> > CPU: 1 PID: 1 Comm: init Not tainted 6.7.0+ #1119
> > Hardware name: linux,dummy-virt (DT)
> > Call trace:
> >  dump_backtrace+0xa0/0x128
> >  show_stack+0x20/0x38
> >  dump_stack_lvl+0x48/0x60
> >  dump_stack+0x18/0x28
> >  panic+0x380/0x3c0
> >  do_exit+0x89c/0x9a0
> >  do_group_exit+0x3c/0xa0
> >  get_signal+0x968/0x970
> >  do_notify_resume+0x21c/0x1460
> >  el0_ia+0xa0/0xb0
> >  el0t_64_sync_handler+0xd0/0x130
> >  el0t_64_sync+0x190/0x198
> > SMP: stopping secondary CPUs
> > Kernel Offset: 0x2a8c93a00000 from 0xffff800080000000
> > PHYS_OFFSET: 0xffff82f980000000
> > CPU features: 0x0,00000001,7002014a,2101720b
> > Memory Limit: none
> > ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000007 ]---
> >
> > Upstream kernel as of yesterday.  Nothing particular 'exciting' in the
> > configurations. Not attempting to use Nested virt.
> > -M virt,gic-version=3,virtualization=true
> > -cpu cortex-a76 (happens with max as well but switched to a76 for testing
> > to reduce possible sources of problems).
> >
> > Doesn't happen if single cpu in the guest, or if using gic v2 in both.
> >
> > Bisection points at this patch - so far no idea why but I've only
> > just started digging into this.  
> 
> Bisecting to this patch is a bit weird because at this point
> in the series emulation of FEAT_NV2 should be disabled and
> the code being added should never be used. You could put
> an assert(0) into the code in translate-a64.c before the
> call to syn_data_abort_vncr() and in arm_deliver_fault()
> assert(!is_vncr) to confirm that we're not somehow getting
> into this code for some non-FEAT_NV2 situation, I guess.

Not that, but surprisingly is_vncr == true.
in arm_deliver_fault()

Frigging that to be false gets me up and running. I'll see
if I can figure out why it is set.

J
> 
> thanks
> -- PMM



^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly
  2024-01-16 14:50       ` Jonathan Cameron via
@ 2024-01-16 14:59         ` Peter Maydell
  2024-01-16 15:29           ` Jonathan Cameron via
  0 siblings, 1 reply; 84+ messages in thread
From: Peter Maydell @ 2024-01-16 14:59 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: qemu-arm, qemu-devel

On Tue, 16 Jan 2024 at 14:50, Jonathan Cameron
<Jonathan.Cameron@huawei.com> wrote:
>
> On Tue, 16 Jan 2024 13:20:33 +0000
> Peter Maydell <peter.maydell@linaro.org> wrote:
> > Bisecting to this patch is a bit weird because at this point
> > in the series emulation of FEAT_NV2 should be disabled and
> > the code being added should never be used. You could put
> > an assert(0) into the code in translate-a64.c before the
> > call to syn_data_abort_vncr() and in arm_deliver_fault()
> > assert(!is_vncr) to confirm that we're not somehow getting
> > into this code for some non-FEAT_NV2 situation, I guess.
>
> Not that, but surprisingly is_vncr == true.
> in arm_deliver_fault()
>
> Frigging that to be false gets me up and running. I'll see
> if I can figure out why it is set.

I don't know if this is the cause, but looking again at the
line that sets is_vncr I see at least one obvious bug:

    bool is_vncr = (mmu_idx != MMU_INST_FETCH) &&
        (env->exception.syndrome & ARM_EL_VNCR);

is testing the wrong variable -- the first part
of the condition should be "access_type != MMU_INST_FETCH".

If you fix that does the failure go away ?

Yay for C and its very sloppy typing :-/

-- PMM


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly
  2024-01-16 14:59         ` Peter Maydell
@ 2024-01-16 15:29           ` Jonathan Cameron via
  2024-01-16 15:35             ` Peter Maydell
  0 siblings, 1 reply; 84+ messages in thread
From: Jonathan Cameron via @ 2024-01-16 15:29 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-arm, qemu-devel

On Tue, 16 Jan 2024 14:59:15 +0000
Peter Maydell <peter.maydell@linaro.org> wrote:

> On Tue, 16 Jan 2024 at 14:50, Jonathan Cameron
> <Jonathan.Cameron@huawei.com> wrote:
> >
> > On Tue, 16 Jan 2024 13:20:33 +0000
> > Peter Maydell <peter.maydell@linaro.org> wrote:  
> > > Bisecting to this patch is a bit weird because at this point
> > > in the series emulation of FEAT_NV2 should be disabled and
> > > the code being added should never be used. You could put
> > > an assert(0) into the code in translate-a64.c before the
> > > call to syn_data_abort_vncr() and in arm_deliver_fault()
> > > assert(!is_vncr) to confirm that we're not somehow getting
> > > into this code for some non-FEAT_NV2 situation, I guess.  
> >
> > Not that, but surprisingly is_vncr == true.
> > in arm_deliver_fault()
> >
> > Frigging that to be false gets me up and running. I'll see
> > if I can figure out why it is set.  
> 
> I don't know if this is the cause, but looking again at the
> line that sets is_vncr I see at least one obvious bug:
> 
>     bool is_vncr = (mmu_idx != MMU_INST_FETCH) &&
>         (env->exception.syndrome & ARM_EL_VNCR);
> 
> is testing the wrong variable -- the first part
> of the condition should be "access_type != MMU_INST_FETCH".
> 
> If you fix that does the failure go away ?
Ah - indeed that fixes it.

I guess that makes sense. Presumably the bit is used for
something else for instruction fetches.

Thanks for your quick help!

Jonathan


> 
> Yay for C and its very sloppy typing :-/
> 
> -- PMM



^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly
  2024-01-16 15:29           ` Jonathan Cameron via
@ 2024-01-16 15:35             ` Peter Maydell
  0 siblings, 0 replies; 84+ messages in thread
From: Peter Maydell @ 2024-01-16 15:35 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: qemu-arm, qemu-devel

On Tue, 16 Jan 2024 at 15:29, Jonathan Cameron
<Jonathan.Cameron@huawei.com> wrote:
>
> On Tue, 16 Jan 2024 14:59:15 +0000
> Peter Maydell <peter.maydell@linaro.org> wrote:
>
> > On Tue, 16 Jan 2024 at 14:50, Jonathan Cameron
> > <Jonathan.Cameron@huawei.com> wrote:
> > >
> > > On Tue, 16 Jan 2024 13:20:33 +0000
> > > Peter Maydell <peter.maydell@linaro.org> wrote:
> > > > Bisecting to this patch is a bit weird because at this point
> > > > in the series emulation of FEAT_NV2 should be disabled and
> > > > the code being added should never be used. You could put
> > > > an assert(0) into the code in translate-a64.c before the
> > > > call to syn_data_abort_vncr() and in arm_deliver_fault()
> > > > assert(!is_vncr) to confirm that we're not somehow getting
> > > > into this code for some non-FEAT_NV2 situation, I guess.
> > >
> > > Not that, but surprisingly is_vncr == true.
> > > in arm_deliver_fault()
> > >
> > > Frigging that to be false gets me up and running. I'll see
> > > if I can figure out why it is set.
> >
> > I don't know if this is the cause, but looking again at the
> > line that sets is_vncr I see at least one obvious bug:
> >
> >     bool is_vncr = (mmu_idx != MMU_INST_FETCH) &&
> >         (env->exception.syndrome & ARM_EL_VNCR);
> >
> > is testing the wrong variable -- the first part
> > of the condition should be "access_type != MMU_INST_FETCH".
> >
> > If you fix that does the failure go away ?
> Ah - indeed that fixes it.
>
> I guess that makes sense. Presumably the bit is used for
> something else for instruction fetches.
>
> Thanks for your quick help!

Thanks for testing -- I'll send out a proper patch in
a bit.

-- PMM


^ permalink raw reply	[flat|nested] 84+ messages in thread

end of thread, other threads:[~2024-01-16 15:36 UTC | newest]

Thread overview: 84+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-18 11:32 [PATCH 00/35] target/arm: Implement emulation of nested virtualization Peter Maydell
2023-12-18 11:32 ` [PATCH 01/35] target/arm: Don't implement *32_EL2 registers when EL1 is AArch64 only Peter Maydell
2023-12-18 11:32 ` [PATCH 02/35] target/arm: Set CTR_EL0.{IDC,DIC} for the 'max' CPU Peter Maydell
2023-12-27 21:08   ` [PATCH 02/35] target/arm: Set CTR_EL0.{IDC, DIC} " Richard Henderson
2023-12-18 11:32 ` [PATCH 03/35] hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers Peter Maydell
2023-12-27 21:11   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 04/35] target/arm: Handle HCR_EL2 accesses for bits introduced with FEAT_NV Peter Maydell
2023-12-27 21:42   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 05/35] target/arm: Implement HCR_EL2.AT handling Peter Maydell
2023-12-27 22:01   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 06/35] target/arm: Enable trapping of ERET for FEAT_NV Peter Maydell
2023-12-27 22:06   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 07/35] target/arm: Always honour HCR_EL2.TSC when HCR_EL2.NV is set Peter Maydell
2023-12-27 22:18   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 08/35] target/arm: Allow use of upper 32 bits of TBFLAG_A64 Peter Maydell
2023-12-27 22:20   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 09/35] target/arm: Record correct opcode fields in cpreg for E2H aliases Peter Maydell
2023-12-27 22:23   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 10/35] target/arm: *_EL12 registers should UNDEF when HCR_EL2.E2H is 0 Peter Maydell
2023-12-27 22:25   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 11/35] target/arm: Make EL2 cpreg accessfns safe for FEAT_NV EL1 accesses Peter Maydell
2023-12-27 22:31   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 12/35] target/arm: Move FPU/SVE/SME access checks up above ARM_CP_SPECIAL_MASK check Peter Maydell
2023-12-27 22:32   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 13/35] target/arm: Trap sysreg accesses for FEAT_NV Peter Maydell
2023-12-27 22:40   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 14/35] target/arm: Make NV reads of CurrentEL return EL2 Peter Maydell
2023-12-27 22:42   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 15/35] target/arm: Set SPSR_EL1.M correctly when nested virt is enabled Peter Maydell
2023-12-27 22:43   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 16/35] target/arm: Trap registers when HCR_EL2.{NV, NV1} == {1, 1} Peter Maydell
2023-12-27 22:47   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 17/35] target/arm: Always use arm_pan_enabled() when checking if PAN is enabled Peter Maydell
2023-12-27 22:50   ` Richard Henderson
2024-01-04 15:59     ` Peter Maydell
2023-12-18 11:32 ` [PATCH 18/35] target/arm: Don't honour PSTATE.PAN when HCR_EL2.{NV, NV1} == {1, 1} Peter Maydell
2023-12-27 22:52   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 19/35] target/arm: Treat LDTR* and STTR* as LDR/STR when NV, NV1 is 1, 1 Peter Maydell
2023-12-27 22:53   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 20/35] target/arm: Handle FEAT_NV page table attribute changes Peter Maydell
2023-12-27 22:57   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 21/35] target/arm: Add FEAT_NV to max, neoverse-n2, neoverse-v1 CPUs Peter Maydell
2023-12-27 22:59   ` Richard Henderson
2023-12-29 11:37   ` Marcin Juszkiewicz
2024-01-04 11:36     ` Peter Maydell
2023-12-18 11:32 ` [PATCH 22/35] target/arm: Handle HCR_EL2 accesses for FEAT_NV2 bits Peter Maydell
2023-12-27 22:59   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 23/35] target/arm: Implement VNCR_EL2 register Peter Maydell
2023-12-27 23:01   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 24/35] target/arm: Handle FEAT_NV2 changes to when SPSR_EL1.M reports EL2 Peter Maydell
2023-12-27 23:06   ` Richard Henderson
2024-01-04 16:03     ` Peter Maydell
2023-12-18 11:32 ` [PATCH 25/35] target/arm: Handle FEAT_NV2 redirection of SPSR_EL2, ELR_EL2, ESR_EL2, FAR_EL2 Peter Maydell
2023-12-27 23:11   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 26/35] target/arm: Implement FEAT_NV2 redirection of sysregs to RAM Peter Maydell
2023-12-27 23:55   ` Richard Henderson
2024-01-04 16:23     ` Peter Maydell
2024-01-09  8:40       ` Richard Henderson
2023-12-18 11:32 ` [PATCH 27/35] target/arm: Report VNCR_EL2 based faults correctly Peter Maydell
2023-12-28  0:03   ` Richard Henderson
2024-01-16 13:09   ` Jonathan Cameron via
2024-01-16 13:20     ` Peter Maydell
2024-01-16 14:50       ` Jonathan Cameron via
2024-01-16 14:59         ` Peter Maydell
2024-01-16 15:29           ` Jonathan Cameron via
2024-01-16 15:35             ` Peter Maydell
2023-12-18 11:32 ` [PATCH 28/35] target/arm: Mark up VNCR offsets (offsets 0x0..0xff) Peter Maydell
2023-12-28  0:35   ` Richard Henderson
2023-12-18 11:32 ` [PATCH 29/35] target/arm: Mark up VNCR offsets (offsets 0x100..0x160) Peter Maydell
2023-12-28  0:42   ` Richard Henderson
2024-01-04 16:24     ` Peter Maydell
2023-12-18 11:33 ` [PATCH 30/35] target/arm: Mark up VNCR offsets (offsets 0x168..0x1f8) Peter Maydell
2023-12-28  0:45   ` Richard Henderson
2023-12-18 11:33 ` [PATCH 31/35] target/arm: Mark up VNCR offsets (offsets >= 0x200, except GIC) Peter Maydell
2023-12-28  0:50   ` Richard Henderson
2023-12-18 11:33 ` [PATCH 32/35] hw/intc/arm_gicv3_cpuif: Mark up VNCR offsets for GIC CPU registers Peter Maydell
2023-12-28  0:52   ` Richard Henderson
2023-12-18 11:33 ` [PATCH 33/35] target/arm: Report HCR_EL2.{NV,NV1,NV2} in cpu dumps Peter Maydell
2023-12-28  0:54   ` Richard Henderson
2023-12-18 11:33 ` [PATCH 34/35] target/arm: Enhance CPU_LOG_INT to show SPSR on AArch64 exception-entry Peter Maydell
2023-12-28  0:54   ` Richard Henderson
2023-12-18 11:33 ` [PATCH 35/35] target/arm: Add FEAT_NV2 to max, neoverse-n2, neoverse-v1 CPUs Peter Maydell
2023-12-28  0:58   ` Richard Henderson
2023-12-22 14:23 ` [PATCH 00/35] target/arm: Implement emulation of nested virtualization Miguel Luis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).