qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128
@ 2025-08-27  1:03 Richard Henderson
  2025-08-27  1:03 ` [PATCH 01/61] target/arm: Introduce KVMID_AA64_SYS_REG64 Richard Henderson
                   ` (65 more replies)
  0 siblings, 66 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Requesting feedback on the implementation of 128-bit registers.

Note that there ought to be no functional change with all of this,
because 128-bit sysregs are not hereing enabled.  Despite all of the
different FEAT_* names, it's all indivisible from FEAT_D128.

I've used Int128 throughout, which seems sensible at first glance,
but *really* complicates the definition of the registers within
ARMCPU, especially when the low part is aliased with AArch32.
The only saving grace is that there are so few 128-bit registers.

Gettng there isn't trivial either.  I wasn't happy with the idea
of replicating the orig_{read,write,access} set of hooks used by
VHE, so I've rewritten that to perform the VHE redirection at
translation time, much like how we do for NV2.

In the process of rewriting VHE, re-organize registration to
simplify memory management and reduce the number of arguments
to the inner helper functions.

At one point in development, I did not have CP_REG_AA64_128BIT_MASK,
which was going to require cpreg_to_kvm_id to also take a
ARMCPRegInfo pointer.  There aren't a whole lot of calls to that
helper, but the one in hvf required reorganization to handle.
With CP_REG_AA64_128BIT_MASK, that reorganization is not required,
but I still think it's a good cleanup so I have kept it.

Alternate implementation strategies:

  (1) Disconnect the 64-bit halves of the sysregs.
      Cons:
        - The 128-bit-ness isn't screamingly obvious.
      Pros:
        - Avoid having to rearrange the ARMCPU layout, and simpler
          integration with AArch32.
        - Avoid Int128 most places, since we wind up doing quite a
          lot of packing and unpacking the structure.
        - Because Int128 *isn't* a structure for most 64-bit builds,
          we can accidentally assign a 64-bit local to a 128-bit field.
        - Possibly easier migration changes; I havn't thought about
          that too much.

  (2) Avoid adding read128fn, raw_*128fn, and most write128fn, at
      least for now, because no defined sysregs need such handling.
      E.g. the 128-bit write of TTBR0_EL1 could call the existing
      writefn for the low half and directly store the high half.
      We do still need write128fn for the TLBIP set of insns, not
      yet implemented here, but even that could avoid Int128 by
      having 2 64-bit arguments.


Thoughts?


r~


Richard Henderson (61):
  target/arm: Introduce KVMID_AA64_SYS_REG64
  target/arm: Move compare_u64 to helper.c
  target/arm/hvf: Split out sysreg.c.inc
  target/arm/hvf: Reorder DEF_SYSREG arguments
  target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID
  target/arm/hvf: Remove hvf_sreg_match.key
  target/arm/hvf: Replace hvf_sreg_match with hvf_sreg_list
  target/arm/hvf: Sort the cpreg_indexes array
  target/arm/hvf: Use raw_read, raw_write to access
  target/arm: Use raw_write in cp_reg_reset
  target/arm: Rename all ARMCPRegInfo from opaque to ri
  target/arm: Drop define_one_arm_cp_reg_with_opaque
  target/arm: Restrict the scope of CPREG_FIELD32, CPREG_FIELD64
  target/arm: Replace cpreg_field_is_64bit with cpreg_field_type
  target/arm: Add CP_REG_AA32_64BIT_{SHIFT,MASK}
  target/arm: Rename CP_REG_AA32_NS_{SHIFT,MASK}
  target/arm: Convert init_cpreg_list to g_hash_table_foreach
  target/arm: Remove cp argument to ENCODE_AA64_CP_REG
  target/arm: Reorder ENCODE_AA64_CP_REG arguments
  target/arm: Split out add_cpreg_to_hashtable_aa{32,64}
  target/arm: Improve asserts in define_one_arm_cp_reg
  target/arm: Move cp processing to define_one_arm_cp_reg
  target/arm: Move cpreg elimination to define_one_arm_cp_reg
  target/arm: Add key parameter to add_cpreg_to_hashtable
  target/arm: Split out alloc_cpreg
  target/arm: Hoist the allocation of ARMCPRegInfo
  target/arm: Remove name argument to alloc_cpreg
  target/arm: Move alias setting for wildcards
  target/arm: Move writeback of CP_ANY fields
  target/arm: Move endianness fixup for 32-bit registers
  target/arm: Rename TBFLAG_A64_NV2_MEM_E20 with *_E2H
  target/arm: Split out redirect_cpreg
  target/arm: Redirect VHE FOO_EL1 -> FOO_EL2 during translation
  target/arm: Redirect VHE FOO_EL12 to FOO_EL1 during translation
  target/arm: Rename some cpreg to their aarch64 names
  target/arm: Remove define_arm_vh_e2h_redirects_aliases
  target/arm: Implement isar tests for FEAT_SYSREG128, FEAT_SYSINSTR128
  target/arm: Define CP_REG_SIZE_U128
  target/arm: Update ARMCPRegInfo for 128-bit sysregs
  target/arm: Assert ARM_CP_128BIT only with ARM_CP_STATE_AA64
  target/arm: Split add_cpreg_to_hashtable_aa64
  target/arm: Add raw_read128, raw_write128
  target/arm: Add read_raw_cp_reg128, write_raw_cp_reg128
  target/arm: Put 128-bit sysregs into a separate list
  target/arm/kvm: Assert no 128-bit sysregs in kvm_arm_init_cpreg_list
  target/arm/hvf: Assert no 128-bit sysregs in hvf_arch_init_vcpu
  migration: Add vmstate_info_int128
  target/arm: Migrate cpreg128 registers
  target/arm: Add syn_aa64_sysreg128trap
  target/arm: Introduce helper_{get,set}_cp_reg128
  target/arm: Implement MRRS, MSRR, SYSP
  include/qemu/compiler: Introduce HOST_ENDIAN_FIELDS
  include/hw/core/cpu: Use HOST_ENDIAN_FIELDS in IcountDecr
  include/qemu/host-utils: Use HOST_ENDIAN_FIELDS in muldiv64_rounding
  target/arm: Use HOST_ENDIAN_FIELDS in CPUARMState
  target/arm: Consolidate definitions of PAR
  target/arm: Extend PAR_EL1 to 128-bit
  target/arm: Consolidate definitions of TTBR[01]
  target/arm: Split out flush_if_asid_change
  target/arm: Use flush_if_asid_change in vmsa_ttbr_write
  target/arm: Extend TTBR system registers to 128-bit

 include/hw/core/cpu.h          |    8 +-
 include/migration/vmstate.h    |    1 +
 include/qemu/compiler.h        |   11 +
 include/qemu/host-utils.h      |    6 +-
 target/arm/cpregs.h            |  134 +--
 target/arm/cpu-features.h      |   10 +
 target/arm/cpu.h               |   95 +-
 target/arm/internals.h         |    4 +
 target/arm/kvm-consts.h        |   16 +-
 target/arm/syndrome.h          |   10 +
 target/arm/tcg/helper.h        |    2 +
 target/arm/tcg/translate.h     |    2 +
 hw/intc/arm_gicv3_cpuif.c      |   10 +-
 migration/vmstate-types.c      |   30 +
 target/arm/cpu.c               |   10 +-
 target/arm/gdbstub.c           |   14 +-
 target/arm/helper.c            | 1536 +++++++++++++++++++-------------
 target/arm/hvf/hvf.c           |  243 ++---
 target/arm/kvm.c               |   13 +-
 target/arm/machine.c           |   50 ++
 target/arm/ptw.c               |   14 +-
 target/arm/tcg/cpregs-at.c     |    4 +-
 target/arm/tcg/hflags.c        |    8 +-
 target/arm/tcg/op_helper.c     |   28 +
 target/arm/tcg/translate-a64.c |  207 ++++-
 target/arm/hvf/sysreg.c.inc    |  146 +++
 target/arm/tcg/a64.decode      |   12 +-
 27 files changed, 1595 insertions(+), 1029 deletions(-)
 create mode 100644 target/arm/hvf/sysreg.c.inc

-- 
2.43.0



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

* [PATCH 01/61] target/arm: Introduce KVMID_AA64_SYS_REG64
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-27  1:03 ` [PATCH 02/61] target/arm: Move compare_u64 to helper.c Richard Henderson
                   ` (64 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Allow us to create kvm ids directly, rather than going
through ENCODE_AA64_CP_REG + cpreg_to_kvm_id.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/kvm-consts.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h
index c44d23dbe7..fdb305eea1 100644
--- a/target/arm/kvm-consts.h
+++ b/target/arm/kvm-consts.h
@@ -180,4 +180,15 @@ MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP2_SHIFT, KVM_REG_ARM64_SYSREG_OP2_SHIFT);
 
 #undef MISMATCH_CHECK
 
+#define KVMID_AA64_SYS_REG_(op0, op1, crn, crm, op2)    \
+    (CP_REG_AA64_MASK | CP_REG_ARM64_SYSREG |           \
+     ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) |         \
+     ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) |         \
+     ((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) |         \
+     ((crm) << CP_REG_ARM64_SYSREG_CRM_SHIFT) |         \
+     ((op2) << CP_REG_ARM64_SYSREG_OP2_SHIFT))
+
+#define KVMID_AA64_SYS_REG64(op0, op1, crn, crm, op2)   \
+    (KVMID_AA64_SYS_REG_(op0, op1, crn, crm, op2) | CP_REG_SIZE_U64)
+
 #endif
-- 
2.43.0



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

* [PATCH 02/61] target/arm: Move compare_u64 to helper.c
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
  2025-08-27  1:03 ` [PATCH 01/61] target/arm: Introduce KVMID_AA64_SYS_REG64 Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-28 12:19   ` Manos Pitsidianakis
  2025-08-27  1:03 ` [PATCH 03/61] target/arm/hvf: Split out sysreg.c.inc Richard Henderson
                   ` (63 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

We will use this function beyond kvm.c.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/internals.h |  3 +++
 target/arm/helper.c    | 11 +++++++++++
 target/arm/kvm.c       | 11 -----------
 3 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/target/arm/internals.h b/target/arm/internals.h
index 1b3d0244fd..08e2acdb99 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1981,4 +1981,7 @@ void vfp_clear_float_status_exc_flags(CPUARMState *env);
 void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask);
 bool arm_pan_enabled(CPUARMState *env);
 
+/* Compare uint64_t for qsort and bsearch. */
+int compare_u64(const void *a, const void *b);
+
 #endif
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0c1299ff84..d230f9e766 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -40,6 +40,17 @@
 
 static void switch_mode(CPUARMState *env, int mode);
 
+int compare_u64(const void *a, const void *b)
+{
+    if (*(uint64_t *)a > *(uint64_t *)b) {
+        return 1;
+    }
+    if (*(uint64_t *)a < *(uint64_t *)b) {
+        return -1;
+    }
+    return 0;
+}
+
 uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     assert(ri->fieldoffset);
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 6672344855..9e569eff65 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -718,17 +718,6 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group,
     memory_region_ref(kd->mr);
 }
 
-static int compare_u64(const void *a, const void *b)
-{
-    if (*(uint64_t *)a > *(uint64_t *)b) {
-        return 1;
-    }
-    if (*(uint64_t *)a < *(uint64_t *)b) {
-        return -1;
-    }
-    return 0;
-}
-
 /*
  * cpreg_values are sorted in ascending order by KVM register ID
  * (see kvm_arm_init_cpreg_list). This allows us to cheaply find
-- 
2.43.0



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

* [PATCH 03/61] target/arm/hvf: Split out sysreg.c.inc
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
  2025-08-27  1:03 ` [PATCH 01/61] target/arm: Introduce KVMID_AA64_SYS_REG64 Richard Henderson
  2025-08-27  1:03 ` [PATCH 02/61] target/arm: Move compare_u64 to helper.c Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-29  6:58   ` Manos Pitsidianakis
  2025-08-27  1:03 ` [PATCH 4/7] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID Richard Henderson
                   ` (62 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Move the list of supported sysregs to a reuseable file.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c        | 147 ++----------------------------------
 target/arm/hvf/sysreg.c.inc | 146 +++++++++++++++++++++++++++++++++++
 2 files changed, 152 insertions(+), 141 deletions(-)
 create mode 100644 target/arm/hvf/sysreg.c.inc

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 47b0cd3a35..f0e4b75e6a 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -403,150 +403,15 @@ struct hvf_sreg_match {
     uint32_t cp_idx;
 };
 
+#define DEF_SYSREG(HVF_ID, crn, crm, op0, op1, op2) \
+    { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
+
 static struct hvf_sreg_match hvf_sreg_match[] = {
-    { HV_SYS_REG_DBGBVR0_EL1, HVF_SYSREG(0, 0, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR0_EL1, HVF_SYSREG(0, 0, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR0_EL1, HVF_SYSREG(0, 0, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR0_EL1, HVF_SYSREG(0, 0, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR1_EL1, HVF_SYSREG(0, 1, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR1_EL1, HVF_SYSREG(0, 1, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR1_EL1, HVF_SYSREG(0, 1, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR1_EL1, HVF_SYSREG(0, 1, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR2_EL1, HVF_SYSREG(0, 2, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR2_EL1, HVF_SYSREG(0, 2, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR2_EL1, HVF_SYSREG(0, 2, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR2_EL1, HVF_SYSREG(0, 2, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR3_EL1, HVF_SYSREG(0, 3, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR3_EL1, HVF_SYSREG(0, 3, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR3_EL1, HVF_SYSREG(0, 3, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR3_EL1, HVF_SYSREG(0, 3, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR4_EL1, HVF_SYSREG(0, 4, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR4_EL1, HVF_SYSREG(0, 4, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR4_EL1, HVF_SYSREG(0, 4, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR4_EL1, HVF_SYSREG(0, 4, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR5_EL1, HVF_SYSREG(0, 5, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR5_EL1, HVF_SYSREG(0, 5, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR5_EL1, HVF_SYSREG(0, 5, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR5_EL1, HVF_SYSREG(0, 5, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR6_EL1, HVF_SYSREG(0, 6, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR6_EL1, HVF_SYSREG(0, 6, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR6_EL1, HVF_SYSREG(0, 6, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR6_EL1, HVF_SYSREG(0, 6, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR7_EL1, HVF_SYSREG(0, 7, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR7_EL1, HVF_SYSREG(0, 7, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR7_EL1, HVF_SYSREG(0, 7, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR7_EL1, HVF_SYSREG(0, 7, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR8_EL1, HVF_SYSREG(0, 8, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR8_EL1, HVF_SYSREG(0, 8, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR8_EL1, HVF_SYSREG(0, 8, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR8_EL1, HVF_SYSREG(0, 8, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR9_EL1, HVF_SYSREG(0, 9, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR9_EL1, HVF_SYSREG(0, 9, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR9_EL1, HVF_SYSREG(0, 9, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR9_EL1, HVF_SYSREG(0, 9, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR10_EL1, HVF_SYSREG(0, 10, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR10_EL1, HVF_SYSREG(0, 10, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR10_EL1, HVF_SYSREG(0, 10, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR10_EL1, HVF_SYSREG(0, 10, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR11_EL1, HVF_SYSREG(0, 11, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR11_EL1, HVF_SYSREG(0, 11, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR11_EL1, HVF_SYSREG(0, 11, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR11_EL1, HVF_SYSREG(0, 11, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR12_EL1, HVF_SYSREG(0, 12, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR12_EL1, HVF_SYSREG(0, 12, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR12_EL1, HVF_SYSREG(0, 12, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR12_EL1, HVF_SYSREG(0, 12, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR13_EL1, HVF_SYSREG(0, 13, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR13_EL1, HVF_SYSREG(0, 13, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR13_EL1, HVF_SYSREG(0, 13, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR13_EL1, HVF_SYSREG(0, 13, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR14_EL1, HVF_SYSREG(0, 14, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR14_EL1, HVF_SYSREG(0, 14, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR14_EL1, HVF_SYSREG(0, 14, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR14_EL1, HVF_SYSREG(0, 14, 2, 0, 7) },
-
-    { HV_SYS_REG_DBGBVR15_EL1, HVF_SYSREG(0, 15, 2, 0, 4) },
-    { HV_SYS_REG_DBGBCR15_EL1, HVF_SYSREG(0, 15, 2, 0, 5) },
-    { HV_SYS_REG_DBGWVR15_EL1, HVF_SYSREG(0, 15, 2, 0, 6) },
-    { HV_SYS_REG_DBGWCR15_EL1, HVF_SYSREG(0, 15, 2, 0, 7) },
-
-#ifdef SYNC_NO_RAW_REGS
-    /*
-     * The registers below are manually synced on init because they are
-     * marked as NO_RAW. We still list them to make number space sync easier.
-     */
-    { HV_SYS_REG_MDCCINT_EL1, HVF_SYSREG(0, 2, 2, 0, 0) },
-    { HV_SYS_REG_MIDR_EL1, HVF_SYSREG(0, 0, 3, 0, 0) },
-    { HV_SYS_REG_MPIDR_EL1, HVF_SYSREG(0, 0, 3, 0, 5) },
-    { HV_SYS_REG_ID_AA64PFR0_EL1, HVF_SYSREG(0, 4, 3, 0, 0) },
-#endif
-    { HV_SYS_REG_ID_AA64PFR1_EL1, HVF_SYSREG(0, 4, 3, 0, 1) },
-    { HV_SYS_REG_ID_AA64DFR0_EL1, HVF_SYSREG(0, 5, 3, 0, 0) },
-    { HV_SYS_REG_ID_AA64DFR1_EL1, HVF_SYSREG(0, 5, 3, 0, 1) },
-    { HV_SYS_REG_ID_AA64ISAR0_EL1, HVF_SYSREG(0, 6, 3, 0, 0) },
-    { HV_SYS_REG_ID_AA64ISAR1_EL1, HVF_SYSREG(0, 6, 3, 0, 1) },
-#ifdef SYNC_NO_MMFR0
-    /* We keep the hardware MMFR0 around. HW limits are there anyway */
-    { HV_SYS_REG_ID_AA64MMFR0_EL1, HVF_SYSREG(0, 7, 3, 0, 0) },
-#endif
-    { HV_SYS_REG_ID_AA64MMFR1_EL1, HVF_SYSREG(0, 7, 3, 0, 1) },
-    { HV_SYS_REG_ID_AA64MMFR2_EL1, HVF_SYSREG(0, 7, 3, 0, 2) },
-    /* Add ID_AA64MMFR3_EL1 here when HVF supports it */
-
-    { HV_SYS_REG_MDSCR_EL1, HVF_SYSREG(0, 2, 2, 0, 2) },
-    { HV_SYS_REG_SCTLR_EL1, HVF_SYSREG(1, 0, 3, 0, 0) },
-    { HV_SYS_REG_CPACR_EL1, HVF_SYSREG(1, 0, 3, 0, 2) },
-    { HV_SYS_REG_TTBR0_EL1, HVF_SYSREG(2, 0, 3, 0, 0) },
-    { HV_SYS_REG_TTBR1_EL1, HVF_SYSREG(2, 0, 3, 0, 1) },
-    { HV_SYS_REG_TCR_EL1, HVF_SYSREG(2, 0, 3, 0, 2) },
-
-    { HV_SYS_REG_APIAKEYLO_EL1, HVF_SYSREG(2, 1, 3, 0, 0) },
-    { HV_SYS_REG_APIAKEYHI_EL1, HVF_SYSREG(2, 1, 3, 0, 1) },
-    { HV_SYS_REG_APIBKEYLO_EL1, HVF_SYSREG(2, 1, 3, 0, 2) },
-    { HV_SYS_REG_APIBKEYHI_EL1, HVF_SYSREG(2, 1, 3, 0, 3) },
-    { HV_SYS_REG_APDAKEYLO_EL1, HVF_SYSREG(2, 2, 3, 0, 0) },
-    { HV_SYS_REG_APDAKEYHI_EL1, HVF_SYSREG(2, 2, 3, 0, 1) },
-    { HV_SYS_REG_APDBKEYLO_EL1, HVF_SYSREG(2, 2, 3, 0, 2) },
-    { HV_SYS_REG_APDBKEYHI_EL1, HVF_SYSREG(2, 2, 3, 0, 3) },
-    { HV_SYS_REG_APGAKEYLO_EL1, HVF_SYSREG(2, 3, 3, 0, 0) },
-    { HV_SYS_REG_APGAKEYHI_EL1, HVF_SYSREG(2, 3, 3, 0, 1) },
-
-    { HV_SYS_REG_SPSR_EL1, HVF_SYSREG(4, 0, 3, 0, 0) },
-    { HV_SYS_REG_ELR_EL1, HVF_SYSREG(4, 0, 3, 0, 1) },
-    { HV_SYS_REG_SP_EL0, HVF_SYSREG(4, 1, 3, 0, 0) },
-    { HV_SYS_REG_AFSR0_EL1, HVF_SYSREG(5, 1, 3, 0, 0) },
-    { HV_SYS_REG_AFSR1_EL1, HVF_SYSREG(5, 1, 3, 0, 1) },
-    { HV_SYS_REG_ESR_EL1, HVF_SYSREG(5, 2, 3, 0, 0) },
-    { HV_SYS_REG_FAR_EL1, HVF_SYSREG(6, 0, 3, 0, 0) },
-    { HV_SYS_REG_PAR_EL1, HVF_SYSREG(7, 4, 3, 0, 0) },
-    { HV_SYS_REG_MAIR_EL1, HVF_SYSREG(10, 2, 3, 0, 0) },
-    { HV_SYS_REG_AMAIR_EL1, HVF_SYSREG(10, 3, 3, 0, 0) },
-    { HV_SYS_REG_VBAR_EL1, HVF_SYSREG(12, 0, 3, 0, 0) },
-    { HV_SYS_REG_CONTEXTIDR_EL1, HVF_SYSREG(13, 0, 3, 0, 1) },
-    { HV_SYS_REG_TPIDR_EL1, HVF_SYSREG(13, 0, 3, 0, 4) },
-    { HV_SYS_REG_CNTKCTL_EL1, HVF_SYSREG(14, 1, 3, 0, 0) },
-    { HV_SYS_REG_CSSELR_EL1, HVF_SYSREG(0, 0, 3, 2, 0) },
-    { HV_SYS_REG_TPIDR_EL0, HVF_SYSREG(13, 0, 3, 3, 2) },
-    { HV_SYS_REG_TPIDRRO_EL0, HVF_SYSREG(13, 0, 3, 3, 3) },
-    { HV_SYS_REG_CNTV_CTL_EL0, HVF_SYSREG(14, 3, 3, 3, 1) },
-    { HV_SYS_REG_CNTV_CVAL_EL0, HVF_SYSREG(14, 3, 3, 3, 2) },
-    { HV_SYS_REG_SP_EL1, HVF_SYSREG(4, 1, 3, 4, 0) },
+#include "sysreg.c.inc"
 };
 
+#undef DEF_SYSREG
+
 int hvf_get_registers(CPUState *cpu)
 {
     ARMCPU *arm_cpu = ARM_CPU(cpu);
diff --git a/target/arm/hvf/sysreg.c.inc b/target/arm/hvf/sysreg.c.inc
new file mode 100644
index 0000000000..222698f1d1
--- /dev/null
+++ b/target/arm/hvf/sysreg.c.inc
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR0_EL1, 0, 0, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR0_EL1, 0, 0, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR0_EL1, 0, 0, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR0_EL1, 0, 0, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR1_EL1, 0, 1, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR1_EL1, 0, 1, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR1_EL1, 0, 1, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR1_EL1, 0, 1, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR2_EL1, 0, 2, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR2_EL1, 0, 2, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR2_EL1, 0, 2, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR2_EL1, 0, 2, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR3_EL1, 0, 3, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR3_EL1, 0, 3, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR3_EL1, 0, 3, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR3_EL1, 0, 3, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR4_EL1, 0, 4, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR4_EL1, 0, 4, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR4_EL1, 0, 4, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR4_EL1, 0, 4, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR5_EL1, 0, 5, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR5_EL1, 0, 5, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR5_EL1, 0, 5, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR5_EL1, 0, 5, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR6_EL1, 0, 6, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR6_EL1, 0, 6, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR6_EL1, 0, 6, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR6_EL1, 0, 6, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR7_EL1, 0, 7, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR7_EL1, 0, 7, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR7_EL1, 0, 7, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR7_EL1, 0, 7, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR8_EL1, 0, 8, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR8_EL1, 0, 8, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR8_EL1, 0, 8, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR8_EL1, 0, 8, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR9_EL1, 0, 9, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR9_EL1, 0, 9, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR9_EL1, 0, 9, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR9_EL1, 0, 9, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR10_EL1, 0, 10, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR10_EL1, 0, 10, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR10_EL1, 0, 10, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR10_EL1, 0, 10, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR11_EL1, 0, 11, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR11_EL1, 0, 11, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR11_EL1, 0, 11, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR11_EL1, 0, 11, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR12_EL1, 0, 12, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR12_EL1, 0, 12, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR12_EL1, 0, 12, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR12_EL1, 0, 12, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR13_EL1, 0, 13, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR13_EL1, 0, 13, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR13_EL1, 0, 13, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR13_EL1, 0, 13, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR14_EL1, 0, 14, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR14_EL1, 0, 14, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR14_EL1, 0, 14, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR14_EL1, 0, 14, 2, 0, 7)
+
+DEF_SYSREG(HV_SYS_REG_DBGBVR15_EL1, 0, 15, 2, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR15_EL1, 0, 15, 2, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR15_EL1, 0, 15, 2, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR15_EL1, 0, 15, 2, 0, 7)
+
+#ifdef SYNC_NO_RAW_REGS
+/*
+ * The registers below are manually synced on init because they are
+ * marked as NO_RAW. We still list them to make number space sync easier.
+ */
+DEF_SYSREG(HV_SYS_REG_MDCCINT_EL1, 0, 2, 2, 0, 0)
+DEF_SYSREG(HV_SYS_REG_MIDR_EL1, 0, 0, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_MPIDR_EL1, 0, 0, 3, 0, 5)
+DEF_SYSREG(HV_SYS_REG_ID_AA64PFR0_EL1, 0, 4, 3, 0, 0)
+#endif
+
+DEF_SYSREG(HV_SYS_REG_ID_AA64PFR1_EL1, 0, 4, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_ID_AA64DFR0_EL1, 0, 5, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_ID_AA64DFR1_EL1, 0, 5, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR0_EL1, 0, 6, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR1_EL1, 0, 6, 3, 0, 1)
+
+#ifdef SYNC_NO_MMFR0
+/* We keep the hardware MMFR0 around. HW limits are there anyway */
+DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR0_EL1, 0, 7, 3, 0, 0)
+#endif
+
+DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR1_EL1, 0, 7, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR2_EL1, 0, 7, 3, 0, 2)
+/* Add ID_AA64MMFR3_EL1 here when HVF supports it */
+
+DEF_SYSREG(HV_SYS_REG_MDSCR_EL1, 0, 2, 2, 0, 2)
+DEF_SYSREG(HV_SYS_REG_SCTLR_EL1, 1, 0, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_CPACR_EL1, 1, 0, 3, 0, 2)
+DEF_SYSREG(HV_SYS_REG_TTBR0_EL1, 2, 0, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_TTBR1_EL1, 2, 0, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_TCR_EL1, 2, 0, 3, 0, 2)
+
+DEF_SYSREG(HV_SYS_REG_APIAKEYLO_EL1, 2, 1, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_APIAKEYHI_EL1, 2, 1, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_APIBKEYLO_EL1, 2, 1, 3, 0, 2)
+DEF_SYSREG(HV_SYS_REG_APIBKEYHI_EL1, 2, 1, 3, 0, 3)
+DEF_SYSREG(HV_SYS_REG_APDAKEYLO_EL1, 2, 2, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_APDAKEYHI_EL1, 2, 2, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_APDBKEYLO_EL1, 2, 2, 3, 0, 2)
+DEF_SYSREG(HV_SYS_REG_APDBKEYHI_EL1, 2, 2, 3, 0, 3)
+DEF_SYSREG(HV_SYS_REG_APGAKEYLO_EL1, 2, 3, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_APGAKEYHI_EL1, 2, 3, 3, 0, 1)
+
+DEF_SYSREG(HV_SYS_REG_SPSR_EL1, 4, 0, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_ELR_EL1, 4, 0, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_SP_EL0, 4, 1, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_AFSR0_EL1, 5, 1, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_AFSR1_EL1, 5, 1, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_ESR_EL1, 5, 2, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_FAR_EL1, 6, 0, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_PAR_EL1, 7, 4, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_MAIR_EL1, 10, 2, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_AMAIR_EL1, 10, 3, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_VBAR_EL1, 12, 0, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_CONTEXTIDR_EL1, 13, 0, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_TPIDR_EL1, 13, 0, 3, 0, 4)
+DEF_SYSREG(HV_SYS_REG_CNTKCTL_EL1, 14, 1, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_CSSELR_EL1, 0, 0, 3, 2, 0)
+DEF_SYSREG(HV_SYS_REG_TPIDR_EL0, 13, 0, 3, 3, 2)
+DEF_SYSREG(HV_SYS_REG_TPIDRRO_EL0, 13, 0, 3, 3, 3)
+DEF_SYSREG(HV_SYS_REG_CNTV_CTL_EL0, 14, 3, 3, 3, 1)
+DEF_SYSREG(HV_SYS_REG_CNTV_CVAL_EL0, 14, 3, 3, 3, 2)
+DEF_SYSREG(HV_SYS_REG_SP_EL1, 4, 1, 3, 4, 0)
-- 
2.43.0



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

* [PATCH 4/7] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (2 preceding siblings ...)
  2025-08-27  1:03 ` [PATCH 03/61] target/arm/hvf: Split out sysreg.c.inc Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-28 12:22   ` Manos Pitsidianakis
  2025-08-27  1:03 ` [PATCH 04/61] target/arm/hvf: Reorder DEF_SYSREG arguments Richard Henderson
                   ` (61 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Conversion between KVM system registers ids and the HVF system
register ids is trivial.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index f0e4b75e6a..2577dc1c0c 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -403,6 +403,26 @@ struct hvf_sreg_match {
     uint32_t cp_idx;
 };
 
+/*
+ * QEMU uses KVM system register ids in the migration format.
+ * Conveniently, HVF uses the same encoding of the op* and cr* parameters
+ * within the low 16 bits of the ids.  Thus conversion between the
+ * formats is trivial.
+ */
+
+#define KVMID_TO_HVF(KVM)  ((KVM) & 0xffff)
+#define HVF_TO_KVMID(HVF)  \
+    (CP_REG_ARM64 | CP_REG_SIZE_U64 | CP_REG_ARM64_SYSREG | (HVF))
+
+/* Verify this at compile-time. */
+
+#define DEF_SYSREG(HVF_ID, ...) \
+  QEMU_BUILD_BUG_ON(HVF_ID != KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__)));
+
+#include "sysreg.c.inc"
+
+#undef DEF_SYSREG
+
 #define DEF_SYSREG(HVF_ID, crn, crm, op0, op1, op2) \
     { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
 
-- 
2.43.0



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

* [PATCH 04/61] target/arm/hvf: Reorder DEF_SYSREG arguments
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (3 preceding siblings ...)
  2025-08-27  1:03 ` [PATCH 4/7] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-28 12:17   ` Manos Pitsidianakis
  2025-08-27  1:03 ` [PATCH 05/61] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID Richard Henderson
                   ` (60 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

The order of the parameters in the Arm ARM is

  op0, op1, crn, crm, op2

Reorder the arguments of DEF_SYSREG to match.
Mechanical change to sysreg.c.inc using

  sed 's/\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)/\1,\4,\5,\2,\3/'

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c        |   2 +-
 target/arm/hvf/sysreg.c.inc | 224 ++++++++++++++++++------------------
 2 files changed, 113 insertions(+), 113 deletions(-)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index f0e4b75e6a..7b0413093d 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -403,7 +403,7 @@ struct hvf_sreg_match {
     uint32_t cp_idx;
 };
 
-#define DEF_SYSREG(HVF_ID, crn, crm, op0, op1, op2) \
+#define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2) \
     { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
 
 static struct hvf_sreg_match hvf_sreg_match[] = {
diff --git a/target/arm/hvf/sysreg.c.inc b/target/arm/hvf/sysreg.c.inc
index 222698f1d1..f2276d534e 100644
--- a/target/arm/hvf/sysreg.c.inc
+++ b/target/arm/hvf/sysreg.c.inc
@@ -1,146 +1,146 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR0_EL1, 0, 0, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR0_EL1, 0, 0, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR0_EL1, 0, 0, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR0_EL1, 0, 0, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR0_EL1, 2, 0, 0, 0, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR0_EL1, 2, 0, 0, 0, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR0_EL1, 2, 0, 0, 0, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR0_EL1, 2, 0, 0, 0, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR1_EL1, 0, 1, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR1_EL1, 0, 1, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR1_EL1, 0, 1, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR1_EL1, 0, 1, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR1_EL1, 2, 0, 0, 1, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR1_EL1, 2, 0, 0, 1, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR1_EL1, 2, 0, 0, 1, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR1_EL1, 2, 0, 0, 1, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR2_EL1, 0, 2, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR2_EL1, 0, 2, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR2_EL1, 0, 2, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR2_EL1, 0, 2, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR2_EL1, 2, 0, 0, 2, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR2_EL1, 2, 0, 0, 2, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR2_EL1, 2, 0, 0, 2, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR2_EL1, 2, 0, 0, 2, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR3_EL1, 0, 3, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR3_EL1, 0, 3, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR3_EL1, 0, 3, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR3_EL1, 0, 3, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR3_EL1, 2, 0, 0, 3, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR3_EL1, 2, 0, 0, 3, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR3_EL1, 2, 0, 0, 3, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR3_EL1, 2, 0, 0, 3, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR4_EL1, 0, 4, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR4_EL1, 0, 4, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR4_EL1, 0, 4, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR4_EL1, 0, 4, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR4_EL1, 2, 0, 0, 4, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR4_EL1, 2, 0, 0, 4, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR4_EL1, 2, 0, 0, 4, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR4_EL1, 2, 0, 0, 4, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR5_EL1, 0, 5, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR5_EL1, 0, 5, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR5_EL1, 0, 5, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR5_EL1, 0, 5, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR5_EL1, 2, 0, 0, 5, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR5_EL1, 2, 0, 0, 5, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR5_EL1, 2, 0, 0, 5, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR5_EL1, 2, 0, 0, 5, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR6_EL1, 0, 6, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR6_EL1, 0, 6, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR6_EL1, 0, 6, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR6_EL1, 0, 6, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR6_EL1, 2, 0, 0, 6, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR6_EL1, 2, 0, 0, 6, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR6_EL1, 2, 0, 0, 6, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR6_EL1, 2, 0, 0, 6, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR7_EL1, 0, 7, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR7_EL1, 0, 7, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR7_EL1, 0, 7, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR7_EL1, 0, 7, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR7_EL1, 2, 0, 0, 7, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR7_EL1, 2, 0, 0, 7, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR7_EL1, 2, 0, 0, 7, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR7_EL1, 2, 0, 0, 7, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR8_EL1, 0, 8, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR8_EL1, 0, 8, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR8_EL1, 0, 8, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR8_EL1, 0, 8, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR8_EL1, 2, 0, 0, 8, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR8_EL1, 2, 0, 0, 8, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR8_EL1, 2, 0, 0, 8, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR8_EL1, 2, 0, 0, 8, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR9_EL1, 0, 9, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR9_EL1, 0, 9, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR9_EL1, 0, 9, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR9_EL1, 0, 9, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR9_EL1, 2, 0, 0, 9, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR9_EL1, 2, 0, 0, 9, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR9_EL1, 2, 0, 0, 9, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR9_EL1, 2, 0, 0, 9, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR10_EL1, 0, 10, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR10_EL1, 0, 10, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR10_EL1, 0, 10, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR10_EL1, 0, 10, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR10_EL1, 2, 0, 0, 10, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR10_EL1, 2, 0, 0, 10, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR10_EL1, 2, 0, 0, 10, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR10_EL1, 2, 0, 0, 10, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR11_EL1, 0, 11, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR11_EL1, 0, 11, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR11_EL1, 0, 11, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR11_EL1, 0, 11, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR11_EL1, 2, 0, 0, 11, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR11_EL1, 2, 0, 0, 11, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR11_EL1, 2, 0, 0, 11, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR11_EL1, 2, 0, 0, 11, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR12_EL1, 0, 12, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR12_EL1, 0, 12, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR12_EL1, 0, 12, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR12_EL1, 0, 12, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR12_EL1, 2, 0, 0, 12, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR12_EL1, 2, 0, 0, 12, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR12_EL1, 2, 0, 0, 12, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR12_EL1, 2, 0, 0, 12, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR13_EL1, 0, 13, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR13_EL1, 0, 13, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR13_EL1, 0, 13, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR13_EL1, 0, 13, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR13_EL1, 2, 0, 0, 13, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR13_EL1, 2, 0, 0, 13, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR13_EL1, 2, 0, 0, 13, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR13_EL1, 2, 0, 0, 13, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR14_EL1, 0, 14, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR14_EL1, 0, 14, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR14_EL1, 0, 14, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR14_EL1, 0, 14, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR14_EL1, 2, 0, 0, 14, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR14_EL1, 2, 0, 0, 14, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR14_EL1, 2, 0, 0, 14, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR14_EL1, 2, 0, 0, 14, 7)
 
-DEF_SYSREG(HV_SYS_REG_DBGBVR15_EL1, 0, 15, 2, 0, 4)
-DEF_SYSREG(HV_SYS_REG_DBGBCR15_EL1, 0, 15, 2, 0, 5)
-DEF_SYSREG(HV_SYS_REG_DBGWVR15_EL1, 0, 15, 2, 0, 6)
-DEF_SYSREG(HV_SYS_REG_DBGWCR15_EL1, 0, 15, 2, 0, 7)
+DEF_SYSREG(HV_SYS_REG_DBGBVR15_EL1, 2, 0, 0, 15, 4)
+DEF_SYSREG(HV_SYS_REG_DBGBCR15_EL1, 2, 0, 0, 15, 5)
+DEF_SYSREG(HV_SYS_REG_DBGWVR15_EL1, 2, 0, 0, 15, 6)
+DEF_SYSREG(HV_SYS_REG_DBGWCR15_EL1, 2, 0, 0, 15, 7)
 
 #ifdef SYNC_NO_RAW_REGS
 /*
  * The registers below are manually synced on init because they are
  * marked as NO_RAW. We still list them to make number space sync easier.
  */
-DEF_SYSREG(HV_SYS_REG_MDCCINT_EL1, 0, 2, 2, 0, 0)
-DEF_SYSREG(HV_SYS_REG_MIDR_EL1, 0, 0, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_MPIDR_EL1, 0, 0, 3, 0, 5)
-DEF_SYSREG(HV_SYS_REG_ID_AA64PFR0_EL1, 0, 4, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_MDCCINT_EL1, 2, 0, 0, 2, 0)
+DEF_SYSREG(HV_SYS_REG_MIDR_EL1, 3, 0, 0, 0, 0)
+DEF_SYSREG(HV_SYS_REG_MPIDR_EL1, 3, 0, 0, 0, 5)
+DEF_SYSREG(HV_SYS_REG_ID_AA64PFR0_EL1, 3, 0, 0, 4, 0)
 #endif
 
-DEF_SYSREG(HV_SYS_REG_ID_AA64PFR1_EL1, 0, 4, 3, 0, 1)
-DEF_SYSREG(HV_SYS_REG_ID_AA64DFR0_EL1, 0, 5, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_ID_AA64DFR1_EL1, 0, 5, 3, 0, 1)
-DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR0_EL1, 0, 6, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR1_EL1, 0, 6, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_ID_AA64PFR1_EL1, 3, 0, 0, 4, 1)
+DEF_SYSREG(HV_SYS_REG_ID_AA64DFR0_EL1, 3, 0, 0, 5, 0)
+DEF_SYSREG(HV_SYS_REG_ID_AA64DFR1_EL1, 3, 0, 0, 5, 1)
+DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0)
+DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR1_EL1, 3, 0, 0, 6, 1)
 
 #ifdef SYNC_NO_MMFR0
 /* We keep the hardware MMFR0 around. HW limits are there anyway */
-DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR0_EL1, 0, 7, 3, 0, 0)
+DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0)
 #endif
 
-DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR1_EL1, 0, 7, 3, 0, 1)
-DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR2_EL1, 0, 7, 3, 0, 2)
+DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR1_EL1, 3, 0, 0, 7, 1)
+DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR2_EL1, 3, 0, 0, 7, 2)
 /* Add ID_AA64MMFR3_EL1 here when HVF supports it */
 
-DEF_SYSREG(HV_SYS_REG_MDSCR_EL1, 0, 2, 2, 0, 2)
-DEF_SYSREG(HV_SYS_REG_SCTLR_EL1, 1, 0, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_CPACR_EL1, 1, 0, 3, 0, 2)
-DEF_SYSREG(HV_SYS_REG_TTBR0_EL1, 2, 0, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_TTBR1_EL1, 2, 0, 3, 0, 1)
-DEF_SYSREG(HV_SYS_REG_TCR_EL1, 2, 0, 3, 0, 2)
+DEF_SYSREG(HV_SYS_REG_MDSCR_EL1, 2, 0, 0, 2, 2)
+DEF_SYSREG(HV_SYS_REG_SCTLR_EL1, 3, 0, 1, 0, 0)
+DEF_SYSREG(HV_SYS_REG_CPACR_EL1, 3, 0, 1, 0, 2)
+DEF_SYSREG(HV_SYS_REG_TTBR0_EL1, 3, 0, 2, 0, 0)
+DEF_SYSREG(HV_SYS_REG_TTBR1_EL1, 3, 0, 2, 0, 1)
+DEF_SYSREG(HV_SYS_REG_TCR_EL1, 3, 0, 2, 0, 2)
 
-DEF_SYSREG(HV_SYS_REG_APIAKEYLO_EL1, 2, 1, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_APIAKEYHI_EL1, 2, 1, 3, 0, 1)
-DEF_SYSREG(HV_SYS_REG_APIBKEYLO_EL1, 2, 1, 3, 0, 2)
-DEF_SYSREG(HV_SYS_REG_APIBKEYHI_EL1, 2, 1, 3, 0, 3)
-DEF_SYSREG(HV_SYS_REG_APDAKEYLO_EL1, 2, 2, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_APDAKEYHI_EL1, 2, 2, 3, 0, 1)
-DEF_SYSREG(HV_SYS_REG_APDBKEYLO_EL1, 2, 2, 3, 0, 2)
-DEF_SYSREG(HV_SYS_REG_APDBKEYHI_EL1, 2, 2, 3, 0, 3)
-DEF_SYSREG(HV_SYS_REG_APGAKEYLO_EL1, 2, 3, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_APGAKEYHI_EL1, 2, 3, 3, 0, 1)
+DEF_SYSREG(HV_SYS_REG_APIAKEYLO_EL1, 3, 0, 2, 1, 0)
+DEF_SYSREG(HV_SYS_REG_APIAKEYHI_EL1, 3, 0, 2, 1, 1)
+DEF_SYSREG(HV_SYS_REG_APIBKEYLO_EL1, 3, 0, 2, 1, 2)
+DEF_SYSREG(HV_SYS_REG_APIBKEYHI_EL1, 3, 0, 2, 1, 3)
+DEF_SYSREG(HV_SYS_REG_APDAKEYLO_EL1, 3, 0, 2, 2, 0)
+DEF_SYSREG(HV_SYS_REG_APDAKEYHI_EL1, 3, 0, 2, 2, 1)
+DEF_SYSREG(HV_SYS_REG_APDBKEYLO_EL1, 3, 0, 2, 2, 2)
+DEF_SYSREG(HV_SYS_REG_APDBKEYHI_EL1, 3, 0, 2, 2, 3)
+DEF_SYSREG(HV_SYS_REG_APGAKEYLO_EL1, 3, 0, 2, 3, 0)
+DEF_SYSREG(HV_SYS_REG_APGAKEYHI_EL1, 3, 0, 2, 3, 1)
 
-DEF_SYSREG(HV_SYS_REG_SPSR_EL1, 4, 0, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_ELR_EL1, 4, 0, 3, 0, 1)
-DEF_SYSREG(HV_SYS_REG_SP_EL0, 4, 1, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_AFSR0_EL1, 5, 1, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_AFSR1_EL1, 5, 1, 3, 0, 1)
-DEF_SYSREG(HV_SYS_REG_ESR_EL1, 5, 2, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_FAR_EL1, 6, 0, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_PAR_EL1, 7, 4, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_MAIR_EL1, 10, 2, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_AMAIR_EL1, 10, 3, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_VBAR_EL1, 12, 0, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_CONTEXTIDR_EL1, 13, 0, 3, 0, 1)
-DEF_SYSREG(HV_SYS_REG_TPIDR_EL1, 13, 0, 3, 0, 4)
-DEF_SYSREG(HV_SYS_REG_CNTKCTL_EL1, 14, 1, 3, 0, 0)
-DEF_SYSREG(HV_SYS_REG_CSSELR_EL1, 0, 0, 3, 2, 0)
-DEF_SYSREG(HV_SYS_REG_TPIDR_EL0, 13, 0, 3, 3, 2)
-DEF_SYSREG(HV_SYS_REG_TPIDRRO_EL0, 13, 0, 3, 3, 3)
-DEF_SYSREG(HV_SYS_REG_CNTV_CTL_EL0, 14, 3, 3, 3, 1)
-DEF_SYSREG(HV_SYS_REG_CNTV_CVAL_EL0, 14, 3, 3, 3, 2)
-DEF_SYSREG(HV_SYS_REG_SP_EL1, 4, 1, 3, 4, 0)
+DEF_SYSREG(HV_SYS_REG_SPSR_EL1, 3, 0, 4, 0, 0)
+DEF_SYSREG(HV_SYS_REG_ELR_EL1, 3, 0, 4, 0, 1)
+DEF_SYSREG(HV_SYS_REG_SP_EL0, 3, 0, 4, 1, 0)
+DEF_SYSREG(HV_SYS_REG_AFSR0_EL1, 3, 0, 5, 1, 0)
+DEF_SYSREG(HV_SYS_REG_AFSR1_EL1, 3, 0, 5, 1, 1)
+DEF_SYSREG(HV_SYS_REG_ESR_EL1, 3, 0, 5, 2, 0)
+DEF_SYSREG(HV_SYS_REG_FAR_EL1, 3, 0, 6, 0, 0)
+DEF_SYSREG(HV_SYS_REG_PAR_EL1, 3, 0, 7, 4, 0)
+DEF_SYSREG(HV_SYS_REG_MAIR_EL1, 3, 0, 10, 2, 0)
+DEF_SYSREG(HV_SYS_REG_AMAIR_EL1, 3, 0, 10, 3, 0)
+DEF_SYSREG(HV_SYS_REG_VBAR_EL1, 3, 0, 12, 0, 0)
+DEF_SYSREG(HV_SYS_REG_CONTEXTIDR_EL1, 3, 0, 13, 0, 1)
+DEF_SYSREG(HV_SYS_REG_TPIDR_EL1, 3, 0, 13, 0, 4)
+DEF_SYSREG(HV_SYS_REG_CNTKCTL_EL1, 3, 0, 14, 1, 0)
+DEF_SYSREG(HV_SYS_REG_CSSELR_EL1, 3, 2, 0, 0, 0)
+DEF_SYSREG(HV_SYS_REG_TPIDR_EL0, 3, 3, 13, 0, 2)
+DEF_SYSREG(HV_SYS_REG_TPIDRRO_EL0, 3, 3, 13, 0, 3)
+DEF_SYSREG(HV_SYS_REG_CNTV_CTL_EL0, 3, 3, 14, 3, 1)
+DEF_SYSREG(HV_SYS_REG_CNTV_CVAL_EL0, 3, 3, 14, 3, 2)
+DEF_SYSREG(HV_SYS_REG_SP_EL1, 3, 4, 4, 1, 0)
-- 
2.43.0



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

* [PATCH 05/61] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (4 preceding siblings ...)
  2025-08-27  1:03 ` [PATCH 04/61] target/arm/hvf: Reorder DEF_SYSREG arguments Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-29  6:59   ` Manos Pitsidianakis
  2025-08-27  1:03 ` [PATCH 5/7] target/arm/hvf: Remove hvf_sreg_match.key Richard Henderson
                   ` (59 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Conversion between KVM system registers ids and the HVF system
register ids is trivial.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 7b0413093d..47165bd29c 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -403,6 +403,26 @@ struct hvf_sreg_match {
     uint32_t cp_idx;
 };
 
+/*
+ * QEMU uses KVM system register ids in the migration format.
+ * Conveniently, HVF uses the same encoding of the op* and cr* parameters
+ * within the low 16 bits of the ids.  Thus conversion between the
+ * formats is trivial.
+ */
+
+#define KVMID_TO_HVF(KVM)  ((KVM) & 0xffff)
+#define HVF_TO_KVMID(HVF)  \
+    (CP_REG_ARM64 | CP_REG_SIZE_U64 | CP_REG_ARM64_SYSREG | (HVF))
+
+/* Verify this at compile-time. */
+
+#define DEF_SYSREG(HVF_ID, ...) \
+  QEMU_BUILD_BUG_ON(HVF_ID != KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__)));
+
+#include "sysreg.c.inc"
+
+#undef DEF_SYSREG
+
 #define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2) \
     { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
 
-- 
2.43.0



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

* [PATCH 5/7] target/arm/hvf: Remove hvf_sreg_match.key
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (5 preceding siblings ...)
  2025-08-27  1:03 ` [PATCH 05/61] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-27  1:03 ` [PATCH 06/61] " Richard Henderson
                   ` (58 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Use conversion functions instead of table lookup.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 2577dc1c0c..46e52e8d34 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -152,9 +152,6 @@ void hvf_arm_init_debug(void)
         g_array_sized_new(true, true, sizeof(HWWatchpoint), max_hw_wps);
 }
 
-#define HVF_SYSREG(crn, crm, op0, op1, op2) \
-        ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)
-
 #define SYSREG_OP0_SHIFT      20
 #define SYSREG_OP0_MASK       0x3
 #define SYSREG_OP0(sysreg)    ((sysreg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK)
@@ -399,7 +396,6 @@ static const struct hvf_reg_match hvf_fpreg_match[] = {
 
 struct hvf_sreg_match {
     int reg;
-    uint32_t key;
     uint32_t cp_idx;
 };
 
@@ -423,8 +419,7 @@ struct hvf_sreg_match {
 
 #undef DEF_SYSREG
 
-#define DEF_SYSREG(HVF_ID, crn, crm, op0, op1, op2) \
-    { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
+#define DEF_SYSREG(HVF_ID, crn, crm, op0, op1, op2)  { HVF_ID },
 
 static struct hvf_sreg_match hvf_sreg_match[] = {
 #include "sysreg.c.inc"
@@ -469,13 +464,16 @@ int hvf_get_registers(CPUState *cpu)
     pstate_write(env, val);
 
     for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
+        int hvf_id = hvf_sreg_match[i].reg;
+        uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
+
         if (hvf_sreg_match[i].cp_idx == -1) {
             continue;
         }
 
         if (cpu->accel->guest_debug_enabled) {
             /* Handle debug registers */
-            switch (hvf_sreg_match[i].reg) {
+            switch (hvf_id) {
             case HV_SYS_REG_DBGBVR0_EL1:
             case HV_SYS_REG_DBGBCR0_EL1:
             case HV_SYS_REG_DBGWVR0_EL1:
@@ -549,8 +547,10 @@ int hvf_get_registers(CPUState *cpu)
                  * vCPU but simply keep the values from the previous
                  * environment.
                  */
-                const ARMCPRegInfo *ri;
-                ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_sreg_match[i].key);
+                uint32_t key = kvm_to_cpreg_id(kvm_id);
+                const ARMCPRegInfo *ri =
+                    get_arm_cp_reginfo(arm_cpu->cp_regs, key);
+
                 val = read_raw_cp_reg(env, ri);
 
                 arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
@@ -559,7 +559,7 @@ int hvf_get_registers(CPUState *cpu)
             }
         }
 
-        ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_sreg_match[i].reg, &val);
+        ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_id, &val);
         assert_hvf_ok(ret);
 
         arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
@@ -606,13 +606,15 @@ int hvf_put_registers(CPUState *cpu)
 
     assert(write_cpustate_to_list(arm_cpu, false));
     for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
+        int hvf_id = hvf_sreg_match[i].reg;
+
         if (hvf_sreg_match[i].cp_idx == -1) {
             continue;
         }
 
         if (cpu->accel->guest_debug_enabled) {
             /* Handle debug registers */
-            switch (hvf_sreg_match[i].reg) {
+            switch (hvf_id) {
             case HV_SYS_REG_DBGBVR0_EL1:
             case HV_SYS_REG_DBGBCR0_EL1:
             case HV_SYS_REG_DBGWVR0_EL1:
@@ -687,7 +689,7 @@ int hvf_put_registers(CPUState *cpu)
         }
 
         val = arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx];
-        ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_sreg_match[i].reg, val);
+        ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_id, val);
         assert_hvf_ok(ret);
     }
 
@@ -922,14 +924,15 @@ int hvf_arch_init_vcpu(CPUState *cpu)
 
     /* Populate cp list for all known sysregs */
     for (i = 0; i < sregs_match_len; i++) {
-        const ARMCPRegInfo *ri;
-        uint32_t key = hvf_sreg_match[i].key;
+        int hvf_id = hvf_sreg_match[i].reg;
+        uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
+        uint32_t key = kvm_to_cpreg_id(kvm_id);
+        const ARMCPRegInfo *ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
 
-        ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
         if (ri) {
             assert(!(ri->type & ARM_CP_NO_RAW));
             hvf_sreg_match[i].cp_idx = sregs_cnt;
-            arm_cpu->cpreg_indexes[sregs_cnt++] = cpreg_to_kvm_id(key);
+            arm_cpu->cpreg_indexes[sregs_cnt++] = kvm_id;
         } else {
             hvf_sreg_match[i].cp_idx = -1;
         }
-- 
2.43.0



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

* [PATCH 06/61] target/arm/hvf: Remove hvf_sreg_match.key
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (6 preceding siblings ...)
  2025-08-27  1:03 ` [PATCH 5/7] target/arm/hvf: Remove hvf_sreg_match.key Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-29  7:00   ` Manos Pitsidianakis
  2025-08-27  1:03 ` [PATCH 6/7] target/arm/hvf: Replace hvf_sreg_match with hvf_sreg_list Richard Henderson
                   ` (57 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Use conversion functions instead of table lookup.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 47165bd29c..5fcfa9a999 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -152,9 +152,6 @@ void hvf_arm_init_debug(void)
         g_array_sized_new(true, true, sizeof(HWWatchpoint), max_hw_wps);
 }
 
-#define HVF_SYSREG(crn, crm, op0, op1, op2) \
-        ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)
-
 #define SYSREG_OP0_SHIFT      20
 #define SYSREG_OP0_MASK       0x3
 #define SYSREG_OP0(sysreg)    ((sysreg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK)
@@ -399,7 +396,6 @@ static const struct hvf_reg_match hvf_fpreg_match[] = {
 
 struct hvf_sreg_match {
     int reg;
-    uint32_t key;
     uint32_t cp_idx;
 };
 
@@ -423,8 +419,7 @@ struct hvf_sreg_match {
 
 #undef DEF_SYSREG
 
-#define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2) \
-    { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
+#define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2)  { HVF_ID },
 
 static struct hvf_sreg_match hvf_sreg_match[] = {
 #include "sysreg.c.inc"
@@ -469,13 +464,16 @@ int hvf_get_registers(CPUState *cpu)
     pstate_write(env, val);
 
     for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
+        int hvf_id = hvf_sreg_match[i].reg;
+        uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
+
         if (hvf_sreg_match[i].cp_idx == -1) {
             continue;
         }
 
         if (cpu->accel->guest_debug_enabled) {
             /* Handle debug registers */
-            switch (hvf_sreg_match[i].reg) {
+            switch (hvf_id) {
             case HV_SYS_REG_DBGBVR0_EL1:
             case HV_SYS_REG_DBGBCR0_EL1:
             case HV_SYS_REG_DBGWVR0_EL1:
@@ -549,8 +547,10 @@ int hvf_get_registers(CPUState *cpu)
                  * vCPU but simply keep the values from the previous
                  * environment.
                  */
-                const ARMCPRegInfo *ri;
-                ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_sreg_match[i].key);
+                uint32_t key = kvm_to_cpreg_id(kvm_id);
+                const ARMCPRegInfo *ri =
+                    get_arm_cp_reginfo(arm_cpu->cp_regs, key);
+
                 val = read_raw_cp_reg(env, ri);
 
                 arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
@@ -559,7 +559,7 @@ int hvf_get_registers(CPUState *cpu)
             }
         }
 
-        ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_sreg_match[i].reg, &val);
+        ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_id, &val);
         assert_hvf_ok(ret);
 
         arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
@@ -606,13 +606,15 @@ int hvf_put_registers(CPUState *cpu)
 
     assert(write_cpustate_to_list(arm_cpu, false));
     for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
+        int hvf_id = hvf_sreg_match[i].reg;
+
         if (hvf_sreg_match[i].cp_idx == -1) {
             continue;
         }
 
         if (cpu->accel->guest_debug_enabled) {
             /* Handle debug registers */
-            switch (hvf_sreg_match[i].reg) {
+            switch (hvf_id) {
             case HV_SYS_REG_DBGBVR0_EL1:
             case HV_SYS_REG_DBGBCR0_EL1:
             case HV_SYS_REG_DBGWVR0_EL1:
@@ -687,7 +689,7 @@ int hvf_put_registers(CPUState *cpu)
         }
 
         val = arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx];
-        ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_sreg_match[i].reg, val);
+        ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_id, val);
         assert_hvf_ok(ret);
     }
 
@@ -922,14 +924,15 @@ int hvf_arch_init_vcpu(CPUState *cpu)
 
     /* Populate cp list for all known sysregs */
     for (i = 0; i < sregs_match_len; i++) {
-        const ARMCPRegInfo *ri;
-        uint32_t key = hvf_sreg_match[i].key;
+        int hvf_id = hvf_sreg_match[i].reg;
+        uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
+        uint32_t key = kvm_to_cpreg_id(kvm_id);
+        const ARMCPRegInfo *ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
 
-        ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
         if (ri) {
             assert(!(ri->type & ARM_CP_NO_RAW));
             hvf_sreg_match[i].cp_idx = sregs_cnt;
-            arm_cpu->cpreg_indexes[sregs_cnt++] = cpreg_to_kvm_id(key);
+            arm_cpu->cpreg_indexes[sregs_cnt++] = kvm_id;
         } else {
             hvf_sreg_match[i].cp_idx = -1;
         }
-- 
2.43.0



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

* [PATCH 6/7] target/arm/hvf: Replace hvf_sreg_match with hvf_sreg_list
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (7 preceding siblings ...)
  2025-08-27  1:03 ` [PATCH 06/61] " Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-27  1:03 ` [PATCH 07/61] " Richard Henderson
                   ` (56 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Change hvf_get_registers and hvf_put_registers to iterate over
cpregs_indexes instead of hvf_sreg_match.

This lets us drop the cp_idx member of hvf_sreg_match, which leaves
only one member in the struct.  Replace the struct with a const array.
Instead of int, use the proper enum type: hv_sys_reg_t.
Rename from hvf_sreg_match to hvf_sreg_list because there is no
longer any matching going on.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 45 +++++++++++++++-----------------------------
 1 file changed, 15 insertions(+), 30 deletions(-)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 46e52e8d34..647eb675ef 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -394,11 +394,6 @@ static const struct hvf_reg_match hvf_fpreg_match[] = {
     { HV_SIMD_FP_REG_Q31, offsetof(CPUARMState, vfp.zregs[31]) },
 };
 
-struct hvf_sreg_match {
-    int reg;
-    uint32_t cp_idx;
-};
-
 /*
  * QEMU uses KVM system register ids in the migration format.
  * Conveniently, HVF uses the same encoding of the op* and cr* parameters
@@ -419,9 +414,9 @@ struct hvf_sreg_match {
 
 #undef DEF_SYSREG
 
-#define DEF_SYSREG(HVF_ID, crn, crm, op0, op1, op2)  { HVF_ID },
+#define DEF_SYSREG(HVF_ID, crn, crm, op0, op1, op2)  HVF_ID,
 
-static struct hvf_sreg_match hvf_sreg_match[] = {
+static const hv_sys_reg_t hvf_sreg_list[] = {
 #include "sysreg.c.inc"
 };
 
@@ -434,7 +429,7 @@ int hvf_get_registers(CPUState *cpu)
     hv_return_t ret;
     uint64_t val;
     hv_simd_fp_uchar16_t fpval;
-    int i;
+    int i, n;
 
     for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) {
         ret = hv_vcpu_get_reg(cpu->accel->fd, hvf_reg_match[i].reg, &val);
@@ -463,13 +458,9 @@ int hvf_get_registers(CPUState *cpu)
     assert_hvf_ok(ret);
     pstate_write(env, val);
 
-    for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
-        int hvf_id = hvf_sreg_match[i].reg;
-        uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
-
-        if (hvf_sreg_match[i].cp_idx == -1) {
-            continue;
-        }
+    for (i = 0, n = arm_cpu->cpreg_array_len; i < n; i++) {
+        uint64_t kvm_id = arm_cpu->cpreg_indexes[i];
+        int hvf_id = KVMID_TO_HVF(kvm_id);
 
         if (cpu->accel->guest_debug_enabled) {
             /* Handle debug registers */
@@ -553,7 +544,7 @@ int hvf_get_registers(CPUState *cpu)
 
                 val = read_raw_cp_reg(env, ri);
 
-                arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
+                arm_cpu->cpreg_values[i] = val;
                 continue;
             }
             }
@@ -562,7 +553,7 @@ int hvf_get_registers(CPUState *cpu)
         ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_id, &val);
         assert_hvf_ok(ret);
 
-        arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
+        arm_cpu->cpreg_values[i] = val;
     }
     assert(write_list_to_cpustate(arm_cpu));
 
@@ -578,7 +569,7 @@ int hvf_put_registers(CPUState *cpu)
     hv_return_t ret;
     uint64_t val;
     hv_simd_fp_uchar16_t fpval;
-    int i;
+    int i, n;
 
     for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) {
         val = *(uint64_t *)((void *)env + hvf_reg_match[i].offset);
@@ -605,12 +596,9 @@ int hvf_put_registers(CPUState *cpu)
     aarch64_save_sp(env, arm_current_el(env));
 
     assert(write_cpustate_to_list(arm_cpu, false));
-    for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
-        int hvf_id = hvf_sreg_match[i].reg;
-
-        if (hvf_sreg_match[i].cp_idx == -1) {
-            continue;
-        }
+    for (i = 0, n = arm_cpu->cpreg_array_len; i < n; i++) {
+        uint64_t kvm_id = arm_cpu->cpreg_indexes[i];
+        int hvf_id = KVMID_TO_HVF(kvm_id);
 
         if (cpu->accel->guest_debug_enabled) {
             /* Handle debug registers */
@@ -688,7 +676,7 @@ int hvf_put_registers(CPUState *cpu)
             }
         }
 
-        val = arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx];
+        val = arm_cpu->cpreg_values[i];
         ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_id, val);
         assert_hvf_ok(ret);
     }
@@ -899,7 +887,7 @@ int hvf_arch_init_vcpu(CPUState *cpu)
 {
     ARMCPU *arm_cpu = ARM_CPU(cpu);
     CPUARMState *env = &arm_cpu->env;
-    uint32_t sregs_match_len = ARRAY_SIZE(hvf_sreg_match);
+    uint32_t sregs_match_len = ARRAY_SIZE(hvf_sreg_list);
     uint32_t sregs_cnt = 0;
     uint64_t pfr;
     hv_return_t ret;
@@ -924,17 +912,14 @@ int hvf_arch_init_vcpu(CPUState *cpu)
 
     /* Populate cp list for all known sysregs */
     for (i = 0; i < sregs_match_len; i++) {
-        int hvf_id = hvf_sreg_match[i].reg;
+        hv_sys_reg_t hvf_id = hvf_sreg_list[i];
         uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
         uint32_t key = kvm_to_cpreg_id(kvm_id);
         const ARMCPRegInfo *ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
 
         if (ri) {
             assert(!(ri->type & ARM_CP_NO_RAW));
-            hvf_sreg_match[i].cp_idx = sregs_cnt;
             arm_cpu->cpreg_indexes[sregs_cnt++] = kvm_id;
-        } else {
-            hvf_sreg_match[i].cp_idx = -1;
         }
     }
     arm_cpu->cpreg_array_len = sregs_cnt;
-- 
2.43.0



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

* [PATCH 07/61] target/arm/hvf: Replace hvf_sreg_match with hvf_sreg_list
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (8 preceding siblings ...)
  2025-08-27  1:03 ` [PATCH 6/7] target/arm/hvf: Replace hvf_sreg_match with hvf_sreg_list Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-27  1:03 ` [PATCH 7/7] target/arm/hvf: Sort the cpreg_indexes array Richard Henderson
                   ` (55 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Change hvf_get_registers and hvf_put_registers to iterate over
cpregs_indexes instead of hvf_sreg_match.

This lets us drop the cp_idx member of hvf_sreg_match, which leaves
only one member in the struct.  Replace the struct with a const array.
Instead of int, use the proper enum type: hv_sys_reg_t.
Rename from hvf_sreg_match to hvf_sreg_list because there is no
longer any matching going on.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 45 +++++++++++++++-----------------------------
 1 file changed, 15 insertions(+), 30 deletions(-)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 5fcfa9a999..37d8f795eb 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -394,11 +394,6 @@ static const struct hvf_reg_match hvf_fpreg_match[] = {
     { HV_SIMD_FP_REG_Q31, offsetof(CPUARMState, vfp.zregs[31]) },
 };
 
-struct hvf_sreg_match {
-    int reg;
-    uint32_t cp_idx;
-};
-
 /*
  * QEMU uses KVM system register ids in the migration format.
  * Conveniently, HVF uses the same encoding of the op* and cr* parameters
@@ -419,9 +414,9 @@ struct hvf_sreg_match {
 
 #undef DEF_SYSREG
 
-#define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2)  { HVF_ID },
+#define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2)  HVF_ID,
 
-static struct hvf_sreg_match hvf_sreg_match[] = {
+static const hv_sys_reg_t hvf_sreg_list[] = {
 #include "sysreg.c.inc"
 };
 
@@ -434,7 +429,7 @@ int hvf_get_registers(CPUState *cpu)
     hv_return_t ret;
     uint64_t val;
     hv_simd_fp_uchar16_t fpval;
-    int i;
+    int i, n;
 
     for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) {
         ret = hv_vcpu_get_reg(cpu->accel->fd, hvf_reg_match[i].reg, &val);
@@ -463,13 +458,9 @@ int hvf_get_registers(CPUState *cpu)
     assert_hvf_ok(ret);
     pstate_write(env, val);
 
-    for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
-        int hvf_id = hvf_sreg_match[i].reg;
-        uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
-
-        if (hvf_sreg_match[i].cp_idx == -1) {
-            continue;
-        }
+    for (i = 0, n = arm_cpu->cpreg_array_len; i < n; i++) {
+        uint64_t kvm_id = arm_cpu->cpreg_indexes[i];
+        int hvf_id = KVMID_TO_HVF(kvm_id);
 
         if (cpu->accel->guest_debug_enabled) {
             /* Handle debug registers */
@@ -553,7 +544,7 @@ int hvf_get_registers(CPUState *cpu)
 
                 val = read_raw_cp_reg(env, ri);
 
-                arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
+                arm_cpu->cpreg_values[i] = val;
                 continue;
             }
             }
@@ -562,7 +553,7 @@ int hvf_get_registers(CPUState *cpu)
         ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_id, &val);
         assert_hvf_ok(ret);
 
-        arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
+        arm_cpu->cpreg_values[i] = val;
     }
     assert(write_list_to_cpustate(arm_cpu));
 
@@ -578,7 +569,7 @@ int hvf_put_registers(CPUState *cpu)
     hv_return_t ret;
     uint64_t val;
     hv_simd_fp_uchar16_t fpval;
-    int i;
+    int i, n;
 
     for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) {
         val = *(uint64_t *)((void *)env + hvf_reg_match[i].offset);
@@ -605,12 +596,9 @@ int hvf_put_registers(CPUState *cpu)
     aarch64_save_sp(env, arm_current_el(env));
 
     assert(write_cpustate_to_list(arm_cpu, false));
-    for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
-        int hvf_id = hvf_sreg_match[i].reg;
-
-        if (hvf_sreg_match[i].cp_idx == -1) {
-            continue;
-        }
+    for (i = 0, n = arm_cpu->cpreg_array_len; i < n; i++) {
+        uint64_t kvm_id = arm_cpu->cpreg_indexes[i];
+        int hvf_id = KVMID_TO_HVF(kvm_id);
 
         if (cpu->accel->guest_debug_enabled) {
             /* Handle debug registers */
@@ -688,7 +676,7 @@ int hvf_put_registers(CPUState *cpu)
             }
         }
 
-        val = arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx];
+        val = arm_cpu->cpreg_values[i];
         ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_id, val);
         assert_hvf_ok(ret);
     }
@@ -899,7 +887,7 @@ int hvf_arch_init_vcpu(CPUState *cpu)
 {
     ARMCPU *arm_cpu = ARM_CPU(cpu);
     CPUARMState *env = &arm_cpu->env;
-    uint32_t sregs_match_len = ARRAY_SIZE(hvf_sreg_match);
+    uint32_t sregs_match_len = ARRAY_SIZE(hvf_sreg_list);
     uint32_t sregs_cnt = 0;
     uint64_t pfr;
     hv_return_t ret;
@@ -924,17 +912,14 @@ int hvf_arch_init_vcpu(CPUState *cpu)
 
     /* Populate cp list for all known sysregs */
     for (i = 0; i < sregs_match_len; i++) {
-        int hvf_id = hvf_sreg_match[i].reg;
+        hv_sys_reg_t hvf_id = hvf_sreg_list[i];
         uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
         uint32_t key = kvm_to_cpreg_id(kvm_id);
         const ARMCPRegInfo *ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
 
         if (ri) {
             assert(!(ri->type & ARM_CP_NO_RAW));
-            hvf_sreg_match[i].cp_idx = sregs_cnt;
             arm_cpu->cpreg_indexes[sregs_cnt++] = kvm_id;
-        } else {
-            hvf_sreg_match[i].cp_idx = -1;
         }
     }
     arm_cpu->cpreg_array_len = sregs_cnt;
-- 
2.43.0



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

* [PATCH 7/7] target/arm/hvf: Sort the cpreg_indexes array
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (9 preceding siblings ...)
  2025-08-27  1:03 ` [PATCH 07/61] " Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-27  1:03 ` [PATCH 08/61] " Richard Henderson
                   ` (54 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 647eb675ef..88ed96be11 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -925,6 +925,9 @@ int hvf_arch_init_vcpu(CPUState *cpu)
     arm_cpu->cpreg_array_len = sregs_cnt;
     arm_cpu->cpreg_vmstate_array_len = sregs_cnt;
 
+    /* cpreg tuples must be in strictly ascending order */
+    qsort(arm_cpu->cpreg_indexes, sregs_cnt, sizeof(uint64_t), compare_u64);
+
     assert(write_cpustate_to_list(arm_cpu, false));
 
     /* Set CP_NO_RAW system registers on init */
-- 
2.43.0



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

* [PATCH 08/61] target/arm/hvf: Sort the cpreg_indexes array
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (10 preceding siblings ...)
  2025-08-27  1:03 ` [PATCH 7/7] target/arm/hvf: Sort the cpreg_indexes array Richard Henderson
@ 2025-08-27  1:03 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 09/61] target/arm/hvf: Use raw_read, raw_write to access Richard Henderson
                   ` (53 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 37d8f795eb..5f19347bc5 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -925,6 +925,9 @@ int hvf_arch_init_vcpu(CPUState *cpu)
     arm_cpu->cpreg_array_len = sregs_cnt;
     arm_cpu->cpreg_vmstate_array_len = sregs_cnt;
 
+    /* cpreg tuples must be in strictly ascending order */
+    qsort(arm_cpu->cpreg_indexes, sregs_cnt, sizeof(uint64_t), compare_u64);
+
     assert(write_cpustate_to_list(arm_cpu, false));
 
     /* Set CP_NO_RAW system registers on init */
-- 
2.43.0



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

* [PATCH 09/61] target/arm/hvf: Use raw_read, raw_write to access
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (11 preceding siblings ...)
  2025-08-27  1:03 ` [PATCH 08/61] " Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 10/61] target/arm: Use raw_write in cp_reg_reset Richard Henderson
                   ` (52 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Reduce the places that know about field types by 2.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 5f19347bc5..9dffa99ed1 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1153,7 +1153,7 @@ static bool hvf_sysreg_read_cp(CPUState *cpu, uint32_t reg, uint64_t *val)
         } else if (ri->readfn) {
             *val = ri->readfn(env, ri);
         } else {
-            *val = CPREG_FIELD64(env, ri);
+            *val = raw_read(env, ri);
         }
         trace_hvf_vgic_read(ri->name, *val);
         return true;
@@ -1435,7 +1435,7 @@ static bool hvf_sysreg_write_cp(CPUState *cpu, uint32_t reg, uint64_t val)
         if (ri->writefn) {
             ri->writefn(env, ri, val);
         } else {
-            CPREG_FIELD64(env, ri) = val;
+            raw_write(env, ri, val);
         }
 
         trace_hvf_vgic_write(ri->name, val);
-- 
2.43.0



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

* [PATCH 10/61] target/arm: Use raw_write in cp_reg_reset
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (12 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 09/61] target/arm/hvf: Use raw_read, raw_write to access Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-29  7:05   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 11/61] target/arm: Rename all ARMCPRegInfo from opaque to ri Richard Henderson
                   ` (51 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Reduce the places that know about field types by 1.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index e2b2337399..ed40e102fc 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -192,14 +192,8 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
      * This is basically only used for fields in non-core coprocessors
      * (like the pxa2xx ones).
      */
-    if (!ri->fieldoffset) {
-        return;
-    }
-
-    if (cpreg_field_is_64bit(ri)) {
-        CPREG_FIELD64(&cpu->env, ri) = ri->resetvalue;
-    } else {
-        CPREG_FIELD32(&cpu->env, ri) = ri->resetvalue;
+    if (ri->fieldoffset) {
+        raw_write(&cpu->env, ri, ri->resetvalue);
     }
 }
 
-- 
2.43.0



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

* [PATCH 11/61] target/arm: Rename all ARMCPRegInfo from opaque to ri
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (13 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 10/61] target/arm: Use raw_write in cp_reg_reset Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-28 12:41   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 12/61] target/arm: Drop define_one_arm_cp_reg_with_opaque Richard Henderson
                   ` (50 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

These pointers are no opaque, they have a specific type.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h | 10 +++++-----
 target/arm/helper.c |  6 +++---
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index c9506aa6d5..3344a02bd3 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -841,15 +841,15 @@ typedef struct ARMCPRegInfo ARMCPRegInfo;
  * Access functions for coprocessor registers. These cannot fail and
  * may not raise exceptions.
  */
-typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque);
-typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
+typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *ri);
+typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *ri,
                        uint64_t value);
 /* Access permission check functions for coprocessor registers. */
 typedef CPAccessResult CPAccessFn(CPUARMState *env,
-                                  const ARMCPRegInfo *opaque,
+                                  const ARMCPRegInfo *ri,
                                   bool isread);
 /* Hook function for register reset */
-typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
+typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *ri);
 
 #define CP_ANY 0xff
 
@@ -1075,7 +1075,7 @@ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value);
  * CPResetFn that does nothing, for use if no reset is required even
  * if fieldoffset is non zero.
  */
-void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque);
+void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri);
 
 /*
  * Return true if this reginfo struct's field in the cpu state struct
diff --git a/target/arm/helper.c b/target/arm/helper.c
index d230f9e766..e03cbc0394 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -1067,7 +1067,7 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
       .resetvalue = 0 },
 };
 
-static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque)
+static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     ARMCPU *cpu = env_archcpu(env);
 
@@ -5407,7 +5407,7 @@ static const ARMCPRegInfo rndr_reginfo[] = {
       .access = PL0_R, .readfn = rndr_readfn },
 };
 
-static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
+static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *ri,
                           uint64_t value)
 {
 #ifdef CONFIG_TCG
@@ -7730,7 +7730,7 @@ uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri)
     return 0;
 }
 
-void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque)
+void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     /* Helper coprocessor reset function for do-nothing-on-reset registers */
 }
-- 
2.43.0



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

* [PATCH 12/61] target/arm: Drop define_one_arm_cp_reg_with_opaque
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (14 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 11/61] target/arm: Rename all ARMCPRegInfo from opaque to ri Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-29  7:06   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 13/61] target/arm: Restrict the scope of CPREG_FIELD32, CPREG_FIELD64 Richard Henderson
                   ` (49 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

The last use of this interface was removed in 603bc048a27f
("hw/arm: Remove pxa2xx_pic").  As the comment in gicv3
stated, keeping pointer references to cpregs has SMP issues,
so avoid future temptation by removing the interface.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h       | 32 ++++++++------------------------
 hw/intc/arm_gicv3_cpuif.c | 10 +---------
 target/arm/helper.c       | 29 +++++++++++------------------
 3 files changed, 20 insertions(+), 51 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 3344a02bd3..b610716c24 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -906,11 +906,7 @@ struct ARMCPRegInfo {
      */
     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
-     * register read/write functions, since they are passed the ARMCPRegInfo*.
-     */
+    /* This is used only by VHE. */
     void *opaque;
     /*
      * Value of this register, if it is ARM_CP_CONST. Otherwise, if
@@ -1004,27 +1000,15 @@ struct ARMCPRegInfo {
 #define CPREG_FIELD64(env, ri) \
     (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
 
-void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, const ARMCPRegInfo *reg,
-                                       void *opaque);
+void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs);
+void define_arm_cp_regs_len(ARMCPU *cpu, const ARMCPRegInfo *regs, size_t len);
 
-static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs)
-{
-    define_one_arm_cp_reg_with_opaque(cpu, regs, NULL);
-}
-
-void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
-                                        void *opaque, size_t len);
-
-#define define_arm_cp_regs_with_opaque(CPU, REGS, OPAQUE)               \
-    do {                                                                \
-        QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0);                       \
-        define_arm_cp_regs_with_opaque_len(CPU, REGS, OPAQUE,           \
-                                           ARRAY_SIZE(REGS));           \
+#define define_arm_cp_regs(CPU, REGS)                           \
+    do {                                                        \
+        QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0);               \
+        define_arm_cp_regs_len(CPU, REGS, ARRAY_SIZE(REGS));    \
     } while (0)
 
-#define define_arm_cp_regs(CPU, REGS) \
-    define_arm_cp_regs_with_opaque(CPU, REGS, NULL)
-
 const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp);
 
 /*
@@ -1143,7 +1127,7 @@ static inline bool arm_cpreg_traps_in_nv(const ARMCPRegInfo *ri)
      * 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().)
+     * define_one_arm_cp_reg().)
      * 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.
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 4b4cf09157..72e91f971a 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -3037,15 +3037,7 @@ void gicv3_init_cpuif(GICv3State *s)
          *  cpu->gic_pribits
          */
 
-        /* Note that we can't just use the GICv3CPUState as an opaque pointer
-         * in define_arm_cp_regs_with_opaque(), because when we're called back
-         * it might be with code translated by CPU 0 but run by CPU 1, in
-         * which case we'd get the wrong value.
-         * So instead we define the regs with no ri->opaque info, and
-         * get back to the GICv3CPUState from the CPUARMState.
-         *
-         * These CP regs callbacks can be called from either TCG or HVF code.
-         */
+        /* These CP regs callbacks can be called from either TCG or HVF. */
         define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
 
         /*
diff --git a/target/arm/helper.c b/target/arm/helper.c
index e03cbc0394..35a176ea3b 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7256,12 +7256,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
 }
 
 /*
- * Private utility function for define_one_arm_cp_reg_with_opaque():
+ * Private utility function for define_one_arm_cp_reg():
  * add a single reginfo struct to the hash table.
  */
 static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
-                                   void *opaque, CPState state,
-                                   CPSecureState secstate,
+                                   CPState state, CPSecureState secstate,
                                    int crm, int opc1, int opc2,
                                    const char *name)
 {
@@ -7349,9 +7348,6 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
     r2->opc2 = opc2;
     r2->state = state;
     r2->secure = secstate;
-    if (opaque) {
-        r2->opaque = opaque;
-    }
 
     if (make_const) {
         /* This should not have been a very special register to begin. */
@@ -7456,8 +7452,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
 }
 
 
-void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
-                                       const ARMCPRegInfo *r, void *opaque)
+void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
 {
     /*
      * Define implementations of coprocessor registers.
@@ -7616,7 +7611,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
                         if (nxs_ri.fgt) {
                             nxs_ri.fgt |= R_FGT_NXS_MASK;
                         }
-                        add_cpreg_to_hashtable(cpu, &nxs_ri, opaque, state,
+                        add_cpreg_to_hashtable(cpu, &nxs_ri, state,
                                                ARM_CP_SECSTATE_NS,
                                                crm, opc1, opc2, name);
                     }
@@ -7630,17 +7625,17 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
                         switch (r->secure) {
                         case ARM_CP_SECSTATE_S:
                         case ARM_CP_SECSTATE_NS:
-                            add_cpreg_to_hashtable(cpu, r, opaque, state,
+                            add_cpreg_to_hashtable(cpu, r, state,
                                                    r->secure, crm, opc1, opc2,
                                                    r->name);
                             break;
                         case ARM_CP_SECSTATE_BOTH:
                             name = g_strdup_printf("%s_S", r->name);
-                            add_cpreg_to_hashtable(cpu, r, opaque, state,
+                            add_cpreg_to_hashtable(cpu, r, state,
                                                    ARM_CP_SECSTATE_S,
                                                    crm, opc1, opc2, name);
                             g_free(name);
-                            add_cpreg_to_hashtable(cpu, r, opaque, state,
+                            add_cpreg_to_hashtable(cpu, r, state,
                                                    ARM_CP_SECSTATE_NS,
                                                    crm, opc1, opc2, r->name);
                             break;
@@ -7652,7 +7647,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
                          * AArch64 registers get mapped to non-secure instance
                          * of AArch32
                          */
-                        add_cpreg_to_hashtable(cpu, r, opaque, state,
+                        add_cpreg_to_hashtable(cpu, r, state,
                                                ARM_CP_SECSTATE_NS,
                                                crm, opc1, opc2, r->name);
                     }
@@ -7663,12 +7658,10 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
 }
 
 /* Define a whole list of registers */
-void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
-                                        void *opaque, size_t len)
+void define_arm_cp_regs_len(ARMCPU *cpu, const ARMCPRegInfo *regs, size_t len)
 {
-    size_t i;
-    for (i = 0; i < len; ++i) {
-        define_one_arm_cp_reg_with_opaque(cpu, regs + i, opaque);
+    for (size_t i = 0; i < len; ++i) {
+        define_one_arm_cp_reg(cpu, regs + i);
     }
 }
 
-- 
2.43.0



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

* [PATCH 13/61] target/arm: Restrict the scope of CPREG_FIELD32, CPREG_FIELD64
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (15 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 12/61] target/arm: Drop define_one_arm_cp_reg_with_opaque Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-29  7:09   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 14/61] target/arm: Replace cpreg_field_is_64bit with cpreg_field_type Richard Henderson
                   ` (48 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h |  9 ---------
 target/arm/helper.c | 12 ++++++++++++
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index b610716c24..812fb1340a 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -991,15 +991,6 @@ struct ARMCPRegInfo {
     CPAccessFn *orig_accessfn;
 };
 
-/*
- * Macros which are lvalues for the field in CPUARMState for the
- * ARMCPRegInfo *ri.
- */
-#define CPREG_FIELD32(env, ri) \
-    (*(uint32_t *)((char *)(env) + (ri)->fieldoffset))
-#define CPREG_FIELD64(env, ri) \
-    (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
-
 void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs);
 void define_arm_cp_regs_len(ARMCPU *cpu, const ARMCPRegInfo *regs, size_t len);
 
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 35a176ea3b..3a9d8f0ddc 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -51,6 +51,15 @@ int compare_u64(const void *a, const void *b)
     return 0;
 }
 
+/*
+ * Macros which are lvalues for the field in CPUARMState for the
+ * ARMCPRegInfo *ri.
+ */
+#define CPREG_FIELD32(env, ri) \
+    (*(uint32_t *)((char *)(env) + (ri)->fieldoffset))
+#define CPREG_FIELD64(env, ri) \
+    (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
+
 uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     assert(ri->fieldoffset);
@@ -71,6 +80,9 @@ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
     }
 }
 
+#undef CPREG_FIELD32
+#undef CPREG_FIELD64
+
 static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     return (char *)env + ri->fieldoffset;
-- 
2.43.0



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

* [PATCH 14/61] target/arm: Replace cpreg_field_is_64bit with cpreg_field_type
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (16 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 13/61] target/arm: Restrict the scope of CPREG_FIELD32, CPREG_FIELD64 Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-29  7:13   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 15/61] target/arm: Add CP_REG_AA32_64BIT_{SHIFT,MASK} Richard Henderson
                   ` (47 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Prepare for 128-bit fields by using a better query api.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h  | 10 ++++++----
 target/arm/gdbstub.c |  7 +++++--
 target/arm/helper.c  | 18 +++++++++++++-----
 3 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 812fb1340a..b6c8eff0dd 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -22,6 +22,7 @@
 #define TARGET_ARM_CPREGS_H
 
 #include "hw/registerfields.h"
+#include "exec/memop.h"
 #include "target/arm/kvm-consts.h"
 #include "cpu.h"
 
@@ -1053,12 +1054,13 @@ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value);
 void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri);
 
 /*
- * Return true if this reginfo struct's field in the cpu state struct
- * is 64 bits wide.
+ * Return MO_32 if the field in CPUARMState is uint32_t or
+ * MO_64 if the field in CPUARMState is uint64_t.
  */
-static inline bool cpreg_field_is_64bit(const ARMCPRegInfo *ri)
+static inline MemOp cpreg_field_type(const ARMCPRegInfo *ri)
 {
-    return (ri->state == ARM_CP_STATE_AA64) || (ri->type & ARM_CP_64BIT);
+    return (ri->state == ARM_CP_STATE_AA64 || (ri->type & ARM_CP_64BIT)
+            ? MO_64 : MO_32);
 }
 
 static inline bool cp_access_ok(int current_el,
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index ce4497ad7c..e2fc389170 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -247,10 +247,13 @@ static int arm_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg)
     key = cpu->dyn_sysreg_feature.data.cpregs.keys[reg];
     ri = get_arm_cp_reginfo(cpu->cp_regs, key);
     if (ri) {
-        if (cpreg_field_is_64bit(ri)) {
+        switch (cpreg_field_type(ri)) {
+        case MO_64:
             return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri));
-        } else {
+        case MO_32:
             return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri));
+        default:
+            g_assert_not_reached();
         }
     }
     return 0;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3a9d8f0ddc..c4103d958a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -63,20 +63,28 @@ int compare_u64(const void *a, const void *b)
 uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     assert(ri->fieldoffset);
-    if (cpreg_field_is_64bit(ri)) {
+    switch (cpreg_field_type(ri)) {
+    case MO_64:
         return CPREG_FIELD64(env, ri);
-    } else {
+    case MO_32:
         return CPREG_FIELD32(env, ri);
+    default:
+        g_assert_not_reached();
     }
 }
 
 void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     assert(ri->fieldoffset);
-    if (cpreg_field_is_64bit(ri)) {
+    switch (cpreg_field_type(ri)) {
+    case MO_64:
         CPREG_FIELD64(env, ri) = value;
-    } else {
+        break;
+    case MO_32:
         CPREG_FIELD32(env, ri) = value;
+        break;
+    default:
+        g_assert_not_reached();
     }
 }
 
@@ -2748,7 +2756,7 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                             uint64_t value)
 {
     /* If the ASID changes (with a 64-bit write), we must flush the TLB.  */
-    if (cpreg_field_is_64bit(ri) &&
+    if (cpreg_field_type(ri) == MO_64 &&
         extract64(raw_read(env, ri) ^ value, 48, 16) != 0) {
         ARMCPU *cpu = env_archcpu(env);
         tlb_flush(CPU(cpu));
-- 
2.43.0



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

* [PATCH 15/61] target/arm: Add CP_REG_AA32_64BIT_{SHIFT,MASK}
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (17 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 14/61] target/arm: Replace cpreg_field_is_64bit with cpreg_field_type Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-29  7:27   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 16/61] target/arm: Rename CP_REG_AA32_NS_{SHIFT,MASK} Richard Henderson
                   ` (46 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Give a name to the bit we're already using.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index b6c8eff0dd..3dc4c9927b 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -178,9 +178,14 @@ enum {
 #define CP_REG_NS_SHIFT 29
 #define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT)
 
+/* Distinguish 32-bit and 64-bit views of AArch32 system registers. */
+#define CP_REG_AA32_64BIT_SHIFT  15
+#define CP_REG_AA32_64BIT_MASK   (1 << CP_REG_AA32_64BIT_SHIFT)
+
 #define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2)   \
-    ((ns) << CP_REG_NS_SHIFT | ((cp) << 16) | ((is64) << 15) |   \
-     ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
+    (((ns) << CP_REG_NS_SHIFT) |                            \
+     ((is64) << CP_REG_AA32_64BIT_SHIFT) |                  \
+     ((cp) << 16) | ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
 
 #define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
     (CP_REG_AA64_MASK |                                 \
@@ -202,7 +207,7 @@ static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
         cpregid |= CP_REG_AA64_MASK;
     } else {
         if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) {
-            cpregid |= (1 << 15);
+            cpregid |= CP_REG_AA32_64BIT_MASK;
         }
 
         /*
@@ -226,8 +231,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
         kvmid = cpregid & ~CP_REG_AA64_MASK;
         kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM64;
     } else {
-        kvmid = cpregid & ~(1 << 15);
-        if (cpregid & (1 << 15)) {
+        kvmid = cpregid & ~CP_REG_AA32_64BIT_MASK;
+        if (cpregid & CP_REG_AA32_64BIT_MASK) {
             kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM;
         } else {
             kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM;
-- 
2.43.0



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

* [PATCH 16/61] target/arm: Rename CP_REG_AA32_NS_{SHIFT,MASK}
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (18 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 15/61] target/arm: Add CP_REG_AA32_64BIT_{SHIFT,MASK} Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-29  7:30   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 17/61] target/arm: Convert init_cpreg_list to g_hash_table_foreach Richard Henderson
                   ` (45 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Rename from CP_REG_NS_* to emphasize this is
specific to AArch32.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 3dc4c9927b..7ebe404163 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -175,15 +175,15 @@ enum {
  * add a bit to distinguish between secure and non-secure cpregs in the
  * hashtable.
  */
-#define CP_REG_NS_SHIFT 29
-#define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT)
+#define CP_REG_AA32_NS_SHIFT     29
+#define CP_REG_AA32_NS_MASK      (1 << CP_REG_AA32_NS_SHIFT)
 
 /* Distinguish 32-bit and 64-bit views of AArch32 system registers. */
 #define CP_REG_AA32_64BIT_SHIFT  15
 #define CP_REG_AA32_64BIT_MASK   (1 << CP_REG_AA32_64BIT_SHIFT)
 
 #define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2)   \
-    (((ns) << CP_REG_NS_SHIFT) |                            \
+    (((ns) << CP_REG_AA32_NS_SHIFT) |                       \
      ((is64) << CP_REG_AA32_64BIT_SHIFT) |                  \
      ((cp) << 16) | ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
 
@@ -214,7 +214,7 @@ static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
          * KVM is always non-secure so add the NS flag on AArch32 register
          * entries.
          */
-         cpregid |= 1 << CP_REG_NS_SHIFT;
+         cpregid |= CP_REG_AA32_NS_MASK;
     }
     return cpregid;
 }
-- 
2.43.0



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

* [PATCH 17/61] target/arm: Convert init_cpreg_list to g_hash_table_foreach
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (19 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 16/61] target/arm: Rename CP_REG_AA32_NS_{SHIFT,MASK} Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 18/61] target/arm: Remove cp argument to ENCODE_AA64_CP_REG Richard Henderson
                   ` (44 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Adjust count_cpreg and add_cpreg_to_list to be used with
g_hash_table_foreach instead of g_list_foreach.  In this way we have
the ARMCPRegInfo pointer directly rather than having to look it up
from the key.

Delay the sorting of the cpreg_indexes until after add_cpreg_to_list.
This allows us to sort the data that we actually care about,
the kvm id, as computed within add_cpreg_to_list, instead of
having to repeatedly compute the kvm id within cpreg_key_compare.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 54 ++++++++++++++++++---------------------------
 1 file changed, 21 insertions(+), 33 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index c4103d958a..268cad905f 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -229,11 +229,11 @@ bool write_list_to_cpustate(ARMCPU *cpu)
     return ok;
 }
 
-static void add_cpreg_to_list(gpointer key, gpointer opaque)
+static void add_cpreg_to_list(gpointer key, gpointer value, gpointer opaque)
 {
     ARMCPU *cpu = opaque;
     uint32_t regidx = (uintptr_t)key;
-    const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
+    const ARMCPRegInfo *ri = value;
 
     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) {
         cpu->cpreg_indexes[cpu->cpreg_array_len] = cpreg_to_kvm_id(regidx);
@@ -242,61 +242,49 @@ static void add_cpreg_to_list(gpointer key, gpointer opaque)
     }
 }
 
-static void count_cpreg(gpointer key, gpointer opaque)
+static void count_cpreg(gpointer key, gpointer value, gpointer opaque)
 {
     ARMCPU *cpu = opaque;
-    const ARMCPRegInfo *ri;
-
-    ri = g_hash_table_lookup(cpu->cp_regs, key);
+    const ARMCPRegInfo *ri = value;
 
     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) {
         cpu->cpreg_array_len++;
     }
 }
 
-static gint cpreg_key_compare(gconstpointer a, gconstpointer b, gpointer d)
-{
-    uint64_t aidx = cpreg_to_kvm_id((uintptr_t)a);
-    uint64_t bidx = cpreg_to_kvm_id((uintptr_t)b);
-
-    if (aidx > bidx) {
-        return 1;
-    }
-    if (aidx < bidx) {
-        return -1;
-    }
-    return 0;
-}
-
 void init_cpreg_list(ARMCPU *cpu)
 {
     /*
      * Initialise the cpreg_tuples[] array based on the cp_regs hash.
      * Note that we require cpreg_tuples[] to be sorted by key ID.
      */
-    GList *keys;
     int arraylen;
 
-    keys = g_hash_table_get_keys(cpu->cp_regs);
-    keys = g_list_sort_with_data(keys, cpreg_key_compare, NULL);
-
     cpu->cpreg_array_len = 0;
-
-    g_list_foreach(keys, count_cpreg, cpu);
+    g_hash_table_foreach(cpu->cp_regs, count_cpreg, cpu);
 
     arraylen = cpu->cpreg_array_len;
-    cpu->cpreg_indexes = g_new(uint64_t, arraylen);
-    cpu->cpreg_values = g_new(uint64_t, arraylen);
-    cpu->cpreg_vmstate_indexes = g_new(uint64_t, arraylen);
-    cpu->cpreg_vmstate_values = g_new(uint64_t, arraylen);
-    cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len;
+    if (arraylen) {
+        cpu->cpreg_indexes = g_new(uint64_t, arraylen);
+        cpu->cpreg_values = g_new(uint64_t, arraylen);
+        cpu->cpreg_vmstate_indexes = g_new(uint64_t, arraylen);
+        cpu->cpreg_vmstate_values = g_new(uint64_t, arraylen);
+    } else {
+        cpu->cpreg_indexes = NULL;
+        cpu->cpreg_values = NULL;
+        cpu->cpreg_vmstate_indexes = NULL;
+        cpu->cpreg_vmstate_values = NULL;
+    }
+    cpu->cpreg_vmstate_array_len = arraylen;
     cpu->cpreg_array_len = 0;
 
-    g_list_foreach(keys, add_cpreg_to_list, cpu);
+    g_hash_table_foreach(cpu->cp_regs, add_cpreg_to_list, cpu);
 
     assert(cpu->cpreg_array_len == arraylen);
 
-    g_list_free(keys);
+    if (arraylen) {
+        qsort(cpu->cpreg_indexes, arraylen, sizeof(uint64_t), compare_u64);
+    }
 }
 
 bool arm_pan_enabled(CPUARMState *env)
-- 
2.43.0



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

* [PATCH 18/61] target/arm: Remove cp argument to ENCODE_AA64_CP_REG
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (20 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 17/61] target/arm: Convert init_cpreg_list to g_hash_table_foreach Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-29  7:36   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 19/61] target/arm: Reorder ENCODE_AA64_CP_REG arguments Richard Henderson
                   ` (43 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

All invocations were required to pass the same value,
CP_REG_ARM64_SYSREG_CP.  Bake that in to the result directly.
Remove CP_REG_ARM64_SYSREG_CP as unused.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h            |  5 ++---
 target/arm/kvm-consts.h        |  3 ---
 target/arm/helper.c            | 11 +++++------
 target/arm/hvf/hvf.c           |  3 +--
 target/arm/tcg/translate-a64.c |  6 ++----
 5 files changed, 10 insertions(+), 18 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 7ebe404163..95b0b9c78e 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -187,9 +187,8 @@ enum {
      ((is64) << CP_REG_AA32_64BIT_SHIFT) |                  \
      ((cp) << 16) | ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
 
-#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
-    (CP_REG_AA64_MASK |                                 \
-     ((cp) << CP_REG_ARM_COPROC_SHIFT) |                \
+#define ENCODE_AA64_CP_REG(crn, crm, op0, op1, op2) \
+    (CP_REG_AA64_MASK | CP_REG_ARM64_SYSREG |           \
      ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) |         \
      ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) |         \
      ((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) |         \
diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h
index fdb305eea1..54ae5da7ce 100644
--- a/target/arm/kvm-consts.h
+++ b/target/arm/kvm-consts.h
@@ -160,9 +160,6 @@ MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53);
 #define CP_REG_ARM64_SYSREG_OP2_MASK   0x0000000000000007
 #define CP_REG_ARM64_SYSREG_OP2_SHIFT  0
 
-/* No kernel define but it's useful to QEMU */
-#define CP_REG_ARM64_SYSREG_CP (CP_REG_ARM64_SYSREG >> CP_REG_ARM_COPROC_SHIFT)
-
 MISMATCH_CHECK(CP_REG_ARM64, KVM_REG_ARM64);
 MISMATCH_CHECK(CP_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_MASK);
 MISMATCH_CHECK(CP_REG_ARM_COPROC_SHIFT, KVM_REG_ARM_COPROC_SHIFT);
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 268cad905f..93cae888e2 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4527,7 +4527,7 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
     };
 
 #define K(op0, op1, crn, crm, op2) \
-    ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)
+    ENCODE_AA64_CP_REG(crn, crm, op0, op1, op2)
 
     static const struct E2HAlias aliases[] = {
         { K(3, 0,  1, 0, 0), K(3, 4,  1, 0, 0), K(3, 5, 1, 0, 0),
@@ -7297,10 +7297,9 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
          * in their AArch64 view (the .cp value may be non-zero for the
          * benefit of the AArch32 view).
          */
-        if (cp == 0 || r->state == ARM_CP_STATE_BOTH) {
-            cp = CP_REG_ARM64_SYSREG_CP;
-        }
-        key = ENCODE_AA64_CP_REG(cp, r->crn, crm, r->opc0, opc1, opc2);
+        assert(cp == 0 || r->state == ARM_CP_STATE_BOTH);
+        cp = 0;
+        key = ENCODE_AA64_CP_REG(r->crn, crm, r->opc0, opc1, opc2);
         break;
     default:
         g_assert_not_reached();
@@ -7525,7 +7524,7 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
         }
         break;
     case ARM_CP_STATE_AA64:
-        assert(r->cp == 0 || r->cp == CP_REG_ARM64_SYSREG_CP);
+        assert(r->cp == 0);
         break;
     default:
         g_assert_not_reached();
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 9dffa99ed1..af03fc7fc1 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1124,8 +1124,7 @@ static bool is_id_sysreg(uint32_t reg)
 
 static uint32_t hvf_reg2cp_reg(uint32_t reg)
 {
-    return ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
-                              (reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK,
+    return ENCODE_AA64_CP_REG((reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK,
                               (reg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK,
                               (reg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK,
                               (reg >> SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK,
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index dbf47595db..743c5a10e1 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2466,8 +2466,7 @@ static void handle_sys(DisasContext *s, bool isread,
                        unsigned int op0, unsigned int op1, unsigned int op2,
                        unsigned int crn, unsigned int crm, unsigned int rt)
 {
-    uint32_t key = ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
-                                      crn, crm, op0, op1, op2);
+    uint32_t key = ENCODE_AA64_CP_REG(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;
@@ -2603,8 +2602,7 @@ static void handle_sys(DisasContext *s, bool isread,
          * 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);
+        key = ENCODE_AA64_CP_REG(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));
-- 
2.43.0



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

* [PATCH 19/61] target/arm: Reorder ENCODE_AA64_CP_REG arguments
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (21 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 18/61] target/arm: Remove cp argument to ENCODE_AA64_CP_REG Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-29  7:40   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 20/61] target/arm: Split out add_cpreg_to_hashtable_aa{32,64} Richard Henderson
                   ` (42 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

The order of the parameters in the Arm ARM is

  op0, op1, crn, crm, op2

Reorder the arguments of ENCODE_AA64_CP_REG to match.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h            | 2 +-
 target/arm/helper.c            | 4 ++--
 target/arm/hvf/hvf.c           | 6 +++---
 target/arm/tcg/translate-a64.c | 4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 95b0b9c78e..7bdf6cf847 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -187,7 +187,7 @@ enum {
      ((is64) << CP_REG_AA32_64BIT_SHIFT) |                  \
      ((cp) << 16) | ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
 
-#define ENCODE_AA64_CP_REG(crn, crm, op0, op1, op2) \
+#define ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2) \
     (CP_REG_AA64_MASK | CP_REG_ARM64_SYSREG |           \
      ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) |         \
      ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) |         \
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 93cae888e2..b48b669a6a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4527,7 +4527,7 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
     };
 
 #define K(op0, op1, crn, crm, op2) \
-    ENCODE_AA64_CP_REG(crn, crm, op0, op1, op2)
+    ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2)
 
     static const struct E2HAlias aliases[] = {
         { K(3, 0,  1, 0, 0), K(3, 4,  1, 0, 0), K(3, 5, 1, 0, 0),
@@ -7299,7 +7299,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
          */
         assert(cp == 0 || r->state == ARM_CP_STATE_BOTH);
         cp = 0;
-        key = ENCODE_AA64_CP_REG(r->crn, crm, r->opc0, opc1, opc2);
+        key = ENCODE_AA64_CP_REG(r->opc0, opc1, r->crn, crm, opc2);
         break;
     default:
         g_assert_not_reached();
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index af03fc7fc1..bda57614ed 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1124,10 +1124,10 @@ static bool is_id_sysreg(uint32_t reg)
 
 static uint32_t hvf_reg2cp_reg(uint32_t reg)
 {
-    return ENCODE_AA64_CP_REG((reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK,
-                              (reg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK,
-                              (reg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK,
+    return ENCODE_AA64_CP_REG((reg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK,
                               (reg >> SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK,
+                              (reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK,
+                              (reg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK,
                               (reg >> SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK);
 }
 
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 743c5a10e1..58303c224f 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2466,7 +2466,7 @@ static void handle_sys(DisasContext *s, bool isread,
                        unsigned int op0, unsigned int op1, unsigned int op2,
                        unsigned int crn, unsigned int crm, unsigned int rt)
 {
-    uint32_t key = ENCODE_AA64_CP_REG(crn, crm, op0, op1, op2);
+    uint32_t key = ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2);
     const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
     bool need_exit_tb = false;
     bool nv_trap_to_el2 = false;
@@ -2602,7 +2602,7 @@ static void handle_sys(DisasContext *s, bool isread,
          * 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(crn, crm, op0, 0, op2);
+        key = ENCODE_AA64_CP_REG(op0, 0, crn, crm, op2);
         ri = get_arm_cp_reginfo(s->cp_regs, key);
         assert(ri);
         assert(cp_access_ok(s->current_el, ri, isread));
-- 
2.43.0



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

* [PATCH 20/61] target/arm: Split out add_cpreg_to_hashtable_aa{32,64}
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (22 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 19/61] target/arm: Reorder ENCODE_AA64_CP_REG arguments Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 21/61] target/arm: Improve asserts in define_one_arm_cp_reg Richard Henderson
                   ` (41 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

The nesting level for the inner loop of define_one_arm_cp_reg
was overly deep.  Split out that code into two functions, for
the AArch32 and AArch64 paths separately.  Simplify the innermost
loop to a switch statement over r->state.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 147 +++++++++++++++++++++++---------------------
 1 file changed, 76 insertions(+), 71 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index b48b669a6a..7ce03336fe 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7458,6 +7458,66 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
     g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r2);
 }
 
+static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, const ARMCPRegInfo *r,
+                                        int crm, int opc1, int opc2)
+{
+    /*
+     * Under AArch32 CP registers can be common
+     * (same for secure and non-secure world) or banked.
+     */
+    char *name;
+
+    assert(!(r->type & ARM_CP_ADD_TLBI_NXS)); /* aa64 only */
+
+    switch (r->secure) {
+    case ARM_CP_SECSTATE_S:
+    case ARM_CP_SECSTATE_NS:
+        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32,
+                               r->secure, crm, opc1, opc2, r->name);
+        break;
+    case ARM_CP_SECSTATE_BOTH:
+        name = g_strdup_printf("%s_S", r->name);
+        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32,
+                               ARM_CP_SECSTATE_S, crm, opc1, opc2, name);
+        g_free(name);
+        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32,
+                               ARM_CP_SECSTATE_NS, crm, opc1, opc2, r->name);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, const ARMCPRegInfo *r,
+                                        int crm, int opc1, int opc2)
+{
+    if ((r->type & ARM_CP_ADD_TLBI_NXS) &&
+        cpu_isar_feature(aa64_xs, cpu)) {
+        /*
+         * This is a TLBI insn which has an NXS variant. The
+         * NXS variant is at the same encoding except that
+         * crn is +1, and has the same behaviour except for
+         * fine-grained trapping. Add the NXS insn here and
+         * then fall through to add the normal register.
+         * add_cpreg_to_hashtable() copies the cpreg struct
+         * and name that it is passed, so it's OK to use
+         * a local struct here.
+         */
+        ARMCPRegInfo nxs_ri = *r;
+        g_autofree char *name = g_strdup_printf("%sNXS", r->name);
+
+        assert(nxs_ri.crn < 0xf);
+        nxs_ri.crn++;
+        if (nxs_ri.fgt) {
+            nxs_ri.fgt |= R_FGT_NXS_MASK;
+        }
+        add_cpreg_to_hashtable(cpu, &nxs_ri, ARM_CP_STATE_AA64,
+                               ARM_CP_SECSTATE_NS, crm, opc1, opc2, name);
+    }
+
+    add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA64, ARM_CP_SECSTATE_NS,
+                           crm, opc1, opc2, r->name);
+}
 
 void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
 {
@@ -7485,14 +7545,12 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
      * bits; the ARM_CP_64BIT* flag applies only to the AArch32 view of
      * the register, if any.
      */
-    int crm, opc1, opc2;
     int crmmin = (r->crm == CP_ANY) ? 0 : r->crm;
     int crmmax = (r->crm == CP_ANY) ? 15 : r->crm;
     int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1;
     int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1;
     int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2;
     int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
-    CPState state;
 
     /* 64 bit registers have only CRm and Opc1 fields */
     assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn)));
@@ -7589,75 +7647,22 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
         }
     }
 
-    for (crm = crmmin; crm <= crmmax; crm++) {
-        for (opc1 = opc1min; opc1 <= opc1max; opc1++) {
-            for (opc2 = opc2min; opc2 <= opc2max; opc2++) {
-                for (state = ARM_CP_STATE_AA32;
-                     state <= ARM_CP_STATE_AA64; state++) {
-                    if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
-                        continue;
-                    }
-                    if ((r->type & ARM_CP_ADD_TLBI_NXS) &&
-                        cpu_isar_feature(aa64_xs, cpu)) {
-                        /*
-                         * This is a TLBI insn which has an NXS variant. The
-                         * NXS variant is at the same encoding except that
-                         * crn is +1, and has the same behaviour except for
-                         * fine-grained trapping. Add the NXS insn here and
-                         * then fall through to add the normal register.
-                         * add_cpreg_to_hashtable() copies the cpreg struct
-                         * and name that it is passed, so it's OK to use
-                         * a local struct here.
-                         */
-                        ARMCPRegInfo nxs_ri = *r;
-                        g_autofree char *name = g_strdup_printf("%sNXS", r->name);
-
-                        assert(state == ARM_CP_STATE_AA64);
-                        assert(nxs_ri.crn < 0xf);
-                        nxs_ri.crn++;
-                        if (nxs_ri.fgt) {
-                            nxs_ri.fgt |= R_FGT_NXS_MASK;
-                        }
-                        add_cpreg_to_hashtable(cpu, &nxs_ri, state,
-                                               ARM_CP_SECSTATE_NS,
-                                               crm, opc1, opc2, name);
-                    }
-                    if (state == ARM_CP_STATE_AA32) {
-                        /*
-                         * Under AArch32 CP registers can be common
-                         * (same for secure and non-secure world) or banked.
-                         */
-                        char *name;
-
-                        switch (r->secure) {
-                        case ARM_CP_SECSTATE_S:
-                        case ARM_CP_SECSTATE_NS:
-                            add_cpreg_to_hashtable(cpu, r, state,
-                                                   r->secure, crm, opc1, opc2,
-                                                   r->name);
-                            break;
-                        case ARM_CP_SECSTATE_BOTH:
-                            name = g_strdup_printf("%s_S", r->name);
-                            add_cpreg_to_hashtable(cpu, r, state,
-                                                   ARM_CP_SECSTATE_S,
-                                                   crm, opc1, opc2, name);
-                            g_free(name);
-                            add_cpreg_to_hashtable(cpu, r, state,
-                                                   ARM_CP_SECSTATE_NS,
-                                                   crm, opc1, opc2, r->name);
-                            break;
-                        default:
-                            g_assert_not_reached();
-                        }
-                    } else {
-                        /*
-                         * AArch64 registers get mapped to non-secure instance
-                         * of AArch32
-                         */
-                        add_cpreg_to_hashtable(cpu, r, state,
-                                               ARM_CP_SECSTATE_NS,
-                                               crm, opc1, opc2, r->name);
-                    }
+    for (int crm = crmmin; crm <= crmmax; crm++) {
+        for (int opc1 = opc1min; opc1 <= opc1max; opc1++) {
+            for (int opc2 = opc2min; opc2 <= opc2max; opc2++) {
+                switch (r->state) {
+                case ARM_CP_STATE_AA32:
+                    add_cpreg_to_hashtable_aa32(cpu, r, crm, opc1, opc2);
+                    break;
+                case ARM_CP_STATE_AA64:
+                    add_cpreg_to_hashtable_aa64(cpu, r, crm, opc1, opc2);
+                    break;
+                case ARM_CP_STATE_BOTH:
+                    add_cpreg_to_hashtable_aa32(cpu, r, crm, opc1, opc2);
+                    add_cpreg_to_hashtable_aa64(cpu, r, crm, opc1, opc2);
+                    break;
+                default:
+                    g_assert_not_reached();
                 }
             }
         }
-- 
2.43.0



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

* [PATCH 21/61] target/arm: Improve asserts in define_one_arm_cp_reg
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (23 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 20/61] target/arm: Split out add_cpreg_to_hashtable_aa{32,64} Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 22/61] target/arm: Move cp processing to define_one_arm_cp_reg Richard Henderson
                   ` (40 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Reject ARM_CP_64BIT with ARM_CP_STATE_BOTH, because encoding
constrains prevent it from working.  Remove some extra parens;
distribute ! across && to simplify.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 7ce03336fe..da6a8f0a8f 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7552,12 +7552,17 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
     int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2;
     int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
 
-    /* 64 bit registers have only CRm and Opc1 fields */
-    assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn)));
+    /*
+     * AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless.
+     * Moreover, the encoding test just following in general prevents
+     * shared encoding so ARM_CP_STATE_BOTH won't work either.
+     */
+    assert(r->state == ARM_CP_STATE_AA32 || !(r->type & ARM_CP_64BIT));
+    /* AArch32 64-bit registers have only CRm and Opc1 fields. */
+    assert(!(r->type & ARM_CP_64BIT) || !(r->opc2 || r->crn));
     /* op0 only exists in the AArch64 encodings */
-    assert((r->state != ARM_CP_STATE_AA32) || (r->opc0 == 0));
-    /* AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless */
-    assert((r->state != ARM_CP_STATE_AA64) || !(r->type & ARM_CP_64BIT));
+    assert(r->state != ARM_CP_STATE_AA32 || r->opc0 == 0);
+
     /*
      * This API is only for Arm's system coprocessors (14 and 15) or
      * (M-profile or v7A-and-earlier only) for implementation defined
-- 
2.43.0



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

* [PATCH 22/61] target/arm: Move cp processing to define_one_arm_cp_reg
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (24 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 21/61] target/arm: Improve asserts in define_one_arm_cp_reg Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 23/61] target/arm: Move cpreg elimination " Richard Henderson
                   ` (39 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Processing of cp was split between add_cpreg_to_hashtable and
define_one_arm_cp_reg.  Unify it all to the top-level function.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 53 +++++++++++++++++++--------------------------
 1 file changed, 22 insertions(+), 31 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index da6a8f0a8f..a9d6ed1270 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7269,7 +7269,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
  */
 static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
                                    CPState state, CPSecureState secstate,
-                                   int crm, int opc1, int opc2,
+                                   int cp, int crm, int opc1, int opc2,
                                    const char *name)
 {
     CPUARMState *env = &cpu->env;
@@ -7277,28 +7277,14 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
     ARMCPRegInfo *r2;
     bool is64 = r->type & ARM_CP_64BIT;
     bool ns = secstate & ARM_CP_SECSTATE_NS;
-    int cp = r->cp;
     size_t name_len;
     bool make_const;
 
     switch (state) {
     case ARM_CP_STATE_AA32:
-        /* We assume it is a cp15 register if the .cp field is left unset. */
-        if (cp == 0 && r->state == ARM_CP_STATE_BOTH) {
-            cp = 15;
-        }
         key = ENCODE_CP_REG(cp, is64, ns, r->crn, crm, opc1, opc2);
         break;
     case ARM_CP_STATE_AA64:
-        /*
-         * To allow abbreviation of ARMCPRegInfo definitions, we treat
-         * cp == 0 as equivalent to the value for "standard guest-visible
-         * sysreg".  STATE_BOTH definitions are also always "standard sysreg"
-         * in their AArch64 view (the .cp value may be non-zero for the
-         * benefit of the AArch32 view).
-         */
-        assert(cp == 0 || r->state == ARM_CP_STATE_BOTH);
-        cp = 0;
         key = ENCODE_AA64_CP_REG(r->opc0, opc1, r->crn, crm, opc2);
         break;
     default:
@@ -7459,7 +7445,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
 }
 
 static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, const ARMCPRegInfo *r,
-                                        int crm, int opc1, int opc2)
+                                        int cp, int crm, int opc1, int opc2)
 {
     /*
      * Under AArch32 CP registers can be common
@@ -7472,16 +7458,16 @@ static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, const ARMCPRegInfo *r,
     switch (r->secure) {
     case ARM_CP_SECSTATE_S:
     case ARM_CP_SECSTATE_NS:
-        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32,
-                               r->secure, crm, opc1, opc2, r->name);
+        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, r->secure,
+                               cp, crm, opc1, opc2, r->name);
         break;
     case ARM_CP_SECSTATE_BOTH:
         name = g_strdup_printf("%s_S", r->name);
-        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32,
-                               ARM_CP_SECSTATE_S, crm, opc1, opc2, name);
+        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, ARM_CP_SECSTATE_S,
+                               cp, crm, opc1, opc2, name);
         g_free(name);
-        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32,
-                               ARM_CP_SECSTATE_NS, crm, opc1, opc2, r->name);
+        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, ARM_CP_SECSTATE_NS,
+                               cp, crm, opc1, opc2, r->name);
         break;
     default:
         g_assert_not_reached();
@@ -7512,11 +7498,11 @@ static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, const ARMCPRegInfo *r,
             nxs_ri.fgt |= R_FGT_NXS_MASK;
         }
         add_cpreg_to_hashtable(cpu, &nxs_ri, ARM_CP_STATE_AA64,
-                               ARM_CP_SECSTATE_NS, crm, opc1, opc2, name);
+                               ARM_CP_SECSTATE_NS, 0, crm, opc1, opc2, name);
     }
 
     add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA64, ARM_CP_SECSTATE_NS,
-                           crm, opc1, opc2, r->name);
+                           0, crm, opc1, opc2, r->name);
 }
 
 void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
@@ -7551,6 +7537,7 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
     int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1;
     int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2;
     int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
+    int cp = r->cp;
 
     /*
      * AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless.
@@ -7573,21 +7560,25 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
      */
     switch (r->state) {
     case ARM_CP_STATE_BOTH:
-        /* 0 has a special meaning, but otherwise the same rules as AA32. */
-        if (r->cp == 0) {
+        /*
+         * If the cp field is left unset, assume cp15.
+         * Otherwise apply the same rules as AA32.
+         */
+        if (cp == 0) {
+            cp = 15;
             break;
         }
         /* fall through */
     case ARM_CP_STATE_AA32:
         if (arm_feature(&cpu->env, ARM_FEATURE_V8) &&
             !arm_feature(&cpu->env, ARM_FEATURE_M)) {
-            assert(r->cp >= 14 && r->cp <= 15);
+            assert(cp >= 14 && cp <= 15);
         } else {
-            assert(r->cp < 8 || (r->cp >= 14 && r->cp <= 15));
+            assert(cp < 8 || (cp >= 14 && cp <= 15));
         }
         break;
     case ARM_CP_STATE_AA64:
-        assert(r->cp == 0);
+        assert(cp == 0);
         break;
     default:
         g_assert_not_reached();
@@ -7657,13 +7648,13 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
             for (int opc2 = opc2min; opc2 <= opc2max; opc2++) {
                 switch (r->state) {
                 case ARM_CP_STATE_AA32:
-                    add_cpreg_to_hashtable_aa32(cpu, r, crm, opc1, opc2);
+                    add_cpreg_to_hashtable_aa32(cpu, r, cp, crm, opc1, opc2);
                     break;
                 case ARM_CP_STATE_AA64:
                     add_cpreg_to_hashtable_aa64(cpu, r, crm, opc1, opc2);
                     break;
                 case ARM_CP_STATE_BOTH:
-                    add_cpreg_to_hashtable_aa32(cpu, r, crm, opc1, opc2);
+                    add_cpreg_to_hashtable_aa32(cpu, r, cp, crm, opc1, opc2);
                     add_cpreg_to_hashtable_aa64(cpu, r, crm, opc1, opc2);
                     break;
                 default:
-- 
2.43.0



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

* [PATCH 23/61] target/arm: Move cpreg elimination to define_one_arm_cp_reg
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (25 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 22/61] target/arm: Move cp processing to define_one_arm_cp_reg Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 24/61] target/arm: Add key parameter to add_cpreg_to_hashtable Richard Henderson
                   ` (38 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Eliminate unused registers earlier, so that by the time we
arrive in add_cpreg_to_hashtable we never skip.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 123 +++++++++++++++++++++++---------------------
 1 file changed, 64 insertions(+), 59 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index a9d6ed1270..02c155418b 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7278,7 +7278,6 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
     bool is64 = r->type & ARM_CP_64BIT;
     bool ns = secstate & ARM_CP_SECSTATE_NS;
     size_t name_len;
-    bool make_const;
 
     switch (state) {
     case ARM_CP_STATE_AA32:
@@ -7299,32 +7298,6 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
         }
     }
 
-    /*
-     * Eliminate registers that are not present because the EL is missing.
-     * Doing this here makes it easier to put all registers for a given
-     * feature into the same ARMCPRegInfo array and define them all at once.
-     */
-    make_const = false;
-    if (arm_feature(env, ARM_FEATURE_EL3)) {
-        /*
-         * An EL2 register without EL2 but with EL3 is (usually) RES0.
-         * See rule RJFFP in section D1.1.3 of DDI0487H.a.
-         */
-        int min_el = ctz32(r->access) / 2;
-        if (min_el == 2 && !arm_feature(env, ARM_FEATURE_EL2)) {
-            if (r->type & ARM_CP_EL3_NO_EL2_UNDEF) {
-                return;
-            }
-            make_const = !(r->type & ARM_CP_EL3_NO_EL2_KEEP);
-        }
-    } else {
-        CPAccessRights max_el = (arm_feature(env, ARM_FEATURE_EL2)
-                                 ? PL2_RW : PL1_RW);
-        if ((r->access & max_el) == 0) {
-            return;
-        }
-    }
-
     /* Combine cpreg and name into one allocation. */
     name_len = strlen(name) + 1;
     r2 = g_malloc(sizeof(*r2) + name_len);
@@ -7342,38 +7315,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
     r2->state = state;
     r2->secure = secstate;
 
-    if (make_const) {
-        /* This should not have been a very special register to begin. */
-        int old_special = r2->type & ARM_CP_SPECIAL_MASK;
-        assert(old_special == 0 || old_special == ARM_CP_NOP);
-        /*
-         * Set the special function to CONST, retaining the other flags.
-         * This is important for e.g. ARM_CP_SVE so that we still
-         * take the SVE trap if CPTR_EL3.EZ == 0.
-         */
-        r2->type = (r2->type & ~ARM_CP_SPECIAL_MASK) | ARM_CP_CONST;
-        /*
-         * Usually, these registers become RES0, but there are a few
-         * special cases like VPIDR_EL2 which have a constant non-zero
-         * value with writes ignored.
-         */
-        if (!(r->type & ARM_CP_EL3_NO_EL2_C_NZ)) {
-            r2->resetvalue = 0;
-        }
-        /*
-         * ARM_CP_CONST has precedence, so removing the callbacks and
-         * offsets are not strictly necessary, but it is potentially
-         * less confusing to debug later.
-         */
-        r2->readfn = NULL;
-        r2->writefn = NULL;
-        r2->raw_readfn = NULL;
-        r2->raw_writefn = NULL;
-        r2->resetfn = NULL;
-        r2->fieldoffset = 0;
-        r2->bank_fieldoffsets[0] = 0;
-        r2->bank_fieldoffsets[1] = 0;
-    } else {
+    {
         bool isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1];
 
         if (isbanked) {
@@ -7538,6 +7480,8 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
     int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2;
     int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
     int cp = r->cp;
+    ARMCPRegInfo r_const;
+    CPUARMState *env = &cpu->env;
 
     /*
      * AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless.
@@ -7643,6 +7587,67 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
         }
     }
 
+    /*
+     * Eliminate registers that are not present because the EL is missing.
+     * Doing this here makes it easier to put all registers for a given
+     * feature into the same ARMCPRegInfo array and define them all at once.
+     */
+    if (arm_feature(env, ARM_FEATURE_EL3)) {
+        /*
+         * An EL2 register without EL2 but with EL3 is (usually) RES0.
+         * See rule RJFFP in section D1.1.3 of DDI0487H.a.
+         */
+        int min_el = ctz32(r->access) / 2;
+        if (min_el == 2 && !arm_feature(env, ARM_FEATURE_EL2)) {
+            if (r->type & ARM_CP_EL3_NO_EL2_UNDEF) {
+                return;
+            }
+            if (!(r->type & ARM_CP_EL3_NO_EL2_KEEP)) {
+                /* This should not have been a very special register. */
+                int old_special = r->type & ARM_CP_SPECIAL_MASK;
+                assert(old_special == 0 || old_special == ARM_CP_NOP);
+
+                r_const = *r;
+
+                /*
+                 * Set the special function to CONST, retaining the other flags.
+                 * This is important for e.g. ARM_CP_SVE so that we still
+                 * take the SVE trap if CPTR_EL3.EZ == 0.
+                 */
+                r_const.type = (r->type & ~ARM_CP_SPECIAL_MASK) | ARM_CP_CONST;
+                /*
+                 * Usually, these registers become RES0, but there are a few
+                 * special cases like VPIDR_EL2 which have a constant non-zero
+                 * value with writes ignored.
+                 */
+                if (!(r->type & ARM_CP_EL3_NO_EL2_C_NZ)) {
+                    r_const.resetvalue = 0;
+                }
+                /*
+                 * ARM_CP_CONST has precedence, so removing the callbacks and
+                 * offsets are not strictly necessary, but it is potentially
+                 * less confusing to debug later.
+                 */
+                r_const.readfn = NULL;
+                r_const.writefn = NULL;
+                r_const.raw_readfn = NULL;
+                r_const.raw_writefn = NULL;
+                r_const.resetfn = NULL;
+                r_const.fieldoffset = 0;
+                r_const.bank_fieldoffsets[0] = 0;
+                r_const.bank_fieldoffsets[1] = 0;
+
+                r = &r_const;
+            }
+        }
+    } else {
+        CPAccessRights max_el = (arm_feature(env, ARM_FEATURE_EL2)
+                                 ? PL2_RW : PL1_RW);
+        if ((r->access & max_el) == 0) {
+            return;
+        }
+    }
+
     for (int crm = crmmin; crm <= crmmax; crm++) {
         for (int opc1 = opc1min; opc1 <= opc1max; opc1++) {
             for (int opc2 = opc2min; opc2 <= opc2max; opc2++) {
-- 
2.43.0



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

* [PATCH 24/61] target/arm: Add key parameter to add_cpreg_to_hashtable
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (26 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 23/61] target/arm: Move cpreg elimination " Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 25/61] target/arm: Split out alloc_cpreg Richard Henderson
                   ` (37 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Hoist the computation of key into the caller, where
state is a known constant.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 39 +++++++++++++++++++--------------------
 1 file changed, 19 insertions(+), 20 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 02c155418b..a4cd4cf232 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7270,26 +7270,13 @@ void register_cp_regs_for_features(ARMCPU *cpu)
 static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
                                    CPState state, CPSecureState secstate,
                                    int cp, int crm, int opc1, int opc2,
-                                   const char *name)
+                                   const char *name, uint32_t key)
 {
     CPUARMState *env = &cpu->env;
-    uint32_t key;
     ARMCPRegInfo *r2;
-    bool is64 = r->type & ARM_CP_64BIT;
     bool ns = secstate & ARM_CP_SECSTATE_NS;
     size_t name_len;
 
-    switch (state) {
-    case ARM_CP_STATE_AA32:
-        key = ENCODE_CP_REG(cp, is64, ns, r->crn, crm, opc1, opc2);
-        break;
-    case ARM_CP_STATE_AA64:
-        key = ENCODE_AA64_CP_REG(r->opc0, opc1, r->crn, crm, opc2);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
     /* Overriding of an existing definition must be explicitly requested. */
     if (!(r->type & ARM_CP_OVERRIDE)) {
         const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key);
@@ -7394,22 +7381,28 @@ static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, const ARMCPRegInfo *r,
      * (same for secure and non-secure world) or banked.
      */
     char *name;
+    bool is64 = r->type & ARM_CP_64BIT;
+    uint32_t key = ENCODE_CP_REG(cp, is64, 0, r->crn, crm, opc1, opc2);
 
     assert(!(r->type & ARM_CP_ADD_TLBI_NXS)); /* aa64 only */
 
     switch (r->secure) {
-    case ARM_CP_SECSTATE_S:
     case ARM_CP_SECSTATE_NS:
+        key |= CP_REG_AA32_NS_MASK;
+        /* fall through */
+    case ARM_CP_SECSTATE_S:
         add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, r->secure,
-                               cp, crm, opc1, opc2, r->name);
+                               cp, crm, opc1, opc2, r->name, key);
         break;
     case ARM_CP_SECSTATE_BOTH:
         name = g_strdup_printf("%s_S", r->name);
         add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, ARM_CP_SECSTATE_S,
-                               cp, crm, opc1, opc2, name);
+                               cp, crm, opc1, opc2, name, key);
         g_free(name);
+
+        key |= CP_REG_AA32_NS_MASK;
         add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, ARM_CP_SECSTATE_NS,
-                               cp, crm, opc1, opc2, r->name);
+                               cp, crm, opc1, opc2, r->name, key);
         break;
     default:
         g_assert_not_reached();
@@ -7419,6 +7412,8 @@ static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, const ARMCPRegInfo *r,
 static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, const ARMCPRegInfo *r,
                                         int crm, int opc1, int opc2)
 {
+    uint32_t key = ENCODE_AA64_CP_REG(r->opc0, opc1, r->crn, crm, opc2);
+
     if ((r->type & ARM_CP_ADD_TLBI_NXS) &&
         cpu_isar_feature(aa64_xs, cpu)) {
         /*
@@ -7433,18 +7428,22 @@ static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, const ARMCPRegInfo *r,
          */
         ARMCPRegInfo nxs_ri = *r;
         g_autofree char *name = g_strdup_printf("%sNXS", r->name);
+        uint32_t nxs_key;
 
         assert(nxs_ri.crn < 0xf);
         nxs_ri.crn++;
+        nxs_key = key + (1 << CP_REG_ARM64_SYSREG_CRN_SHIFT);
         if (nxs_ri.fgt) {
             nxs_ri.fgt |= R_FGT_NXS_MASK;
         }
+
         add_cpreg_to_hashtable(cpu, &nxs_ri, ARM_CP_STATE_AA64,
-                               ARM_CP_SECSTATE_NS, 0, crm, opc1, opc2, name);
+                               ARM_CP_SECSTATE_NS, 0, crm, opc1, opc2,
+                               name, nxs_key);
     }
 
     add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA64, ARM_CP_SECSTATE_NS,
-                           0, crm, opc1, opc2, r->name);
+                           0, crm, opc1, opc2, r->name, key);
 }
 
 void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
-- 
2.43.0



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

* [PATCH 25/61] target/arm: Split out alloc_cpreg
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (27 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 24/61] target/arm: Add key parameter to add_cpreg_to_hashtable Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 26/61] target/arm: Hoist the allocation of ARMCPRegInfo Richard Henderson
                   ` (36 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Include provision for a name suffix.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index a4cd4cf232..0e4be14606 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7263,6 +7263,28 @@ void register_cp_regs_for_features(ARMCPU *cpu)
 #endif
 }
 
+/*
+ * Copy a ARMCPRegInfo structure, allocating it along with the name
+ * and an optional suffix to the name.
+ */
+static ARMCPRegInfo *alloc_cpreg(const ARMCPRegInfo *in,
+                                 const char *name, const char *suffix)
+{
+    size_t name_len = strlen(name);
+    size_t suff_len = suffix ? strlen(suffix) : 0;
+    ARMCPRegInfo *out = g_malloc(sizeof(*in) + name_len + suff_len + 1);
+    char *p = (char *)(out + 1);
+
+    *out = *in;
+    out->name = p;
+
+    memcpy(p, name, name_len + 1);
+    if (suffix) {
+        memcpy(p + name_len, suffix, suff_len + 1);
+    }
+    return out;
+}
+
 /*
  * Private utility function for define_one_arm_cp_reg():
  * add a single reginfo struct to the hash table.
@@ -7275,7 +7297,6 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
     CPUARMState *env = &cpu->env;
     ARMCPRegInfo *r2;
     bool ns = secstate & ARM_CP_SECSTATE_NS;
-    size_t name_len;
 
     /* Overriding of an existing definition must be explicitly requested. */
     if (!(r->type & ARM_CP_OVERRIDE)) {
@@ -7285,11 +7306,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
         }
     }
 
-    /* Combine cpreg and name into one allocation. */
-    name_len = strlen(name) + 1;
-    r2 = g_malloc(sizeof(*r2) + name_len);
-    *r2 = *r;
-    r2->name = memcpy(r2 + 1, name, name_len);
+    r2 = alloc_cpreg(r, name, NULL);
 
     /*
      * Update fields to match the instantiation, overwiting wildcards
-- 
2.43.0



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

* [PATCH 26/61] target/arm: Hoist the allocation of ARMCPRegInfo
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (28 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 25/61] target/arm: Split out alloc_cpreg Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 27/61] target/arm: Remove name argument to alloc_cpreg Richard Henderson
                   ` (35 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Pass in a newly allocated structure, rather than having to
dance around allocation of the name and the structure.

Since we no longer have two copies of the structure handy
within add_cpreg_to_hashtable, delay the writeback of concrete
values over wildcards until we're done querying the wildcards.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 97 ++++++++++++++++++++++-----------------------
 1 file changed, 48 insertions(+), 49 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0e4be14606..d9ac6a20a7 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7289,13 +7289,12 @@ static ARMCPRegInfo *alloc_cpreg(const ARMCPRegInfo *in,
  * Private utility function for define_one_arm_cp_reg():
  * add a single reginfo struct to the hash table.
  */
-static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
+static void add_cpreg_to_hashtable(ARMCPU *cpu, ARMCPRegInfo *r,
                                    CPState state, CPSecureState secstate,
                                    int cp, int crm, int opc1, int opc2,
-                                   const char *name, uint32_t key)
+                                   uint32_t key)
 {
     CPUARMState *env = &cpu->env;
-    ARMCPRegInfo *r2;
     bool ns = secstate & ARM_CP_SECSTATE_NS;
 
     /* Overriding of an existing definition must be explicitly requested. */
@@ -7306,19 +7305,6 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
         }
     }
 
-    r2 = alloc_cpreg(r, name, NULL);
-
-    /*
-     * Update fields to match the instantiation, overwiting wildcards
-     * such as CP_ANY, ARM_CP_STATE_BOTH, or ARM_CP_SECSTATE_BOTH.
-     */
-    r2->cp = cp;
-    r2->crm = crm;
-    r2->opc1 = opc1;
-    r2->opc2 = opc2;
-    r2->state = state;
-    r2->secure = secstate;
-
     {
         bool isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1];
 
@@ -7328,7 +7314,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
              * Overwriting fieldoffset as the array is only used to define
              * banked registers but later only fieldoffset is used.
              */
-            r2->fieldoffset = r->bank_fieldoffsets[ns];
+            r->fieldoffset = r->bank_fieldoffsets[ns];
         }
         if (state == ARM_CP_STATE_AA32) {
             if (isbanked) {
@@ -7345,19 +7331,19 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
                  */
                 if ((r->state == ARM_CP_STATE_BOTH && ns) ||
                     (arm_feature(env, ARM_FEATURE_V8) && !ns)) {
-                    r2->type |= ARM_CP_ALIAS;
+                    r->type |= ARM_CP_ALIAS;
                 }
             } else if ((secstate != r->secure) && !ns) {
                 /*
                  * The register is not banked so we only want to allow
                  * migration of the non-secure instance.
                  */
-                r2->type |= ARM_CP_ALIAS;
+                r->type |= ARM_CP_ALIAS;
             }
 
             if (HOST_BIG_ENDIAN &&
-                r->state == ARM_CP_STATE_BOTH && r2->fieldoffset) {
-                r2->fieldoffset += sizeof(uint32_t);
+                r->state == ARM_CP_STATE_BOTH && r->fieldoffset) {
+                r->fieldoffset += sizeof(uint32_t);
             }
         }
     }
@@ -7369,35 +7355,46 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
      * multiple times. Special registers (ie NOP/WFI) are
      * never migratable and not even raw-accessible.
      */
-    if (r2->type & ARM_CP_SPECIAL_MASK) {
-        r2->type |= ARM_CP_NO_RAW;
+    if (r->type & ARM_CP_SPECIAL_MASK) {
+        r->type |= ARM_CP_NO_RAW;
     }
     if (((r->crm == CP_ANY) && crm != 0) ||
         ((r->opc1 == CP_ANY) && opc1 != 0) ||
         ((r->opc2 == CP_ANY) && opc2 != 0)) {
-        r2->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB;
+        r->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB;
     }
 
+    /*
+     * Update fields to match the instantiation, overwiting wildcards
+     * such as CP_ANY, ARM_CP_STATE_BOTH, or ARM_CP_SECSTATE_BOTH.
+     */
+    r->cp = cp;
+    r->crm = crm;
+    r->opc1 = opc1;
+    r->opc2 = opc2;
+    r->state = state;
+    r->secure = secstate;
+
     /*
      * Check that raw accesses are either forbidden or handled. Note that
      * we can't assert this earlier because the setup of fieldoffset for
      * banked registers has to be done first.
      */
-    if (!(r2->type & ARM_CP_NO_RAW)) {
-        assert(!raw_accessors_invalid(r2));
+    if (!(r->type & ARM_CP_NO_RAW)) {
+        assert(!raw_accessors_invalid(r));
     }
 
-    g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r2);
+    g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r);
 }
 
-static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, const ARMCPRegInfo *r,
+static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, ARMCPRegInfo *r,
                                         int cp, int crm, int opc1, int opc2)
 {
     /*
      * Under AArch32 CP registers can be common
      * (same for secure and non-secure world) or banked.
      */
-    char *name;
+    ARMCPRegInfo *r_s;
     bool is64 = r->type & ARM_CP_64BIT;
     uint32_t key = ENCODE_CP_REG(cp, is64, 0, r->crn, crm, opc1, opc2);
 
@@ -7409,24 +7406,23 @@ static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, const ARMCPRegInfo *r,
         /* fall through */
     case ARM_CP_SECSTATE_S:
         add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, r->secure,
-                               cp, crm, opc1, opc2, r->name, key);
+                               cp, crm, opc1, opc2, key);
         break;
     case ARM_CP_SECSTATE_BOTH:
-        name = g_strdup_printf("%s_S", r->name);
-        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, ARM_CP_SECSTATE_S,
-                               cp, crm, opc1, opc2, name, key);
-        g_free(name);
+        r_s = alloc_cpreg(r, r->name, "_S");
+        add_cpreg_to_hashtable(cpu, r_s, ARM_CP_STATE_AA32, ARM_CP_SECSTATE_S,
+                               cp, crm, opc1, opc2, key);
 
         key |= CP_REG_AA32_NS_MASK;
         add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, ARM_CP_SECSTATE_NS,
-                               cp, crm, opc1, opc2, r->name, key);
+                               cp, crm, opc1, opc2, key);
         break;
     default:
         g_assert_not_reached();
     }
 }
 
-static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, const ARMCPRegInfo *r,
+static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r,
                                         int crm, int opc1, int opc2)
 {
     uint32_t key = ENCODE_AA64_CP_REG(r->opc0, opc1, r->crn, crm, opc2);
@@ -7443,24 +7439,23 @@ static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, const ARMCPRegInfo *r,
          * and name that it is passed, so it's OK to use
          * a local struct here.
          */
-        ARMCPRegInfo nxs_ri = *r;
-        g_autofree char *name = g_strdup_printf("%sNXS", r->name);
+        ARMCPRegInfo *nxs_ri = alloc_cpreg(r, r->name, "NXS");
         uint32_t nxs_key;
 
-        assert(nxs_ri.crn < 0xf);
-        nxs_ri.crn++;
+        assert(nxs_ri->crn < 0xf);
+        nxs_ri->crn++;
         nxs_key = key + (1 << CP_REG_ARM64_SYSREG_CRN_SHIFT);
-        if (nxs_ri.fgt) {
-            nxs_ri.fgt |= R_FGT_NXS_MASK;
+        if (nxs_ri->fgt) {
+            nxs_ri->fgt |= R_FGT_NXS_MASK;
         }
 
-        add_cpreg_to_hashtable(cpu, &nxs_ri, ARM_CP_STATE_AA64,
+        add_cpreg_to_hashtable(cpu, nxs_ri, ARM_CP_STATE_AA64,
                                ARM_CP_SECSTATE_NS, 0, crm, opc1, opc2,
-                               name, nxs_key);
+                               nxs_key);
     }
 
     add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA64, ARM_CP_SECSTATE_NS,
-                           0, crm, opc1, opc2, r->name, key);
+                           0, crm, opc1, opc2, key);
 }
 
 void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
@@ -7667,16 +7662,20 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
     for (int crm = crmmin; crm <= crmmax; crm++) {
         for (int opc1 = opc1min; opc1 <= opc1max; opc1++) {
             for (int opc2 = opc2min; opc2 <= opc2max; opc2++) {
+                ARMCPRegInfo *r2 = alloc_cpreg(r, r->name, NULL);
+                ARMCPRegInfo *r3;
+
                 switch (r->state) {
                 case ARM_CP_STATE_AA32:
-                    add_cpreg_to_hashtable_aa32(cpu, r, cp, crm, opc1, opc2);
+                    add_cpreg_to_hashtable_aa32(cpu, r2, cp, crm, opc1, opc2);
                     break;
                 case ARM_CP_STATE_AA64:
-                    add_cpreg_to_hashtable_aa64(cpu, r, crm, opc1, opc2);
+                    add_cpreg_to_hashtable_aa64(cpu, r2, crm, opc1, opc2);
                     break;
                 case ARM_CP_STATE_BOTH:
-                    add_cpreg_to_hashtable_aa32(cpu, r, cp, crm, opc1, opc2);
-                    add_cpreg_to_hashtable_aa64(cpu, r, crm, opc1, opc2);
+                    r3 = alloc_cpreg(r2, r2->name, NULL);
+                    add_cpreg_to_hashtable_aa32(cpu, r2, cp, crm, opc1, opc2);
+                    add_cpreg_to_hashtable_aa64(cpu, r3, crm, opc1, opc2);
                     break;
                 default:
                     g_assert_not_reached();
-- 
2.43.0



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

* [PATCH 27/61] target/arm: Remove name argument to alloc_cpreg
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (29 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 26/61] target/arm: Hoist the allocation of ARMCPRegInfo Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 28/61] target/arm: Move alias setting for wildcards Richard Henderson
                   ` (34 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

All callers now pass in->name, so take the value from there.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index d9ac6a20a7..3cd4546494 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7267,9 +7267,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
  * Copy a ARMCPRegInfo structure, allocating it along with the name
  * and an optional suffix to the name.
  */
-static ARMCPRegInfo *alloc_cpreg(const ARMCPRegInfo *in,
-                                 const char *name, const char *suffix)
+static ARMCPRegInfo *alloc_cpreg(const ARMCPRegInfo *in, const char *suffix)
 {
+    const char *name = in->name;
     size_t name_len = strlen(name);
     size_t suff_len = suffix ? strlen(suffix) : 0;
     ARMCPRegInfo *out = g_malloc(sizeof(*in) + name_len + suff_len + 1);
@@ -7409,7 +7409,7 @@ static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, ARMCPRegInfo *r,
                                cp, crm, opc1, opc2, key);
         break;
     case ARM_CP_SECSTATE_BOTH:
-        r_s = alloc_cpreg(r, r->name, "_S");
+        r_s = alloc_cpreg(r, "_S");
         add_cpreg_to_hashtable(cpu, r_s, ARM_CP_STATE_AA32, ARM_CP_SECSTATE_S,
                                cp, crm, opc1, opc2, key);
 
@@ -7439,7 +7439,7 @@ static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r,
          * and name that it is passed, so it's OK to use
          * a local struct here.
          */
-        ARMCPRegInfo *nxs_ri = alloc_cpreg(r, r->name, "NXS");
+        ARMCPRegInfo *nxs_ri = alloc_cpreg(r, "NXS");
         uint32_t nxs_key;
 
         assert(nxs_ri->crn < 0xf);
@@ -7662,7 +7662,7 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
     for (int crm = crmmin; crm <= crmmax; crm++) {
         for (int opc1 = opc1min; opc1 <= opc1max; opc1++) {
             for (int opc2 = opc2min; opc2 <= opc2max; opc2++) {
-                ARMCPRegInfo *r2 = alloc_cpreg(r, r->name, NULL);
+                ARMCPRegInfo *r2 = alloc_cpreg(r, NULL);
                 ARMCPRegInfo *r3;
 
                 switch (r->state) {
@@ -7673,7 +7673,7 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
                     add_cpreg_to_hashtable_aa64(cpu, r2, crm, opc1, opc2);
                     break;
                 case ARM_CP_STATE_BOTH:
-                    r3 = alloc_cpreg(r2, r2->name, NULL);
+                    r3 = alloc_cpreg(r2, NULL);
                     add_cpreg_to_hashtable_aa32(cpu, r2, cp, crm, opc1, opc2);
                     add_cpreg_to_hashtable_aa64(cpu, r3, crm, opc1, opc2);
                     break;
-- 
2.43.0



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

* [PATCH 28/61] target/arm: Move alias setting for wildcards
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (30 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 27/61] target/arm: Remove name argument to alloc_cpreg Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 29/61] target/arm: Move writeback of CP_ANY fields Richard Henderson
                   ` (33 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Move this test from add_cpreg_to_hashtable to
define_one_arm_cp_reg_with_opaque, where we can also
simplify it based on the loop variables.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3cd4546494..1a321ad181 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7349,20 +7349,12 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, ARMCPRegInfo *r,
     }
 
     /*
-     * By convention, for wildcarded registers only the first
-     * entry is used for migration; the others are marked as
-     * ALIAS so we don't try to transfer the register
-     * multiple times. Special registers (ie NOP/WFI) are
-     * never migratable and not even raw-accessible.
+     * Special registers (ie NOP/WFI) are never migratable and
+     * are not even raw-accessible.
      */
     if (r->type & ARM_CP_SPECIAL_MASK) {
         r->type |= ARM_CP_NO_RAW;
     }
-    if (((r->crm == CP_ANY) && crm != 0) ||
-        ((r->opc1 == CP_ANY) && opc1 != 0) ||
-        ((r->opc2 == CP_ANY) && opc2 != 0)) {
-        r->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB;
-    }
 
     /*
      * Update fields to match the instantiation, overwiting wildcards
@@ -7665,6 +7657,16 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
                 ARMCPRegInfo *r2 = alloc_cpreg(r, NULL);
                 ARMCPRegInfo *r3;
 
+                /*
+                 * By convention for wildcarded registers, only the first
+                 * entry is used for migration; the others are marked as
+                 * ALIAS so we don't try to transfer the register
+                 * multiple times.
+                 */
+                if (crm != crmmin || opc1 != opc1min || opc2 != opc2min) {
+                    r2->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB;
+                }
+
                 switch (r->state) {
                 case ARM_CP_STATE_AA32:
                     add_cpreg_to_hashtable_aa32(cpu, r2, cp, crm, opc1, opc2);
-- 
2.43.0



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

* [PATCH 29/61] target/arm: Move writeback of CP_ANY fields
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (31 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 28/61] target/arm: Move alias setting for wildcards Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 30/61] target/arm: Move endianness fixup for 32-bit registers Richard Henderson
                   ` (32 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Move the writeback of cp, crm, opc1, opc2 to define_one_arm_cp_reg,
which means we don't have to pass all those parameters down
to subroutines.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 52 ++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 1a321ad181..66e70abc76 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7291,7 +7291,6 @@ static ARMCPRegInfo *alloc_cpreg(const ARMCPRegInfo *in, const char *suffix)
  */
 static void add_cpreg_to_hashtable(ARMCPU *cpu, ARMCPRegInfo *r,
                                    CPState state, CPSecureState secstate,
-                                   int cp, int crm, int opc1, int opc2,
                                    uint32_t key)
 {
     CPUARMState *env = &cpu->env;
@@ -7358,12 +7357,8 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, ARMCPRegInfo *r,
 
     /*
      * Update fields to match the instantiation, overwiting wildcards
-     * such as CP_ANY, ARM_CP_STATE_BOTH, or ARM_CP_SECSTATE_BOTH.
+     * such as ARM_CP_STATE_BOTH or ARM_CP_SECSTATE_BOTH.
      */
-    r->cp = cp;
-    r->crm = crm;
-    r->opc1 = opc1;
-    r->opc2 = opc2;
     r->state = state;
     r->secure = secstate;
 
@@ -7379,8 +7374,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, ARMCPRegInfo *r,
     g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r);
 }
 
-static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, ARMCPRegInfo *r,
-                                        int cp, int crm, int opc1, int opc2)
+static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, ARMCPRegInfo *r)
 {
     /*
      * Under AArch32 CP registers can be common
@@ -7388,7 +7382,8 @@ static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, ARMCPRegInfo *r,
      */
     ARMCPRegInfo *r_s;
     bool is64 = r->type & ARM_CP_64BIT;
-    uint32_t key = ENCODE_CP_REG(cp, is64, 0, r->crn, crm, opc1, opc2);
+    uint32_t key = ENCODE_CP_REG(r->cp, is64, 0, r->crn,
+                                 r->crm, r->opc1, r->opc2);
 
     assert(!(r->type & ARM_CP_ADD_TLBI_NXS)); /* aa64 only */
 
@@ -7397,27 +7392,26 @@ static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, ARMCPRegInfo *r,
         key |= CP_REG_AA32_NS_MASK;
         /* fall through */
     case ARM_CP_SECSTATE_S:
-        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, r->secure,
-                               cp, crm, opc1, opc2, key);
+        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, r->secure, key);
         break;
     case ARM_CP_SECSTATE_BOTH:
         r_s = alloc_cpreg(r, "_S");
-        add_cpreg_to_hashtable(cpu, r_s, ARM_CP_STATE_AA32, ARM_CP_SECSTATE_S,
-                               cp, crm, opc1, opc2, key);
+        add_cpreg_to_hashtable(cpu, r_s, ARM_CP_STATE_AA32,
+                               ARM_CP_SECSTATE_S, key);
 
         key |= CP_REG_AA32_NS_MASK;
-        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, ARM_CP_SECSTATE_NS,
-                               cp, crm, opc1, opc2, key);
+        add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32,
+                               ARM_CP_SECSTATE_NS, key);
         break;
     default:
         g_assert_not_reached();
     }
 }
 
-static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r,
-                                        int crm, int opc1, int opc2)
+static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r)
 {
-    uint32_t key = ENCODE_AA64_CP_REG(r->opc0, opc1, r->crn, crm, opc2);
+    uint32_t key = ENCODE_AA64_CP_REG(r->opc0, r->opc1,
+                                      r->crn, r->crm, r->opc2);
 
     if ((r->type & ARM_CP_ADD_TLBI_NXS) &&
         cpu_isar_feature(aa64_xs, cpu)) {
@@ -7442,12 +7436,11 @@ static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r,
         }
 
         add_cpreg_to_hashtable(cpu, nxs_ri, ARM_CP_STATE_AA64,
-                               ARM_CP_SECSTATE_NS, 0, crm, opc1, opc2,
-                               nxs_key);
+                               ARM_CP_SECSTATE_NS, nxs_key);
     }
 
-    add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA64, ARM_CP_SECSTATE_NS,
-                           0, crm, opc1, opc2, key);
+    add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA64,
+                           ARM_CP_SECSTATE_NS, key);
 }
 
 void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
@@ -7667,17 +7660,24 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
                     r2->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB;
                 }
 
+                /* Overwrite CP_ANY with the instantiation. */
+                r2->crm = crm;
+                r2->opc1 = opc1;
+                r2->opc2 = opc2;
+
                 switch (r->state) {
                 case ARM_CP_STATE_AA32:
-                    add_cpreg_to_hashtable_aa32(cpu, r2, cp, crm, opc1, opc2);
+                    add_cpreg_to_hashtable_aa32(cpu, r2);
                     break;
                 case ARM_CP_STATE_AA64:
-                    add_cpreg_to_hashtable_aa64(cpu, r2, crm, opc1, opc2);
+                    add_cpreg_to_hashtable_aa64(cpu, r2);
                     break;
                 case ARM_CP_STATE_BOTH:
                     r3 = alloc_cpreg(r2, NULL);
-                    add_cpreg_to_hashtable_aa32(cpu, r2, cp, crm, opc1, opc2);
-                    add_cpreg_to_hashtable_aa64(cpu, r3, crm, opc1, opc2);
+                    r2->cp = cp;
+                    add_cpreg_to_hashtable_aa32(cpu, r2);
+                    r3->cp = 0;
+                    add_cpreg_to_hashtable_aa64(cpu, r3);
                     break;
                 default:
                     g_assert_not_reached();
-- 
2.43.0



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

* [PATCH 30/61] target/arm: Move endianness fixup for 32-bit registers
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (32 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 29/61] target/arm: Move writeback of CP_ANY fields Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 31/61] target/arm: Rename TBFLAG_A64_NV2_MEM_E20 with *_E2H Richard Henderson
                   ` (31 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Move the test outside of the banked register block,
and repeat the AA32 test.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 66e70abc76..d0ccc23811 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7339,14 +7339,21 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, ARMCPRegInfo *r,
                  */
                 r->type |= ARM_CP_ALIAS;
             }
-
-            if (HOST_BIG_ENDIAN &&
-                r->state == ARM_CP_STATE_BOTH && r->fieldoffset) {
-                r->fieldoffset += sizeof(uint32_t);
-            }
         }
     }
 
+    /*
+     * For 32-bit AArch32 regs shared with 64-bit AArch64 regs,
+     * adjust the field offset for endianness.  This had to be
+     * delayed until banked registers were resolved.
+     */
+    if (HOST_BIG_ENDIAN &&
+        state == ARM_CP_STATE_AA32 &&
+        r->state == ARM_CP_STATE_BOTH &&
+        r->fieldoffset) {
+        r->fieldoffset += sizeof(uint32_t);
+    }
+
     /*
      * Special registers (ie NOP/WFI) are never migratable and
      * are not even raw-accessible.
-- 
2.43.0



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

* [PATCH 31/61] target/arm: Rename TBFLAG_A64_NV2_MEM_E20 with *_E2H
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (33 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 30/61] target/arm: Move endianness fixup for 32-bit registers Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 32/61] target/arm: Split out redirect_cpreg Richard Henderson
                   ` (30 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Install e2h in tbflags and compute nv2_mem_e20 from
that in aarch64_tr_init_disas_context.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h               | 3 +--
 target/arm/tcg/translate.h     | 2 ++
 target/arm/tcg/hflags.c        | 8 +++++---
 target/arm/tcg/translate-a64.c | 3 ++-
 4 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index dc9b6dce4c..919bd3d7eb 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3076,8 +3076,7 @@ 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)
+FIELD(TBFLAG_A64, E2H, 35, 1)
 /* Set if FEAT_NV2 RAM accesses are big-endian */
 FIELD(TBFLAG_A64, NV2_MEM_BE, 36, 1)
 FIELD(TBFLAG_A64, AH, 37, 1)   /* FPCR.AH */
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index f974996f3f..cd67c0ed07 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -150,6 +150,8 @@ typedef struct DisasContext {
     bool trap_eret;
     /* True if FEAT_LSE2 SCTLR_ELx.nAA is set */
     bool naa;
+    /* True if HCR_EL2.E2H is set */
+    bool e2h;
     /* True if FEAT_NV HCR_EL2.NV is enabled */
     bool nv;
     /* True if NV enabled and HCR_EL2.NV1 is set */
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index 59ab526375..6969d41ea0 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -258,6 +258,11 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
     DP_TBFLAG_A64(flags, TBII, tbii);
     DP_TBFLAG_A64(flags, TBID, tbid);
 
+    /* E2H is used by both VHE and NV2. */
+    if (hcr & HCR_E2H) {
+        DP_TBFLAG_A64(flags, E2H, 1);
+    }
+
     if (cpu_isar_feature(aa64_sve, env_archcpu(env))) {
         int sve_el = sve_exception_el(env, el);
 
@@ -390,9 +395,6 @@ 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 58303c224f..648463f44a 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -10153,10 +10153,11 @@ 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->e2h = EX_TBFLAG_A64(tb_flags, E2H);
     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_e20 = dc->nv2 && dc->e2h;
     dc->nv2_mem_be = EX_TBFLAG_A64(tb_flags, NV2_MEM_BE);
     dc->fpcr_ah = EX_TBFLAG_A64(tb_flags, AH);
     dc->fpcr_nep = EX_TBFLAG_A64(tb_flags, NEP);
-- 
2.43.0



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

* [PATCH 32/61] target/arm: Split out redirect_cpreg
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (34 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 31/61] target/arm: Rename TBFLAG_A64_NV2_MEM_E20 with *_E2H Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 33/61] target/arm: Redirect VHE FOO_EL1 -> FOO_EL2 during translation Richard Henderson
                   ` (29 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/tcg/translate-a64.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 648463f44a..8303f0dac2 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2455,6 +2455,19 @@ static void gen_sysreg_undef(DisasContext *s, bool isread,
     gen_exception_insn(s, 0, EXCP_UDEF, syndrome);
 }
 
+/*
+ * Look up @key, returning the cpreg, which must exist.
+ * Additionally, the new cpreg must also be accessible.
+ */
+static const ARMCPRegInfo *
+redirect_cpreg(DisasContext *s, uint32_t key, bool isread)
+{
+    const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
+    assert(ri);
+    assert(cp_access_ok(s->current_el, ri, isread));
+    return ri;
+}
+
 /* MRS - move from system register
  * MSR (register) - move to system register
  * SYS
@@ -2603,9 +2616,7 @@ static void handle_sys(DisasContext *s, bool isread,
          * fine-grained-traps on EL1 also do not apply here.
          */
         key = ENCODE_AA64_CP_REG(op0, 0, crn, crm, op2);
-        ri = get_arm_cp_reginfo(s->cp_regs, key);
-        assert(ri);
-        assert(cp_access_ok(s->current_el, ri, isread));
+        ri = redirect_cpreg(s, key, 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.
-- 
2.43.0



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

* [PATCH 33/61] target/arm: Redirect VHE FOO_EL1 -> FOO_EL2 during translation
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (35 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 32/61] target/arm: Split out redirect_cpreg Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-28 12:39   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 34/61] target/arm: Redirect VHE FOO_EL12 to FOO_EL1 " Richard Henderson
                   ` (28 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h            |  6 ++++
 target/arm/gdbstub.c           |  5 ++++
 target/arm/helper.c            | 53 +---------------------------------
 target/arm/tcg/translate-a64.c |  9 ++++++
 4 files changed, 21 insertions(+), 52 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 7bdf6cf847..d34ed0d40b 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -911,6 +911,12 @@ struct ARMCPRegInfo {
      */
     uint32_t nv2_redirect_offset;
 
+    /*
+     * With VHE, with E2H, at EL2, access to this EL0/EL1 reg redirects
+     * to the EL2 reg with the specified key.
+     */
+    uint32_t vhe_redir_to_el2;
+
     /* This is used only by VHE. */
     void *opaque;
     /*
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index e2fc389170..3727dc01af 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -249,6 +249,11 @@ static int arm_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg)
     if (ri) {
         switch (cpreg_field_type(ri)) {
         case MO_64:
+            if (ri->vhe_redir_to_el2 &&
+                (arm_hcr_el2_eff(env) & HCR_E2H) &&
+                arm_current_el(env) == 2) {
+                ri = get_arm_cp_reginfo(cpu->cp_regs, ri->vhe_redir_to_el2);
+            }
             return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri));
         case MO_32:
             return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri));
diff --git a/target/arm/helper.c b/target/arm/helper.c
index d0ccc23811..3f69ce6cb5 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4441,47 +4441,6 @@ static CPAccessResult access_el1nvvct(CPUARMState *env, const ARMCPRegInfo *ri,
     return e2h_access(env, ri, isread);
 }
 
-/* Test if system register redirection is to occur in the current state.  */
-static bool redirect_for_e2h(CPUARMState *env)
-{
-    return arm_current_el(env) == 2 && (arm_hcr_el2_eff(env) & HCR_E2H);
-}
-
-static uint64_t el2_e2h_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
-    CPReadFn *readfn;
-
-    if (redirect_for_e2h(env)) {
-        /* Switch to the saved EL2 version of the register.  */
-        ri = ri->opaque;
-        readfn = ri->readfn;
-    } else {
-        readfn = ri->orig_readfn;
-    }
-    if (readfn == NULL) {
-        readfn = raw_read;
-    }
-    return readfn(env, ri);
-}
-
-static void el2_e2h_write(CPUARMState *env, const ARMCPRegInfo *ri,
-                          uint64_t value)
-{
-    CPWriteFn *writefn;
-
-    if (redirect_for_e2h(env)) {
-        /* Switch to the saved EL2 version of the register.  */
-        ri = ri->opaque;
-        writefn = ri->writefn;
-    } else {
-        writefn = ri->orig_writefn;
-    }
-    if (writefn == NULL) {
-        writefn = raw_write;
-    }
-    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 */
@@ -4657,17 +4616,7 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
                                  (gpointer)(uintptr_t)a->new_key, new_reg);
         g_assert(ok);
 
-        src_reg->opaque = dst_reg;
-        src_reg->orig_readfn = src_reg->readfn ?: raw_read;
-        src_reg->orig_writefn = src_reg->writefn ?: raw_write;
-        if (!src_reg->raw_readfn) {
-            src_reg->raw_readfn = raw_read;
-        }
-        if (!src_reg->raw_writefn) {
-            src_reg->raw_writefn = raw_write;
-        }
-        src_reg->readfn = el2_e2h_read;
-        src_reg->writefn = el2_e2h_write;
+        src_reg->vhe_redir_to_el2 = a->dst_key;
     }
 }
 #endif
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 8303f0dac2..8fcc74d151 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2573,6 +2573,15 @@ static void handle_sys(DisasContext *s, bool isread,
         }
     }
 
+    if (ri->vhe_redir_to_el2 && s->current_el == 2 && s->e2h) {
+        /*
+         * This one of the FOO_EL1 registers which redirect to FOO_EL2
+         * from EL2 when HCR_EL2.E2H is set.
+         */
+        key = ri->vhe_redir_to_el2;
+        ri = redirect_cpreg(s, key, isread);
+    }
+
     if (ri->accessfn || (ri->fgt && s->fgt_active)) {
         /* Emit code to perform further access permissions checks at
          * runtime; this may result in an exception.
-- 
2.43.0



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

* [PATCH 34/61] target/arm: Redirect VHE FOO_EL12 to FOO_EL1 during translation
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (36 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 33/61] target/arm: Redirect VHE FOO_EL1 -> FOO_EL2 during translation Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 35/61] target/arm: Rename some cpreg to their aarch64 names Richard Henderson
                   ` (27 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h            | 22 ++++---------
 target/arm/gdbstub.c           |  2 ++
 target/arm/helper.c            | 57 +++-------------------------------
 target/arm/tcg/translate-a64.c | 12 +++++++
 4 files changed, 25 insertions(+), 68 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index d34ed0d40b..f5d6a1c386 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -917,8 +917,12 @@ struct ARMCPRegInfo {
      */
     uint32_t vhe_redir_to_el2;
 
-    /* This is used only by VHE. */
-    void *opaque;
+    /*
+     * With VHE, with E2H, at EL2+, access to this EL02/EL12 reg
+     * redirects to the EL0/EL1 reg with the specified key.
+     */
+    uint32_t vhe_redir_to_el01;
+
     /*
      * Value of this register, if it is ARM_CP_CONST. Otherwise, if
      * fieldoffset is non-zero, the reset value of the register.
@@ -986,20 +990,6 @@ struct ARMCPRegInfo {
      * fieldoffset is 0 then no reset will be done.
      */
     CPResetFn *resetfn;
-
-    /*
-     * "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
-     * forwards the operation.  Before overwriting the accessors,
-     * the original function is copied here, so that accesses that
-     * really do go to the EL1/EL0 version proceed normally.
-     * (The corresponding EL2 register is linked via opaque.)
-     */
-    CPReadFn *orig_readfn;
-    CPWriteFn *orig_writefn;
-    CPAccessFn *orig_accessfn;
 };
 
 void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs);
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 3727dc01af..269bc6c132 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -253,6 +253,8 @@ static int arm_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg)
                 (arm_hcr_el2_eff(env) & HCR_E2H) &&
                 arm_current_el(env) == 2) {
                 ri = get_arm_cp_reginfo(cpu->cp_regs, ri->vhe_redir_to_el2);
+            } else if (ri->vhe_redir_to_el01) {
+                ri = get_arm_cp_reginfo(cpu->cp_regs, ri->vhe_redir_to_el01);
             }
             return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri));
         case MO_32:
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3f69ce6cb5..a19406e136 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4441,42 +4441,6 @@ static CPAccessResult access_el1nvvct(CPUARMState *env, const ARMCPRegInfo *ri,
     return e2h_access(env, ri, isread);
 }
 
-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 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_UNDEFINED;
-    }
-    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 {
@@ -4566,9 +4530,6 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
         g_assert(strcmp(src_reg->name, a->src_name) == 0);
         g_assert(strcmp(dst_reg->name, a->dst_name) == 0);
 
-        /* None of the core system registers use opaque; we will.  */
-        g_assert(src_reg->opaque == NULL);
-
         /* Create alias before redirection so we dup the right data. */
         new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo));
 
@@ -4587,19 +4548,11 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
             >> 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;
-        new_reg->orig_accessfn = src_reg->accessfn;
-        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;
-        new_reg->accessfn = el2_e2h_e12_access;
+        new_reg->vhe_redir_to_el01 = a->src_key;
+        new_reg->readfn = NULL;
+        new_reg->writefn = NULL;
+        new_reg->accessfn = NULL;
+        new_reg->fieldoffset = 0;
 
         /*
          * If the _EL1 register is redirected to memory by FEAT_NV2,
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 8fcc74d151..7de8717056 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2580,6 +2580,18 @@ static void handle_sys(DisasContext *s, bool isread,
          */
         key = ri->vhe_redir_to_el2;
         ri = redirect_cpreg(s, key, isread);
+    } else if (ri->vhe_redir_to_el01 && s->current_el >= 2) {
+        /*
+         * This is one of the FOO_EL12 registers.
+         * With !E2H, they all UNDEF.
+         * With E2H, from EL2 or EL3, they redirect to FOO_EL1.
+         */
+        if (!s->e2h) {
+            gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt);
+            return;
+        }
+        key = ri->vhe_redir_to_el01;
+        ri = redirect_cpreg(s, key, isread);
     }
 
     if (ri->accessfn || (ri->fgt && s->fgt_active)) {
-- 
2.43.0



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

* [PATCH 35/61] target/arm: Rename some cpreg to their aarch64 names
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (37 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 34/61] target/arm: Redirect VHE FOO_EL12 to FOO_EL1 " Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-09-01  6:53   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 36/61] target/arm: Remove define_arm_vh_e2h_redirects_aliases Richard Henderson
                   ` (26 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Rename those registers which will have FOO_EL12 aliases.

Signed-off-by: Richard Henderson <richard.henderson@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 a19406e136..255ca6fdcb 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -671,7 +671,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
      */
     { .name = "WFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, },
-    { .name = "CPACR", .state = ARM_CP_STATE_BOTH, .opc0 = 3,
+    { .name = "CPACR_EL1", .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,
@@ -2012,7 +2012,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
       .resetfn = arm_gt_cntfrq_reset,
     },
     /* overall control: mostly access permissions */
-    { .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH,
+    { .name = "CNTKCTL_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 0, .crn = 14, .crm = 1, .opc2 = 0,
       .access = PL1_RW,
       .fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl),
@@ -3071,8 +3071,8 @@ static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
 }
 
 static const ARMCPRegInfo lpae_cp_reginfo[] = {
-    /* NOP AMAIR0/1 */
-    { .name = "AMAIR0", .state = ARM_CP_STATE_BOTH,
+    /* AMAIR0 is mapped to AMAIR_EL1[31:0] */
+    { .name = "AMAIR_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_AMAIR_EL1,
@@ -4454,9 +4454,9 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
 
     static const struct E2HAlias aliases[] = {
         { K(3, 0,  1, 0, 0), K(3, 4,  1, 0, 0), K(3, 5, 1, 0, 0),
-          "SCTLR", "SCTLR_EL2", "SCTLR_EL12" },
+          "SCTLR_EL1", "SCTLR_EL2", "SCTLR_EL12" },
         { K(3, 0,  1, 0, 2), K(3, 4,  1, 1, 2), K(3, 5, 1, 0, 2),
-          "CPACR", "CPTR_EL2", "CPACR_EL12" },
+          "CPACR_EL1", "CPTR_EL2", "CPACR_EL12" },
         { K(3, 0,  2, 0, 0), K(3, 4,  2, 0, 0), K(3, 5, 2, 0, 0),
           "TTBR0_EL1", "TTBR0_EL2", "TTBR0_EL12" },
         { K(3, 0,  2, 0, 1), K(3, 4,  2, 0, 1), K(3, 5, 2, 0, 1),
@@ -4478,13 +4478,13 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
         { K(3, 0, 10, 2, 0), K(3, 4, 10, 2, 0), K(3, 5, 10, 2, 0),
           "MAIR_EL1", "MAIR_EL2", "MAIR_EL12" },
         { K(3, 0, 10, 3, 0), K(3, 4, 10, 3, 0), K(3, 5, 10, 3, 0),
-          "AMAIR0", "AMAIR_EL2", "AMAIR_EL12" },
+          "AMAIR_EL1", "AMAIR_EL2", "AMAIR_EL12" },
         { K(3, 0, 12, 0, 0), K(3, 4, 12, 0, 0), K(3, 5, 12, 0, 0),
-          "VBAR", "VBAR_EL2", "VBAR_EL12" },
+          "VBAR_EL1", "VBAR_EL2", "VBAR_EL12" },
         { K(3, 0, 13, 0, 1), K(3, 4, 13, 0, 1), K(3, 5, 13, 0, 1),
           "CONTEXTIDR_EL1", "CONTEXTIDR_EL2", "CONTEXTIDR_EL12" },
         { K(3, 0, 14, 1, 0), K(3, 4, 14, 1, 0), K(3, 5, 14, 1, 0),
-          "CNTKCTL", "CNTHCTL_EL2", "CNTKCTL_EL12" },
+          "CNTKCTL_EL1", "CNTHCTL_EL2", "CNTKCTL_EL12" },
 
         /*
          * Note that redirection of ZCR is mentioned in the description
@@ -6999,7 +6999,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
 
     if (arm_feature(env, ARM_FEATURE_VBAR)) {
         static const ARMCPRegInfo vbar_cp_reginfo[] = {
-            { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
+            { .name = "VBAR_EL1", .state = ARM_CP_STATE_BOTH,
               .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
               .access = PL1_RW, .writefn = vbar_write,
               .accessfn = access_nv1,
@@ -7015,7 +7015,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
     /* Generic registers whose values depend on the implementation */
     {
         ARMCPRegInfo sctlr = {
-            .name = "SCTLR", .state = ARM_CP_STATE_BOTH,
+            .name = "SCTLR_EL1", .state = ARM_CP_STATE_BOTH,
             .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0,
             .access = PL1_RW, .accessfn = access_tvm_trvm,
             .fgt = FGT_SCTLR_EL1,
-- 
2.43.0



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

* [PATCH 36/61] target/arm: Remove define_arm_vh_e2h_redirects_aliases
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (38 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 35/61] target/arm: Rename some cpreg to their aarch64 names Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 37/61] target/arm: Implement isar tests for FEAT_SYSREG128, FEAT_SYSINSTR128 Richard Henderson
                   ` (25 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Populate vhe_redir_to_{el2,el01} on each ARMCPRegInfo.
Clear the fields within add_cpreg_to_hashtable_aa32.
Create the FOO_EL12 cpreg within add_cpreg_to_hashtable_aa64;
add ARM_CP_NO_RAW.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h |   6 +-
 target/arm/helper.c | 241 ++++++++++++++++++--------------------------
 2 files changed, 103 insertions(+), 144 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index f5d6a1c386..9818be4429 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -918,8 +918,10 @@ struct ARMCPRegInfo {
     uint32_t vhe_redir_to_el2;
 
     /*
-     * With VHE, with E2H, at EL2+, access to this EL02/EL12 reg
-     * redirects to the EL0/EL1 reg with the specified key.
+     * For VHE.  Before registration, this field holds the key for an
+     * EL02/EL12 reg to be created to point back to this EL0/EL1 reg.
+     * After registration, this field is set only on the EL02/EL12 reg
+     * and points back to the EL02/EL12 reg for redirection with E2H.
      */
     uint32_t vhe_redir_to_el01;
 
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 255ca6fdcb..64a987d143 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -454,6 +454,8 @@ static const ARMCPRegInfo cp_reginfo[] = {
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_CONTEXTIDR_EL1,
       .nv2_redirect_offset = 0x108 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 13, 0, 1),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 13, 0, 1),
       .secure = ARM_CP_SECSTATE_NS,
       .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[1]),
       .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, },
@@ -674,6 +676,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
     { .name = "CPACR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3,
       .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access,
       .fgt = FGT_CPACR_EL1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 1, 1, 2),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 1, 0, 2),
       .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 },
@@ -950,12 +954,16 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_AFSR0_EL1,
       .nv2_redirect_offset = 0x128 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 5, 1, 0),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 5, 1, 0),
       .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,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 5, 1, 1),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 5, 1, 1),
       .type = ARM_CP_CONST, .resetvalue = 0 },
     /*
      * MAIR can just read-as-written because we don't implement caches
@@ -966,6 +974,8 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_MAIR_EL1,
       .nv2_redirect_offset = 0x140 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 10, 2, 0),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 10, 2, 0),
       .fieldoffset = offsetof(CPUARMState, cp15.mair_el[1]),
       .resetvalue = 0 },
     { .name = "MAIR_EL3", .state = ARM_CP_STATE_AA64,
@@ -2015,6 +2025,8 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
     { .name = "CNTKCTL_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 0, .crn = 14, .crm = 1, .opc2 = 0,
       .access = PL1_RW,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 14, 1, 0),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 14, 1, 0),
       .fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl),
       .resetvalue = 0,
     },
@@ -2805,6 +2817,8 @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = {
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_FAR_EL1,
       .nv2_redirect_offset = 0x220 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 6, 0, 0),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 6, 0, 0),
       .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
       .resetvalue = 0, },
 };
@@ -2815,12 +2829,16 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_ESR_EL1,
       .nv2_redirect_offset = 0x138 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 5, 2, 0),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 5, 2, 0),
       .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,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_TTBR0_EL1,
       .nv2_redirect_offset = 0x200 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 0),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 0),
       .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write,
       .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s),
                              offsetof(CPUARMState, cp15.ttbr0_ns) } },
@@ -2829,6 +2847,8 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_TTBR1_EL1,
       .nv2_redirect_offset = 0x210 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 1),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 1),
       .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write,
       .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
                              offsetof(CPUARMState, cp15.ttbr1_ns) } },
@@ -2837,6 +2857,8 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_TCR_EL1,
       .nv2_redirect_offset = 0x120 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 2),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 2),
       .writefn = vmsa_tcr_el12_write,
       .raw_writefn = raw_write,
       .resetvalue = 0,
@@ -3077,6 +3099,8 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .fgt = FGT_AMAIR_EL1,
       .nv2_redirect_offset = 0x148 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 10, 3, 0),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 10, 3, 0),
       .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,
@@ -3602,12 +3626,16 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
       .access = PL1_RW, .accessfn = access_nv1,
       .nv2_redirect_offset = 0x230 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 4, 0, 1),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 4, 0, 1),
       .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, .accessfn = access_nv1,
       .nv2_redirect_offset = 0x160 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 4, 0, 0),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 4, 0, 0),
       .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_SVC]) },
     /*
      * We rely on the access checks not allowing the guest to write to the
@@ -4440,138 +4468,6 @@ static CPAccessResult access_el1nvvct(CPUARMState *env, const ARMCPRegInfo *ri,
     }
     return e2h_access(env, ri, isread);
 }
-
-static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
-{
-    struct E2HAlias {
-        uint32_t src_key, dst_key, new_key;
-        const char *src_name, *dst_name, *new_name;
-        bool (*feature)(const ARMISARegisters *id);
-    };
-
-#define K(op0, op1, crn, crm, op2) \
-    ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2)
-
-    static const struct E2HAlias aliases[] = {
-        { K(3, 0,  1, 0, 0), K(3, 4,  1, 0, 0), K(3, 5, 1, 0, 0),
-          "SCTLR_EL1", "SCTLR_EL2", "SCTLR_EL12" },
-        { K(3, 0,  1, 0, 2), K(3, 4,  1, 1, 2), K(3, 5, 1, 0, 2),
-          "CPACR_EL1", "CPTR_EL2", "CPACR_EL12" },
-        { K(3, 0,  2, 0, 0), K(3, 4,  2, 0, 0), K(3, 5, 2, 0, 0),
-          "TTBR0_EL1", "TTBR0_EL2", "TTBR0_EL12" },
-        { K(3, 0,  2, 0, 1), K(3, 4,  2, 0, 1), K(3, 5, 2, 0, 1),
-          "TTBR1_EL1", "TTBR1_EL2", "TTBR1_EL12" },
-        { K(3, 0,  2, 0, 2), K(3, 4,  2, 0, 2), K(3, 5, 2, 0, 2),
-          "TCR_EL1", "TCR_EL2", "TCR_EL12" },
-        { K(3, 0,  4, 0, 0), K(3, 4,  4, 0, 0), K(3, 5, 4, 0, 0),
-          "SPSR_EL1", "SPSR_EL2", "SPSR_EL12" },
-        { K(3, 0,  4, 0, 1), K(3, 4,  4, 0, 1), K(3, 5, 4, 0, 1),
-          "ELR_EL1", "ELR_EL2", "ELR_EL12" },
-        { K(3, 0,  5, 1, 0), K(3, 4,  5, 1, 0), K(3, 5, 5, 1, 0),
-          "AFSR0_EL1", "AFSR0_EL2", "AFSR0_EL12" },
-        { K(3, 0,  5, 1, 1), K(3, 4,  5, 1, 1), K(3, 5, 5, 1, 1),
-          "AFSR1_EL1", "AFSR1_EL2", "AFSR1_EL12" },
-        { K(3, 0,  5, 2, 0), K(3, 4,  5, 2, 0), K(3, 5, 5, 2, 0),
-          "ESR_EL1", "ESR_EL2", "ESR_EL12" },
-        { K(3, 0,  6, 0, 0), K(3, 4,  6, 0, 0), K(3, 5, 6, 0, 0),
-          "FAR_EL1", "FAR_EL2", "FAR_EL12" },
-        { K(3, 0, 10, 2, 0), K(3, 4, 10, 2, 0), K(3, 5, 10, 2, 0),
-          "MAIR_EL1", "MAIR_EL2", "MAIR_EL12" },
-        { K(3, 0, 10, 3, 0), K(3, 4, 10, 3, 0), K(3, 5, 10, 3, 0),
-          "AMAIR_EL1", "AMAIR_EL2", "AMAIR_EL12" },
-        { K(3, 0, 12, 0, 0), K(3, 4, 12, 0, 0), K(3, 5, 12, 0, 0),
-          "VBAR_EL1", "VBAR_EL2", "VBAR_EL12" },
-        { K(3, 0, 13, 0, 1), K(3, 4, 13, 0, 1), K(3, 5, 13, 0, 1),
-          "CONTEXTIDR_EL1", "CONTEXTIDR_EL2", "CONTEXTIDR_EL12" },
-        { K(3, 0, 14, 1, 0), K(3, 4, 14, 1, 0), K(3, 5, 14, 1, 0),
-          "CNTKCTL_EL1", "CNTHCTL_EL2", "CNTKCTL_EL12" },
-
-        /*
-         * Note that redirection of ZCR is mentioned in the description
-         * of ZCR_EL2, and aliasing in the description of ZCR_EL1, but
-         * not in the summary table.
-         */
-        { K(3, 0,  1, 2, 0), K(3, 4,  1, 2, 0), K(3, 5, 1, 2, 0),
-          "ZCR_EL1", "ZCR_EL2", "ZCR_EL12", isar_feature_aa64_sve },
-        { K(3, 0,  1, 2, 6), K(3, 4,  1, 2, 6), K(3, 5, 1, 2, 6),
-          "SMCR_EL1", "SMCR_EL2", "SMCR_EL12", isar_feature_aa64_sme },
-
-        { K(3, 0,  5, 6, 0), K(3, 4,  5, 6, 0), K(3, 5, 5, 6, 0),
-          "TFSR_EL1", "TFSR_EL2", "TFSR_EL12", isar_feature_aa64_mte },
-
-        { K(3, 0, 13, 0, 7), K(3, 4, 13, 0, 7), K(3, 5, 13, 0, 7),
-          "SCXTNUM_EL1", "SCXTNUM_EL2", "SCXTNUM_EL12",
-          isar_feature_aa64_scxtnum },
-
-        /* TODO: ARMv8.2-SPE -- PMSCR_EL2 */
-        /* TODO: ARMv8.4-Trace -- TRFCR_EL2 */
-    };
-#undef K
-
-    size_t i;
-
-    for (i = 0; i < ARRAY_SIZE(aliases); i++) {
-        const struct E2HAlias *a = &aliases[i];
-        ARMCPRegInfo *src_reg, *dst_reg, *new_reg;
-        bool ok;
-
-        if (a->feature && !a->feature(&cpu->isar)) {
-            continue;
-        }
-
-        src_reg = g_hash_table_lookup(cpu->cp_regs,
-                                      (gpointer)(uintptr_t)a->src_key);
-        dst_reg = g_hash_table_lookup(cpu->cp_regs,
-                                      (gpointer)(uintptr_t)a->dst_key);
-        g_assert(src_reg != NULL);
-        g_assert(dst_reg != NULL);
-
-        /* Cross-compare names to detect typos in the keys.  */
-        g_assert(strcmp(src_reg->name, a->src_name) == 0);
-        g_assert(strcmp(dst_reg->name, a->dst_name) == 0);
-
-        /* Create alias before redirection so we dup the right data. */
-        new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo));
-
-        new_reg->name = a->new_name;
-        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->vhe_redir_to_el01 = a->src_key;
-        new_reg->readfn = NULL;
-        new_reg->writefn = NULL;
-        new_reg->accessfn = NULL;
-        new_reg->fieldoffset = 0;
-
-        /*
-         * 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);
-
-        src_reg->vhe_redir_to_el2 = a->dst_key;
-    }
-}
 #endif
 
 static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -4864,6 +4760,8 @@ 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,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 1, 2, 0),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 1, 2, 0),
       .access = PL1_RW, .type = ARM_CP_SVE,
       .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]),
       .writefn = zcr_write, .raw_writefn = raw_write },
@@ -5009,6 +4907,8 @@ static const ARMCPRegInfo sme_reginfo[] = {
     { .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,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 1, 2, 6),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 1, 2, 6),
       .access = PL1_RW, .type = ARM_CP_SME,
       .fieldoffset = offsetof(CPUARMState, vfp.smcr_el[1]),
       .writefn = smcr_write, .raw_writefn = raw_write },
@@ -5454,6 +5354,8 @@ static const ARMCPRegInfo mte_reginfo[] = {
       .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 6, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tfsr_el1,
       .nv2_redirect_offset = 0x190 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 5, 6, 0),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 5, 6, 0),
       .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) },
     { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_NV2_REDIRECT,
@@ -5629,6 +5531,8 @@ static const ARMCPRegInfo scxtnum_reginfo[] = {
       .access = PL1_RW, .accessfn = access_scxtnum_el1,
       .fgt = FGT_SCXTNUM_EL1,
       .nv2_redirect_offset = 0x188 | NV2_REDIR_NV1,
+      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 13, 0, 7),
+      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 13, 0, 7),
       .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) },
     { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 7,
@@ -7005,6 +6909,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
               .accessfn = access_nv1,
               .fgt = FGT_VBAR_EL1,
               .nv2_redirect_offset = 0x250 | NV2_REDIR_NV1,
+              .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 12, 0, 0),
+              .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 12, 0, 0),
               .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s),
                                      offsetof(CPUARMState, cp15.vbar_ns) },
               .resetvalue = 0 },
@@ -7019,6 +6925,8 @@ 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,
+            .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 1, 0, 0),
+            .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 1, 0, 0),
             .nv2_redirect_offset = 0x110 | NV2_REDIR_NV1,
             .bank_fieldoffsets = { offsetof(CPUARMState, cp15.sctlr_s),
                                    offsetof(CPUARMState, cp15.sctlr_ns) },
@@ -7153,16 +7061,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
     }
 
     define_pm_cpregs(cpu);
-
-#ifndef CONFIG_USER_ONLY
-    /*
-     * Register redirections and aliases must be done last,
-     * after the registers from the other extensions have been defined.
-     */
-    if (arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu)) {
-        define_arm_vh_e2h_redirects_aliases(cpu);
-    }
-#endif
 }
 
 /*
@@ -7295,6 +7193,8 @@ static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, ARMCPRegInfo *r)
                                  r->crm, r->opc1, r->opc2);
 
     assert(!(r->type & ARM_CP_ADD_TLBI_NXS)); /* aa64 only */
+    r->vhe_redir_to_el2 = 0;
+    r->vhe_redir_to_el01 = 0;
 
     switch (r->secure) {
     case ARM_CP_SECSTATE_NS:
@@ -7348,6 +7248,63 @@ static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r)
                                ARM_CP_SECSTATE_NS, nxs_key);
     }
 
+    if (!r->vhe_redir_to_el01) {
+        assert(!r->vhe_redir_to_el2);
+    } else if (!arm_feature(&cpu->env, ARM_FEATURE_EL2) ||
+               !cpu_isar_feature(aa64_vh, cpu)) {
+        r->vhe_redir_to_el2 = 0;
+        r->vhe_redir_to_el01 = 0;
+    } else {
+        /* Create the FOO_EL12 alias. */
+        ARMCPRegInfo *r2 = alloc_cpreg(r, "2");
+        uint32_t key2 = r->vhe_redir_to_el01;
+
+        /*
+         * Clear EL1 redirection on the FOO_EL1 reg;
+         * Clear EL2 redirection on the FOO_EL12 reg;
+         * Install redirection from FOO_EL12 back to FOO_EL1.
+         */
+        r->vhe_redir_to_el01 = 0;
+        r2->vhe_redir_to_el2 = 0;
+        r2->vhe_redir_to_el01 = key;
+
+        r2->type |= ARM_CP_ALIAS | ARM_CP_NO_RAW;
+        /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place.  */
+        r2->access &= PL2_RW | PL3_RW;
+        /* The new_reg op fields are as per new_key, not the target reg */
+        r2->crn = (key2 & CP_REG_ARM64_SYSREG_CRN_MASK)
+            >> CP_REG_ARM64_SYSREG_CRN_SHIFT;
+        r2->crm = (key2 & CP_REG_ARM64_SYSREG_CRM_MASK)
+            >> CP_REG_ARM64_SYSREG_CRM_SHIFT;
+        r2->opc0 = (key2 & CP_REG_ARM64_SYSREG_OP0_MASK)
+            >> CP_REG_ARM64_SYSREG_OP0_SHIFT;
+        r2->opc1 = (key2 & CP_REG_ARM64_SYSREG_OP1_MASK)
+            >> CP_REG_ARM64_SYSREG_OP1_SHIFT;
+        r2->opc2 = (key2 & CP_REG_ARM64_SYSREG_OP2_MASK)
+            >> CP_REG_ARM64_SYSREG_OP2_SHIFT;
+
+        /* Non-redirected access to this register will abort. */
+        r2->readfn = NULL;
+        r2->writefn = NULL;
+        r2->raw_readfn = NULL;
+        r2->raw_writefn = NULL;
+        r2->accessfn = NULL;
+        r2->fieldoffset = 0;
+
+        /*
+         * 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 (r2->nv2_redirect_offset) {
+            assert(r2->nv2_redirect_offset & NV2_REDIR_NV1);
+            r2->nv2_redirect_offset &= ~NV2_REDIR_NV1;
+            r2->nv2_redirect_offset |= NV2_REDIR_NO_NV1;
+        }
+        add_cpreg_to_hashtable(cpu, r2, ARM_CP_STATE_AA64,
+                               ARM_CP_SECSTATE_NS, key2);
+    }
+
     add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA64,
                            ARM_CP_SECSTATE_NS, key);
 }
-- 
2.43.0



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

* [PATCH 37/61] target/arm: Implement isar tests for FEAT_SYSREG128, FEAT_SYSINSTR128
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (39 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 36/61] target/arm: Remove define_arm_vh_e2h_redirects_aliases Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-09-01  6:55   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 38/61] target/arm: Define CP_REG_SIZE_U128 Richard Henderson
                   ` (24 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu-features.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index 5876162428..7a0e515aeb 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -599,6 +599,16 @@ static inline bool isar_feature_aa64_mops(const ARMISARegisters *id)
     return FIELD_EX64_IDREG(id, ID_AA64ISAR2, MOPS);
 }
 
+static inline bool isar_feature_aa64_sysreg128(const ARMISARegisters *id)
+{
+    return FIELD_EX64_IDREG(id, ID_AA64ISAR2, SYSREG_128) != 0;
+}
+
+static inline bool isar_feature_aa64_sysinstr128(const ARMISARegisters *id)
+{
+    return FIELD_EX64_IDREG(id, ID_AA64ISAR2, SYSINSTR_128) != 0;
+}
+
 static inline bool isar_feature_aa64_rpres(const ARMISARegisters *id)
 {
     return FIELD_EX64_IDREG(id, ID_AA64ISAR2, RPRES);
-- 
2.43.0



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

* [PATCH 38/61] target/arm: Define CP_REG_SIZE_U128
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (40 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 37/61] target/arm: Implement isar tests for FEAT_SYSREG128, FEAT_SYSINSTR128 Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-09-01  6:55   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 39/61] target/arm: Update ARMCPRegInfo for 128-bit sysregs Richard Henderson
                   ` (23 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/kvm-consts.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h
index 54ae5da7ce..1b3c10c0d3 100644
--- a/target/arm/kvm-consts.h
+++ b/target/arm/kvm-consts.h
@@ -30,6 +30,7 @@
 #define CP_REG_SIZE_MASK       0x00f0000000000000ULL
 #define CP_REG_SIZE_U32        0x0020000000000000ULL
 #define CP_REG_SIZE_U64        0x0030000000000000ULL
+#define CP_REG_SIZE_U128       0x0040000000000000ULL
 #define CP_REG_ARM             0x4000000000000000ULL
 #define CP_REG_ARCH_MASK       0xff00000000000000ULL
 
@@ -37,6 +38,7 @@ MISMATCH_CHECK(CP_REG_SIZE_SHIFT, KVM_REG_SIZE_SHIFT);
 MISMATCH_CHECK(CP_REG_SIZE_MASK, KVM_REG_SIZE_MASK);
 MISMATCH_CHECK(CP_REG_SIZE_U32, KVM_REG_SIZE_U32);
 MISMATCH_CHECK(CP_REG_SIZE_U64, KVM_REG_SIZE_U64);
+MISMATCH_CHECK(CP_REG_SIZE_U128, KVM_REG_SIZE_U128);
 MISMATCH_CHECK(CP_REG_ARM, KVM_REG_ARM);
 MISMATCH_CHECK(CP_REG_ARCH_MASK, KVM_REG_ARCH_MASK);
 
-- 
2.43.0



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

* [PATCH 39/61] target/arm: Update ARMCPRegInfo for 128-bit sysregs
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (41 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 38/61] target/arm: Define CP_REG_SIZE_U128 Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-09-01  6:56   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 40/61] target/arm: Assert ARM_CP_128BIT only with ARM_CP_STATE_AA64 Richard Henderson
                   ` (22 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Add ARM_CP_128BIT for type and functions describing 128-bit access.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 9818be4429..90f14dbb18 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -136,6 +136,8 @@ enum {
      * identically to the normal one, other than FGT trapping handling.)
      */
     ARM_CP_ADD_TLBI_NXS          = 1 << 21,
+    /* Flag: For ARM_CP_STATE_AA64, sysreg is 128-bit. */
+    ARM_CP_128BIT                = 1 << 22,
 };
 
 /*
@@ -178,6 +180,10 @@ enum {
 #define CP_REG_AA32_NS_SHIFT     29
 #define CP_REG_AA32_NS_MASK      (1 << CP_REG_AA32_NS_SHIFT)
 
+/* Distinguish 64-bit and 128-bit views of AArch64 system registers. */
+#define CP_REG_AA64_128BIT_SHIFT 30
+#define CP_REG_AA64_128BIT_MASK  (1 << CP_REG_AA64_128BIT_SHIFT)
+
 /* Distinguish 32-bit and 64-bit views of AArch32 system registers. */
 #define CP_REG_AA32_64BIT_SHIFT  15
 #define CP_REG_AA32_64BIT_MASK   (1 << CP_REG_AA32_64BIT_SHIFT)
@@ -849,6 +855,9 @@ typedef struct ARMCPRegInfo ARMCPRegInfo;
 typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *ri);
 typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *ri,
                        uint64_t value);
+typedef Int128 CPRead128Fn(CPUARMState *env, const ARMCPRegInfo *opaque);
+typedef void CPWrite128Fn(CPUARMState *env, const ARMCPRegInfo *opaque,
+                          Int128 value);
 /* Access permission check functions for coprocessor registers. */
 typedef CPAccessResult CPAccessFn(CPUARMState *env,
                                   const ARMCPRegInfo *ri,
@@ -992,6 +1001,13 @@ struct ARMCPRegInfo {
      * fieldoffset is 0 then no reset will be done.
      */
     CPResetFn *resetfn;
+
+    /* For ARM_CP_128BIT, when accessed via MRRS/MSRR. */
+    CPAccessFn *access128fn;
+    CPRead128Fn *read128fn;
+    CPWrite128Fn *write128fn;
+    CPRead128Fn *raw_read128fn;
+    CPWrite128Fn *raw_write128fn;
 };
 
 void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs);
@@ -1061,6 +1077,9 @@ void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri);
  */
 static inline MemOp cpreg_field_type(const ARMCPRegInfo *ri)
 {
+    if (ri->type & ARM_CP_128BIT) {
+        return MO_128;
+    }
     return (ri->state == ARM_CP_STATE_AA64 || (ri->type & ARM_CP_64BIT)
             ? MO_64 : MO_32);
 }
-- 
2.43.0



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

* [PATCH 40/61] target/arm: Assert ARM_CP_128BIT only with ARM_CP_STATE_AA64
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (42 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 39/61] target/arm: Update ARMCPRegInfo for 128-bit sysregs Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-09-01  6:58   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 41/61] target/arm: Split add_cpreg_to_hashtable_aa64 Richard Henderson
                   ` (21 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 64a987d143..3b765408f2 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7353,6 +7353,11 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
     assert(r->state == ARM_CP_STATE_AA32 || !(r->type & ARM_CP_64BIT));
     /* AArch32 64-bit registers have only CRm and Opc1 fields. */
     assert(!(r->type & ARM_CP_64BIT) || !(r->opc2 || r->crn));
+    /*
+     * Only AArch64 regs are 128-bit.  There is usually an AArch32 64-bit
+     * alias, but must be defined separately due to encoding conflicts above.
+     */
+    assert(r->state == ARM_CP_STATE_AA64 || !(r->type & ARM_CP_128BIT));
     /* op0 only exists in the AArch64 encodings */
     assert(r->state != ARM_CP_STATE_AA32 || r->opc0 == 0);
 
-- 
2.43.0



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

* [PATCH 41/61] target/arm: Split add_cpreg_to_hashtable_aa64
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (43 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 40/61] target/arm: Assert ARM_CP_128BIT only with ARM_CP_STATE_AA64 Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 42/61] target/arm: Add raw_read128, raw_write128 Richard Henderson
                   ` (20 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Rename the existing add_cpreg_to_hashtable_aa64 as *_1.
Introduce a new add_cpreg_to_hashtable_aa64 that handles
128-bit and 64-bit views of an AArch64 system register.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 63 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 4 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3b765408f2..18af67742d 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7217,11 +7217,9 @@ static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, ARMCPRegInfo *r)
     }
 }
 
-static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r)
+static void add_cpreg_to_hashtable_aa64_1(ARMCPU *cpu, ARMCPRegInfo *r,
+                                          uint32_t key)
 {
-    uint32_t key = ENCODE_AA64_CP_REG(r->opc0, r->opc1,
-                                      r->crn, r->crm, r->opc2);
-
     if ((r->type & ARM_CP_ADD_TLBI_NXS) &&
         cpu_isar_feature(aa64_xs, cpu)) {
         /*
@@ -7288,6 +7286,10 @@ static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r)
         r2->writefn = NULL;
         r2->raw_readfn = NULL;
         r2->raw_writefn = NULL;
+        r2->read128fn = NULL;
+        r2->write128fn = NULL;
+        r2->raw_read128fn = NULL;
+        r2->raw_write128fn = NULL;
         r2->accessfn = NULL;
         r2->fieldoffset = 0;
 
@@ -7309,6 +7311,59 @@ static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r)
                            ARM_CP_SECSTATE_NS, key);
 }
 
+static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r)
+{
+    uint32_t key64 = ENCODE_AA64_CP_REG(r->opc0, r->opc1,
+                                        r->crn, r->crm, r->opc2);
+
+    /*
+     * All 128-bit system registers and instructions have 64-bit aliases.
+     * If the 128-bit feature is enabled, create a duplicate.
+     */
+    if (r->type & ARM_CP_128BIT) {
+        if (cpu_isar_feature(aa64_sysreg128, cpu) ||
+            cpu_isar_feature(aa64_sysinstr128, cpu)) {
+            ARMCPRegInfo *r128 = alloc_cpreg(r, NULL);
+            uint32_t key128 = key64 | CP_REG_AA64_128BIT_MASK;
+
+            r128->accessfn = r128->access128fn;
+            r128->access128fn = NULL;
+            r128->readfn = NULL;
+            r128->writefn = NULL;
+            r128->raw_readfn = NULL;
+            r128->raw_writefn = NULL;
+
+            if (r128->vhe_redir_to_el2) {
+                r128->vhe_redir_to_el2 |= CP_REG_AA64_128BIT_MASK;
+            }
+            if (r128->vhe_redir_to_el01) {
+                r128->vhe_redir_to_el01 |= CP_REG_AA64_128BIT_MASK;
+            }
+
+            add_cpreg_to_hashtable_aa64_1(cpu, r128, key128);
+
+            /*
+             * The 128-bit definition is the canonical view.
+             * The 64-bit definition is an alias, hidden from gdb.
+             */
+            r->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB;
+        }
+
+        /* Squash the original to create the 64-bit view. */
+        r->type &= ~ARM_CP_128BIT;
+        r->access128fn = NULL;
+        r->read128fn = NULL;
+        r->write128fn = NULL;
+        r->raw_read128fn = NULL;
+        r->raw_write128fn = NULL;
+        if (HOST_BIG_ENDIAN && r->fieldoffset) {
+            r->fieldoffset += sizeof(uint64_t);
+        }
+    }
+
+    add_cpreg_to_hashtable_aa64_1(cpu, r, key64);
+}
+
 void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
 {
     /*
-- 
2.43.0



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

* [PATCH 42/61] target/arm: Add raw_read128, raw_write128
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (44 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 41/61] target/arm: Split add_cpreg_to_hashtable_aa64 Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-09-01  7:02   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 43/61] target/arm: Add read_raw_cp_reg128, write_raw_cp_reg128 Richard Henderson
                   ` (19 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h |  5 +++++
 target/arm/helper.c | 17 +++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 90f14dbb18..0d8c45b60c 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -21,6 +21,7 @@
 #ifndef TARGET_ARM_CPREGS_H
 #define TARGET_ARM_CPREGS_H
 
+#include "qemu/int128.h"
 #include "hw/registerfields.h"
 #include "exec/memop.h"
 #include "target/arm/kvm-consts.h"
@@ -1065,6 +1066,10 @@ uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri);
 /* CPWriteFn that just writes the value to ri->fieldoffset */
 void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value);
 
+/* Likewise for 128-bit fields. */
+Int128 raw_read128(CPUARMState *env, const ARMCPRegInfo *opaque);
+void raw_write128(CPUARMState *env, const ARMCPRegInfo *opaque, Int128 value);
+
 /*
  * CPResetFn that does nothing, for use if no reset is required even
  * if fieldoffset is non zero.
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 18af67742d..7568b78c49 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -59,6 +59,8 @@ int compare_u64(const void *a, const void *b)
     (*(uint32_t *)((char *)(env) + (ri)->fieldoffset))
 #define CPREG_FIELD64(env, ri) \
     (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
+#define CPREG_FIELD128(env, ri) \
+    (*(Int128 *)((char *)(env) + (ri)->fieldoffset))
 
 uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
@@ -88,8 +90,23 @@ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
     }
 }
 
+Int128 raw_read128(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    assert(ri->type & ARM_CP_128BIT);
+    assert(ri->fieldoffset);
+    return CPREG_FIELD128(env, ri);
+}
+
+void raw_write128(CPUARMState *env, const ARMCPRegInfo *ri, Int128 value)
+{
+    assert(ri->type & ARM_CP_128BIT);
+    assert(ri->fieldoffset);
+    CPREG_FIELD128(env, ri) = value;
+}
+
 #undef CPREG_FIELD32
 #undef CPREG_FIELD64
+#undef CPREG_FIELD128
 
 static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri)
 {
-- 
2.43.0



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

* [PATCH 43/61] target/arm: Add read_raw_cp_reg128, write_raw_cp_reg128
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (45 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 42/61] target/arm: Add raw_read128, raw_write128 Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-09-01  7:05   ` Manos Pitsidianakis
  2025-08-27  1:04 ` [PATCH 44/61] target/arm: Put 128-bit sysregs into a separate list Richard Henderson
                   ` (18 subsequent siblings)
  65 siblings, 1 reply; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Add the functions and update raw_accessors_invalid to match.
Add assertions for !ARM_CP_128BIT in read_raw_cp_reg and
write_raw_cp_reg.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpregs.h |  1 +
 target/arm/helper.c | 43 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 0d8c45b60c..bd26a4a260 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -1097,6 +1097,7 @@ static inline bool cp_access_ok(int current_el,
 
 /* Raw read of a coprocessor register (as needed for migration, etc) */
 uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri);
+Int128 read_raw_cp_reg128(CPUARMState *env, const ARMCPRegInfo *ri);
 
 /*
  * Return true if the cp register encoding is in the "feature ID space" as
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 7568b78c49..3efc14da3a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -115,6 +115,7 @@ static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri)
 
 uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri)
 {
+    assert(!(ri->type & ARM_CP_128BIT));
     /* Raw read of a coprocessor register (as needed for migration, etc). */
     if (ri->type & ARM_CP_CONST) {
         return ri->resetvalue;
@@ -130,6 +131,7 @@ uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri)
 static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
                              uint64_t v)
 {
+    assert(!(ri->type & ARM_CP_128BIT));
     /*
      * Raw write of a coprocessor register (as needed for migration, etc).
      * Note that constant registers are treated as write-ignored; the
@@ -147,6 +149,32 @@ static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
     }
 }
 
+Int128 read_raw_cp_reg128(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    assert(ri->type & ARM_CP_128BIT);
+    if (ri->raw_read128fn) {
+        return ri->raw_read128fn(env, ri);
+    } else if (ri->read128fn) {
+        return ri->read128fn(env, ri);
+    } else {
+        return raw_read128(env, ri);
+    }
+}
+
+__attribute__((unused))
+static void write_raw_cp_reg128(CPUARMState *env, const ARMCPRegInfo *ri,
+                                Int128 v)
+{
+    assert(ri->type & ARM_CP_128BIT);
+    if (ri->raw_write128fn) {
+        ri->raw_write128fn(env, ri, v);
+    } else if (ri->write128fn) {
+        ri->write128fn(env, ri, v);
+    } else {
+        raw_write128(env, ri, v);
+    }
+}
+
 static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
 {
    /*
@@ -161,12 +189,19 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
     * The tests here line up with the conditions in read/write_raw_cp_reg()
     * and assertions in raw_read()/raw_write().
     */
-    if ((ri->type & ARM_CP_CONST) ||
-        ri->fieldoffset ||
-        ((ri->raw_writefn || ri->writefn) && (ri->raw_readfn || ri->readfn))) {
+    if (ri->type & ARM_CP_CONST) {
+        return ri->type & ARM_CP_128BIT;
+    }
+    if (ri->fieldoffset) {
         return false;
     }
-    return true;
+    if (ri->type & ARM_CP_128BIT) {
+        return !((ri->raw_write128fn || ri->write128fn) &&
+                 (ri->raw_read128fn || ri->read128fn));
+    } else {
+        return !((ri->raw_writefn || ri->writefn) &&
+                 (ri->raw_readfn || ri->readfn));
+    }
 }
 
 bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync)
-- 
2.43.0



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

* [PATCH 44/61] target/arm: Put 128-bit sysregs into a separate list
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (46 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 43/61] target/arm: Add read_raw_cp_reg128, write_raw_cp_reg128 Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 45/61] target/arm/kvm: Assert no 128-bit sysregs in kvm_arm_init_cpreg_list Richard Henderson
                   ` (17 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Duplicate the cpreg_{indexes,values,array_len} array as
cpreg128_{indexes,values,array_len}.  Similarly for
cpreg_vmstate_{indexes,values,array_len}.

Split the values between the two arrays during
write_cpustate_to_list, write_list_to_cpustate,
count_cpreg, and add_cpreg_to_list.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h    |  19 +++++--
 target/arm/helper.c | 125 +++++++++++++++++++++++++++++++++++---------
 2 files changed, 116 insertions(+), 28 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 919bd3d7eb..a5a8779aba 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -911,25 +911,36 @@ struct ArchCPU {
 
     /* Coprocessor information */
     GHashTable *cp_regs;
-    /* For marshalling (mostly coprocessor) register state between the
+    /*
+     * For marshalling (mostly coprocessor) register state between the
      * kernel and QEMU (for KVM) and between two QEMUs (for migration),
      * we use these arrays.
      */
-    /* List of register indexes managed via these arrays; (full KVM style
-     * 64 bit indexes, not CPRegInfo 32 bit indexes)
+    /*
+     * List of register indexes managed via these arrays (full KVM style
+     * 64 bit indexes, not CPRegInfo 32 bit indexes).  The registers are
+     * segregated by size, with 64-bit registers in cpreg_indexes and
+     * 128-bit registers in cpreg128_indexes.
      */
     uint64_t *cpreg_indexes;
+    uint64_t *cpreg128_indexes;
     /* Values of the registers (cpreg_indexes[i]'s value is cpreg_values[i]) */
     uint64_t *cpreg_values;
+    Int128 *cpreg128_values;
     /* Length of the indexes, values, reset_values arrays */
     int32_t cpreg_array_len;
-    /* These are used only for migration: incoming data arrives in
+    int32_t cpreg128_array_len;
+    /*
+     * These are used only for migration: incoming data arrives in
      * these fields and is sanity checked in post_load before copying
      * to the working data structures above.
      */
     uint64_t *cpreg_vmstate_indexes;
+    uint64_t *cpreg128_vmstate_indexes;
     uint64_t *cpreg_vmstate_values;
+    Int128 *cpreg128_vmstate_values;
     int32_t cpreg_vmstate_array_len;
+    int32_t cpreg128_vmstate_array_len;
 
     DynamicGDBFeatureInfo dyn_sysreg_feature;
     DynamicGDBFeatureInfo dyn_svereg_feature;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3efc14da3a..6f20d3986e 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -207,10 +207,11 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
 bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync)
 {
     /* Write the coprocessor state from cpu->env to the (index,value) list. */
-    int i;
+    int i, n;
     bool ok = true;
 
-    for (i = 0; i < cpu->cpreg_array_len; i++) {
+    n = cpu->cpreg_array_len;
+    for (i = 0; i < n; i++) {
         uint32_t regidx = kvm_to_cpreg_id(cpu->cpreg_indexes[i]);
         const ARMCPRegInfo *ri;
         uint64_t newval;
@@ -220,6 +221,10 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync)
             ok = false;
             continue;
         }
+        if (ri->type & ARM_CP_128BIT) {
+            ok = false;
+            continue;
+        }
         if (ri->type & ARM_CP_NO_RAW) {
             continue;
         }
@@ -247,35 +252,77 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync)
         }
         cpu->cpreg_values[i] = newval;
     }
-    return ok;
-}
 
-bool write_list_to_cpustate(ARMCPU *cpu)
-{
-    int i;
-    bool ok = true;
+    n = cpu->cpreg128_array_len;
+    if (n == 0) {
+        return ok;
+    }
+    assert(!kvm_sync);
 
-    for (i = 0; i < cpu->cpreg_array_len; i++) {
-        uint32_t regidx = kvm_to_cpreg_id(cpu->cpreg_indexes[i]);
-        uint64_t v = cpu->cpreg_values[i];
-        const ARMCPRegInfo *ri;
+    for (i = 0; i < n; i++) {
+        uint32_t regidx = kvm_to_cpreg_id(cpu->cpreg128_indexes[i]);
+        const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
 
-        ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
         if (!ri) {
             ok = false;
             continue;
         }
+        if (!(ri->type & ARM_CP_128BIT)) {
+            ok = false;
+            continue;
+        }
         if (ri->type & ARM_CP_NO_RAW) {
             continue;
         }
-        /*
-         * Write value and confirm it reads back as written
-         * (to catch read-only registers and partially read-only
-         * registers where the incoming migration value doesn't match)
-         */
-        write_raw_cp_reg(&cpu->env, ri, v);
-        if (read_raw_cp_reg(&cpu->env, ri) != v) {
+
+        cpu->cpreg128_values[i] = read_raw_cp_reg128(&cpu->env, ri);
+    }
+    return ok;
+}
+
+bool write_list_to_cpustate(ARMCPU *cpu)
+{
+    int i, n;
+    bool ok = true;
+
+    n = cpu->cpreg_array_len;
+    for (i = 0; i < n; i++) {
+        uint32_t regidx = kvm_to_cpreg_id(cpu->cpreg_indexes[i]);
+        const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
+
+        if (!ri) {
             ok = false;
+        } else if (ri->type & ARM_CP_128BIT) {
+            ok = false;
+        } else if (!(ri->type & ARM_CP_NO_RAW)) {
+            /*
+             * Write value and confirm it reads back as written
+             * (to catch read-only registers and partially read-only
+             * registers where the incoming migration value doesn't match)
+             */
+            uint64_t v = cpu->cpreg_values[i];
+            write_raw_cp_reg(&cpu->env, ri, v);
+            if (read_raw_cp_reg(&cpu->env, ri) != v) {
+                ok = false;
+            }
+        }
+    }
+
+    n = cpu->cpreg128_array_len;
+    for (i = 0; i < n; i++) {
+        uint32_t regidx = kvm_to_cpreg_id(cpu->cpreg128_indexes[i]);
+        const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
+
+        if (!ri) {
+            ok = false;
+        } else if (!(ri->type & ARM_CP_128BIT)) {
+            ok = false;
+        } else if (!(ri->type & ARM_CP_NO_RAW)) {
+            Int128 v = cpu->cpreg128_values[i];
+            write_raw_cp_reg128(&cpu->env, ri, v);
+            if (int128_ne(read_raw_cp_reg128(&cpu->env, ri), v)) {
+                ok = false;
+            }
         }
     }
     return ok;
@@ -288,9 +335,14 @@ static void add_cpreg_to_list(gpointer key, gpointer value, gpointer opaque)
     const ARMCPRegInfo *ri = value;
 
     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) {
-        cpu->cpreg_indexes[cpu->cpreg_array_len] = cpreg_to_kvm_id(regidx);
+        uint64_t idx = cpreg_to_kvm_id(regidx);
+
         /* The value array need not be initialized at this point */
-        cpu->cpreg_array_len++;
+        if (ri->type & ARM_CP_128BIT) {
+            cpu->cpreg128_indexes[cpu->cpreg128_array_len++] = idx;
+        } else {
+            cpu->cpreg_indexes[cpu->cpreg_array_len++] = idx;
+        }
     }
 }
 
@@ -300,7 +352,11 @@ static void count_cpreg(gpointer key, gpointer value, gpointer opaque)
     const ARMCPRegInfo *ri = value;
 
     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) {
-        cpu->cpreg_array_len++;
+        if (ri->type & ARM_CP_128BIT) {
+            cpu->cpreg128_array_len++;
+        } else {
+            cpu->cpreg_array_len++;
+        }
     }
 }
 
@@ -310,9 +366,10 @@ void init_cpreg_list(ARMCPU *cpu)
      * Initialise the cpreg_tuples[] array based on the cp_regs hash.
      * Note that we require cpreg_tuples[] to be sorted by key ID.
      */
-    int arraylen;
+    int arraylen, array128len;
 
     cpu->cpreg_array_len = 0;
+    cpu->cpreg128_array_len = 0;
     g_hash_table_foreach(cpu->cp_regs, count_cpreg, cpu);
 
     arraylen = cpu->cpreg_array_len;
@@ -330,13 +387,33 @@ void init_cpreg_list(ARMCPU *cpu)
     cpu->cpreg_vmstate_array_len = arraylen;
     cpu->cpreg_array_len = 0;
 
+    array128len = cpu->cpreg128_array_len;
+    if (array128len) {
+        cpu->cpreg128_indexes = g_new(uint64_t, array128len);
+        cpu->cpreg128_values = g_new(Int128, array128len);
+        cpu->cpreg128_vmstate_indexes = g_new(uint64_t, array128len);
+        cpu->cpreg128_vmstate_values = g_new(Int128, array128len);
+    } else {
+        cpu->cpreg128_indexes = NULL;
+        cpu->cpreg128_values = NULL;
+        cpu->cpreg128_vmstate_indexes = NULL;
+        cpu->cpreg128_vmstate_values = NULL;
+    }
+    cpu->cpreg128_vmstate_array_len = array128len;
+    cpu->cpreg128_array_len = 0;
+
     g_hash_table_foreach(cpu->cp_regs, add_cpreg_to_list, cpu);
 
     assert(cpu->cpreg_array_len == arraylen);
+    assert(cpu->cpreg128_array_len == array128len);
 
     if (arraylen) {
         qsort(cpu->cpreg_indexes, arraylen, sizeof(uint64_t), compare_u64);
     }
+    if (array128len) {
+        qsort(cpu->cpreg128_indexes, array128len,
+              sizeof(uint64_t), compare_u64);
+    }
 }
 
 bool arm_pan_enabled(CPUARMState *env)
-- 
2.43.0



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

* [PATCH 45/61] target/arm/kvm: Assert no 128-bit sysregs in kvm_arm_init_cpreg_list
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (47 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 44/61] target/arm: Put 128-bit sysregs into a separate list Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 46/61] target/arm/hvf: Assert no 128-bit sysregs in hvf_arch_init_vcpu Richard Henderson
                   ` (16 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

KVM has not yet enabled 128-bit system registers.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/kvm.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 9e569eff65..53c79041e1 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -803,6 +803,8 @@ static int kvm_arm_init_cpreg_list(ARMCPU *cpu)
         arraylen++;
     }
 
+    assert(cpu->cpreg128_array_len == 0);
+
     cpu->cpreg_indexes = g_renew(uint64_t, cpu->cpreg_indexes, arraylen);
     cpu->cpreg_values = g_renew(uint64_t, cpu->cpreg_values, arraylen);
     cpu->cpreg_vmstate_indexes = g_renew(uint64_t, cpu->cpreg_vmstate_indexes,
-- 
2.43.0



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

* [PATCH 46/61] target/arm/hvf: Assert no 128-bit sysregs in hvf_arch_init_vcpu
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (48 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 45/61] target/arm/kvm: Assert no 128-bit sysregs in kvm_arm_init_cpreg_list Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 47/61] migration: Add vmstate_info_int128 Richard Henderson
                   ` (15 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

HVF has not yet enabled 128-bit system registers.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/hvf/hvf.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index bda57614ed..c05e81b4e5 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -896,6 +896,9 @@ int hvf_arch_init_vcpu(CPUState *cpu)
     env->aarch64 = true;
     asm volatile("mrs %0, cntfrq_el0" : "=r"(arm_cpu->gt_cntfrq_hz));
 
+    /* No support yet for FEAT_D128 */
+    assert(arm_cpu->cpreg128_array_len == 0);
+
     /* Allocate enough space for our sysreg sync */
     arm_cpu->cpreg_indexes = g_renew(uint64_t, arm_cpu->cpreg_indexes,
                                      sregs_match_len);
@@ -919,6 +922,7 @@ int hvf_arch_init_vcpu(CPUState *cpu)
 
         if (ri) {
             assert(!(ri->type & ARM_CP_NO_RAW));
+            assert(!(ri->type & ARM_CP_128BIT));
             arm_cpu->cpreg_indexes[sregs_cnt++] = kvm_id;
         }
     }
-- 
2.43.0



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

* [PATCH 47/61] migration: Add vmstate_info_int128
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (49 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 46/61] target/arm/hvf: Assert no 128-bit sysregs in hvf_arch_init_vcpu Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 48/61] target/arm: Migrate cpreg128 registers Richard Henderson
                   ` (14 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/migration/vmstate.h |  1 +
 migration/vmstate-types.c   | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 1ff7bd9ac4..3b3416c2c9 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -222,6 +222,7 @@ extern const VMStateInfo vmstate_info_int8;
 extern const VMStateInfo vmstate_info_int16;
 extern const VMStateInfo vmstate_info_int32;
 extern const VMStateInfo vmstate_info_int64;
+extern const VMStateInfo vmstate_info_int128;
 
 extern const VMStateInfo vmstate_info_uint8_equal;
 extern const VMStateInfo vmstate_info_uint16_equal;
diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
index 741a588b7e..1476c278e1 100644
--- a/migration/vmstate-types.c
+++ b/migration/vmstate-types.c
@@ -18,6 +18,7 @@
 #include "migration/client-options.h"
 #include "qemu/error-report.h"
 #include "qemu/queue.h"
+#include "qemu/int128.h"
 #include "trace.h"
 
 /* bool */
@@ -193,6 +194,35 @@ const VMStateInfo vmstate_info_int64 = {
     .put  = put_int64,
 };
 
+/* 128 bit int */
+
+static int get_int128(QEMUFile *f, void *pv, size_t size,
+                      const VMStateField *field)
+{
+    Int128 *v = pv;
+    uint64_t hi, lo;
+
+    qemu_get_be64s(f, &hi);
+    qemu_get_be64s(f, &lo);
+    *v = int128_make128(lo, hi);
+    return 0;
+}
+
+static int put_int128(QEMUFile *f, void *pv, size_t size,
+                      const VMStateField *field, JSONWriter *vmdesc)
+{
+    Int128 *v = pv;
+    qemu_put_be64(f, int128_gethi(*v));
+    qemu_put_be64(f, int128_getlo(*v));
+    return 0;
+}
+
+const VMStateInfo vmstate_info_int128 = {
+    .name = "int128",
+    .get  = get_int128,
+    .put  = put_int128,
+};
+
 /* 8 bit unsigned int */
 
 static int get_uint8(QEMUFile *f, void *pv, size_t size,
-- 
2.43.0



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

* [PATCH 48/61] target/arm: Migrate cpreg128 registers
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (50 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 47/61] migration: Add vmstate_info_int128 Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 49/61] target/arm: Add syn_aa64_sysreg128trap Richard Henderson
                   ` (13 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/machine.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/target/arm/machine.c b/target/arm/machine.c
index 6986915bee..35ff28cc30 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -868,6 +868,34 @@ static const VMStateInfo vmstate_powered_off = {
     .put = put_power,
 };
 
+static bool sysreg128_needed(void *opaque)
+{
+    ARMCPU *cpu = opaque;
+    return cpu->cpreg128_array_len != 0;
+}
+
+static const VMStateDescription vmstate_sysreg128 = {
+    .name = "cpu/sysreg128",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = sysreg128_needed,
+    .fields = (const VMStateField[]) {
+        /*
+         * The length-check must come before the arrays to avoid
+         * incoming data possibly overflowing the array.
+         */
+        VMSTATE_INT32_POSITIVE_LE(cpreg128_vmstate_array_len, ARMCPU),
+        VMSTATE_VARRAY_INT32(cpreg128_vmstate_indexes, ARMCPU,
+                             cpreg128_vmstate_array_len,
+                             0, vmstate_info_uint64, uint64_t),
+        VMSTATE_VARRAY_INT32(cpreg128_vmstate_values, ARMCPU,
+                             cpreg128_vmstate_array_len,
+                             0, vmstate_info_int128, Int128),
+
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static int cpu_pre_save(void *opaque)
 {
     ARMCPU *cpu = opaque;
@@ -900,6 +928,12 @@ static int cpu_pre_save(void *opaque)
     memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values,
            cpu->cpreg_array_len * sizeof(uint64_t));
 
+    cpu->cpreg128_vmstate_array_len = cpu->cpreg128_array_len;
+    memcpy(cpu->cpreg128_vmstate_indexes, cpu->cpreg128_indexes,
+           cpu->cpreg128_array_len * sizeof(uint64_t));
+    memcpy(cpu->cpreg128_vmstate_values, cpu->cpreg128_values,
+           cpu->cpreg128_array_len * sizeof(Int128));
+
     return 0;
 }
 
@@ -994,6 +1028,21 @@ static int cpu_post_load(void *opaque, int version_id)
         v++;
     }
 
+    for (i = 0, v = 0; i < cpu->cpreg128_array_len
+             && v < cpu->cpreg128_vmstate_array_len; i++) {
+        if (cpu->cpreg128_vmstate_indexes[v] > cpu->cpreg128_indexes[i]) {
+            /* register in our list but not incoming : skip it */
+            continue;
+        }
+        if (cpu->cpreg128_vmstate_indexes[v] < cpu->cpreg128_indexes[i]) {
+            /* register in their list but not ours: fail migration */
+            return -1;
+        }
+        /* matching register, copy the value over */
+        cpu->cpreg128_values[i] = cpu->cpreg128_vmstate_values[v];
+        v++;
+    }
+
     if (kvm_enabled()) {
         if (!kvm_arm_cpu_post_load(cpu)) {
             return -1;
@@ -1119,6 +1168,7 @@ const VMStateDescription vmstate_arm_cpu = {
         &vmstate_serror,
         &vmstate_irq_line_state,
         &vmstate_wfxt_timer,
+        &vmstate_sysreg128,
         NULL
     }
 };
-- 
2.43.0



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

* [PATCH 49/61] target/arm: Add syn_aa64_sysreg128trap
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (51 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 48/61] target/arm: Migrate cpreg128 registers Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 50/61] target/arm: Introduce helper_{get,set}_cp_reg128 Richard Henderson
                   ` (12 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

System register access with MRRS/MSRR use a different
exception class.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/syndrome.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
index c48d3b8587..c65678e820 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -45,6 +45,7 @@ enum arm_exception_class {
     EC_AA32_SVC               = 0x11,
     EC_AA32_HVC               = 0x12,
     EC_AA32_SMC               = 0x13,
+    EC_SYSTEMREGISTER128TRAP  = 0x14,
     EC_AA64_SVC               = 0x15,
     EC_AA64_HVC               = 0x16,
     EC_AA64_SMC               = 0x17,
@@ -169,6 +170,15 @@ static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
         | (crm << 1) | isread;
 }
 
+static inline uint32_t syn_aa64_sysreg128trap(int op0, int op1, int op2,
+                                              int crn, int crm, int rt,
+                                              int isread)
+{
+    return (EC_SYSTEMREGISTER128TRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL
+        | (op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (rt << 5)
+        | (crm << 1) | isread;
+}
+
 static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
                                         int crn, int crm, int rt, int isread,
                                         bool is_16bit)
-- 
2.43.0



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

* [PATCH 50/61] target/arm: Introduce helper_{get,set}_cp_reg128
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (52 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 49/61] target/arm: Add syn_aa64_sysreg128trap Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 51/61] target/arm: Implement MRRS, MSRR, SYSP Richard Henderson
                   ` (11 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Helper functions to invoke the write128fn and read128fn
methods of ARMCPRegInfo.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/tcg/helper.h    |  2 ++
 target/arm/tcg/op_helper.c | 28 ++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/target/arm/tcg/helper.h b/target/arm/tcg/helper.h
index 4da32db902..82592d070d 100644
--- a/target/arm/tcg/helper.h
+++ b/target/arm/tcg/helper.h
@@ -90,6 +90,8 @@ DEF_HELPER_3(set_cp_reg, void, env, cptr, i32)
 DEF_HELPER_2(get_cp_reg, i32, env, cptr)
 DEF_HELPER_3(set_cp_reg64, void, env, cptr, i64)
 DEF_HELPER_2(get_cp_reg64, i64, env, cptr)
+DEF_HELPER_3(set_cp_reg128, void, env, cptr, i128)
+DEF_HELPER_2(get_cp_reg128, i128, env, cptr)
 
 DEF_HELPER_2(get_r13_banked, i32, env, i32)
 DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c
index 575e566280..a3ae175a45 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -1025,6 +1025,34 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, const void *rip)
     return res;
 }
 
+void HELPER(set_cp_reg128)(CPUARMState *env, const void *rip, Int128 value)
+{
+    const ARMCPRegInfo *ri = rip;
+
+    if (ri->type & ARM_CP_IO) {
+        bql_lock();
+        ri->write128fn(env, ri, value);
+        bql_unlock();
+    } else {
+        ri->write128fn(env, ri, value);
+    }
+}
+
+Int128 HELPER(get_cp_reg128)(CPUARMState *env, const void *rip)
+{
+    const ARMCPRegInfo *ri = rip;
+    Int128 res;
+
+    if (ri->type & ARM_CP_IO) {
+        bql_lock();
+        res = ri->read128fn(env, ri);
+        bql_unlock();
+    } else {
+        res = ri->read128fn(env, ri);
+    }
+    return res;
+}
+
 void HELPER(pre_hvc)(CPUARMState *env)
 {
     ARMCPU *cpu = env_archcpu(env);
-- 
2.43.0



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

* [PATCH 51/61] target/arm: Implement MRRS, MSRR, SYSP
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (53 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 50/61] target/arm: Introduce helper_{get,set}_cp_reg128 Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 52/61] include/qemu/compiler: Introduce HOST_ENDIAN_FIELDS Richard Henderson
                   ` (10 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/tcg/translate-a64.c | 162 +++++++++++++++++++++++++--------
 target/arm/tcg/a64.decode      |  12 ++-
 2 files changed, 132 insertions(+), 42 deletions(-)

diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 7de8717056..2ec088b641 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -2470,17 +2470,23 @@ redirect_cpreg(DisasContext *s, uint32_t key, bool isread)
 
 /* MRS - move from system register
  * MSR (register) - move to system register
+ * MRRS
+ * MSRR
  * SYS
  * SYSL
+ * SYSP
  * These are all essentially the same insn in 'read' and 'write'
  * versions, with varying op0 fields.
+ *
+ * RT2 is non-zero if and only if this is a 128-bit access.
  */
 static void handle_sys(DisasContext *s, bool isread,
                        unsigned int op0, unsigned int op1, unsigned int op2,
-                       unsigned int crn, unsigned int crm, unsigned int rt)
+                       unsigned int crn, unsigned int crm, unsigned int rt,
+                       unsigned int rt2)
 {
     uint32_t key = ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2);
-    const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
+    const ARMCPRegInfo *ri;
     bool need_exit_tb = false;
     bool nv_trap_to_el2 = false;
     bool nv_redirect_reg = false;
@@ -2488,7 +2494,16 @@ static void handle_sys(DisasContext *s, bool isread,
     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);
+    uint32_t syndrome;
+    bool is128 = rt2 != 0;
+
+    if (is128) {
+        key |= CP_REG_AA64_128BIT_MASK;
+        syndrome = syn_aa64_sysreg128trap(op0, op1, op2, crn, crm, rt, isread);
+    } else {
+        syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
+    }
+    ri = get_arm_cp_reginfo(s->cp_regs, key);
 
     if (crn == 11 || crn == 15) {
         /*
@@ -2508,12 +2523,14 @@ static void handle_sys(DisasContext *s, bool isread,
     }
 
     if (!ri) {
-        /* Unknown register; this might be a guest error or a QEMU
-         * unimplemented feature.
+        /*
+         * Unknown register, or 128-bit access to a 64-bit register.
+         * This might be a guest error or a QEMU unimplemented feature.
          */
-        qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch64 "
+        qemu_log_mask(LOG_UNIMP, "%s%s access to unsupported AArch64 "
                       "system register op0:%d op1:%d crn:%d crm:%d op2:%d\n",
-                      isread ? "read" : "write", op0, op1, crn, crm, op2);
+                      isread ? "read" : "write", is128 ? "128" : "",
+                      op0, op1, crn, crm, op2);
         gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt);
         return;
     }
@@ -2636,7 +2653,7 @@ static void handle_sys(DisasContext *s, bool isread,
          * 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(op0, 0, crn, crm, op2);
+        key &= ~CP_REG_ARM64_SYSREG_OP1_MASK;
         ri = redirect_cpreg(s, key, isread);
         /*
          * We might not have done an update_pc earlier, so check we don't
@@ -2651,32 +2668,44 @@ static void handle_sys(DisasContext *s, bool isread,
          * 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.
+         * The access is 64-bit (R_VFMQB) or 128-bit (R_BSBZP) 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;
+        MemOp mop = MO_ALIGN | MO_ATOM_IFALIGN;
         ARMMMUIdx armmemidx = s->nv2_mem_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_E2;
         int memidx = arm_to_core_mmu_idx(armmemidx);
-        uint32_t syn;
 
         mop |= (s->nv2_mem_be ? MO_BE : MO_LE);
+        disas_set_insn_syndrome(s, syn_data_abort_vncr(0, !isread, 0));
 
         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);
 
-        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);
+        if (is128) {
+            TCGv_i128 t128 = tcg_temp_new_i128();
+
+            mop |= MO_128;
+            if (isread) {
+                tcg_gen_qemu_ld_i128(t128, ptr, memidx, mop);
+                tcg_gen_extr_i128_i64(cpu_reg(s, rt), cpu_reg(s, rt2), t128);
+            } else {
+                tcg_gen_concat_i64_i128(t128, cpu_reg(s, rt), cpu_reg(s, rt2));
+                tcg_gen_qemu_st_i128(t128, ptr, memidx, mop);
+            }
         } else {
-            tcg_gen_qemu_st_i64(tcg_rt, ptr, memidx, mop);
+            mop |= MO_64;
+            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;
     }
@@ -2772,28 +2801,56 @@ static void handle_sys(DisasContext *s, bool isread,
 
     tcg_rt = cpu_reg(s, rt);
 
-    if (isread) {
-        if (ri->type & ARM_CP_CONST) {
-            tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
-        } else if (ri->readfn) {
-            if (!tcg_ri) {
-                tcg_ri = gen_lookup_cp_reg(key);
+    if (is128) {
+        TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
+        TCGv_i128 t128 = tcg_temp_new_i128();
+
+        assert(!(ri->type & ARM_CP_CONST));
+        if (isread) {
+            if (ri->read128fn) {
+                if (!tcg_ri) {
+                    tcg_ri = gen_lookup_cp_reg(key);
+                }
+                gen_helper_get_cp_reg128(t128, tcg_env, tcg_ri);
+            } else {
+                tcg_gen_ld_i128(t128, tcg_env, ri->fieldoffset);
             }
-            gen_helper_get_cp_reg64(tcg_rt, tcg_env, tcg_ri);
+            tcg_gen_extr_i128_i64(tcg_rt, tcg_rt2, t128);
         } else {
-            tcg_gen_ld_i64(tcg_rt, tcg_env, ri->fieldoffset);
+            tcg_gen_concat_i64_i128(t128, tcg_rt, tcg_rt2);
+            if (ri->write128fn) {
+                if (!tcg_ri) {
+                    tcg_ri = gen_lookup_cp_reg(key);
+                }
+                gen_helper_set_cp_reg128(tcg_env, tcg_ri, t128);
+            } else {
+                tcg_gen_st_i128(t128, tcg_env, ri->fieldoffset);
+            }
         }
     } else {
-        if (ri->type & ARM_CP_CONST) {
-            /* If not forbidden by access permissions, treat as WI */
-            return;
-        } else if (ri->writefn) {
-            if (!tcg_ri) {
-                tcg_ri = gen_lookup_cp_reg(key);
+        if (isread) {
+            if (ri->type & ARM_CP_CONST) {
+                tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
+            } else if (ri->readfn) {
+                if (!tcg_ri) {
+                    tcg_ri = gen_lookup_cp_reg(key);
+                }
+                gen_helper_get_cp_reg64(tcg_rt, tcg_env, tcg_ri);
+            } else {
+                tcg_gen_ld_i64(tcg_rt, tcg_env, ri->fieldoffset);
             }
-            gen_helper_set_cp_reg64(tcg_env, tcg_ri, tcg_rt);
         } else {
-            tcg_gen_st_i64(tcg_rt, tcg_env, ri->fieldoffset);
+            if (ri->type & ARM_CP_CONST) {
+                /* If not forbidden by access permissions, treat as WI */
+                return;
+            } else if (ri->writefn) {
+                if (!tcg_ri) {
+                    tcg_ri = gen_lookup_cp_reg(key);
+                }
+                gen_helper_set_cp_reg64(tcg_env, tcg_ri, tcg_rt);
+            } else {
+                tcg_gen_st_i64(tcg_rt, tcg_env, ri->fieldoffset);
+            }
         }
     }
 
@@ -2817,7 +2874,34 @@ static void handle_sys(DisasContext *s, bool isread,
 
 static bool trans_SYS(DisasContext *s, arg_SYS *a)
 {
-    handle_sys(s, a->l, a->op0, a->op1, a->op2, a->crn, a->crm, a->rt);
+    handle_sys(s, a->l, a->op0, a->op1, a->op2, a->crn, a->crm, a->rt, 0);
+    return true;
+}
+
+static bool trans_SYS128(DisasContext *s, arg_sys *a)
+{
+    if (!dc_isar_feature(aa64_sysreg128, s) || (a->rt & 1)) {
+        return false;
+    }
+    handle_sys(s, a->l, a->op0, a->op1, a->op2, a->crn, a->crm,
+               a->rt, a->rt + 1);
+    return true;
+}
+
+static bool trans_SYSP(DisasContext *s, arg_sys *a)
+{
+    int rt2;
+    if (!dc_isar_feature(aa64_sysinstr128, s)) {
+        return false;
+    }
+    if (a->rt == 31) {
+        rt2 = 31;
+    } else if (a->rt & 1) {
+        return false;
+    } else {
+        rt2 = a->rt + 1;
+    }
+    handle_sys(s, a->l, a->op0, a->op1, a->op2, a->crn, a->crm, a->rt, rt2);
     return true;
 }
 
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
index 8c798cde2b..ef9086b6fe 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -290,9 +290,15 @@ MSR_i_SVCR      1101 0101 0000 0 011 0100 0 mask:2 imm:1 011 11111
 # same instruction as far as QEMU is concerned.
 # NB: op0 is bits [20:19], but op0=0b00 is other insns, so we have
 # to hand-decode it.
-SYS             1101 0101 00 l:1 01 op1:3 crn:4 crm:4 op2:3 rt:5 op0=1
-SYS             1101 0101 00 l:1 10 op1:3 crn:4 crm:4 op2:3 rt:5 op0=2
-SYS             1101 0101 00 l:1 11 op1:3 crn:4 crm:4 op2:3 rt:5 op0=3
+&sys            l op0 op1 op2 crn crm rt
+SYS             1101 0101 00 l:1 01 op1:3 crn:4 crm:4 op2:3 rt:5 &sys op0=1
+SYS             1101 0101 00 l:1 10 op1:3 crn:4 crm:4 op2:3 rt:5 &sys op0=2
+SYS             1101 0101 00 l:1 11 op1:3 crn:4 crm:4 op2:3 rt:5 &sys op0=3
+
+# MRRS, MSRR
+SYS128          1101 0101 01 l:1 10 op1:3 crn:4 crm:4 op2:3 rt:5 &sys op0=2
+SYS128          1101 0101 01 l:1 11 op1:3 crn:4 crm:4 op2:3 rt:5 &sys op0=3
+SYSP            1101 0101 01 0   01 op1:3 crn:4 crm:4 op2:3 rt:5 &sys op0=1 l=0
 
 # Exception generation
 
-- 
2.43.0



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

* [PATCH 52/61] include/qemu/compiler: Introduce HOST_ENDIAN_FIELDS
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (54 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 51/61] target/arm: Implement MRRS, MSRR, SYSP Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 53/61] include/hw/core/cpu: Use HOST_ENDIAN_FIELDS in IcountDecr Richard Henderson
                   ` (9 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qemu/compiler.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
index 1c2b673c05..4b9a8ff419 100644
--- a/include/qemu/compiler.h
+++ b/include/qemu/compiler.h
@@ -9,6 +9,17 @@
 
 #define HOST_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
 
+/*
+ * Place two fields, LO, HI, in the order that corresponds to
+ * the host-endian ordering.  To be used when the pair will be
+ * visible through a union with a larger type.
+ */
+#if HOST_BIG_ENDIAN
+#define HOST_ENDIAN_FIELDS(LO, HI)  HI, LO
+#else
+#define HOST_ENDIAN_FIELDS(LO, HI)  LO, HI
+#endif
+
 /* HOST_LONG_BITS is the size of a native pointer in bits. */
 #define HOST_LONG_BITS (__SIZEOF_POINTER__ * 8)
 
-- 
2.43.0



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

* [PATCH 53/61] include/hw/core/cpu: Use HOST_ENDIAN_FIELDS in IcountDecr
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (55 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 52/61] include/qemu/compiler: Introduce HOST_ENDIAN_FIELDS Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 54/61] include/qemu/host-utils: Use HOST_ENDIAN_FIELDS in muldiv64_rounding Richard Henderson
                   ` (8 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/hw/core/cpu.h | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 5eaf41a566..2c0edc2912 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -341,13 +341,7 @@ typedef struct CPUTLB {
 typedef union IcountDecr {
     uint32_t u32;
     struct {
-#if HOST_BIG_ENDIAN
-        uint16_t high;
-        uint16_t low;
-#else
-        uint16_t low;
-        uint16_t high;
-#endif
+        uint16_t HOST_ENDIAN_FIELDS(low, high);
     } u16;
 } IcountDecr;
 
-- 
2.43.0



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

* [PATCH 54/61] include/qemu/host-utils: Use HOST_ENDIAN_FIELDS in muldiv64_rounding
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (56 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 53/61] include/hw/core/cpu: Use HOST_ENDIAN_FIELDS in IcountDecr Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 55/61] target/arm: Use HOST_ENDIAN_FIELDS in CPUARMState Richard Henderson
                   ` (7 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/qemu/host-utils.h | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h
index dd558589cb..5a7e623909 100644
--- a/include/qemu/host-utils.h
+++ b/include/qemu/host-utils.h
@@ -94,11 +94,7 @@ static inline uint64_t muldiv64_rounding(uint64_t a, uint32_t b, uint32_t c,
     union {
         uint64_t ll;
         struct {
-#if HOST_BIG_ENDIAN
-            uint32_t high, low;
-#else
-            uint32_t low, high;
-#endif
+            uint32_t HOST_ENDIAN_FIELDS(low, high);
         } l;
     } u, res;
     uint64_t rl, rh;
-- 
2.43.0



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

* [PATCH 55/61] target/arm: Use HOST_ENDIAN_FIELDS in CPUARMState
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (57 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 54/61] include/qemu/host-utils: Use HOST_ENDIAN_FIELDS in muldiv64_rounding Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 56/61] target/arm: Consolidate definitions of PAR Richard Henderson
                   ` (6 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h | 28 ++++------------------------
 1 file changed, 4 insertions(+), 24 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index a5a8779aba..f7b861c6d6 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -407,17 +407,8 @@ typedef struct CPUArchState {
         union { /* Fault address registers. */
             struct {
                 uint64_t _unused_far0;
-#if HOST_BIG_ENDIAN
-                uint32_t ifar_ns;
-                uint32_t dfar_ns;
-                uint32_t ifar_s;
-                uint32_t dfar_s;
-#else
-                uint32_t dfar_ns;
-                uint32_t ifar_ns;
-                uint32_t dfar_s;
-                uint32_t ifar_s;
-#endif
+                uint32_t HOST_ENDIAN_FIELDS(dfar_ns, ifar_ns);
+                uint32_t HOST_ENDIAN_FIELDS(dfar_s, ifar_s);
                 uint64_t _unused_far3;
             };
             uint64_t far_el[4];
@@ -444,21 +435,10 @@ typedef struct CPUArchState {
         uint64_t c9_pminten; /* perf monitor interrupt enables */
         union { /* Memory attribute redirection */
             struct {
-#if HOST_BIG_ENDIAN
                 uint64_t _unused_mair_0;
-                uint32_t mair1_ns;
-                uint32_t mair0_ns;
+                uint32_t HOST_ENDIAN_FIELDS(mair0_ns, mair1_ns);
                 uint64_t _unused_mair_1;
-                uint32_t mair1_s;
-                uint32_t mair0_s;
-#else
-                uint64_t _unused_mair_0;
-                uint32_t mair0_ns;
-                uint32_t mair1_ns;
-                uint64_t _unused_mair_1;
-                uint32_t mair0_s;
-                uint32_t mair1_s;
-#endif
+                uint32_t HOST_ENDIAN_FIELDS(mair0_s, mair1_s);
             };
             uint64_t mair_el[4];
         };
-- 
2.43.0



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

* [PATCH 56/61] target/arm: Consolidate definitions of PAR
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (58 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 55/61] target/arm: Use HOST_ENDIAN_FIELDS in CPUARMState Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 57/61] target/arm: Extend PAR_EL1 to 128-bit Richard Henderson
                   ` (5 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Create a function define_par_register which handles the 3
distinct cases for PAR.  It is easier to understand with
the definitions all in one place.

Make the aarch64 to be the primary definition, when present,
rather than being an alias of the 64-bit non-secure aa32 reg.
Remove the unnecessary .writefn from the aarch64 defintion,
and drop it from the 32-bit definition with LPAE.

Remove the LPAE test from par_write, since it will no longer
be used in that situation.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 103 +++++++++++++++++++++++++++++++-------------
 1 file changed, 73 insertions(+), 30 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 6f20d3986e..0282e41c59 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2439,9 +2439,7 @@ static const ARMCPRegInfo gen_timer_ecv_cp_reginfo[] = {
 
 static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
-    if (arm_feature(env, ARM_FEATURE_LPAE)) {
-        raw_write(env, ri, value);
-    } else if (arm_feature(env, ARM_FEATURE_V7)) {
+    if (arm_feature(env, ARM_FEATURE_V7)) {
         raw_write(env, ri, value & 0xfffff6ff);
     } else {
         raw_write(env, ri, value & 0xfffff1ff);
@@ -3235,10 +3233,11 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
     { .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .type = ARM_CP_CONST, .resetvalue = 0 },
-    { .name = "PAR", .cp = 15, .crm = 7, .opc1 = 0,
-      .access = PL1_RW, .type = ARM_CP_64BIT, .resetvalue = 0,
-      .bank_fieldoffsets = { offsetof(CPUARMState, cp15.par_s),
-                             offsetof(CPUARMState, cp15.par_ns)} },
+
+    /*
+     * The primary definitions of TTBR[01]_EL1 are in vmsa_cp_reginfo[].
+     * Here we need only provide the 64-bit views for AArch32.
+     */
     { .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .type = ARM_CP_64BIT | ARM_CP_ALIAS,
@@ -3253,6 +3252,71 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
       .writefn = vmsa_ttbr_write, .raw_writefn = raw_write },
 };
 
+static void define_par_register(ARMCPU *cpu)
+{
+    /*
+     * For v8:
+     * The aarch64 reg is primary, since it might be 128-bit.
+     * The aarch32 64-bit non-secure reg is secondary to aa64.
+     * The aarch32 64-bit secure reg is primary.
+     *
+     * For v7:
+     * The aarch32 64-bit s+ns regs are primary.
+     *
+     * The aarch32 32-bit regs are secondary to one of the above,
+     * and we also don't expose them to gdb.
+     */
+    static const ARMCPRegInfo parv8_reginfo = {
+        .name = "PAR_EL1", .state = ARM_CP_STATE_AA64,
+        .opc0 = 3, .opc1 = 0, .crn = 7, .crm = 4, .opc2 = 0,
+        .access = PL1_RW, .fgt = FGT_PAR_EL1,
+        .fieldoffset = offsetof(CPUARMState, cp15.par_el[1])
+    };
+
+    static ARMCPRegInfo par64_reginfo[2] = {
+        [0 ... 1] = {
+            .state = ARM_CP_STATE_AA32,
+            .cp = 15, .crm = 7, .opc1 = 0,
+            .type = ARM_CP_64BIT, .access = PL1_RW,
+        },
+        [0].name = "PAR",
+        [0].secure = ARM_CP_SECSTATE_NS,
+        [0].fieldoffset = offsetof(CPUARMState, cp15.par_ns),
+        [1].name = "PAR_S",
+        [1].secure = ARM_CP_SECSTATE_S,
+        [1].fieldoffset = offsetof(CPUARMState, cp15.par_s),
+    };
+
+    static ARMCPRegInfo par32_reginfo = {
+        .name = "PAR", .state = ARM_CP_STATE_AA32,
+        .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
+        .access = PL1_RW, .resetvalue = 0,
+        .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.par_s),
+                               offsetoflow32(CPUARMState, cp15.par_ns) },
+        .writefn = par_write,
+    };
+
+    CPUARMState *env = &cpu->env;
+
+    /* With only VAPA, define a 32-bit reg that filters bits from write. */
+    if (!arm_feature(env, ARM_FEATURE_LPAE)) {
+        define_one_arm_cp_reg(cpu, &par32_reginfo);
+        return;
+    }
+
+    /* With LPAE, the 32-bit regs are aliases of 64-bit regs. */
+    par32_reginfo.type = ARM_CP_ALIAS | ARM_CP_NO_GDB;
+    par32_reginfo.writefn = NULL;
+    define_one_arm_cp_reg(cpu, &par32_reginfo);
+
+    if (arm_feature(env, ARM_FEATURE_V8)) {
+        define_one_arm_cp_reg(cpu, &parv8_reginfo);
+        par64_reginfo[0].type |= ARM_CP_ALIAS;
+    }
+
+    define_arm_cp_regs(cpu, par64_reginfo);
+}
+
 static uint64_t aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     return vfp_get_fpcr(env);
@@ -3710,13 +3774,6 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2,
       .fgt = FGT_DCCISW,
       .access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP },
-    { .name = "PAR_EL1", .state = ARM_CP_STATE_AA64,
-      .type = ARM_CP_ALIAS,
-      .opc0 = 3, .opc1 = 0, .crn = 7, .crm = 4, .opc2 = 0,
-      .access = PL1_RW, .resetvalue = 0,
-      .fgt = FGT_PAR_EL1,
-      .fieldoffset = offsetof(CPUARMState, cp15.par_el[1]),
-      .writefn = par_write },
     /* 32 bit cache operations */
     { .name = "ICIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0,
       .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_ticab },
@@ -6674,23 +6731,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
         define_one_arm_cp_reg(cpu, &gen_timer_cntpoff_reginfo);
     }
 #endif
-    if (arm_feature(env, ARM_FEATURE_VAPA)) {
-        ARMCPRegInfo vapa_cp_reginfo[] = {
-            { .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
-              .access = PL1_RW, .resetvalue = 0,
-              .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.par_s),
-                                     offsetoflow32(CPUARMState, cp15.par_ns) },
-              .writefn = par_write},
-        };
 
-        /*
-         * When LPAE exists this 32-bit PAR register is an alias of the
-         * 64-bit AArch32 PAR register defined in lpae_cp_reginfo[]
-         */
-        if (arm_feature(env, ARM_FEATURE_LPAE)) {
-            vapa_cp_reginfo[0].type = ARM_CP_ALIAS | ARM_CP_NO_GDB;
-        }
-        define_arm_cp_regs(cpu, vapa_cp_reginfo);
+    if (arm_feature(env, ARM_FEATURE_VAPA)) {
+        define_par_register(cpu);
     }
     if (arm_feature(env, ARM_FEATURE_CACHE_TEST_CLEAN)) {
         define_arm_cp_regs(cpu, cache_test_clean_cp_reginfo);
-- 
2.43.0



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

* [PATCH 57/61] target/arm: Extend PAR_EL1 to 128-bit
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (59 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 56/61] target/arm: Consolidate definitions of PAR Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 58/61] target/arm: Consolidate definitions of TTBR[01] Richard Henderson
                   ` (4 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

So far, just extend the data type and check access; do not yet
produce the 128-bit AT format result.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h           | 14 +++++++-------
 target/arm/internals.h     |  1 +
 target/arm/helper.c        | 17 ++++++++++++++++-
 target/arm/tcg/cpregs-at.c |  4 +++-
 4 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index f7b861c6d6..57e298363c 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -415,15 +415,14 @@ typedef struct CPUArchState {
         };
         uint64_t hpfar_el2;
         uint64_t hstr_el2;
-        union { /* Translation result. */
+        /* Translation result. */
+        union {
             struct {
-                uint64_t _unused_par_0;
-                uint64_t par_ns;
-                uint64_t _unused_par_1;
-                uint64_t par_s;
-            };
-            uint64_t par_el[4];
+                uint64_t HOST_ENDIAN_FIELDS(par_ns, _unused_par_0);
+            };                  /* aa32 */
+            Int128 par_el1;     /* aa64 */
         };
+        uint64_t par_s;         /* aa32 */
 
         uint32_t c9_insn; /* Cache lockdown registers.  */
         uint32_t c9_data;
@@ -1703,6 +1702,7 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
 #define SCR_HXEN              (1ULL << 38)
 #define SCR_TRNDR             (1ULL << 40)
 #define SCR_ENTP2             (1ULL << 41)
+#define SCR_D128EN            (1ULL << 47)
 #define SCR_GPF               (1ULL << 48)
 #define SCR_NSE               (1ULL << 62)
 
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 08e2acdb99..31934435db 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -232,6 +232,7 @@ FIELD(VTCR, SL2, 33, 1)
 #define HCRX_CMOW     (1ULL << 9)
 #define HCRX_MCE2     (1ULL << 10)
 #define HCRX_MSCEN    (1ULL << 11)
+#define HCRX_D128EN   (1ULL << 17)
 
 #define HPFAR_NS      (1ULL << 63)
 
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0282e41c59..fb37d0674b 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -498,6 +498,20 @@ static CPAccessResult access_tacr(CPUARMState *env, const ARMCPRegInfo *ri,
     return CP_ACCESS_OK;
 }
 
+static CPAccessResult access_d128(CPUARMState *env, const ARMCPRegInfo *ri,
+                                  bool isread)
+{
+    int el = arm_current_el(env);
+
+    if (el <= 1 && !(arm_hcrx_el2_eff(env) & HCRX_D128EN)) {
+        return CP_ACCESS_TRAP_EL2;
+    }
+    if (el <= 2 && !(env->cp15.scr_el3 & SCR_D128EN)) {
+        return CP_ACCESS_TRAP_EL3;
+    }
+    return CP_ACCESS_OK;
+}
+
 static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     ARMCPU *cpu = env_archcpu(env);
@@ -3270,7 +3284,8 @@ static void define_par_register(ARMCPU *cpu)
         .name = "PAR_EL1", .state = ARM_CP_STATE_AA64,
         .opc0 = 3, .opc1 = 0, .crn = 7, .crm = 4, .opc2 = 0,
         .access = PL1_RW, .fgt = FGT_PAR_EL1,
-        .fieldoffset = offsetof(CPUARMState, cp15.par_el[1])
+        .type = ARM_CP_128BIT, .access128fn = access_d128,
+        .fieldoffset = offsetof(CPUARMState, cp15.par_el1)
     };
 
     static ARMCPRegInfo par64_reginfo[2] = {
diff --git a/target/arm/tcg/cpregs-at.c b/target/arm/tcg/cpregs-at.c
index 398a61d398..ebf5a04a11 100644
--- a/target/arm/tcg/cpregs-at.c
+++ b/target/arm/tcg/cpregs-at.c
@@ -322,6 +322,7 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
     bool regime_e20 = (hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE);
     bool for_el3 = false;
     ARMSecuritySpace ss;
+    uint64_t par64;
 
     switch (ri->opc2 & 6) {
     case 0:
@@ -359,7 +360,8 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
     }
 
     ss = for_el3 ? arm_security_space(env) : arm_security_space_below_el3(env);
-    env->cp15.par_el[1] = do_ats_write(env, value, access_type, mmu_idx, ss);
+    par64 = do_ats_write(env, value, access_type, mmu_idx, ss);
+    env->cp15.par_el1 = int128_make64(par64);
 }
 
 static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri,
-- 
2.43.0



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

* [PATCH 58/61] target/arm: Consolidate definitions of TTBR[01]
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (60 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 57/61] target/arm: Extend PAR_EL1 to 128-bit Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 59/61] target/arm: Split out flush_if_asid_change Richard Henderson
                   ` (3 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Create a function define_ttbr_register which handles the 3
distinct cases for TTBR[01] registers.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 165 +++++++++++++++++++++++++++++++-------------
 1 file changed, 116 insertions(+), 49 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index fb37d0674b..3dde778369 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2973,26 +2973,6 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 5, 2, 0),
       .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 5, 2, 0),
       .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,
-      .access = PL1_RW, .accessfn = access_tvm_trvm,
-      .fgt = FGT_TTBR0_EL1,
-      .nv2_redirect_offset = 0x200 | NV2_REDIR_NV1,
-      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 0),
-      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 0),
-      .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write,
-      .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s),
-                             offsetof(CPUARMState, cp15.ttbr0_ns) } },
-    { .name = "TTBR1_EL1", .state = ARM_CP_STATE_BOTH,
-      .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,
-      .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 1),
-      .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 1),
-      .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write,
-      .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
-                             offsetof(CPUARMState, cp15.ttbr1_ns) } },
     { .name = "TCR_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
@@ -3247,23 +3227,6 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
     { .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1,
       .access = PL1_RW, .accessfn = access_tvm_trvm,
       .type = ARM_CP_CONST, .resetvalue = 0 },
-
-    /*
-     * The primary definitions of TTBR[01]_EL1 are in vmsa_cp_reginfo[].
-     * Here we need only provide the 64-bit views for AArch32.
-     */
-    { .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0,
-      .access = PL1_RW, .accessfn = access_tvm_trvm,
-      .type = ARM_CP_64BIT | ARM_CP_ALIAS,
-      .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s),
-                             offsetof(CPUARMState, cp15.ttbr0_ns) },
-      .writefn = vmsa_ttbr_write, .raw_writefn = raw_write },
-    { .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1,
-      .access = PL1_RW, .accessfn = access_tvm_trvm,
-      .type = ARM_CP_64BIT | ARM_CP_ALIAS,
-      .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
-                             offsetof(CPUARMState, cp15.ttbr1_ns) },
-      .writefn = vmsa_ttbr_write, .raw_writefn = raw_write },
 };
 
 static void define_par_register(ARMCPU *cpu)
@@ -3332,6 +3295,121 @@ static void define_par_register(ARMCPU *cpu)
     define_arm_cp_regs(cpu, par64_reginfo);
 }
 
+static void define_ttbr_registers(ARMCPU *cpu)
+{
+    /*
+     * For v8:
+     * The aarch64 regs are primary, since they might be 128-bit.
+     * The aarch32 64-bit non-secure regs are secondary to aa64 el1.
+     * The aarch32 64-bit httbr is secondary to aa64 el2.
+     * The aarch32 64-bit secure ttbr0 is secondary to aa64 el3.
+     * The aarch32 64-bit secure ttbr1 is primary.
+     *
+     * For v7:
+     * The aarch32 64-bit s+ns regs are primary.
+     *
+     * The aarch32 32-bit regs are secondary to one of the above,
+     * and we also don't expose them to gdb.
+     */
+    static const ARMCPRegInfo ttbrv8_reginfo[] = {
+        { .name = "TTBR0_EL1", .state = ARM_CP_STATE_AA64,
+          .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,
+          .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 0),
+          .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 0),
+          .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
+          .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[1]) },
+        { .name = "TTBR1_EL1", .state = ARM_CP_STATE_AA64,
+          .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,
+          .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 1),
+          .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 1),
+          .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
+          .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el[1]) },
+        { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64,
+          .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0,
+          .access = PL2_RW, .resetvalue = 0,
+          .writefn = vmsa_tcr_ttbr_el2_write, .raw_writefn = raw_write,
+          .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
+        { .name = "TTBR0_EL3", .state = ARM_CP_STATE_AA64,
+          .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 0,
+          .access = PL3_RW, .resetvalue = 0,
+          .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[3]) },
+    };
+
+    static ARMCPRegInfo ttbr64_reginfo[] = {
+        [0 ... 3] = {
+            .cp = 15, .crm = 2, .type = ARM_CP_64BIT,
+            .access = PL1_RW, .accessfn = access_tvm_trvm,
+            .writefn = vmsa_ttbr_write, .raw_writefn = raw_write
+        },
+        [0 ... 1].opc1 = 0,
+        [0].name = "TTBR0",
+        [0].secure = ARM_CP_SECSTATE_NS,
+        [0].fieldoffset = offsetof(CPUARMState, cp15.ttbr0_ns),
+        [1].name = "TTBR0_S",
+        [1].secure = ARM_CP_SECSTATE_S,
+        [1].fieldoffset = offsetof(CPUARMState, cp15.ttbr0_s),
+
+        [2 ... 3].opc1 = 1,
+        [2].name = "TTBR1",
+        [2].secure = ARM_CP_SECSTATE_NS,
+        [2].fieldoffset = offsetof(CPUARMState, cp15.ttbr1_ns),
+        [3].name = "TTBR1_S",
+        [3].secure = ARM_CP_SECSTATE_S,
+        [3].fieldoffset = offsetof(CPUARMState, cp15.ttbr1_s),
+
+        [4] = {
+            .name = "HTTBR", .cp = 15, .crm = 2, .opc1 = 4,
+            .access = PL2_RW, .type = ARM_CP_64BIT,
+            .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2])
+        },
+    };
+
+    static ARMCPRegInfo ttbr32_reginfo[] = {
+        { .name = "TTBR0", .cp = 15, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0,
+          .access = PL1_RW, .accessfn = access_tvm_trvm,
+          .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
+          .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s),
+                                 offsetof(CPUARMState, cp15.ttbr0_ns) } },
+        { .name = "TTBR1", .cp = 15, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1,
+          .access = PL1_RW, .accessfn = access_tvm_trvm,
+          .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
+          .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
+                                 offsetof(CPUARMState, cp15.ttbr1_ns) } },
+    };
+
+    CPUARMState *env = &cpu->env;
+
+    /* With only VMSA, define a 32-bit reg that filters bits from write. */
+    if (!arm_feature(env, ARM_FEATURE_LPAE)) {
+        define_arm_cp_regs(cpu, ttbr32_reginfo);
+        return;
+    }
+
+    /* With LPAE, the 32-bit regs are aliases of 64-bit regs. */
+    for (int i = 0; i < ARRAY_SIZE(ttbr32_reginfo); ++i) {
+        ttbr32_reginfo[i].type = ARM_CP_ALIAS | ARM_CP_NO_GDB;
+    }
+    define_arm_cp_regs(cpu, ttbr32_reginfo);
+
+    if (arm_feature(env, ARM_FEATURE_V8)) {
+        define_arm_cp_regs(cpu, ttbrv8_reginfo);
+
+        ttbr64_reginfo[0].type |= ARM_CP_ALIAS;
+        ttbr64_reginfo[1].type |= ARM_CP_ALIAS;
+        ttbr64_reginfo[2].type |= ARM_CP_ALIAS;
+        /* Index 3, TTBR1_S, is not an alias. */
+        ttbr64_reginfo[4].type |= ARM_CP_ALIAS;
+    }
+
+    define_arm_cp_regs(cpu, ttbr64_reginfo);
+}
+
 static uint64_t aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     return vfp_get_fpcr(env);
@@ -4386,14 +4464,6 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
       .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,
-      .access = PL2_RW, .resetvalue = 0,
-      .writefn = vmsa_tcr_ttbr_el2_write, .raw_writefn = raw_write,
-      .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
-    { .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2,
-      .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS,
-      .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
 #ifndef CONFIG_USER_ONLY
     { .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0,
@@ -4578,10 +4648,6 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
       .access = PL1_RW, .accessfn = access_trap_aa32s_el1,
       .writefn = vbar_write, .resetvalue = 0,
       .fieldoffset = offsetof(CPUARMState, cp15.mvbar) },
-    { .name = "TTBR0_EL3", .state = ARM_CP_STATE_AA64,
-      .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 0,
-      .access = PL3_RW, .resetvalue = 0,
-      .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[3]) },
     { .name = "TCR_EL3", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 2,
       .access = PL3_RW,
@@ -6727,6 +6793,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
     } else {
         define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo);
         define_arm_cp_regs(cpu, vmsa_cp_reginfo);
+        define_ttbr_registers(cpu);
         /* TTCBR2 is introduced with ARMv8.2-AA32HPD.  */
         if (cpu_isar_feature(aa32_hpd, cpu)) {
             define_one_arm_cp_reg(cpu, &ttbcr2_reginfo);
-- 
2.43.0



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

* [PATCH 59/61] target/arm: Split out flush_if_asid_change
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (61 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 58/61] target/arm: Consolidate definitions of TTBR[01] Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 60/61] target/arm: Use flush_if_asid_change in vmsa_ttbr_write Richard Henderson
                   ` (2 subsequent siblings)
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3dde778369..7a817b7e28 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2893,6 +2893,15 @@ static void vmsa_tcr_el12_write(CPUARMState *env, const ARMCPRegInfo *ri,
     raw_write(env, ri, value);
 }
 
+static void flush_if_asid_change(CPUARMState *env, uint64_t old,
+                                 uint64_t new, unsigned mask)
+{
+    /* The ASID or VMID is in bits [63:48]. */
+    if ((old ^ new) >> 48) {
+        tlb_flush_by_mmuidx(env_cpu(env), mask);
+    }
+}
+
 static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                             uint64_t value)
 {
@@ -2914,12 +2923,11 @@ static void vmsa_tcr_ttbr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
      * TCR_EL2.A1 to know if this is really the TTBRx_EL2 that
      * holds the active ASID, only checking the field that might.
      */
-    if (extract64(raw_read(env, ri) ^ value, 48, 16) &&
-        (arm_hcr_el2_eff(env) & HCR_E2H)) {
-        uint16_t mask = ARMMMUIdxBit_E20_2 |
-                        ARMMMUIdxBit_E20_2_PAN |
-                        ARMMMUIdxBit_E20_0;
-        tlb_flush_by_mmuidx(env_cpu(env), mask);
+    if (arm_hcr_el2_eff(env) & HCR_E2H) {
+        flush_if_asid_change(env, raw_read(env, ri), value,
+                             ARMMMUIdxBit_E20_2 |
+                             ARMMMUIdxBit_E20_2_PAN |
+                             ARMMMUIdxBit_E20_0);
     }
     raw_write(env, ri, value);
 }
@@ -2927,16 +2935,11 @@ static void vmsa_tcr_ttbr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
 static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                         uint64_t value)
 {
-    ARMCPU *cpu = env_archcpu(env);
-    CPUState *cs = CPU(cpu);
-
     /*
      * A change in VMID to the stage2 page table (Stage2) invalidates
      * the stage2 and combined stage 1&2 tlbs (EL10_1 and EL10_0).
      */
-    if (extract64(raw_read(env, ri) ^ value, 48, 16) != 0) {
-        tlb_flush_by_mmuidx(cs, alle1_tlbmask(env));
-    }
+    flush_if_asid_change(env, raw_read(env, ri), value, alle1_tlbmask(env));
     raw_write(env, ri, value);
 }
 
-- 
2.43.0



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

* [PATCH 60/61] target/arm: Use flush_if_asid_change in vmsa_ttbr_write
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (62 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 59/61] target/arm: Split out flush_if_asid_change Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  1:04 ` [PATCH 61/61] target/arm: Extend TTBR system registers to 128-bit Richard Henderson
  2025-08-27  2:36 ` [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

Only flush the subset of tlbs that are affected by the ttbr
register to which we are writing.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/helper.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 7a817b7e28..e8442731d4 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2905,11 +2905,20 @@ static void flush_if_asid_change(CPUARMState *env, uint64_t old,
 static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                             uint64_t value)
 {
-    /* If the ASID changes (with a 64-bit write), we must flush the TLB.  */
-    if (cpreg_field_type(ri) == MO_64 &&
-        extract64(raw_read(env, ri) ^ value, 48, 16) != 0) {
-        ARMCPU *cpu = env_archcpu(env);
-        tlb_flush(CPU(cpu));
+    /*
+     * If the ASID changes (with a 64-bit write), we must flush the TLB.
+     * The non-secure ttbr registers affect the EL1 regime;
+     * the secure ttbr registers affect the AA32 EL3 regime.
+     */
+    if (cpreg_field_type(ri) == MO_64) {
+        flush_if_asid_change(env, raw_read(env, ri), value,
+                             ri->secure & ARM_CP_SECSTATE_S
+                             ? (ARMMMUIdxBit_E30_0 |
+                                ARMMMUIdxBit_E30_3_PAN |
+                                ARMMMUIdxBit_E3)
+                             : (ARMMMUIdxBit_E10_1 |
+                                ARMMMUIdxBit_E10_1_PAN |
+                                ARMMMUIdxBit_E10_0));
     }
     raw_write(env, ri, value);
 }
-- 
2.43.0



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

* [PATCH 61/61] target/arm: Extend TTBR system registers to 128-bit
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (63 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 60/61] target/arm: Use flush_if_asid_change in vmsa_ttbr_write Richard Henderson
@ 2025-08-27  1:04 ` Richard Henderson
  2025-08-27  2:36 ` [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  1:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

So far, just extend the data type and check access; do not yet
consume the 128-bit table format.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h    | 31 +++++++++-------
 target/arm/helper.c | 86 ++++++++++++++++++++++++++++++++++++---------
 target/arm/ptw.c    | 14 +++++---
 3 files changed, 96 insertions(+), 35 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 57e298363c..4c929de5ab 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -343,25 +343,30 @@ typedef struct CPUArchState {
         uint32_t c1_xscaleauxcr; /* XScale auxiliary control register.  */
         uint64_t sder; /* Secure debug enable register. */
         uint32_t nsacr; /* Non-secure access control register. */
-        union { /* MMU translation table base 0. */
+        /* MMU translation table bases. */
+        union {
             struct {
-                uint64_t _unused_ttbr0_0;
-                uint64_t ttbr0_ns;
-                uint64_t _unused_ttbr0_1;
-                uint64_t ttbr0_s;
+                uint64_t HOST_ENDIAN_FIELDS(ttbr0_ns, _unused_ttbr0_0);
+                uint64_t HOST_ENDIAN_FIELDS(ttbr1_ns, _unused_ttbr1_0);
             };
-            uint64_t ttbr0_el[4];
+            Int128 ttbr_el1[2];
         };
-        union { /* MMU translation table base 1. */
+        union {
             struct {
-                uint64_t _unused_ttbr1_0;
-                uint64_t ttbr1_ns;
-                uint64_t _unused_ttbr1_1;
-                uint64_t ttbr1_s;
+                uint64_t HOST_ENDIAN_FIELDS(httbr, _unused_httbr_0);
             };
-            uint64_t ttbr1_el[4];
+            Int128 ttbr_el2[2];
+        };
+        union {
+            uint64_t ttbr0_el3;
+            uint64_t ttbr_s[2];
+        };
+        union {
+            struct {
+                uint64_t HOST_ENDIAN_FIELDS(vttbr, _unused_vttbr_0);
+            };
+            Int128 vttbr_el2;
         };
-        uint64_t vttbr_el2; /* Virtualization Translation Table Base.  */
         uint64_t vsttbr_el2; /* Secure Virtualization Translation Table. */
         /* MMU translation table base control. */
         uint64_t tcr_el[4];
diff --git a/target/arm/helper.c b/target/arm/helper.c
index e8442731d4..ebe59a5765 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -512,6 +512,16 @@ static CPAccessResult access_d128(CPUARMState *env, const ARMCPRegInfo *ri,
     return CP_ACCESS_OK;
 }
 
+static CPAccessResult access_tvm_trvm_d128(CPUARMState *env,
+                                           const ARMCPRegInfo *ri, bool isread)
+{
+    CPAccessResult ret = access_tvm_trvm(env, ri, isread);
+    if (ret == CP_ACCESS_OK) {
+        ret = access_d128(env, ri, isread);
+    }
+    return ret;
+}
+
 static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     ARMCPU *cpu = env_archcpu(env);
@@ -2923,6 +2933,17 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
     raw_write(env, ri, value);
 }
 
+static void vmsa_ttbr_write128(CPUARMState *env, const ARMCPRegInfo *ri,
+                               Int128 value)
+{
+    flush_if_asid_change(env, int128_getlo(raw_read128(env, ri)),
+                         int128_getlo(value),
+                         ARMMMUIdxBit_E10_1 |
+                         ARMMMUIdxBit_E10_1_PAN |
+                         ARMMMUIdxBit_E10_0);
+    raw_write128(env, ri, value);
+}
+
 static void vmsa_tcr_ttbr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                     uint64_t value)
 {
@@ -2941,6 +2962,19 @@ static void vmsa_tcr_ttbr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
     raw_write(env, ri, value);
 }
 
+static void vmsa_tcr_ttbr_el2_write128(CPUARMState *env, const ARMCPRegInfo *ri,
+                                       Int128 value)
+{
+    if (arm_hcr_el2_eff(env) & HCR_E2H) {
+        flush_if_asid_change(env, int128_getlo(raw_read128(env, ri)),
+                             int128_getlo(value),
+                             ARMMMUIdxBit_E20_2 |
+                             ARMMMUIdxBit_E20_2_PAN |
+                             ARMMMUIdxBit_E20_0);
+    }
+    raw_write128(env, ri, value);
+}
+
 static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                         uint64_t value)
 {
@@ -2952,6 +2986,14 @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
     raw_write(env, ri, value);
 }
 
+static void vttbr_write128(CPUARMState *env, const ARMCPRegInfo *ri,
+                           Int128 value)
+{
+    flush_if_asid_change(env, int128_getlo(raw_read128(env, ri)),
+                         int128_getlo(value), alle1_tlbmask(env));
+    raw_write128(env, ri, value);
+}
+
 static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = {
     { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .accessfn = access_tvm_trvm, .type = ARM_CP_ALIAS,
@@ -3327,30 +3369,36 @@ static void define_ttbr_registers(ARMCPU *cpu)
         { .name = "TTBR0_EL1", .state = ARM_CP_STATE_AA64,
           .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0,
           .access = PL1_RW, .accessfn = access_tvm_trvm,
-          .fgt = FGT_TTBR0_EL1,
+          .access128fn = access_tvm_trvm_d128,
+          .fgt = FGT_TTBR0_EL1, .type = ARM_CP_128BIT,
           .nv2_redirect_offset = 0x200 | NV2_REDIR_NV1,
           .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 0),
           .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 0),
           .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
-          .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[1]) },
+          .write128fn = vmsa_ttbr_write128, .raw_write128fn = raw_write128,
+          .fieldoffset = offsetof(CPUARMState, cp15.ttbr_el1[0]) },
         { .name = "TTBR1_EL1", .state = ARM_CP_STATE_AA64,
           .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1,
           .access = PL1_RW, .accessfn = access_tvm_trvm,
-          .fgt = FGT_TTBR1_EL1,
+          .access128fn = access_tvm_trvm_d128,
+          .fgt = FGT_TTBR1_EL1, .type = ARM_CP_128BIT,
           .nv2_redirect_offset = 0x210 | NV2_REDIR_NV1,
           .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 1),
           .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 1),
           .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
-          .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el[1]) },
+          .write128fn = vmsa_ttbr_write128, .raw_write128fn = raw_write128,
+          .fieldoffset = offsetof(CPUARMState, cp15.ttbr_el1[1]) },
         { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64,
           .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0,
-          .access = PL2_RW, .resetvalue = 0,
+          .access = PL2_RW, .access128fn = access_d128, .type = ARM_CP_128BIT,
           .writefn = vmsa_tcr_ttbr_el2_write, .raw_writefn = raw_write,
-          .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
+          .write128fn = vmsa_tcr_ttbr_el2_write128,
+          .raw_write128fn = raw_write128,
+          .fieldoffset = offsetof(CPUARMState, cp15.ttbr_el2[0]) },
         { .name = "TTBR0_EL3", .state = ARM_CP_STATE_AA64,
           .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 0,
           .access = PL3_RW, .resetvalue = 0,
-          .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[3]) },
+          .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el3) },
     };
 
     static ARMCPRegInfo ttbr64_reginfo[] = {
@@ -3365,7 +3413,7 @@ static void define_ttbr_registers(ARMCPU *cpu)
         [0].fieldoffset = offsetof(CPUARMState, cp15.ttbr0_ns),
         [1].name = "TTBR0_S",
         [1].secure = ARM_CP_SECSTATE_S,
-        [1].fieldoffset = offsetof(CPUARMState, cp15.ttbr0_s),
+        [1].fieldoffset = offsetof(CPUARMState, cp15.ttbr_s[0]),
 
         [2 ... 3].opc1 = 1,
         [2].name = "TTBR1",
@@ -3373,12 +3421,12 @@ static void define_ttbr_registers(ARMCPU *cpu)
         [2].fieldoffset = offsetof(CPUARMState, cp15.ttbr1_ns),
         [3].name = "TTBR1_S",
         [3].secure = ARM_CP_SECSTATE_S,
-        [3].fieldoffset = offsetof(CPUARMState, cp15.ttbr1_s),
+        [3].fieldoffset = offsetof(CPUARMState, cp15.ttbr_s[1]),
 
         [4] = {
             .name = "HTTBR", .cp = 15, .crm = 2, .opc1 = 4,
             .access = PL2_RW, .type = ARM_CP_64BIT,
-            .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2])
+            .fieldoffset = offsetof(CPUARMState, cp15.httbr)
         },
     };
 
@@ -3386,12 +3434,12 @@ static void define_ttbr_registers(ARMCPU *cpu)
         { .name = "TTBR0", .cp = 15, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0,
           .access = PL1_RW, .accessfn = access_tvm_trvm,
           .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
-          .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s),
+          .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr_s[0]),
                                  offsetof(CPUARMState, cp15.ttbr0_ns) } },
         { .name = "TTBR1", .cp = 15, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1,
           .access = PL1_RW, .accessfn = access_tvm_trvm,
           .writefn = vmsa_ttbr_write, .raw_writefn = raw_write,
-          .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
+          .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr_s[1]),
                                  offsetof(CPUARMState, cp15.ttbr1_ns) } },
     };
 
@@ -4460,11 +4508,14 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
       .cp = 15, .opc1 = 6, .crm = 2,
       .type = ARM_CP_64BIT | ARM_CP_ALIAS,
       .access = PL2_RW, .accessfn = access_el3_aa32ns,
-      .fieldoffset = offsetof(CPUARMState, cp15.vttbr_el2),
+      .fieldoffset = offsetof(CPUARMState, cp15.vttbr),
       .writefn = vttbr_write, .raw_writefn = raw_write },
     { .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,
+      .type = ARM_CP_128BIT,
+      .access = PL2_RW, .access128fn = access_d128,
+      .writefn = vttbr_write, .raw_writefn = raw_write,
+      .write128fn = vttbr_write128, .raw_write128fn = raw_write128,
       .nv2_redirect_offset = 0x20,
       .fieldoffset = offsetof(CPUARMState, cp15.vttbr_el2) },
     { .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH,
@@ -6016,9 +6067,10 @@ static const ARMCPRegInfo contextidr_el2 = {
 static const ARMCPRegInfo vhe_reginfo[] = {
     { .name = "TTBR1_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 1,
-      .access = PL2_RW, .writefn = vmsa_tcr_ttbr_el2_write,
-      .raw_writefn = raw_write,
-      .fieldoffset = offsetof(CPUARMState, cp15.ttbr1_el[2]) },
+      .access = PL2_RW, .access128fn = access_d128, .type = ARM_CP_128BIT,
+      .writefn = vmsa_tcr_ttbr_el2_write, .raw_writefn = raw_write,
+      .write128fn = vmsa_tcr_ttbr_el2_write128, .raw_write128fn = raw_write128,
+      .fieldoffset = offsetof(CPUARMState, cp15.ttbr_el2[1]) },
 #ifndef CONFIG_USER_ONLY
     { .name = "CNTHV_CVAL_EL2", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 3, .opc2 = 2,
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 561bf2678e..105c2cb07b 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -208,7 +208,7 @@ static bool regime_translation_big_endian(CPUARMState *env, ARMMMUIdx mmu_idx)
     return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0;
 }
 
-/* Return the TTBR associated with this translation regime */
+/* Return the 64-bit TTBR associated with this translation regime */
 static uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn)
 {
     if (mmu_idx == ARMMMUIdx_Stage2) {
@@ -217,11 +217,15 @@ static uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, int ttbrn)
     if (mmu_idx == ARMMMUIdx_Stage2_S) {
         return env->cp15.vsttbr_el2;
     }
-    if (ttbrn == 0) {
-        return env->cp15.ttbr0_el[regime_el(env, mmu_idx)];
-    } else {
-        return env->cp15.ttbr1_el[regime_el(env, mmu_idx)];
+    switch (regime_el(env, mmu_idx)) {
+    case 1:
+        return int128_getlo(env->cp15.ttbr_el1[ttbrn]);
+    case 2:
+        return int128_getlo(env->cp15.ttbr_el2[ttbrn]);
+    case 3:
+        return env->cp15.ttbr_s[ttbrn];
     }
+    g_assert_not_reached();
 }
 
 /* Return true if the specified stage of address translation is disabled */
-- 
2.43.0



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

* Re: [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128
  2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
                   ` (64 preceding siblings ...)
  2025-08-27  1:04 ` [PATCH 61/61] target/arm: Extend TTBR system registers to 128-bit Richard Henderson
@ 2025-08-27  2:36 ` Richard Henderson
  65 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-27  2:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm

On 8/27/25 11:03, Richard Henderson wrote:
> Requesting feedback on the implementation of 128-bit registers.

... and of course I also failed to empty out my temp directory,
so there's 4 stale patches that got included.  At least they're
obvious in being N/M instead of NN/MM.


r~


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

* Re: [PATCH 04/61] target/arm/hvf: Reorder DEF_SYSREG arguments
  2025-08-27  1:03 ` [PATCH 04/61] target/arm/hvf: Reorder DEF_SYSREG arguments Richard Henderson
@ 2025-08-28 12:17   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-28 12:17 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, qemu-arm

On Wed, Aug 27, 2025 at 4:06 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> The order of the parameters in the Arm ARM is
>
>   op0, op1, crn, crm, op2
>
> Reorder the arguments of DEF_SYSREG to match.
> Mechanical change to sysreg.c.inc using
>
>   sed 's/\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\)/\1,\4,\5,\2,\3/'
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

>  target/arm/hvf/hvf.c        |   2 +-
>  target/arm/hvf/sysreg.c.inc | 224 ++++++++++++++++++------------------
>  2 files changed, 113 insertions(+), 113 deletions(-)
>
> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
> index f0e4b75e6a..7b0413093d 100644
> --- a/target/arm/hvf/hvf.c
> +++ b/target/arm/hvf/hvf.c
> @@ -403,7 +403,7 @@ struct hvf_sreg_match {
>      uint32_t cp_idx;
>  };
>
> -#define DEF_SYSREG(HVF_ID, crn, crm, op0, op1, op2) \
> +#define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2) \
>      { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
>
>  static struct hvf_sreg_match hvf_sreg_match[] = {
> diff --git a/target/arm/hvf/sysreg.c.inc b/target/arm/hvf/sysreg.c.inc
> index 222698f1d1..f2276d534e 100644
> --- a/target/arm/hvf/sysreg.c.inc
> +++ b/target/arm/hvf/sysreg.c.inc
> @@ -1,146 +1,146 @@
>  /* SPDX-License-Identifier: GPL-2.0-or-later */
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR0_EL1, 0, 0, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR0_EL1, 0, 0, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR0_EL1, 0, 0, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR0_EL1, 0, 0, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR0_EL1, 2, 0, 0, 0, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR0_EL1, 2, 0, 0, 0, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR0_EL1, 2, 0, 0, 0, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR0_EL1, 2, 0, 0, 0, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR1_EL1, 0, 1, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR1_EL1, 0, 1, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR1_EL1, 0, 1, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR1_EL1, 0, 1, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR1_EL1, 2, 0, 0, 1, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR1_EL1, 2, 0, 0, 1, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR1_EL1, 2, 0, 0, 1, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR1_EL1, 2, 0, 0, 1, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR2_EL1, 0, 2, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR2_EL1, 0, 2, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR2_EL1, 0, 2, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR2_EL1, 0, 2, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR2_EL1, 2, 0, 0, 2, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR2_EL1, 2, 0, 0, 2, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR2_EL1, 2, 0, 0, 2, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR2_EL1, 2, 0, 0, 2, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR3_EL1, 0, 3, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR3_EL1, 0, 3, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR3_EL1, 0, 3, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR3_EL1, 0, 3, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR3_EL1, 2, 0, 0, 3, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR3_EL1, 2, 0, 0, 3, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR3_EL1, 2, 0, 0, 3, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR3_EL1, 2, 0, 0, 3, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR4_EL1, 0, 4, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR4_EL1, 0, 4, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR4_EL1, 0, 4, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR4_EL1, 0, 4, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR4_EL1, 2, 0, 0, 4, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR4_EL1, 2, 0, 0, 4, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR4_EL1, 2, 0, 0, 4, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR4_EL1, 2, 0, 0, 4, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR5_EL1, 0, 5, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR5_EL1, 0, 5, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR5_EL1, 0, 5, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR5_EL1, 0, 5, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR5_EL1, 2, 0, 0, 5, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR5_EL1, 2, 0, 0, 5, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR5_EL1, 2, 0, 0, 5, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR5_EL1, 2, 0, 0, 5, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR6_EL1, 0, 6, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR6_EL1, 0, 6, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR6_EL1, 0, 6, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR6_EL1, 0, 6, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR6_EL1, 2, 0, 0, 6, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR6_EL1, 2, 0, 0, 6, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR6_EL1, 2, 0, 0, 6, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR6_EL1, 2, 0, 0, 6, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR7_EL1, 0, 7, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR7_EL1, 0, 7, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR7_EL1, 0, 7, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR7_EL1, 0, 7, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR7_EL1, 2, 0, 0, 7, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR7_EL1, 2, 0, 0, 7, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR7_EL1, 2, 0, 0, 7, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR7_EL1, 2, 0, 0, 7, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR8_EL1, 0, 8, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR8_EL1, 0, 8, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR8_EL1, 0, 8, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR8_EL1, 0, 8, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR8_EL1, 2, 0, 0, 8, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR8_EL1, 2, 0, 0, 8, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR8_EL1, 2, 0, 0, 8, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR8_EL1, 2, 0, 0, 8, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR9_EL1, 0, 9, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR9_EL1, 0, 9, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR9_EL1, 0, 9, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR9_EL1, 0, 9, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR9_EL1, 2, 0, 0, 9, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR9_EL1, 2, 0, 0, 9, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR9_EL1, 2, 0, 0, 9, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR9_EL1, 2, 0, 0, 9, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR10_EL1, 0, 10, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR10_EL1, 0, 10, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR10_EL1, 0, 10, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR10_EL1, 0, 10, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR10_EL1, 2, 0, 0, 10, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR10_EL1, 2, 0, 0, 10, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR10_EL1, 2, 0, 0, 10, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR10_EL1, 2, 0, 0, 10, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR11_EL1, 0, 11, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR11_EL1, 0, 11, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR11_EL1, 0, 11, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR11_EL1, 0, 11, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR11_EL1, 2, 0, 0, 11, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR11_EL1, 2, 0, 0, 11, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR11_EL1, 2, 0, 0, 11, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR11_EL1, 2, 0, 0, 11, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR12_EL1, 0, 12, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR12_EL1, 0, 12, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR12_EL1, 0, 12, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR12_EL1, 0, 12, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR12_EL1, 2, 0, 0, 12, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR12_EL1, 2, 0, 0, 12, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR12_EL1, 2, 0, 0, 12, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR12_EL1, 2, 0, 0, 12, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR13_EL1, 0, 13, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR13_EL1, 0, 13, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR13_EL1, 0, 13, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR13_EL1, 0, 13, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR13_EL1, 2, 0, 0, 13, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR13_EL1, 2, 0, 0, 13, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR13_EL1, 2, 0, 0, 13, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR13_EL1, 2, 0, 0, 13, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR14_EL1, 0, 14, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR14_EL1, 0, 14, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR14_EL1, 0, 14, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR14_EL1, 0, 14, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR14_EL1, 2, 0, 0, 14, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR14_EL1, 2, 0, 0, 14, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR14_EL1, 2, 0, 0, 14, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR14_EL1, 2, 0, 0, 14, 7)
>
> -DEF_SYSREG(HV_SYS_REG_DBGBVR15_EL1, 0, 15, 2, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_DBGBCR15_EL1, 0, 15, 2, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_DBGWVR15_EL1, 0, 15, 2, 0, 6)
> -DEF_SYSREG(HV_SYS_REG_DBGWCR15_EL1, 0, 15, 2, 0, 7)
> +DEF_SYSREG(HV_SYS_REG_DBGBVR15_EL1, 2, 0, 0, 15, 4)
> +DEF_SYSREG(HV_SYS_REG_DBGBCR15_EL1, 2, 0, 0, 15, 5)
> +DEF_SYSREG(HV_SYS_REG_DBGWVR15_EL1, 2, 0, 0, 15, 6)
> +DEF_SYSREG(HV_SYS_REG_DBGWCR15_EL1, 2, 0, 0, 15, 7)
>
>  #ifdef SYNC_NO_RAW_REGS
>  /*
>   * The registers below are manually synced on init because they are
>   * marked as NO_RAW. We still list them to make number space sync easier.
>   */
> -DEF_SYSREG(HV_SYS_REG_MDCCINT_EL1, 0, 2, 2, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_MIDR_EL1, 0, 0, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_MPIDR_EL1, 0, 0, 3, 0, 5)
> -DEF_SYSREG(HV_SYS_REG_ID_AA64PFR0_EL1, 0, 4, 3, 0, 0)
> +DEF_SYSREG(HV_SYS_REG_MDCCINT_EL1, 2, 0, 0, 2, 0)
> +DEF_SYSREG(HV_SYS_REG_MIDR_EL1, 3, 0, 0, 0, 0)
> +DEF_SYSREG(HV_SYS_REG_MPIDR_EL1, 3, 0, 0, 0, 5)
> +DEF_SYSREG(HV_SYS_REG_ID_AA64PFR0_EL1, 3, 0, 0, 4, 0)
>  #endif
>
> -DEF_SYSREG(HV_SYS_REG_ID_AA64PFR1_EL1, 0, 4, 3, 0, 1)
> -DEF_SYSREG(HV_SYS_REG_ID_AA64DFR0_EL1, 0, 5, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_ID_AA64DFR1_EL1, 0, 5, 3, 0, 1)
> -DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR0_EL1, 0, 6, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR1_EL1, 0, 6, 3, 0, 1)
> +DEF_SYSREG(HV_SYS_REG_ID_AA64PFR1_EL1, 3, 0, 0, 4, 1)
> +DEF_SYSREG(HV_SYS_REG_ID_AA64DFR0_EL1, 3, 0, 0, 5, 0)
> +DEF_SYSREG(HV_SYS_REG_ID_AA64DFR1_EL1, 3, 0, 0, 5, 1)
> +DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0)
> +DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR1_EL1, 3, 0, 0, 6, 1)
>
>  #ifdef SYNC_NO_MMFR0
>  /* We keep the hardware MMFR0 around. HW limits are there anyway */
> -DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR0_EL1, 0, 7, 3, 0, 0)
> +DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0)
>  #endif
>
> -DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR1_EL1, 0, 7, 3, 0, 1)
> -DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR2_EL1, 0, 7, 3, 0, 2)
> +DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR1_EL1, 3, 0, 0, 7, 1)
> +DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR2_EL1, 3, 0, 0, 7, 2)
>  /* Add ID_AA64MMFR3_EL1 here when HVF supports it */
>
> -DEF_SYSREG(HV_SYS_REG_MDSCR_EL1, 0, 2, 2, 0, 2)
> -DEF_SYSREG(HV_SYS_REG_SCTLR_EL1, 1, 0, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_CPACR_EL1, 1, 0, 3, 0, 2)
> -DEF_SYSREG(HV_SYS_REG_TTBR0_EL1, 2, 0, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_TTBR1_EL1, 2, 0, 3, 0, 1)
> -DEF_SYSREG(HV_SYS_REG_TCR_EL1, 2, 0, 3, 0, 2)
> +DEF_SYSREG(HV_SYS_REG_MDSCR_EL1, 2, 0, 0, 2, 2)
> +DEF_SYSREG(HV_SYS_REG_SCTLR_EL1, 3, 0, 1, 0, 0)
> +DEF_SYSREG(HV_SYS_REG_CPACR_EL1, 3, 0, 1, 0, 2)
> +DEF_SYSREG(HV_SYS_REG_TTBR0_EL1, 3, 0, 2, 0, 0)
> +DEF_SYSREG(HV_SYS_REG_TTBR1_EL1, 3, 0, 2, 0, 1)
> +DEF_SYSREG(HV_SYS_REG_TCR_EL1, 3, 0, 2, 0, 2)
>
> -DEF_SYSREG(HV_SYS_REG_APIAKEYLO_EL1, 2, 1, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_APIAKEYHI_EL1, 2, 1, 3, 0, 1)
> -DEF_SYSREG(HV_SYS_REG_APIBKEYLO_EL1, 2, 1, 3, 0, 2)
> -DEF_SYSREG(HV_SYS_REG_APIBKEYHI_EL1, 2, 1, 3, 0, 3)
> -DEF_SYSREG(HV_SYS_REG_APDAKEYLO_EL1, 2, 2, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_APDAKEYHI_EL1, 2, 2, 3, 0, 1)
> -DEF_SYSREG(HV_SYS_REG_APDBKEYLO_EL1, 2, 2, 3, 0, 2)
> -DEF_SYSREG(HV_SYS_REG_APDBKEYHI_EL1, 2, 2, 3, 0, 3)
> -DEF_SYSREG(HV_SYS_REG_APGAKEYLO_EL1, 2, 3, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_APGAKEYHI_EL1, 2, 3, 3, 0, 1)
> +DEF_SYSREG(HV_SYS_REG_APIAKEYLO_EL1, 3, 0, 2, 1, 0)
> +DEF_SYSREG(HV_SYS_REG_APIAKEYHI_EL1, 3, 0, 2, 1, 1)
> +DEF_SYSREG(HV_SYS_REG_APIBKEYLO_EL1, 3, 0, 2, 1, 2)
> +DEF_SYSREG(HV_SYS_REG_APIBKEYHI_EL1, 3, 0, 2, 1, 3)
> +DEF_SYSREG(HV_SYS_REG_APDAKEYLO_EL1, 3, 0, 2, 2, 0)
> +DEF_SYSREG(HV_SYS_REG_APDAKEYHI_EL1, 3, 0, 2, 2, 1)
> +DEF_SYSREG(HV_SYS_REG_APDBKEYLO_EL1, 3, 0, 2, 2, 2)
> +DEF_SYSREG(HV_SYS_REG_APDBKEYHI_EL1, 3, 0, 2, 2, 3)
> +DEF_SYSREG(HV_SYS_REG_APGAKEYLO_EL1, 3, 0, 2, 3, 0)
> +DEF_SYSREG(HV_SYS_REG_APGAKEYHI_EL1, 3, 0, 2, 3, 1)
>
> -DEF_SYSREG(HV_SYS_REG_SPSR_EL1, 4, 0, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_ELR_EL1, 4, 0, 3, 0, 1)
> -DEF_SYSREG(HV_SYS_REG_SP_EL0, 4, 1, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_AFSR0_EL1, 5, 1, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_AFSR1_EL1, 5, 1, 3, 0, 1)
> -DEF_SYSREG(HV_SYS_REG_ESR_EL1, 5, 2, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_FAR_EL1, 6, 0, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_PAR_EL1, 7, 4, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_MAIR_EL1, 10, 2, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_AMAIR_EL1, 10, 3, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_VBAR_EL1, 12, 0, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_CONTEXTIDR_EL1, 13, 0, 3, 0, 1)
> -DEF_SYSREG(HV_SYS_REG_TPIDR_EL1, 13, 0, 3, 0, 4)
> -DEF_SYSREG(HV_SYS_REG_CNTKCTL_EL1, 14, 1, 3, 0, 0)
> -DEF_SYSREG(HV_SYS_REG_CSSELR_EL1, 0, 0, 3, 2, 0)
> -DEF_SYSREG(HV_SYS_REG_TPIDR_EL0, 13, 0, 3, 3, 2)
> -DEF_SYSREG(HV_SYS_REG_TPIDRRO_EL0, 13, 0, 3, 3, 3)
> -DEF_SYSREG(HV_SYS_REG_CNTV_CTL_EL0, 14, 3, 3, 3, 1)
> -DEF_SYSREG(HV_SYS_REG_CNTV_CVAL_EL0, 14, 3, 3, 3, 2)
> -DEF_SYSREG(HV_SYS_REG_SP_EL1, 4, 1, 3, 4, 0)
> +DEF_SYSREG(HV_SYS_REG_SPSR_EL1, 3, 0, 4, 0, 0)
> +DEF_SYSREG(HV_SYS_REG_ELR_EL1, 3, 0, 4, 0, 1)
> +DEF_SYSREG(HV_SYS_REG_SP_EL0, 3, 0, 4, 1, 0)
> +DEF_SYSREG(HV_SYS_REG_AFSR0_EL1, 3, 0, 5, 1, 0)
> +DEF_SYSREG(HV_SYS_REG_AFSR1_EL1, 3, 0, 5, 1, 1)
> +DEF_SYSREG(HV_SYS_REG_ESR_EL1, 3, 0, 5, 2, 0)
> +DEF_SYSREG(HV_SYS_REG_FAR_EL1, 3, 0, 6, 0, 0)
> +DEF_SYSREG(HV_SYS_REG_PAR_EL1, 3, 0, 7, 4, 0)
> +DEF_SYSREG(HV_SYS_REG_MAIR_EL1, 3, 0, 10, 2, 0)
> +DEF_SYSREG(HV_SYS_REG_AMAIR_EL1, 3, 0, 10, 3, 0)
> +DEF_SYSREG(HV_SYS_REG_VBAR_EL1, 3, 0, 12, 0, 0)
> +DEF_SYSREG(HV_SYS_REG_CONTEXTIDR_EL1, 3, 0, 13, 0, 1)
> +DEF_SYSREG(HV_SYS_REG_TPIDR_EL1, 3, 0, 13, 0, 4)
> +DEF_SYSREG(HV_SYS_REG_CNTKCTL_EL1, 3, 0, 14, 1, 0)
> +DEF_SYSREG(HV_SYS_REG_CSSELR_EL1, 3, 2, 0, 0, 0)
> +DEF_SYSREG(HV_SYS_REG_TPIDR_EL0, 3, 3, 13, 0, 2)
> +DEF_SYSREG(HV_SYS_REG_TPIDRRO_EL0, 3, 3, 13, 0, 3)
> +DEF_SYSREG(HV_SYS_REG_CNTV_CTL_EL0, 3, 3, 14, 3, 1)
> +DEF_SYSREG(HV_SYS_REG_CNTV_CVAL_EL0, 3, 3, 14, 3, 2)
> +DEF_SYSREG(HV_SYS_REG_SP_EL1, 3, 4, 4, 1, 0)
> --
> 2.43.0
>
>


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

* Re: [PATCH 02/61] target/arm: Move compare_u64 to helper.c
  2025-08-27  1:03 ` [PATCH 02/61] target/arm: Move compare_u64 to helper.c Richard Henderson
@ 2025-08-28 12:19   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-28 12:19 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, qemu-arm

On Wed, Aug 27, 2025 at 4:07 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> We will use this function beyond kvm.c.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

>  target/arm/internals.h |  3 +++
>  target/arm/helper.c    | 11 +++++++++++
>  target/arm/kvm.c       | 11 -----------
>  3 files changed, 14 insertions(+), 11 deletions(-)
>
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 1b3d0244fd..08e2acdb99 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -1981,4 +1981,7 @@ void vfp_clear_float_status_exc_flags(CPUARMState *env);
>  void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask);
>  bool arm_pan_enabled(CPUARMState *env);
>
> +/* Compare uint64_t for qsort and bsearch. */
> +int compare_u64(const void *a, const void *b);
> +
>  #endif
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 0c1299ff84..d230f9e766 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -40,6 +40,17 @@
>
>  static void switch_mode(CPUARMState *env, int mode);
>
> +int compare_u64(const void *a, const void *b)
> +{
> +    if (*(uint64_t *)a > *(uint64_t *)b) {
> +        return 1;
> +    }
> +    if (*(uint64_t *)a < *(uint64_t *)b) {
> +        return -1;
> +    }
> +    return 0;
> +}
> +
>  uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri)
>  {
>      assert(ri->fieldoffset);
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 6672344855..9e569eff65 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -718,17 +718,6 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group,
>      memory_region_ref(kd->mr);
>  }
>
> -static int compare_u64(const void *a, const void *b)
> -{
> -    if (*(uint64_t *)a > *(uint64_t *)b) {
> -        return 1;
> -    }
> -    if (*(uint64_t *)a < *(uint64_t *)b) {
> -        return -1;
> -    }
> -    return 0;
> -}
> -
>  /*
>   * cpreg_values are sorted in ascending order by KVM register ID
>   * (see kvm_arm_init_cpreg_list). This allows us to cheaply find
> --
> 2.43.0
>
>


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

* Re: [PATCH 4/7] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID
  2025-08-27  1:03 ` [PATCH 4/7] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID Richard Henderson
@ 2025-08-28 12:22   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-28 12:22 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, qemu-arm

On Wed, Aug 27, 2025 at 4:07 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Conversion between KVM system registers ids and the HVF system
> register ids is trivial.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

FYI: you sent this as [PATCH 4/7] and [PATCH 05/61] by accident,
happened to a few other patches in this series as well.

>  target/arm/hvf/hvf.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
>
> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
> index f0e4b75e6a..2577dc1c0c 100644
> --- a/target/arm/hvf/hvf.c
> +++ b/target/arm/hvf/hvf.c
> @@ -403,6 +403,26 @@ struct hvf_sreg_match {
>      uint32_t cp_idx;
>  };
>
> +/*
> + * QEMU uses KVM system register ids in the migration format.
> + * Conveniently, HVF uses the same encoding of the op* and cr* parameters
> + * within the low 16 bits of the ids.  Thus conversion between the
> + * formats is trivial.
> + */
> +
> +#define KVMID_TO_HVF(KVM)  ((KVM) & 0xffff)
> +#define HVF_TO_KVMID(HVF)  \
> +    (CP_REG_ARM64 | CP_REG_SIZE_U64 | CP_REG_ARM64_SYSREG | (HVF))
> +
> +/* Verify this at compile-time. */
> +
> +#define DEF_SYSREG(HVF_ID, ...) \
> +  QEMU_BUILD_BUG_ON(HVF_ID != KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__)));
> +
> +#include "sysreg.c.inc"
> +
> +#undef DEF_SYSREG
> +
>  #define DEF_SYSREG(HVF_ID, crn, crm, op0, op1, op2) \
>      { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
>
> --
> 2.43.0
>
>


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

* Re: [PATCH 33/61] target/arm: Redirect VHE FOO_EL1 -> FOO_EL2 during translation
  2025-08-27  1:04 ` [PATCH 33/61] target/arm: Redirect VHE FOO_EL1 -> FOO_EL2 during translation Richard Henderson
@ 2025-08-28 12:39   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-28 12:39 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, qemu-arm

On Wed, Aug 27, 2025 at 4:11 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/arm/cpregs.h            |  6 ++++
>  target/arm/gdbstub.c           |  5 ++++
>  target/arm/helper.c            | 53 +---------------------------------
>  target/arm/tcg/translate-a64.c |  9 ++++++
>  4 files changed, 21 insertions(+), 52 deletions(-)
>
> diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
> index 7bdf6cf847..d34ed0d40b 100644
> --- a/target/arm/cpregs.h
> +++ b/target/arm/cpregs.h
> @@ -911,6 +911,12 @@ struct ARMCPRegInfo {
>       */
>      uint32_t nv2_redirect_offset;
>
> +    /*
> +     * With VHE, with E2H, at EL2, access to this EL0/EL1 reg redirects
> +     * to the EL2 reg with the specified key.
> +     */
> +    uint32_t vhe_redir_to_el2;
> +
>      /* This is used only by VHE. */
>      void *opaque;
>      /*
> diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
> index e2fc389170..3727dc01af 100644
> --- a/target/arm/gdbstub.c
> +++ b/target/arm/gdbstub.c
> @@ -249,6 +249,11 @@ static int arm_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg)
>      if (ri) {
>          switch (cpreg_field_type(ri)) {
>          case MO_64:
> +            if (ri->vhe_redir_to_el2 &&
> +                (arm_hcr_el2_eff(env) & HCR_E2H) &&
> +                arm_current_el(env) == 2) {
> +                ri = get_arm_cp_reginfo(cpu->cp_regs, ri->vhe_redir_to_el2);
> +            }
>              return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri));
>          case MO_32:
>              return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri));
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index d0ccc23811..3f69ce6cb5 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -4441,47 +4441,6 @@ static CPAccessResult access_el1nvvct(CPUARMState *env, const ARMCPRegInfo *ri,
>      return e2h_access(env, ri, isread);
>  }
>
> -/* Test if system register redirection is to occur in the current state.  */
> -static bool redirect_for_e2h(CPUARMState *env)
> -{
> -    return arm_current_el(env) == 2 && (arm_hcr_el2_eff(env) & HCR_E2H);
> -}
> -
> -static uint64_t el2_e2h_read(CPUARMState *env, const ARMCPRegInfo *ri)
> -{
> -    CPReadFn *readfn;
> -
> -    if (redirect_for_e2h(env)) {
> -        /* Switch to the saved EL2 version of the register.  */
> -        ri = ri->opaque;
> -        readfn = ri->readfn;
> -    } else {
> -        readfn = ri->orig_readfn;
> -    }
> -    if (readfn == NULL) {
> -        readfn = raw_read;
> -    }
> -    return readfn(env, ri);
> -}
> -
> -static void el2_e2h_write(CPUARMState *env, const ARMCPRegInfo *ri,
> -                          uint64_t value)
> -{
> -    CPWriteFn *writefn;
> -
> -    if (redirect_for_e2h(env)) {
> -        /* Switch to the saved EL2 version of the register.  */
> -        ri = ri->opaque;
> -        writefn = ri->writefn;
> -    } else {
> -        writefn = ri->orig_writefn;
> -    }
> -    if (writefn == NULL) {
> -        writefn = raw_write;
> -    }
> -    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 */
> @@ -4657,17 +4616,7 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
>                                   (gpointer)(uintptr_t)a->new_key, new_reg);
>          g_assert(ok);
>
> -        src_reg->opaque = dst_reg;
> -        src_reg->orig_readfn = src_reg->readfn ?: raw_read;
> -        src_reg->orig_writefn = src_reg->writefn ?: raw_write;
> -        if (!src_reg->raw_readfn) {
> -            src_reg->raw_readfn = raw_read;
> -        }
> -        if (!src_reg->raw_writefn) {
> -            src_reg->raw_writefn = raw_write;
> -        }
> -        src_reg->readfn = el2_e2h_read;
> -        src_reg->writefn = el2_e2h_write;
> +        src_reg->vhe_redir_to_el2 = a->dst_key;
>      }
>  }
>  #endif
> diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
> index 8303f0dac2..8fcc74d151 100644
> --- a/target/arm/tcg/translate-a64.c
> +++ b/target/arm/tcg/translate-a64.c
> @@ -2573,6 +2573,15 @@ static void handle_sys(DisasContext *s, bool isread,
>          }
>      }
>
> +    if (ri->vhe_redir_to_el2 && s->current_el == 2 && s->e2h) {
> +        /*
> +         * This one of the FOO_EL1 registers which redirect to FOO_EL2
> +         * from EL2 when HCR_EL2.E2H is set.
> +         */
> +        key = ri->vhe_redir_to_el2;
> +        ri = redirect_cpreg(s, key, isread);
> +    }
> +
>      if (ri->accessfn || (ri->fgt && s->fgt_active)) {
>          /* Emit code to perform further access permissions checks at
>           * runtime; this may result in an exception.
> --
> 2.43.0
>
>

This looks much better

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>


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

* Re: [PATCH 11/61] target/arm: Rename all ARMCPRegInfo from opaque to ri
  2025-08-27  1:04 ` [PATCH 11/61] target/arm: Rename all ARMCPRegInfo from opaque to ri Richard Henderson
@ 2025-08-28 12:41   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-28 12:41 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-devel, qemu-arm

On Wed, Aug 27, 2025 at 4:11 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> These pointers are no opaque, they have a specific type.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

>  target/arm/cpregs.h | 10 +++++-----
>  target/arm/helper.c |  6 +++---
>  2 files changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
> index c9506aa6d5..3344a02bd3 100644
> --- a/target/arm/cpregs.h
> +++ b/target/arm/cpregs.h
> @@ -841,15 +841,15 @@ typedef struct ARMCPRegInfo ARMCPRegInfo;
>   * Access functions for coprocessor registers. These cannot fail and
>   * may not raise exceptions.
>   */
> -typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque);
> -typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
> +typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *ri);
> +typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *ri,
>                         uint64_t value);
>  /* Access permission check functions for coprocessor registers. */
>  typedef CPAccessResult CPAccessFn(CPUARMState *env,
> -                                  const ARMCPRegInfo *opaque,
> +                                  const ARMCPRegInfo *ri,
>                                    bool isread);
>  /* Hook function for register reset */
> -typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
> +typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *ri);
>
>  #define CP_ANY 0xff
>
> @@ -1075,7 +1075,7 @@ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value);
>   * CPResetFn that does nothing, for use if no reset is required even
>   * if fieldoffset is non zero.
>   */
> -void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque);
> +void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri);
>
>  /*
>   * Return true if this reginfo struct's field in the cpu state struct
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index d230f9e766..e03cbc0394 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -1067,7 +1067,7 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
>        .resetvalue = 0 },
>  };
>
> -static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque)
> +static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *ri)
>  {
>      ARMCPU *cpu = env_archcpu(env);
>
> @@ -5407,7 +5407,7 @@ static const ARMCPRegInfo rndr_reginfo[] = {
>        .access = PL0_R, .readfn = rndr_readfn },
>  };
>
> -static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
> +static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *ri,
>                            uint64_t value)
>  {
>  #ifdef CONFIG_TCG
> @@ -7730,7 +7730,7 @@ uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri)
>      return 0;
>  }
>
> -void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque)
> +void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri)
>  {
>      /* Helper coprocessor reset function for do-nothing-on-reset registers */
>  }
> --
> 2.43.0
>
>


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

* Re: [PATCH 03/61] target/arm/hvf: Split out sysreg.c.inc
  2025-08-27  1:03 ` [PATCH 03/61] target/arm/hvf: Split out sysreg.c.inc Richard Henderson
@ 2025-08-29  6:58   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  6:58 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:03, Richard Henderson <richard.henderson@linaro.org> wrote:
>Move the list of supported sysregs to a reuseable file.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/hvf/hvf.c        | 147 ++----------------------------------
> target/arm/hvf/sysreg.c.inc | 146 +++++++++++++++++++++++++++++++++++
> 2 files changed, 152 insertions(+), 141 deletions(-)
> create mode 100644 target/arm/hvf/sysreg.c.inc
>
>diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
>index 47b0cd3a35..f0e4b75e6a 100644
>--- a/target/arm/hvf/hvf.c
>+++ b/target/arm/hvf/hvf.c
>@@ -403,150 +403,15 @@ struct hvf_sreg_match {
>     uint32_t cp_idx;
> };
> 
>+#define DEF_SYSREG(HVF_ID, crn, crm, op0, op1, op2) \
>+    { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
>+
> static struct hvf_sreg_match hvf_sreg_match[] = {
>-    { HV_SYS_REG_DBGBVR0_EL1, HVF_SYSREG(0, 0, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR0_EL1, HVF_SYSREG(0, 0, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR0_EL1, HVF_SYSREG(0, 0, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR0_EL1, HVF_SYSREG(0, 0, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR1_EL1, HVF_SYSREG(0, 1, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR1_EL1, HVF_SYSREG(0, 1, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR1_EL1, HVF_SYSREG(0, 1, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR1_EL1, HVF_SYSREG(0, 1, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR2_EL1, HVF_SYSREG(0, 2, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR2_EL1, HVF_SYSREG(0, 2, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR2_EL1, HVF_SYSREG(0, 2, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR2_EL1, HVF_SYSREG(0, 2, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR3_EL1, HVF_SYSREG(0, 3, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR3_EL1, HVF_SYSREG(0, 3, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR3_EL1, HVF_SYSREG(0, 3, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR3_EL1, HVF_SYSREG(0, 3, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR4_EL1, HVF_SYSREG(0, 4, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR4_EL1, HVF_SYSREG(0, 4, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR4_EL1, HVF_SYSREG(0, 4, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR4_EL1, HVF_SYSREG(0, 4, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR5_EL1, HVF_SYSREG(0, 5, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR5_EL1, HVF_SYSREG(0, 5, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR5_EL1, HVF_SYSREG(0, 5, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR5_EL1, HVF_SYSREG(0, 5, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR6_EL1, HVF_SYSREG(0, 6, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR6_EL1, HVF_SYSREG(0, 6, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR6_EL1, HVF_SYSREG(0, 6, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR6_EL1, HVF_SYSREG(0, 6, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR7_EL1, HVF_SYSREG(0, 7, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR7_EL1, HVF_SYSREG(0, 7, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR7_EL1, HVF_SYSREG(0, 7, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR7_EL1, HVF_SYSREG(0, 7, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR8_EL1, HVF_SYSREG(0, 8, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR8_EL1, HVF_SYSREG(0, 8, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR8_EL1, HVF_SYSREG(0, 8, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR8_EL1, HVF_SYSREG(0, 8, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR9_EL1, HVF_SYSREG(0, 9, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR9_EL1, HVF_SYSREG(0, 9, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR9_EL1, HVF_SYSREG(0, 9, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR9_EL1, HVF_SYSREG(0, 9, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR10_EL1, HVF_SYSREG(0, 10, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR10_EL1, HVF_SYSREG(0, 10, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR10_EL1, HVF_SYSREG(0, 10, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR10_EL1, HVF_SYSREG(0, 10, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR11_EL1, HVF_SYSREG(0, 11, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR11_EL1, HVF_SYSREG(0, 11, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR11_EL1, HVF_SYSREG(0, 11, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR11_EL1, HVF_SYSREG(0, 11, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR12_EL1, HVF_SYSREG(0, 12, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR12_EL1, HVF_SYSREG(0, 12, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR12_EL1, HVF_SYSREG(0, 12, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR12_EL1, HVF_SYSREG(0, 12, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR13_EL1, HVF_SYSREG(0, 13, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR13_EL1, HVF_SYSREG(0, 13, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR13_EL1, HVF_SYSREG(0, 13, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR13_EL1, HVF_SYSREG(0, 13, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR14_EL1, HVF_SYSREG(0, 14, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR14_EL1, HVF_SYSREG(0, 14, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR14_EL1, HVF_SYSREG(0, 14, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR14_EL1, HVF_SYSREG(0, 14, 2, 0, 7) },
>-
>-    { HV_SYS_REG_DBGBVR15_EL1, HVF_SYSREG(0, 15, 2, 0, 4) },
>-    { HV_SYS_REG_DBGBCR15_EL1, HVF_SYSREG(0, 15, 2, 0, 5) },
>-    { HV_SYS_REG_DBGWVR15_EL1, HVF_SYSREG(0, 15, 2, 0, 6) },
>-    { HV_SYS_REG_DBGWCR15_EL1, HVF_SYSREG(0, 15, 2, 0, 7) },
>-
>-#ifdef SYNC_NO_RAW_REGS
>-    /*
>-     * The registers below are manually synced on init because they are
>-     * marked as NO_RAW. We still list them to make number space sync easier.
>-     */
>-    { HV_SYS_REG_MDCCINT_EL1, HVF_SYSREG(0, 2, 2, 0, 0) },
>-    { HV_SYS_REG_MIDR_EL1, HVF_SYSREG(0, 0, 3, 0, 0) },
>-    { HV_SYS_REG_MPIDR_EL1, HVF_SYSREG(0, 0, 3, 0, 5) },
>-    { HV_SYS_REG_ID_AA64PFR0_EL1, HVF_SYSREG(0, 4, 3, 0, 0) },
>-#endif
>-    { HV_SYS_REG_ID_AA64PFR1_EL1, HVF_SYSREG(0, 4, 3, 0, 1) },
>-    { HV_SYS_REG_ID_AA64DFR0_EL1, HVF_SYSREG(0, 5, 3, 0, 0) },
>-    { HV_SYS_REG_ID_AA64DFR1_EL1, HVF_SYSREG(0, 5, 3, 0, 1) },
>-    { HV_SYS_REG_ID_AA64ISAR0_EL1, HVF_SYSREG(0, 6, 3, 0, 0) },
>-    { HV_SYS_REG_ID_AA64ISAR1_EL1, HVF_SYSREG(0, 6, 3, 0, 1) },
>-#ifdef SYNC_NO_MMFR0
>-    /* We keep the hardware MMFR0 around. HW limits are there anyway */
>-    { HV_SYS_REG_ID_AA64MMFR0_EL1, HVF_SYSREG(0, 7, 3, 0, 0) },
>-#endif
>-    { HV_SYS_REG_ID_AA64MMFR1_EL1, HVF_SYSREG(0, 7, 3, 0, 1) },
>-    { HV_SYS_REG_ID_AA64MMFR2_EL1, HVF_SYSREG(0, 7, 3, 0, 2) },
>-    /* Add ID_AA64MMFR3_EL1 here when HVF supports it */
>-
>-    { HV_SYS_REG_MDSCR_EL1, HVF_SYSREG(0, 2, 2, 0, 2) },
>-    { HV_SYS_REG_SCTLR_EL1, HVF_SYSREG(1, 0, 3, 0, 0) },
>-    { HV_SYS_REG_CPACR_EL1, HVF_SYSREG(1, 0, 3, 0, 2) },
>-    { HV_SYS_REG_TTBR0_EL1, HVF_SYSREG(2, 0, 3, 0, 0) },
>-    { HV_SYS_REG_TTBR1_EL1, HVF_SYSREG(2, 0, 3, 0, 1) },
>-    { HV_SYS_REG_TCR_EL1, HVF_SYSREG(2, 0, 3, 0, 2) },
>-
>-    { HV_SYS_REG_APIAKEYLO_EL1, HVF_SYSREG(2, 1, 3, 0, 0) },
>-    { HV_SYS_REG_APIAKEYHI_EL1, HVF_SYSREG(2, 1, 3, 0, 1) },
>-    { HV_SYS_REG_APIBKEYLO_EL1, HVF_SYSREG(2, 1, 3, 0, 2) },
>-    { HV_SYS_REG_APIBKEYHI_EL1, HVF_SYSREG(2, 1, 3, 0, 3) },
>-    { HV_SYS_REG_APDAKEYLO_EL1, HVF_SYSREG(2, 2, 3, 0, 0) },
>-    { HV_SYS_REG_APDAKEYHI_EL1, HVF_SYSREG(2, 2, 3, 0, 1) },
>-    { HV_SYS_REG_APDBKEYLO_EL1, HVF_SYSREG(2, 2, 3, 0, 2) },
>-    { HV_SYS_REG_APDBKEYHI_EL1, HVF_SYSREG(2, 2, 3, 0, 3) },
>-    { HV_SYS_REG_APGAKEYLO_EL1, HVF_SYSREG(2, 3, 3, 0, 0) },
>-    { HV_SYS_REG_APGAKEYHI_EL1, HVF_SYSREG(2, 3, 3, 0, 1) },
>-
>-    { HV_SYS_REG_SPSR_EL1, HVF_SYSREG(4, 0, 3, 0, 0) },
>-    { HV_SYS_REG_ELR_EL1, HVF_SYSREG(4, 0, 3, 0, 1) },
>-    { HV_SYS_REG_SP_EL0, HVF_SYSREG(4, 1, 3, 0, 0) },
>-    { HV_SYS_REG_AFSR0_EL1, HVF_SYSREG(5, 1, 3, 0, 0) },
>-    { HV_SYS_REG_AFSR1_EL1, HVF_SYSREG(5, 1, 3, 0, 1) },
>-    { HV_SYS_REG_ESR_EL1, HVF_SYSREG(5, 2, 3, 0, 0) },
>-    { HV_SYS_REG_FAR_EL1, HVF_SYSREG(6, 0, 3, 0, 0) },
>-    { HV_SYS_REG_PAR_EL1, HVF_SYSREG(7, 4, 3, 0, 0) },
>-    { HV_SYS_REG_MAIR_EL1, HVF_SYSREG(10, 2, 3, 0, 0) },
>-    { HV_SYS_REG_AMAIR_EL1, HVF_SYSREG(10, 3, 3, 0, 0) },
>-    { HV_SYS_REG_VBAR_EL1, HVF_SYSREG(12, 0, 3, 0, 0) },
>-    { HV_SYS_REG_CONTEXTIDR_EL1, HVF_SYSREG(13, 0, 3, 0, 1) },
>-    { HV_SYS_REG_TPIDR_EL1, HVF_SYSREG(13, 0, 3, 0, 4) },
>-    { HV_SYS_REG_CNTKCTL_EL1, HVF_SYSREG(14, 1, 3, 0, 0) },
>-    { HV_SYS_REG_CSSELR_EL1, HVF_SYSREG(0, 0, 3, 2, 0) },
>-    { HV_SYS_REG_TPIDR_EL0, HVF_SYSREG(13, 0, 3, 3, 2) },
>-    { HV_SYS_REG_TPIDRRO_EL0, HVF_SYSREG(13, 0, 3, 3, 3) },
>-    { HV_SYS_REG_CNTV_CTL_EL0, HVF_SYSREG(14, 3, 3, 3, 1) },
>-    { HV_SYS_REG_CNTV_CVAL_EL0, HVF_SYSREG(14, 3, 3, 3, 2) },
>-    { HV_SYS_REG_SP_EL1, HVF_SYSREG(4, 1, 3, 4, 0) },
>+#include "sysreg.c.inc"
> };
> 
>+#undef DEF_SYSREG
>+
> int hvf_get_registers(CPUState *cpu)
> {
>     ARMCPU *arm_cpu = ARM_CPU(cpu);
>diff --git a/target/arm/hvf/sysreg.c.inc b/target/arm/hvf/sysreg.c.inc
>new file mode 100644
>index 0000000000..222698f1d1
>--- /dev/null
>+++ b/target/arm/hvf/sysreg.c.inc
>@@ -0,0 +1,146 @@
>+/* SPDX-License-Identifier: GPL-2.0-or-later */
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR0_EL1, 0, 0, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR0_EL1, 0, 0, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR0_EL1, 0, 0, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR0_EL1, 0, 0, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR1_EL1, 0, 1, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR1_EL1, 0, 1, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR1_EL1, 0, 1, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR1_EL1, 0, 1, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR2_EL1, 0, 2, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR2_EL1, 0, 2, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR2_EL1, 0, 2, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR2_EL1, 0, 2, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR3_EL1, 0, 3, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR3_EL1, 0, 3, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR3_EL1, 0, 3, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR3_EL1, 0, 3, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR4_EL1, 0, 4, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR4_EL1, 0, 4, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR4_EL1, 0, 4, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR4_EL1, 0, 4, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR5_EL1, 0, 5, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR5_EL1, 0, 5, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR5_EL1, 0, 5, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR5_EL1, 0, 5, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR6_EL1, 0, 6, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR6_EL1, 0, 6, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR6_EL1, 0, 6, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR6_EL1, 0, 6, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR7_EL1, 0, 7, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR7_EL1, 0, 7, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR7_EL1, 0, 7, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR7_EL1, 0, 7, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR8_EL1, 0, 8, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR8_EL1, 0, 8, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR8_EL1, 0, 8, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR8_EL1, 0, 8, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR9_EL1, 0, 9, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR9_EL1, 0, 9, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR9_EL1, 0, 9, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR9_EL1, 0, 9, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR10_EL1, 0, 10, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR10_EL1, 0, 10, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR10_EL1, 0, 10, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR10_EL1, 0, 10, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR11_EL1, 0, 11, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR11_EL1, 0, 11, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR11_EL1, 0, 11, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR11_EL1, 0, 11, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR12_EL1, 0, 12, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR12_EL1, 0, 12, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR12_EL1, 0, 12, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR12_EL1, 0, 12, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR13_EL1, 0, 13, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR13_EL1, 0, 13, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR13_EL1, 0, 13, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR13_EL1, 0, 13, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR14_EL1, 0, 14, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR14_EL1, 0, 14, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR14_EL1, 0, 14, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR14_EL1, 0, 14, 2, 0, 7)
>+
>+DEF_SYSREG(HV_SYS_REG_DBGBVR15_EL1, 0, 15, 2, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_DBGBCR15_EL1, 0, 15, 2, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_DBGWVR15_EL1, 0, 15, 2, 0, 6)
>+DEF_SYSREG(HV_SYS_REG_DBGWCR15_EL1, 0, 15, 2, 0, 7)
>+
>+#ifdef SYNC_NO_RAW_REGS
>+/*
>+ * The registers below are manually synced on init because they are
>+ * marked as NO_RAW. We still list them to make number space sync easier.
>+ */
>+DEF_SYSREG(HV_SYS_REG_MDCCINT_EL1, 0, 2, 2, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_MIDR_EL1, 0, 0, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_MPIDR_EL1, 0, 0, 3, 0, 5)
>+DEF_SYSREG(HV_SYS_REG_ID_AA64PFR0_EL1, 0, 4, 3, 0, 0)
>+#endif
>+
>+DEF_SYSREG(HV_SYS_REG_ID_AA64PFR1_EL1, 0, 4, 3, 0, 1)
>+DEF_SYSREG(HV_SYS_REG_ID_AA64DFR0_EL1, 0, 5, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_ID_AA64DFR1_EL1, 0, 5, 3, 0, 1)
>+DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR0_EL1, 0, 6, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR1_EL1, 0, 6, 3, 0, 1)
>+
>+#ifdef SYNC_NO_MMFR0
>+/* We keep the hardware MMFR0 around. HW limits are there anyway */
>+DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR0_EL1, 0, 7, 3, 0, 0)
>+#endif
>+
>+DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR1_EL1, 0, 7, 3, 0, 1)
>+DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR2_EL1, 0, 7, 3, 0, 2)
>+/* Add ID_AA64MMFR3_EL1 here when HVF supports it */
>+
>+DEF_SYSREG(HV_SYS_REG_MDSCR_EL1, 0, 2, 2, 0, 2)
>+DEF_SYSREG(HV_SYS_REG_SCTLR_EL1, 1, 0, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_CPACR_EL1, 1, 0, 3, 0, 2)
>+DEF_SYSREG(HV_SYS_REG_TTBR0_EL1, 2, 0, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_TTBR1_EL1, 2, 0, 3, 0, 1)
>+DEF_SYSREG(HV_SYS_REG_TCR_EL1, 2, 0, 3, 0, 2)
>+
>+DEF_SYSREG(HV_SYS_REG_APIAKEYLO_EL1, 2, 1, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_APIAKEYHI_EL1, 2, 1, 3, 0, 1)
>+DEF_SYSREG(HV_SYS_REG_APIBKEYLO_EL1, 2, 1, 3, 0, 2)
>+DEF_SYSREG(HV_SYS_REG_APIBKEYHI_EL1, 2, 1, 3, 0, 3)
>+DEF_SYSREG(HV_SYS_REG_APDAKEYLO_EL1, 2, 2, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_APDAKEYHI_EL1, 2, 2, 3, 0, 1)
>+DEF_SYSREG(HV_SYS_REG_APDBKEYLO_EL1, 2, 2, 3, 0, 2)
>+DEF_SYSREG(HV_SYS_REG_APDBKEYHI_EL1, 2, 2, 3, 0, 3)
>+DEF_SYSREG(HV_SYS_REG_APGAKEYLO_EL1, 2, 3, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_APGAKEYHI_EL1, 2, 3, 3, 0, 1)
>+
>+DEF_SYSREG(HV_SYS_REG_SPSR_EL1, 4, 0, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_ELR_EL1, 4, 0, 3, 0, 1)
>+DEF_SYSREG(HV_SYS_REG_SP_EL0, 4, 1, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_AFSR0_EL1, 5, 1, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_AFSR1_EL1, 5, 1, 3, 0, 1)
>+DEF_SYSREG(HV_SYS_REG_ESR_EL1, 5, 2, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_FAR_EL1, 6, 0, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_PAR_EL1, 7, 4, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_MAIR_EL1, 10, 2, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_AMAIR_EL1, 10, 3, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_VBAR_EL1, 12, 0, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_CONTEXTIDR_EL1, 13, 0, 3, 0, 1)
>+DEF_SYSREG(HV_SYS_REG_TPIDR_EL1, 13, 0, 3, 0, 4)
>+DEF_SYSREG(HV_SYS_REG_CNTKCTL_EL1, 14, 1, 3, 0, 0)
>+DEF_SYSREG(HV_SYS_REG_CSSELR_EL1, 0, 0, 3, 2, 0)
>+DEF_SYSREG(HV_SYS_REG_TPIDR_EL0, 13, 0, 3, 3, 2)
>+DEF_SYSREG(HV_SYS_REG_TPIDRRO_EL0, 13, 0, 3, 3, 3)
>+DEF_SYSREG(HV_SYS_REG_CNTV_CTL_EL0, 14, 3, 3, 3, 1)
>+DEF_SYSREG(HV_SYS_REG_CNTV_CVAL_EL0, 14, 3, 3, 3, 2)
>+DEF_SYSREG(HV_SYS_REG_SP_EL1, 4, 1, 3, 4, 0)
>-- 
>2.43.0
>
>


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

* Re: [PATCH 05/61] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID
  2025-08-27  1:03 ` [PATCH 05/61] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID Richard Henderson
@ 2025-08-29  6:59   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  6:59 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:03, Richard Henderson <richard.henderson@linaro.org> wrote:
>Conversion between KVM system registers ids and the HVF system
>register ids is trivial.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---


Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/hvf/hvf.c | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
>
>diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
>index 7b0413093d..47165bd29c 100644
>--- a/target/arm/hvf/hvf.c
>+++ b/target/arm/hvf/hvf.c
>@@ -403,6 +403,26 @@ struct hvf_sreg_match {
>     uint32_t cp_idx;
> };
> 
>+/*
>+ * QEMU uses KVM system register ids in the migration format.
>+ * Conveniently, HVF uses the same encoding of the op* and cr* parameters
>+ * within the low 16 bits of the ids.  Thus conversion between the
>+ * formats is trivial.
>+ */
>+
>+#define KVMID_TO_HVF(KVM)  ((KVM) & 0xffff)
>+#define HVF_TO_KVMID(HVF)  \
>+    (CP_REG_ARM64 | CP_REG_SIZE_U64 | CP_REG_ARM64_SYSREG | (HVF))
>+
>+/* Verify this at compile-time. */
>+
>+#define DEF_SYSREG(HVF_ID, ...) \
>+  QEMU_BUILD_BUG_ON(HVF_ID != KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__)));
>+
>+#include "sysreg.c.inc"
>+
>+#undef DEF_SYSREG
>+
> #define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2) \
>     { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
> 
>-- 
>2.43.0
>
>


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

* Re: [PATCH 06/61] target/arm/hvf: Remove hvf_sreg_match.key
  2025-08-27  1:03 ` [PATCH 06/61] " Richard Henderson
@ 2025-08-29  7:00   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  7:00 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:03, Richard Henderson <richard.henderson@linaro.org> wrote:
>Use conversion functions instead of table lookup.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/hvf/hvf.c | 35 +++++++++++++++++++----------------
> 1 file changed, 19 insertions(+), 16 deletions(-)
>
>diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
>index 47165bd29c..5fcfa9a999 100644
>--- a/target/arm/hvf/hvf.c
>+++ b/target/arm/hvf/hvf.c
>@@ -152,9 +152,6 @@ void hvf_arm_init_debug(void)
>         g_array_sized_new(true, true, sizeof(HWWatchpoint), max_hw_wps);
> }
> 
>-#define HVF_SYSREG(crn, crm, op0, op1, op2) \
>-        ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)
>-
> #define SYSREG_OP0_SHIFT      20
> #define SYSREG_OP0_MASK       0x3
> #define SYSREG_OP0(sysreg)    ((sysreg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK)
>@@ -399,7 +396,6 @@ static const struct hvf_reg_match hvf_fpreg_match[] = {
> 
> struct hvf_sreg_match {
>     int reg;
>-    uint32_t key;
>     uint32_t cp_idx;
> };
> 
>@@ -423,8 +419,7 @@ struct hvf_sreg_match {
> 
> #undef DEF_SYSREG
> 
>-#define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2) \
>-    { HVF_ID, HVF_SYSREG(crn, crm, op0, op1, op2) },
>+#define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2)  { HVF_ID },
> 
> static struct hvf_sreg_match hvf_sreg_match[] = {
> #include "sysreg.c.inc"
>@@ -469,13 +464,16 @@ int hvf_get_registers(CPUState *cpu)
>     pstate_write(env, val);
> 
>     for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
>+        int hvf_id = hvf_sreg_match[i].reg;
>+        uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
>+
>         if (hvf_sreg_match[i].cp_idx == -1) {
>             continue;
>         }
> 
>         if (cpu->accel->guest_debug_enabled) {
>             /* Handle debug registers */
>-            switch (hvf_sreg_match[i].reg) {
>+            switch (hvf_id) {
>             case HV_SYS_REG_DBGBVR0_EL1:
>             case HV_SYS_REG_DBGBCR0_EL1:
>             case HV_SYS_REG_DBGWVR0_EL1:
>@@ -549,8 +547,10 @@ int hvf_get_registers(CPUState *cpu)
>                  * vCPU but simply keep the values from the previous
>                  * environment.
>                  */
>-                const ARMCPRegInfo *ri;
>-                ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_sreg_match[i].key);
>+                uint32_t key = kvm_to_cpreg_id(kvm_id);
>+                const ARMCPRegInfo *ri =
>+                    get_arm_cp_reginfo(arm_cpu->cp_regs, key);
>+
>                 val = read_raw_cp_reg(env, ri);
> 
>                 arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
>@@ -559,7 +559,7 @@ int hvf_get_registers(CPUState *cpu)
>             }
>         }
> 
>-        ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_sreg_match[i].reg, &val);
>+        ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_id, &val);
>         assert_hvf_ok(ret);
> 
>         arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
>@@ -606,13 +606,15 @@ int hvf_put_registers(CPUState *cpu)
> 
>     assert(write_cpustate_to_list(arm_cpu, false));
>     for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
>+        int hvf_id = hvf_sreg_match[i].reg;
>+
>         if (hvf_sreg_match[i].cp_idx == -1) {
>             continue;
>         }
> 
>         if (cpu->accel->guest_debug_enabled) {
>             /* Handle debug registers */
>-            switch (hvf_sreg_match[i].reg) {
>+            switch (hvf_id) {
>             case HV_SYS_REG_DBGBVR0_EL1:
>             case HV_SYS_REG_DBGBCR0_EL1:
>             case HV_SYS_REG_DBGWVR0_EL1:
>@@ -687,7 +689,7 @@ int hvf_put_registers(CPUState *cpu)
>         }
> 
>         val = arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx];
>-        ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_sreg_match[i].reg, val);
>+        ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_id, val);
>         assert_hvf_ok(ret);
>     }
> 
>@@ -922,14 +924,15 @@ int hvf_arch_init_vcpu(CPUState *cpu)
> 
>     /* Populate cp list for all known sysregs */
>     for (i = 0; i < sregs_match_len; i++) {
>-        const ARMCPRegInfo *ri;
>-        uint32_t key = hvf_sreg_match[i].key;
>+        int hvf_id = hvf_sreg_match[i].reg;
>+        uint64_t kvm_id = HVF_TO_KVMID(hvf_id);
>+        uint32_t key = kvm_to_cpreg_id(kvm_id);
>+        const ARMCPRegInfo *ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
> 
>-        ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
>         if (ri) {
>             assert(!(ri->type & ARM_CP_NO_RAW));
>             hvf_sreg_match[i].cp_idx = sregs_cnt;
>-            arm_cpu->cpreg_indexes[sregs_cnt++] = cpreg_to_kvm_id(key);
>+            arm_cpu->cpreg_indexes[sregs_cnt++] = kvm_id;
>         } else {
>             hvf_sreg_match[i].cp_idx = -1;
>         }
>-- 
>2.43.0
>
>


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

* Re: [PATCH 10/61] target/arm: Use raw_write in cp_reg_reset
  2025-08-27  1:04 ` [PATCH 10/61] target/arm: Use raw_write in cp_reg_reset Richard Henderson
@ 2025-08-29  7:05   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  7:05 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Reduce the places that know about field types by 1.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---


Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/cpu.c | 10 ++--------
> 1 file changed, 2 insertions(+), 8 deletions(-)
>
>diff --git a/target/arm/cpu.c b/target/arm/cpu.c
>index e2b2337399..ed40e102fc 100644
>--- a/target/arm/cpu.c
>+++ b/target/arm/cpu.c
>@@ -192,14 +192,8 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
>      * This is basically only used for fields in non-core coprocessors
>      * (like the pxa2xx ones).
>      */
>-    if (!ri->fieldoffset) {
>-        return;
>-    }
>-
>-    if (cpreg_field_is_64bit(ri)) {
>-        CPREG_FIELD64(&cpu->env, ri) = ri->resetvalue;
>-    } else {
>-        CPREG_FIELD32(&cpu->env, ri) = ri->resetvalue;
>+    if (ri->fieldoffset) {
>+        raw_write(&cpu->env, ri, ri->resetvalue);
>     }
> }
> 
>-- 
>2.43.0
>
>


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

* Re: [PATCH 12/61] target/arm: Drop define_one_arm_cp_reg_with_opaque
  2025-08-27  1:04 ` [PATCH 12/61] target/arm: Drop define_one_arm_cp_reg_with_opaque Richard Henderson
@ 2025-08-29  7:06   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  7:06 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>The last use of this interface was removed in 603bc048a27f
>("hw/arm: Remove pxa2xx_pic").  As the comment in gicv3
>stated, keeping pointer references to cpregs has SMP issues,
>so avoid future temptation by removing the interface.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/cpregs.h       | 32 ++++++++------------------------
> hw/intc/arm_gicv3_cpuif.c | 10 +---------
> target/arm/helper.c       | 29 +++++++++++------------------
> 3 files changed, 20 insertions(+), 51 deletions(-)
>
>diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>index 3344a02bd3..b610716c24 100644
>--- a/target/arm/cpregs.h
>+++ b/target/arm/cpregs.h
>@@ -906,11 +906,7 @@ struct ARMCPRegInfo {
>      */
>     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
>-     * register read/write functions, since they are passed the ARMCPRegInfo*.
>-     */
>+    /* This is used only by VHE. */
>     void *opaque;
>     /*
>      * Value of this register, if it is ARM_CP_CONST. Otherwise, if
>@@ -1004,27 +1000,15 @@ struct ARMCPRegInfo {
> #define CPREG_FIELD64(env, ri) \
>     (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
> 
>-void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, const ARMCPRegInfo *reg,
>-                                       void *opaque);
>+void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs);
>+void define_arm_cp_regs_len(ARMCPU *cpu, const ARMCPRegInfo *regs, size_t len);
> 
>-static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs)
>-{
>-    define_one_arm_cp_reg_with_opaque(cpu, regs, NULL);
>-}
>-
>-void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
>-                                        void *opaque, size_t len);
>-
>-#define define_arm_cp_regs_with_opaque(CPU, REGS, OPAQUE)               \
>-    do {                                                                \
>-        QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0);                       \
>-        define_arm_cp_regs_with_opaque_len(CPU, REGS, OPAQUE,           \
>-                                           ARRAY_SIZE(REGS));           \
>+#define define_arm_cp_regs(CPU, REGS)                           \
>+    do {                                                        \
>+        QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0);               \
>+        define_arm_cp_regs_len(CPU, REGS, ARRAY_SIZE(REGS));    \
>     } while (0)
> 
>-#define define_arm_cp_regs(CPU, REGS) \
>-    define_arm_cp_regs_with_opaque(CPU, REGS, NULL)
>-
> const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp);
> 
> /*
>@@ -1143,7 +1127,7 @@ static inline bool arm_cpreg_traps_in_nv(const ARMCPRegInfo *ri)
>      * 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().)
>+     * define_one_arm_cp_reg().)
>      * 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.
>diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
>index 4b4cf09157..72e91f971a 100644
>--- a/hw/intc/arm_gicv3_cpuif.c
>+++ b/hw/intc/arm_gicv3_cpuif.c
>@@ -3037,15 +3037,7 @@ void gicv3_init_cpuif(GICv3State *s)
>          *  cpu->gic_pribits
>          */
> 
>-        /* Note that we can't just use the GICv3CPUState as an opaque pointer
>-         * in define_arm_cp_regs_with_opaque(), because when we're called back
>-         * it might be with code translated by CPU 0 but run by CPU 1, in
>-         * which case we'd get the wrong value.
>-         * So instead we define the regs with no ri->opaque info, and
>-         * get back to the GICv3CPUState from the CPUARMState.
>-         *
>-         * These CP regs callbacks can be called from either TCG or HVF code.
>-         */
>+        /* These CP regs callbacks can be called from either TCG or HVF. */
>         define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
> 
>         /*
>diff --git a/target/arm/helper.c b/target/arm/helper.c
>index e03cbc0394..35a176ea3b 100644
>--- a/target/arm/helper.c
>+++ b/target/arm/helper.c
>@@ -7256,12 +7256,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> }
> 
> /*
>- * Private utility function for define_one_arm_cp_reg_with_opaque():
>+ * Private utility function for define_one_arm_cp_reg():
>  * add a single reginfo struct to the hash table.
>  */
> static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>-                                   void *opaque, CPState state,
>-                                   CPSecureState secstate,
>+                                   CPState state, CPSecureState secstate,
>                                    int crm, int opc1, int opc2,
>                                    const char *name)
> {
>@@ -7349,9 +7348,6 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>     r2->opc2 = opc2;
>     r2->state = state;
>     r2->secure = secstate;
>-    if (opaque) {
>-        r2->opaque = opaque;
>-    }
> 
>     if (make_const) {
>         /* This should not have been a very special register to begin. */
>@@ -7456,8 +7452,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> }
> 
> 
>-void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
>-                                       const ARMCPRegInfo *r, void *opaque)
>+void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
> {
>     /*
>      * Define implementations of coprocessor registers.
>@@ -7616,7 +7611,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
>                         if (nxs_ri.fgt) {
>                             nxs_ri.fgt |= R_FGT_NXS_MASK;
>                         }
>-                        add_cpreg_to_hashtable(cpu, &nxs_ri, opaque, state,
>+                        add_cpreg_to_hashtable(cpu, &nxs_ri, state,
>                                                ARM_CP_SECSTATE_NS,
>                                                crm, opc1, opc2, name);
>                     }
>@@ -7630,17 +7625,17 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
>                         switch (r->secure) {
>                         case ARM_CP_SECSTATE_S:
>                         case ARM_CP_SECSTATE_NS:
>-                            add_cpreg_to_hashtable(cpu, r, opaque, state,
>+                            add_cpreg_to_hashtable(cpu, r, state,
>                                                    r->secure, crm, opc1, opc2,
>                                                    r->name);
>                             break;
>                         case ARM_CP_SECSTATE_BOTH:
>                             name = g_strdup_printf("%s_S", r->name);
>-                            add_cpreg_to_hashtable(cpu, r, opaque, state,
>+                            add_cpreg_to_hashtable(cpu, r, state,
>                                                    ARM_CP_SECSTATE_S,
>                                                    crm, opc1, opc2, name);
>                             g_free(name);
>-                            add_cpreg_to_hashtable(cpu, r, opaque, state,
>+                            add_cpreg_to_hashtable(cpu, r, state,
>                                                    ARM_CP_SECSTATE_NS,
>                                                    crm, opc1, opc2, r->name);
>                             break;
>@@ -7652,7 +7647,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
>                          * AArch64 registers get mapped to non-secure instance
>                          * of AArch32
>                          */
>-                        add_cpreg_to_hashtable(cpu, r, opaque, state,
>+                        add_cpreg_to_hashtable(cpu, r, state,
>                                                ARM_CP_SECSTATE_NS,
>                                                crm, opc1, opc2, r->name);
>                     }
>@@ -7663,12 +7658,10 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
> }
> 
> /* Define a whole list of registers */
>-void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
>-                                        void *opaque, size_t len)
>+void define_arm_cp_regs_len(ARMCPU *cpu, const ARMCPRegInfo *regs, size_t len)
> {
>-    size_t i;
>-    for (i = 0; i < len; ++i) {
>-        define_one_arm_cp_reg_with_opaque(cpu, regs + i, opaque);
>+    for (size_t i = 0; i < len; ++i) {
>+        define_one_arm_cp_reg(cpu, regs + i);
>     }
> }
> 
>-- 
>2.43.0
>
>


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

* Re: [PATCH 13/61] target/arm: Restrict the scope of CPREG_FIELD32, CPREG_FIELD64
  2025-08-27  1:04 ` [PATCH 13/61] target/arm: Restrict the scope of CPREG_FIELD32, CPREG_FIELD64 Richard Henderson
@ 2025-08-29  7:09   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  7:09 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/cpregs.h |  9 ---------
> target/arm/helper.c | 12 ++++++++++++
> 2 files changed, 12 insertions(+), 9 deletions(-)
>
>diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>index b610716c24..812fb1340a 100644
>--- a/target/arm/cpregs.h
>+++ b/target/arm/cpregs.h
>@@ -991,15 +991,6 @@ struct ARMCPRegInfo {
>     CPAccessFn *orig_accessfn;
> };
> 
>-/*
>- * Macros which are lvalues for the field in CPUARMState for the
>- * ARMCPRegInfo *ri.
>- */
>-#define CPREG_FIELD32(env, ri) \
>-    (*(uint32_t *)((char *)(env) + (ri)->fieldoffset))
>-#define CPREG_FIELD64(env, ri) \
>-    (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
>-
> void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs);
> void define_arm_cp_regs_len(ARMCPU *cpu, const ARMCPRegInfo *regs, size_t len);
> 
>diff --git a/target/arm/helper.c b/target/arm/helper.c
>index 35a176ea3b..3a9d8f0ddc 100644
>--- a/target/arm/helper.c
>+++ b/target/arm/helper.c
>@@ -51,6 +51,15 @@ int compare_u64(const void *a, const void *b)
>     return 0;
> }
> 
>+/*
>+ * Macros which are lvalues for the field in CPUARMState for the
>+ * ARMCPRegInfo *ri.
>+ */
>+#define CPREG_FIELD32(env, ri) \
>+    (*(uint32_t *)((char *)(env) + (ri)->fieldoffset))
>+#define CPREG_FIELD64(env, ri) \
>+    (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
>+
> uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri)
> {
>     assert(ri->fieldoffset);
>@@ -71,6 +80,9 @@ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>     }
> }
> 
>+#undef CPREG_FIELD32
>+#undef CPREG_FIELD64
>+
> static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri)
> {
>     return (char *)env + ri->fieldoffset;
>-- 
>2.43.0
>
>


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

* Re: [PATCH 14/61] target/arm: Replace cpreg_field_is_64bit with cpreg_field_type
  2025-08-27  1:04 ` [PATCH 14/61] target/arm: Replace cpreg_field_is_64bit with cpreg_field_type Richard Henderson
@ 2025-08-29  7:13   ` Manos Pitsidianakis
  2025-09-03  4:48     ` Richard Henderson
  0 siblings, 1 reply; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  7:13 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Prepare for 128-bit fields by using a better query api.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---
> target/arm/cpregs.h  | 10 ++++++----
> target/arm/gdbstub.c |  7 +++++--
> target/arm/helper.c  | 18 +++++++++++++-----
> 3 files changed, 24 insertions(+), 11 deletions(-)
>
>diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>index 812fb1340a..b6c8eff0dd 100644
>--- a/target/arm/cpregs.h
>+++ b/target/arm/cpregs.h
>@@ -22,6 +22,7 @@
> #define TARGET_ARM_CPREGS_H
> 
> #include "hw/registerfields.h"
>+#include "exec/memop.h"
> #include "target/arm/kvm-consts.h"
> #include "cpu.h"
> 
>@@ -1053,12 +1054,13 @@ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value);
> void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri);
> 
> /*
>- * Return true if this reginfo struct's field in the cpu state struct
>- * is 64 bits wide.
>+ * Return MO_32 if the field in CPUARMState is uint32_t or
>+ * MO_64 if the field in CPUARMState is uint64_t.
>  */
>-static inline bool cpreg_field_is_64bit(const ARMCPRegInfo *ri)
>+static inline MemOp cpreg_field_type(const ARMCPRegInfo *ri)

Using MemOp is slightly confusing though I understand where you're 
coming from. Would introducing a BitWidth enum be a good idea?


diff --git a/include/exec/memop.h b/include/exec/memop.h
index cf7da3362e..9104c4f162 100644
--- a/include/exec/memop.h
+++ b/include/exec/memop.h
@@ -14,15 +14,26 @@
 
 #include "qemu/host-utils.h"
 
+typedef enum BitWidth {
+    BW_8     = 0,
+    BW_16    = 1,
+    BW_32    = 2,
+    BW_64    = 3,
+    BW_128   = 4,
+    BW_256   = 5,
+    BW_512   = 6,
+    BW_1024  = 7,
+}
+
 typedef enum MemOp {
-    MO_8     = 0,
-    MO_16    = 1,
-    MO_32    = 2,
-    MO_64    = 3,
-    MO_128   = 4,
-    MO_256   = 5,
-    MO_512   = 6,
-    MO_1024  = 7,
+    MO_8     = BW_8,
+    MO_16    = BW_16,
+    MO_32    = BW_32,
+    MO_64    = BW_64,
+    MO_128   = BW_128,
+    MO_256   = BW_256,
+    MO_512   = BW_512,
+    MO_1024  = BW_1024,
     MO_SIZE  = 0x07,   /* Mask for the above.  */

> {
>-    return (ri->state == ARM_CP_STATE_AA64) || (ri->type & ARM_CP_64BIT);
>+    return (ri->state == ARM_CP_STATE_AA64 || (ri->type & ARM_CP_64BIT)
>+            ? MO_64 : MO_32);
> }
> 
> static inline bool cp_access_ok(int current_el,
>diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
>index ce4497ad7c..e2fc389170 100644
>--- a/target/arm/gdbstub.c
>+++ b/target/arm/gdbstub.c
>@@ -247,10 +247,13 @@ static int arm_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg)
>     key = cpu->dyn_sysreg_feature.data.cpregs.keys[reg];
>     ri = get_arm_cp_reginfo(cpu->cp_regs, key);
>     if (ri) {
>-        if (cpreg_field_is_64bit(ri)) {
>+        switch (cpreg_field_type(ri)) {
>+        case MO_64:
>             return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri));
>-        } else {
>+        case MO_32:
>             return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri));
>+        default:
>+            g_assert_not_reached();
>         }
>     }
>     return 0;
>diff --git a/target/arm/helper.c b/target/arm/helper.c
>index 3a9d8f0ddc..c4103d958a 100644
>--- a/target/arm/helper.c
>+++ b/target/arm/helper.c
>@@ -63,20 +63,28 @@ int compare_u64(const void *a, const void *b)
> uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri)
> {
>     assert(ri->fieldoffset);
>-    if (cpreg_field_is_64bit(ri)) {
>+    switch (cpreg_field_type(ri)) {
>+    case MO_64:
>         return CPREG_FIELD64(env, ri);
>-    } else {
>+    case MO_32:
>         return CPREG_FIELD32(env, ri);
>+    default:
>+        g_assert_not_reached();
>     }
> }
> 
> void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
> {
>     assert(ri->fieldoffset);
>-    if (cpreg_field_is_64bit(ri)) {
>+    switch (cpreg_field_type(ri)) {
>+    case MO_64:
>         CPREG_FIELD64(env, ri) = value;
>-    } else {
>+        break;
>+    case MO_32:
>         CPREG_FIELD32(env, ri) = value;
>+        break;
>+    default:
>+        g_assert_not_reached();
>     }
> }
> 
>@@ -2748,7 +2756,7 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>                             uint64_t value)
> {
>     /* If the ASID changes (with a 64-bit write), we must flush the TLB.  */
>-    if (cpreg_field_is_64bit(ri) &&
>+    if (cpreg_field_type(ri) == MO_64 &&
>         extract64(raw_read(env, ri) ^ value, 48, 16) != 0) {
>         ARMCPU *cpu = env_archcpu(env);
>         tlb_flush(CPU(cpu));
>-- 
>2.43.0
>
>

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>


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

* Re: [PATCH 15/61] target/arm: Add CP_REG_AA32_64BIT_{SHIFT,MASK}
  2025-08-27  1:04 ` [PATCH 15/61] target/arm: Add CP_REG_AA32_64BIT_{SHIFT,MASK} Richard Henderson
@ 2025-08-29  7:27   ` Manos Pitsidianakis
  2025-08-29 13:55     ` Richard Henderson
  0 siblings, 1 reply; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  7:27 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Give a name to the bit we're already using.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---
> target/arm/cpregs.h | 15 ++++++++++-----
> 1 file changed, 10 insertions(+), 5 deletions(-)
>
>diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>index b6c8eff0dd..3dc4c9927b 100644
>--- a/target/arm/cpregs.h
>+++ b/target/arm/cpregs.h
>@@ -178,9 +178,14 @@ enum {
> #define CP_REG_NS_SHIFT 29
> #define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT)
> 
>+/* Distinguish 32-bit and 64-bit views of AArch32 system registers. */
>+#define CP_REG_AA32_64BIT_SHIFT  15
>+#define CP_REG_AA32_64BIT_MASK   (1 << CP_REG_AA32_64BIT_SHIFT)

You could use include/qemu/bitops.h

>+
> #define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2)   \
>-    ((ns) << CP_REG_NS_SHIFT | ((cp) << 16) | ((is64) << 15) |   \
>-     ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
>+    (((ns) << CP_REG_NS_SHIFT) |                            \
>+     ((is64) << CP_REG_AA32_64BIT_SHIFT) |                  \
>+     ((cp) << 16) | ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
> 
> #define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
>     (CP_REG_AA64_MASK |                                 \
>@@ -202,7 +207,7 @@ static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
>         cpregid |= CP_REG_AA64_MASK;
>     } else {
>         if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) {
>-            cpregid |= (1 << 15);
>+            cpregid |= CP_REG_AA32_64BIT_MASK;
>         }
> 
>         /*
>@@ -226,8 +231,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>         kvmid = cpregid & ~CP_REG_AA64_MASK;
>         kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM64;
>     } else {
>-        kvmid = cpregid & ~(1 << 15);
>-        if (cpregid & (1 << 15)) {
>+        kvmid = cpregid & ~CP_REG_AA32_64BIT_MASK;
>+        if (cpregid & CP_REG_AA32_64BIT_MASK) {
>             kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM;
>         } else {
>             kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM;
>-- 

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

>2.43.0
>
>


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

* Re: [PATCH 16/61] target/arm: Rename CP_REG_AA32_NS_{SHIFT,MASK}
  2025-08-27  1:04 ` [PATCH 16/61] target/arm: Rename CP_REG_AA32_NS_{SHIFT,MASK} Richard Henderson
@ 2025-08-29  7:30   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  7:30 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Rename from CP_REG_NS_* to emphasize this is
>specific to AArch32.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/cpregs.h | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
>diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>index 3dc4c9927b..7ebe404163 100644
>--- a/target/arm/cpregs.h
>+++ b/target/arm/cpregs.h
>@@ -175,15 +175,15 @@ enum {
>  * add a bit to distinguish between secure and non-secure cpregs in the
>  * hashtable.
>  */
>-#define CP_REG_NS_SHIFT 29
>-#define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT)
>+#define CP_REG_AA32_NS_SHIFT     29
>+#define CP_REG_AA32_NS_MASK      (1 << CP_REG_AA32_NS_SHIFT)
> 
> /* Distinguish 32-bit and 64-bit views of AArch32 system registers. */
> #define CP_REG_AA32_64BIT_SHIFT  15
> #define CP_REG_AA32_64BIT_MASK   (1 << CP_REG_AA32_64BIT_SHIFT)
> 
> #define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2)   \
>-    (((ns) << CP_REG_NS_SHIFT) |                            \
>+    (((ns) << CP_REG_AA32_NS_SHIFT) |                       \
>      ((is64) << CP_REG_AA32_64BIT_SHIFT) |                  \
>      ((cp) << 16) | ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
> 
>@@ -214,7 +214,7 @@ static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
>          * KVM is always non-secure so add the NS flag on AArch32 register
>          * entries.
>          */
>-         cpregid |= 1 << CP_REG_NS_SHIFT;
>+         cpregid |= CP_REG_AA32_NS_MASK;
>     }
>     return cpregid;
> }
>-- 
>2.43.0
>
>


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

* Re: [PATCH 18/61] target/arm: Remove cp argument to ENCODE_AA64_CP_REG
  2025-08-27  1:04 ` [PATCH 18/61] target/arm: Remove cp argument to ENCODE_AA64_CP_REG Richard Henderson
@ 2025-08-29  7:36   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  7:36 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>All invocations were required to pass the same value,
>CP_REG_ARM64_SYSREG_CP.  Bake that in to the result directly.
>Remove CP_REG_ARM64_SYSREG_CP as unused.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/cpregs.h            |  5 ++---
> target/arm/kvm-consts.h        |  3 ---
> target/arm/helper.c            | 11 +++++------
> target/arm/hvf/hvf.c           |  3 +--
> target/arm/tcg/translate-a64.c |  6 ++----
> 5 files changed, 10 insertions(+), 18 deletions(-)
>
>diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>index 7ebe404163..95b0b9c78e 100644
>--- a/target/arm/cpregs.h
>+++ b/target/arm/cpregs.h
>@@ -187,9 +187,8 @@ enum {
>      ((is64) << CP_REG_AA32_64BIT_SHIFT) |                  \
>      ((cp) << 16) | ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
> 
>-#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
>-    (CP_REG_AA64_MASK |                                 \
>-     ((cp) << CP_REG_ARM_COPROC_SHIFT) |                \
>+#define ENCODE_AA64_CP_REG(crn, crm, op0, op1, op2) \
>+    (CP_REG_AA64_MASK | CP_REG_ARM64_SYSREG |           \
>      ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) |         \
>      ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) |         \
>      ((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) |         \
>diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h
>index fdb305eea1..54ae5da7ce 100644
>--- a/target/arm/kvm-consts.h
>+++ b/target/arm/kvm-consts.h
>@@ -160,9 +160,6 @@ MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53);
> #define CP_REG_ARM64_SYSREG_OP2_MASK   0x0000000000000007
> #define CP_REG_ARM64_SYSREG_OP2_SHIFT  0
> 
>-/* No kernel define but it's useful to QEMU */
>-#define CP_REG_ARM64_SYSREG_CP (CP_REG_ARM64_SYSREG >> CP_REG_ARM_COPROC_SHIFT)
>-
> MISMATCH_CHECK(CP_REG_ARM64, KVM_REG_ARM64);
> MISMATCH_CHECK(CP_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_MASK);
> MISMATCH_CHECK(CP_REG_ARM_COPROC_SHIFT, KVM_REG_ARM_COPROC_SHIFT);
>diff --git a/target/arm/helper.c b/target/arm/helper.c
>index 268cad905f..93cae888e2 100644
>--- a/target/arm/helper.c
>+++ b/target/arm/helper.c
>@@ -4527,7 +4527,7 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
>     };
> 
> #define K(op0, op1, crn, crm, op2) \
>-    ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)
>+    ENCODE_AA64_CP_REG(crn, crm, op0, op1, op2)
> 
>     static const struct E2HAlias aliases[] = {
>         { K(3, 0,  1, 0, 0), K(3, 4,  1, 0, 0), K(3, 5, 1, 0, 0),
>@@ -7297,10 +7297,9 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>          * in their AArch64 view (the .cp value may be non-zero for the
>          * benefit of the AArch32 view).
>          */
>-        if (cp == 0 || r->state == ARM_CP_STATE_BOTH) {
>-            cp = CP_REG_ARM64_SYSREG_CP;
>-        }
>-        key = ENCODE_AA64_CP_REG(cp, r->crn, crm, r->opc0, opc1, opc2);
>+        assert(cp == 0 || r->state == ARM_CP_STATE_BOTH);
>+        cp = 0;
>+        key = ENCODE_AA64_CP_REG(r->crn, crm, r->opc0, opc1, opc2);
>         break;
>     default:
>         g_assert_not_reached();
>@@ -7525,7 +7524,7 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
>         }
>         break;
>     case ARM_CP_STATE_AA64:
>-        assert(r->cp == 0 || r->cp == CP_REG_ARM64_SYSREG_CP);
>+        assert(r->cp == 0);
>         break;
>     default:
>         g_assert_not_reached();
>diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
>index 9dffa99ed1..af03fc7fc1 100644
>--- a/target/arm/hvf/hvf.c
>+++ b/target/arm/hvf/hvf.c
>@@ -1124,8 +1124,7 @@ static bool is_id_sysreg(uint32_t reg)
> 
> static uint32_t hvf_reg2cp_reg(uint32_t reg)
> {
>-    return ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
>-                              (reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK,
>+    return ENCODE_AA64_CP_REG((reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK,
>                               (reg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK,
>                               (reg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK,
>                               (reg >> SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK,
>diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
>index dbf47595db..743c5a10e1 100644
>--- a/target/arm/tcg/translate-a64.c
>+++ b/target/arm/tcg/translate-a64.c
>@@ -2466,8 +2466,7 @@ static void handle_sys(DisasContext *s, bool isread,
>                        unsigned int op0, unsigned int op1, unsigned int op2,
>                        unsigned int crn, unsigned int crm, unsigned int rt)
> {
>-    uint32_t key = ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
>-                                      crn, crm, op0, op1, op2);
>+    uint32_t key = ENCODE_AA64_CP_REG(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;
>@@ -2603,8 +2602,7 @@ static void handle_sys(DisasContext *s, bool isread,
>          * 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);
>+        key = ENCODE_AA64_CP_REG(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));
>-- 
>2.43.0
>
>


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

* Re: [PATCH 19/61] target/arm: Reorder ENCODE_AA64_CP_REG arguments
  2025-08-27  1:04 ` [PATCH 19/61] target/arm: Reorder ENCODE_AA64_CP_REG arguments Richard Henderson
@ 2025-08-29  7:40   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-08-29  7:40 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>The order of the parameters in the Arm ARM is
>
>  op0, op1, crn, crm, op2
>
>Reorder the arguments of ENCODE_AA64_CP_REG to match.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/cpregs.h            | 2 +-
> target/arm/helper.c            | 4 ++--
> target/arm/hvf/hvf.c           | 6 +++---
> target/arm/tcg/translate-a64.c | 4 ++--
> 4 files changed, 8 insertions(+), 8 deletions(-)
>
>diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>index 95b0b9c78e..7bdf6cf847 100644
>--- a/target/arm/cpregs.h
>+++ b/target/arm/cpregs.h
>@@ -187,7 +187,7 @@ enum {
>      ((is64) << CP_REG_AA32_64BIT_SHIFT) |                  \
>      ((cp) << 16) | ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
> 
>-#define ENCODE_AA64_CP_REG(crn, crm, op0, op1, op2) \
>+#define ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2) \
>     (CP_REG_AA64_MASK | CP_REG_ARM64_SYSREG |           \
>      ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) |         \
>      ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) |         \
>diff --git a/target/arm/helper.c b/target/arm/helper.c
>index 93cae888e2..b48b669a6a 100644
>--- a/target/arm/helper.c
>+++ b/target/arm/helper.c
>@@ -4527,7 +4527,7 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
>     };
> 
> #define K(op0, op1, crn, crm, op2) \
>-    ENCODE_AA64_CP_REG(crn, crm, op0, op1, op2)
>+    ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2)
> 
>     static const struct E2HAlias aliases[] = {
>         { K(3, 0,  1, 0, 0), K(3, 4,  1, 0, 0), K(3, 5, 1, 0, 0),
>@@ -7299,7 +7299,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>          */
>         assert(cp == 0 || r->state == ARM_CP_STATE_BOTH);
>         cp = 0;
>-        key = ENCODE_AA64_CP_REG(r->crn, crm, r->opc0, opc1, opc2);
>+        key = ENCODE_AA64_CP_REG(r->opc0, opc1, r->crn, crm, opc2);
>         break;
>     default:
>         g_assert_not_reached();
>diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
>index af03fc7fc1..bda57614ed 100644
>--- a/target/arm/hvf/hvf.c
>+++ b/target/arm/hvf/hvf.c
>@@ -1124,10 +1124,10 @@ static bool is_id_sysreg(uint32_t reg)
> 
> static uint32_t hvf_reg2cp_reg(uint32_t reg)
> {
>-    return ENCODE_AA64_CP_REG((reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK,
>-                              (reg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK,
>-                              (reg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK,
>+    return ENCODE_AA64_CP_REG((reg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK,
>                               (reg >> SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK,
>+                              (reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK,
>+                              (reg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK,
>                               (reg >> SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK);
> }
> 
>diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
>index 743c5a10e1..58303c224f 100644
>--- a/target/arm/tcg/translate-a64.c
>+++ b/target/arm/tcg/translate-a64.c
>@@ -2466,7 +2466,7 @@ static void handle_sys(DisasContext *s, bool isread,
>                        unsigned int op0, unsigned int op1, unsigned int op2,
>                        unsigned int crn, unsigned int crm, unsigned int rt)
> {
>-    uint32_t key = ENCODE_AA64_CP_REG(crn, crm, op0, op1, op2);
>+    uint32_t key = ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2);
>     const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
>     bool need_exit_tb = false;
>     bool nv_trap_to_el2 = false;
>@@ -2602,7 +2602,7 @@ static void handle_sys(DisasContext *s, bool isread,
>          * 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(crn, crm, op0, 0, op2);
>+        key = ENCODE_AA64_CP_REG(op0, 0, crn, crm, op2);
>         ri = get_arm_cp_reginfo(s->cp_regs, key);
>         assert(ri);
>         assert(cp_access_ok(s->current_el, ri, isread));
>-- 
>2.43.0
>
>


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

* Re: [PATCH 15/61] target/arm: Add CP_REG_AA32_64BIT_{SHIFT,MASK}
  2025-08-29  7:27   ` Manos Pitsidianakis
@ 2025-08-29 13:55     ` Richard Henderson
  0 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-08-29 13:55 UTC (permalink / raw)
  To: Manos Pitsidianakis, qemu-devel; +Cc: qemu-arm

On 8/29/25 17:27, Manos Pitsidianakis wrote:
> On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>> Give a name to the bit we're already using.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>> target/arm/cpregs.h | 15 ++++++++++-----
>> 1 file changed, 10 insertions(+), 5 deletions(-)
>>
>> diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>> index b6c8eff0dd..3dc4c9927b 100644
>> --- a/target/arm/cpregs.h
>> +++ b/target/arm/cpregs.h
>> @@ -178,9 +178,14 @@ enum {
>> #define CP_REG_NS_SHIFT 29
>> #define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT)
>>
>> +/* Distinguish 32-bit and 64-bit views of AArch32 system registers. */
>> +#define CP_REG_AA32_64BIT_SHIFT  15
>> +#define CP_REG_AA32_64BIT_MASK   (1 << CP_REG_AA32_64BIT_SHIFT)
> 
> You could use include/qemu/bitops.h

For what purpose?


r~


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

* Re: [PATCH 35/61] target/arm: Rename some cpreg to their aarch64 names
  2025-08-27  1:04 ` [PATCH 35/61] target/arm: Rename some cpreg to their aarch64 names Richard Henderson
@ 2025-09-01  6:53   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-09-01  6:53 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Rename those registers which will have FOO_EL12 aliases.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---


Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@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 a19406e136..255ca6fdcb 100644
>--- a/target/arm/helper.c
>+++ b/target/arm/helper.c
>@@ -671,7 +671,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
>      */
>     { .name = "WFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
>       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, },
>-    { .name = "CPACR", .state = ARM_CP_STATE_BOTH, .opc0 = 3,
>+    { .name = "CPACR_EL1", .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,
>@@ -2012,7 +2012,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
>       .resetfn = arm_gt_cntfrq_reset,
>     },
>     /* overall control: mostly access permissions */
>-    { .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH,
>+    { .name = "CNTKCTL_EL1", .state = ARM_CP_STATE_BOTH,
>       .opc0 = 3, .opc1 = 0, .crn = 14, .crm = 1, .opc2 = 0,
>       .access = PL1_RW,
>       .fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl),
>@@ -3071,8 +3071,8 @@ static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
> }
> 
> static const ARMCPRegInfo lpae_cp_reginfo[] = {
>-    /* NOP AMAIR0/1 */
>-    { .name = "AMAIR0", .state = ARM_CP_STATE_BOTH,
>+    /* AMAIR0 is mapped to AMAIR_EL1[31:0] */
>+    { .name = "AMAIR_EL1", .state = ARM_CP_STATE_BOTH,
>       .opc0 = 3, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0,
>       .access = PL1_RW, .accessfn = access_tvm_trvm,
>       .fgt = FGT_AMAIR_EL1,
>@@ -4454,9 +4454,9 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
> 
>     static const struct E2HAlias aliases[] = {
>         { K(3, 0,  1, 0, 0), K(3, 4,  1, 0, 0), K(3, 5, 1, 0, 0),
>-          "SCTLR", "SCTLR_EL2", "SCTLR_EL12" },
>+          "SCTLR_EL1", "SCTLR_EL2", "SCTLR_EL12" },
>         { K(3, 0,  1, 0, 2), K(3, 4,  1, 1, 2), K(3, 5, 1, 0, 2),
>-          "CPACR", "CPTR_EL2", "CPACR_EL12" },
>+          "CPACR_EL1", "CPTR_EL2", "CPACR_EL12" },
>         { K(3, 0,  2, 0, 0), K(3, 4,  2, 0, 0), K(3, 5, 2, 0, 0),
>           "TTBR0_EL1", "TTBR0_EL2", "TTBR0_EL12" },
>         { K(3, 0,  2, 0, 1), K(3, 4,  2, 0, 1), K(3, 5, 2, 0, 1),
>@@ -4478,13 +4478,13 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
>         { K(3, 0, 10, 2, 0), K(3, 4, 10, 2, 0), K(3, 5, 10, 2, 0),
>           "MAIR_EL1", "MAIR_EL2", "MAIR_EL12" },
>         { K(3, 0, 10, 3, 0), K(3, 4, 10, 3, 0), K(3, 5, 10, 3, 0),
>-          "AMAIR0", "AMAIR_EL2", "AMAIR_EL12" },
>+          "AMAIR_EL1", "AMAIR_EL2", "AMAIR_EL12" },
>         { K(3, 0, 12, 0, 0), K(3, 4, 12, 0, 0), K(3, 5, 12, 0, 0),
>-          "VBAR", "VBAR_EL2", "VBAR_EL12" },
>+          "VBAR_EL1", "VBAR_EL2", "VBAR_EL12" },
>         { K(3, 0, 13, 0, 1), K(3, 4, 13, 0, 1), K(3, 5, 13, 0, 1),
>           "CONTEXTIDR_EL1", "CONTEXTIDR_EL2", "CONTEXTIDR_EL12" },
>         { K(3, 0, 14, 1, 0), K(3, 4, 14, 1, 0), K(3, 5, 14, 1, 0),
>-          "CNTKCTL", "CNTHCTL_EL2", "CNTKCTL_EL12" },
>+          "CNTKCTL_EL1", "CNTHCTL_EL2", "CNTKCTL_EL12" },
> 
>         /*
>          * Note that redirection of ZCR is mentioned in the description
>@@ -6999,7 +6999,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> 
>     if (arm_feature(env, ARM_FEATURE_VBAR)) {
>         static const ARMCPRegInfo vbar_cp_reginfo[] = {
>-            { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
>+            { .name = "VBAR_EL1", .state = ARM_CP_STATE_BOTH,
>               .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
>               .access = PL1_RW, .writefn = vbar_write,
>               .accessfn = access_nv1,
>@@ -7015,7 +7015,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>     /* Generic registers whose values depend on the implementation */
>     {
>         ARMCPRegInfo sctlr = {
>-            .name = "SCTLR", .state = ARM_CP_STATE_BOTH,
>+            .name = "SCTLR_EL1", .state = ARM_CP_STATE_BOTH,
>             .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0,
>             .access = PL1_RW, .accessfn = access_tvm_trvm,
>             .fgt = FGT_SCTLR_EL1,
>-- 
>2.43.0
>
>


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

* Re: [PATCH 37/61] target/arm: Implement isar tests for FEAT_SYSREG128, FEAT_SYSINSTR128
  2025-08-27  1:04 ` [PATCH 37/61] target/arm: Implement isar tests for FEAT_SYSREG128, FEAT_SYSINSTR128 Richard Henderson
@ 2025-09-01  6:55   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-09-01  6:55 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/cpu-features.h | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
>diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
>index 5876162428..7a0e515aeb 100644
>--- a/target/arm/cpu-features.h
>+++ b/target/arm/cpu-features.h
>@@ -599,6 +599,16 @@ static inline bool isar_feature_aa64_mops(const ARMISARegisters *id)
>     return FIELD_EX64_IDREG(id, ID_AA64ISAR2, MOPS);
> }
> 
>+static inline bool isar_feature_aa64_sysreg128(const ARMISARegisters *id)
>+{
>+    return FIELD_EX64_IDREG(id, ID_AA64ISAR2, SYSREG_128) != 0;
>+}
>+
>+static inline bool isar_feature_aa64_sysinstr128(const ARMISARegisters *id)
>+{
>+    return FIELD_EX64_IDREG(id, ID_AA64ISAR2, SYSINSTR_128) != 0;
>+}
>+
> static inline bool isar_feature_aa64_rpres(const ARMISARegisters *id)
> {
>     return FIELD_EX64_IDREG(id, ID_AA64ISAR2, RPRES);
>-- 
>2.43.0
>
>


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

* Re: [PATCH 38/61] target/arm: Define CP_REG_SIZE_U128
  2025-08-27  1:04 ` [PATCH 38/61] target/arm: Define CP_REG_SIZE_U128 Richard Henderson
@ 2025-09-01  6:55   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-09-01  6:55 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/kvm-consts.h | 2 ++
> 1 file changed, 2 insertions(+)
>
>diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h
>index 54ae5da7ce..1b3c10c0d3 100644
>--- a/target/arm/kvm-consts.h
>+++ b/target/arm/kvm-consts.h
>@@ -30,6 +30,7 @@
> #define CP_REG_SIZE_MASK       0x00f0000000000000ULL
> #define CP_REG_SIZE_U32        0x0020000000000000ULL
> #define CP_REG_SIZE_U64        0x0030000000000000ULL
>+#define CP_REG_SIZE_U128       0x0040000000000000ULL
> #define CP_REG_ARM             0x4000000000000000ULL
> #define CP_REG_ARCH_MASK       0xff00000000000000ULL
> 
>@@ -37,6 +38,7 @@ MISMATCH_CHECK(CP_REG_SIZE_SHIFT, KVM_REG_SIZE_SHIFT);
> MISMATCH_CHECK(CP_REG_SIZE_MASK, KVM_REG_SIZE_MASK);
> MISMATCH_CHECK(CP_REG_SIZE_U32, KVM_REG_SIZE_U32);
> MISMATCH_CHECK(CP_REG_SIZE_U64, KVM_REG_SIZE_U64);
>+MISMATCH_CHECK(CP_REG_SIZE_U128, KVM_REG_SIZE_U128);
> MISMATCH_CHECK(CP_REG_ARM, KVM_REG_ARM);
> MISMATCH_CHECK(CP_REG_ARCH_MASK, KVM_REG_ARCH_MASK);
> 
>-- 
>2.43.0
>
>


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

* Re: [PATCH 39/61] target/arm: Update ARMCPRegInfo for 128-bit sysregs
  2025-08-27  1:04 ` [PATCH 39/61] target/arm: Update ARMCPRegInfo for 128-bit sysregs Richard Henderson
@ 2025-09-01  6:56   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-09-01  6:56 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Add ARM_CP_128BIT for type and functions describing 128-bit access.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/cpregs.h | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
>
>diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>index 9818be4429..90f14dbb18 100644
>--- a/target/arm/cpregs.h
>+++ b/target/arm/cpregs.h
>@@ -136,6 +136,8 @@ enum {
>      * identically to the normal one, other than FGT trapping handling.)
>      */
>     ARM_CP_ADD_TLBI_NXS          = 1 << 21,
>+    /* Flag: For ARM_CP_STATE_AA64, sysreg is 128-bit. */
>+    ARM_CP_128BIT                = 1 << 22,
> };
> 
> /*
>@@ -178,6 +180,10 @@ enum {
> #define CP_REG_AA32_NS_SHIFT     29
> #define CP_REG_AA32_NS_MASK      (1 << CP_REG_AA32_NS_SHIFT)
> 
>+/* Distinguish 64-bit and 128-bit views of AArch64 system registers. */
>+#define CP_REG_AA64_128BIT_SHIFT 30
>+#define CP_REG_AA64_128BIT_MASK  (1 << CP_REG_AA64_128BIT_SHIFT)
>+
> /* Distinguish 32-bit and 64-bit views of AArch32 system registers. */
> #define CP_REG_AA32_64BIT_SHIFT  15
> #define CP_REG_AA32_64BIT_MASK   (1 << CP_REG_AA32_64BIT_SHIFT)
>@@ -849,6 +855,9 @@ typedef struct ARMCPRegInfo ARMCPRegInfo;
> typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *ri);
> typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *ri,
>                        uint64_t value);
>+typedef Int128 CPRead128Fn(CPUARMState *env, const ARMCPRegInfo *opaque);
>+typedef void CPWrite128Fn(CPUARMState *env, const ARMCPRegInfo *opaque,
>+                          Int128 value);
> /* Access permission check functions for coprocessor registers. */
> typedef CPAccessResult CPAccessFn(CPUARMState *env,
>                                   const ARMCPRegInfo *ri,
>@@ -992,6 +1001,13 @@ struct ARMCPRegInfo {
>      * fieldoffset is 0 then no reset will be done.
>      */
>     CPResetFn *resetfn;
>+
>+    /* For ARM_CP_128BIT, when accessed via MRRS/MSRR. */
>+    CPAccessFn *access128fn;
>+    CPRead128Fn *read128fn;
>+    CPWrite128Fn *write128fn;
>+    CPRead128Fn *raw_read128fn;
>+    CPWrite128Fn *raw_write128fn;
> };
> 
> void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs);
>@@ -1061,6 +1077,9 @@ void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri);
>  */
> static inline MemOp cpreg_field_type(const ARMCPRegInfo *ri)
> {
>+    if (ri->type & ARM_CP_128BIT) {
>+        return MO_128;
>+    }
>     return (ri->state == ARM_CP_STATE_AA64 || (ri->type & ARM_CP_64BIT)
>             ? MO_64 : MO_32);
> }
>-- 
>2.43.0
>
>


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

* Re: [PATCH 40/61] target/arm: Assert ARM_CP_128BIT only with ARM_CP_STATE_AA64
  2025-08-27  1:04 ` [PATCH 40/61] target/arm: Assert ARM_CP_128BIT only with ARM_CP_STATE_AA64 Richard Henderson
@ 2025-09-01  6:58   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-09-01  6:58 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/helper.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
>diff --git a/target/arm/helper.c b/target/arm/helper.c
>index 64a987d143..3b765408f2 100644
>--- a/target/arm/helper.c
>+++ b/target/arm/helper.c
>@@ -7353,6 +7353,11 @@ void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r)
>     assert(r->state == ARM_CP_STATE_AA32 || !(r->type & ARM_CP_64BIT));
>     /* AArch32 64-bit registers have only CRm and Opc1 fields. */
>     assert(!(r->type & ARM_CP_64BIT) || !(r->opc2 || r->crn));
>+    /*
>+     * Only AArch64 regs are 128-bit.  There is usually an AArch32 64-bit
>+     * alias, but must be defined separately due to encoding conflicts above.
>+     */
>+    assert(r->state == ARM_CP_STATE_AA64 || !(r->type & ARM_CP_128BIT));
>     /* op0 only exists in the AArch64 encodings */
>     assert(r->state != ARM_CP_STATE_AA32 || r->opc0 == 0);
> 
>-- 
>2.43.0
>
>


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

* Re: [PATCH 42/61] target/arm: Add raw_read128, raw_write128
  2025-08-27  1:04 ` [PATCH 42/61] target/arm: Add raw_read128, raw_write128 Richard Henderson
@ 2025-09-01  7:02   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-09-01  7:02 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/cpregs.h |  5 +++++
> target/arm/helper.c | 17 +++++++++++++++++
> 2 files changed, 22 insertions(+)
>
>diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>index 90f14dbb18..0d8c45b60c 100644
>--- a/target/arm/cpregs.h
>+++ b/target/arm/cpregs.h
>@@ -21,6 +21,7 @@
> #ifndef TARGET_ARM_CPREGS_H
> #define TARGET_ARM_CPREGS_H
> 
>+#include "qemu/int128.h"
> #include "hw/registerfields.h"
> #include "exec/memop.h"
> #include "target/arm/kvm-consts.h"
>@@ -1065,6 +1066,10 @@ uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri);
> /* CPWriteFn that just writes the value to ri->fieldoffset */
> void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value);
> 
>+/* Likewise for 128-bit fields. */
>+Int128 raw_read128(CPUARMState *env, const ARMCPRegInfo *opaque);
>+void raw_write128(CPUARMState *env, const ARMCPRegInfo *opaque, Int128 value);
>+
> /*
>  * CPResetFn that does nothing, for use if no reset is required even
>  * if fieldoffset is non zero.
>diff --git a/target/arm/helper.c b/target/arm/helper.c
>index 18af67742d..7568b78c49 100644
>--- a/target/arm/helper.c
>+++ b/target/arm/helper.c
>@@ -59,6 +59,8 @@ int compare_u64(const void *a, const void *b)
>     (*(uint32_t *)((char *)(env) + (ri)->fieldoffset))
> #define CPREG_FIELD64(env, ri) \
>     (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
>+#define CPREG_FIELD128(env, ri) \
>+    (*(Int128 *)((char *)(env) + (ri)->fieldoffset))
> 
> uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri)
> {
>@@ -88,8 +90,23 @@ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>     }
> }
> 
>+Int128 raw_read128(CPUARMState *env, const ARMCPRegInfo *ri)
>+{
>+    assert(ri->type & ARM_CP_128BIT);
>+    assert(ri->fieldoffset);
>+    return CPREG_FIELD128(env, ri);
>+}
>+
>+void raw_write128(CPUARMState *env, const ARMCPRegInfo *ri, Int128 value)
>+{
>+    assert(ri->type & ARM_CP_128BIT);
>+    assert(ri->fieldoffset);
>+    CPREG_FIELD128(env, ri) = value;
>+}
>+
> #undef CPREG_FIELD32
> #undef CPREG_FIELD64
>+#undef CPREG_FIELD128
> 
> static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri)
> {
>-- 
>2.43.0
>
>


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

* Re: [PATCH 43/61] target/arm: Add read_raw_cp_reg128, write_raw_cp_reg128
  2025-08-27  1:04 ` [PATCH 43/61] target/arm: Add read_raw_cp_reg128, write_raw_cp_reg128 Richard Henderson
@ 2025-09-01  7:05   ` Manos Pitsidianakis
  0 siblings, 0 replies; 92+ messages in thread
From: Manos Pitsidianakis @ 2025-09-01  7:05 UTC (permalink / raw)
  To: qemu-devel, Richard Henderson; +Cc: qemu-arm

On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>Add the functions and update raw_accessors_invalid to match.
>Add assertions for !ARM_CP_128BIT in read_raw_cp_reg and
>write_raw_cp_reg.
>
>Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>---

Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>

> target/arm/cpregs.h |  1 +
> target/arm/helper.c | 43 +++++++++++++++++++++++++++++++++++++++----
> 2 files changed, 40 insertions(+), 4 deletions(-)
>
>diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>index 0d8c45b60c..bd26a4a260 100644
>--- a/target/arm/cpregs.h
>+++ b/target/arm/cpregs.h
>@@ -1097,6 +1097,7 @@ static inline bool cp_access_ok(int current_el,
> 
> /* Raw read of a coprocessor register (as needed for migration, etc) */
> uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri);
>+Int128 read_raw_cp_reg128(CPUARMState *env, const ARMCPRegInfo *ri);
> 
> /*
>  * Return true if the cp register encoding is in the "feature ID space" as
>diff --git a/target/arm/helper.c b/target/arm/helper.c
>index 7568b78c49..3efc14da3a 100644
>--- a/target/arm/helper.c
>+++ b/target/arm/helper.c
>@@ -115,6 +115,7 @@ static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri)
> 
> uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri)
> {
>+    assert(!(ri->type & ARM_CP_128BIT));
>     /* Raw read of a coprocessor register (as needed for migration, etc). */
>     if (ri->type & ARM_CP_CONST) {
>         return ri->resetvalue;
>@@ -130,6 +131,7 @@ uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri)
> static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
>                              uint64_t v)
> {
>+    assert(!(ri->type & ARM_CP_128BIT));
>     /*
>      * Raw write of a coprocessor register (as needed for migration, etc).
>      * Note that constant registers are treated as write-ignored; the
>@@ -147,6 +149,32 @@ static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
>     }
> }
> 
>+Int128 read_raw_cp_reg128(CPUARMState *env, const ARMCPRegInfo *ri)
>+{
>+    assert(ri->type & ARM_CP_128BIT);
>+    if (ri->raw_read128fn) {
>+        return ri->raw_read128fn(env, ri);
>+    } else if (ri->read128fn) {
>+        return ri->read128fn(env, ri);
>+    } else {
>+        return raw_read128(env, ri);
>+    }
>+}
>+
>+__attribute__((unused))
>+static void write_raw_cp_reg128(CPUARMState *env, const ARMCPRegInfo *ri,
>+                                Int128 v)
>+{
>+    assert(ri->type & ARM_CP_128BIT);
>+    if (ri->raw_write128fn) {
>+        ri->raw_write128fn(env, ri, v);
>+    } else if (ri->write128fn) {
>+        ri->write128fn(env, ri, v);
>+    } else {
>+        raw_write128(env, ri, v);
>+    }
>+}
>+
> static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
> {
>    /*
>@@ -161,12 +189,19 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
>     * The tests here line up with the conditions in read/write_raw_cp_reg()
>     * and assertions in raw_read()/raw_write().
>     */
>-    if ((ri->type & ARM_CP_CONST) ||
>-        ri->fieldoffset ||
>-        ((ri->raw_writefn || ri->writefn) && (ri->raw_readfn || ri->readfn))) {
>+    if (ri->type & ARM_CP_CONST) {
>+        return ri->type & ARM_CP_128BIT;
>+    }
>+    if (ri->fieldoffset) {
>         return false;
>     }
>-    return true;
>+    if (ri->type & ARM_CP_128BIT) {
>+        return !((ri->raw_write128fn || ri->write128fn) &&
>+                 (ri->raw_read128fn || ri->read128fn));
>+    } else {
>+        return !((ri->raw_writefn || ri->writefn) &&
>+                 (ri->raw_readfn || ri->readfn));
>+    }
> }
> 
> bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync)
>-- 
>2.43.0
>
>


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

* Re: [PATCH 14/61] target/arm: Replace cpreg_field_is_64bit with cpreg_field_type
  2025-08-29  7:13   ` Manos Pitsidianakis
@ 2025-09-03  4:48     ` Richard Henderson
  0 siblings, 0 replies; 92+ messages in thread
From: Richard Henderson @ 2025-09-03  4:48 UTC (permalink / raw)
  To: Manos Pitsidianakis, qemu-devel; +Cc: qemu-arm

On 8/29/25 09:13, Manos Pitsidianakis wrote:
> On Wed, 27 Aug 2025 04:04, Richard Henderson <richard.henderson@linaro.org> wrote:
>> Prepare for 128-bit fields by using a better query api.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>> target/arm/cpregs.h  | 10 ++++++----
>> target/arm/gdbstub.c |  7 +++++--
>> target/arm/helper.c  | 18 +++++++++++++-----
>> 3 files changed, 24 insertions(+), 11 deletions(-)
>>
>> diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
>> index 812fb1340a..b6c8eff0dd 100644
>> --- a/target/arm/cpregs.h
>> +++ b/target/arm/cpregs.h
>> @@ -22,6 +22,7 @@
>> #define TARGET_ARM_CPREGS_H
>>
>> #include "hw/registerfields.h"
>> +#include "exec/memop.h"
>> #include "target/arm/kvm-consts.h"
>> #include "cpu.h"
>>
>> @@ -1053,12 +1054,13 @@ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value);
>> void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri);
>>
>> /*
>> - * Return true if this reginfo struct's field in the cpu state struct
>> - * is 64 bits wide.
>> + * Return MO_32 if the field in CPUARMState is uint32_t or
>> + * MO_64 if the field in CPUARMState is uint64_t.
>>   */
>> -static inline bool cpreg_field_is_64bit(const ARMCPRegInfo *ri)
>> +static inline MemOp cpreg_field_type(const ARMCPRegInfo *ri)
> 
> Using MemOp is slightly confusing though I understand where you're
> coming from. Would introducing a BitWidth enum be a good idea?
> 
> 
> diff --git a/include/exec/memop.h b/include/exec/memop.h
> index cf7da3362e..9104c4f162 100644
> --- a/include/exec/memop.h
> +++ b/include/exec/memop.h
> @@ -14,15 +14,26 @@
>   
>   #include "qemu/host-utils.h"
>   
> +typedef enum BitWidth {
> +    BW_8     = 0,
> +    BW_16    = 1,
> +    BW_32    = 2,
> +    BW_64    = 3,
> +    BW_128   = 4,
> +    BW_256   = 5,
> +    BW_512   = 6,
> +    BW_1024  = 7,
> +}
> +
>   typedef enum MemOp {
> -    MO_8     = 0,
> -    MO_16    = 1,
> -    MO_32    = 2,
> -    MO_64    = 3,
> -    MO_128   = 4,
> -    MO_256   = 5,
> -    MO_512   = 6,
> -    MO_1024  = 7,
> +    MO_8     = BW_8,
> +    MO_16    = BW_16,
> +    MO_32    = BW_32,
> +    MO_64    = BW_64,
> +    MO_128   = BW_128,
> +    MO_256   = BW_256,
> +    MO_512   = BW_512,
> +    MO_1024  = BW_1024,
>       MO_SIZE  = 0x07,   /* Mask for the above.  */

I'm not sure this is helpful.  We already (ab)use MO_n quite often as a symbolic name for 
log8(n) outside of the context of memory operations.


r~


PS. If I were to do it over I'd always count in bytes not bits, since bits are not 
addressable.  Though I suppose we might have been lead by uintN_t and friends.


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

end of thread, other threads:[~2025-09-03  4:49 UTC | newest]

Thread overview: 92+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-27  1:03 [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson
2025-08-27  1:03 ` [PATCH 01/61] target/arm: Introduce KVMID_AA64_SYS_REG64 Richard Henderson
2025-08-27  1:03 ` [PATCH 02/61] target/arm: Move compare_u64 to helper.c Richard Henderson
2025-08-28 12:19   ` Manos Pitsidianakis
2025-08-27  1:03 ` [PATCH 03/61] target/arm/hvf: Split out sysreg.c.inc Richard Henderson
2025-08-29  6:58   ` Manos Pitsidianakis
2025-08-27  1:03 ` [PATCH 4/7] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID Richard Henderson
2025-08-28 12:22   ` Manos Pitsidianakis
2025-08-27  1:03 ` [PATCH 04/61] target/arm/hvf: Reorder DEF_SYSREG arguments Richard Henderson
2025-08-28 12:17   ` Manos Pitsidianakis
2025-08-27  1:03 ` [PATCH 05/61] target/arm/hvf: Add KVMID_TO_HVF, HVF_TO_KVMID Richard Henderson
2025-08-29  6:59   ` Manos Pitsidianakis
2025-08-27  1:03 ` [PATCH 5/7] target/arm/hvf: Remove hvf_sreg_match.key Richard Henderson
2025-08-27  1:03 ` [PATCH 06/61] " Richard Henderson
2025-08-29  7:00   ` Manos Pitsidianakis
2025-08-27  1:03 ` [PATCH 6/7] target/arm/hvf: Replace hvf_sreg_match with hvf_sreg_list Richard Henderson
2025-08-27  1:03 ` [PATCH 07/61] " Richard Henderson
2025-08-27  1:03 ` [PATCH 7/7] target/arm/hvf: Sort the cpreg_indexes array Richard Henderson
2025-08-27  1:03 ` [PATCH 08/61] " Richard Henderson
2025-08-27  1:04 ` [PATCH 09/61] target/arm/hvf: Use raw_read, raw_write to access Richard Henderson
2025-08-27  1:04 ` [PATCH 10/61] target/arm: Use raw_write in cp_reg_reset Richard Henderson
2025-08-29  7:05   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 11/61] target/arm: Rename all ARMCPRegInfo from opaque to ri Richard Henderson
2025-08-28 12:41   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 12/61] target/arm: Drop define_one_arm_cp_reg_with_opaque Richard Henderson
2025-08-29  7:06   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 13/61] target/arm: Restrict the scope of CPREG_FIELD32, CPREG_FIELD64 Richard Henderson
2025-08-29  7:09   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 14/61] target/arm: Replace cpreg_field_is_64bit with cpreg_field_type Richard Henderson
2025-08-29  7:13   ` Manos Pitsidianakis
2025-09-03  4:48     ` Richard Henderson
2025-08-27  1:04 ` [PATCH 15/61] target/arm: Add CP_REG_AA32_64BIT_{SHIFT,MASK} Richard Henderson
2025-08-29  7:27   ` Manos Pitsidianakis
2025-08-29 13:55     ` Richard Henderson
2025-08-27  1:04 ` [PATCH 16/61] target/arm: Rename CP_REG_AA32_NS_{SHIFT,MASK} Richard Henderson
2025-08-29  7:30   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 17/61] target/arm: Convert init_cpreg_list to g_hash_table_foreach Richard Henderson
2025-08-27  1:04 ` [PATCH 18/61] target/arm: Remove cp argument to ENCODE_AA64_CP_REG Richard Henderson
2025-08-29  7:36   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 19/61] target/arm: Reorder ENCODE_AA64_CP_REG arguments Richard Henderson
2025-08-29  7:40   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 20/61] target/arm: Split out add_cpreg_to_hashtable_aa{32,64} Richard Henderson
2025-08-27  1:04 ` [PATCH 21/61] target/arm: Improve asserts in define_one_arm_cp_reg Richard Henderson
2025-08-27  1:04 ` [PATCH 22/61] target/arm: Move cp processing to define_one_arm_cp_reg Richard Henderson
2025-08-27  1:04 ` [PATCH 23/61] target/arm: Move cpreg elimination " Richard Henderson
2025-08-27  1:04 ` [PATCH 24/61] target/arm: Add key parameter to add_cpreg_to_hashtable Richard Henderson
2025-08-27  1:04 ` [PATCH 25/61] target/arm: Split out alloc_cpreg Richard Henderson
2025-08-27  1:04 ` [PATCH 26/61] target/arm: Hoist the allocation of ARMCPRegInfo Richard Henderson
2025-08-27  1:04 ` [PATCH 27/61] target/arm: Remove name argument to alloc_cpreg Richard Henderson
2025-08-27  1:04 ` [PATCH 28/61] target/arm: Move alias setting for wildcards Richard Henderson
2025-08-27  1:04 ` [PATCH 29/61] target/arm: Move writeback of CP_ANY fields Richard Henderson
2025-08-27  1:04 ` [PATCH 30/61] target/arm: Move endianness fixup for 32-bit registers Richard Henderson
2025-08-27  1:04 ` [PATCH 31/61] target/arm: Rename TBFLAG_A64_NV2_MEM_E20 with *_E2H Richard Henderson
2025-08-27  1:04 ` [PATCH 32/61] target/arm: Split out redirect_cpreg Richard Henderson
2025-08-27  1:04 ` [PATCH 33/61] target/arm: Redirect VHE FOO_EL1 -> FOO_EL2 during translation Richard Henderson
2025-08-28 12:39   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 34/61] target/arm: Redirect VHE FOO_EL12 to FOO_EL1 " Richard Henderson
2025-08-27  1:04 ` [PATCH 35/61] target/arm: Rename some cpreg to their aarch64 names Richard Henderson
2025-09-01  6:53   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 36/61] target/arm: Remove define_arm_vh_e2h_redirects_aliases Richard Henderson
2025-08-27  1:04 ` [PATCH 37/61] target/arm: Implement isar tests for FEAT_SYSREG128, FEAT_SYSINSTR128 Richard Henderson
2025-09-01  6:55   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 38/61] target/arm: Define CP_REG_SIZE_U128 Richard Henderson
2025-09-01  6:55   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 39/61] target/arm: Update ARMCPRegInfo for 128-bit sysregs Richard Henderson
2025-09-01  6:56   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 40/61] target/arm: Assert ARM_CP_128BIT only with ARM_CP_STATE_AA64 Richard Henderson
2025-09-01  6:58   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 41/61] target/arm: Split add_cpreg_to_hashtable_aa64 Richard Henderson
2025-08-27  1:04 ` [PATCH 42/61] target/arm: Add raw_read128, raw_write128 Richard Henderson
2025-09-01  7:02   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 43/61] target/arm: Add read_raw_cp_reg128, write_raw_cp_reg128 Richard Henderson
2025-09-01  7:05   ` Manos Pitsidianakis
2025-08-27  1:04 ` [PATCH 44/61] target/arm: Put 128-bit sysregs into a separate list Richard Henderson
2025-08-27  1:04 ` [PATCH 45/61] target/arm/kvm: Assert no 128-bit sysregs in kvm_arm_init_cpreg_list Richard Henderson
2025-08-27  1:04 ` [PATCH 46/61] target/arm/hvf: Assert no 128-bit sysregs in hvf_arch_init_vcpu Richard Henderson
2025-08-27  1:04 ` [PATCH 47/61] migration: Add vmstate_info_int128 Richard Henderson
2025-08-27  1:04 ` [PATCH 48/61] target/arm: Migrate cpreg128 registers Richard Henderson
2025-08-27  1:04 ` [PATCH 49/61] target/arm: Add syn_aa64_sysreg128trap Richard Henderson
2025-08-27  1:04 ` [PATCH 50/61] target/arm: Introduce helper_{get,set}_cp_reg128 Richard Henderson
2025-08-27  1:04 ` [PATCH 51/61] target/arm: Implement MRRS, MSRR, SYSP Richard Henderson
2025-08-27  1:04 ` [PATCH 52/61] include/qemu/compiler: Introduce HOST_ENDIAN_FIELDS Richard Henderson
2025-08-27  1:04 ` [PATCH 53/61] include/hw/core/cpu: Use HOST_ENDIAN_FIELDS in IcountDecr Richard Henderson
2025-08-27  1:04 ` [PATCH 54/61] include/qemu/host-utils: Use HOST_ENDIAN_FIELDS in muldiv64_rounding Richard Henderson
2025-08-27  1:04 ` [PATCH 55/61] target/arm: Use HOST_ENDIAN_FIELDS in CPUARMState Richard Henderson
2025-08-27  1:04 ` [PATCH 56/61] target/arm: Consolidate definitions of PAR Richard Henderson
2025-08-27  1:04 ` [PATCH 57/61] target/arm: Extend PAR_EL1 to 128-bit Richard Henderson
2025-08-27  1:04 ` [PATCH 58/61] target/arm: Consolidate definitions of TTBR[01] Richard Henderson
2025-08-27  1:04 ` [PATCH 59/61] target/arm: Split out flush_if_asid_change Richard Henderson
2025-08-27  1:04 ` [PATCH 60/61] target/arm: Use flush_if_asid_change in vmsa_ttbr_write Richard Henderson
2025-08-27  1:04 ` [PATCH 61/61] target/arm: Extend TTBR system registers to 128-bit Richard Henderson
2025-08-27  2:36 ` [RFC PATCH 00/61] target/arm: Implement FEAT_SYSREG128 Richard Henderson

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