All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 00/21] target-arm queue
@ 2026-05-29 11:47 Peter Maydell
  2026-05-29 11:47 ` [PULL 01/21] target/arm: Enable REVD for SVE2.1 Peter Maydell
                   ` (21 more replies)
  0 siblings, 22 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

Hi; here's an arm pullreq. This is mostly bug fixes; the
new features are emulation of a couple of small Arm CPU features.

thanks
-- PMM


The following changes since commit 2db91528542672cf0db78b3f2cc0e22b36302b38:

  Merge tag 'pull-vfio-20260527' of https://github.com/legoater/qemu into staging (2026-05-27 14:45:58 -0400)

are available in the Git repository at:

  https://gitlab.com/pm215/qemu.git tags/pull-target-arm-20260529

for you to fetch changes up to 44f2c7f3df0028de7991385f568add12e24aca47:

  hw/dma/omap_dma: Fix indentation after ifdef removal (2026-05-29 10:18:11 +0100)

----------------------------------------------------------------
target-arm queue:
 * target/arm: Implement FEAT_CMPBR emulation
 * target/arm: Implement FEAT_RNG_TRAP emulation
 * target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault
 * target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors"
 * target/arm: Enable REVD for SVE2.1
 * zynq: Various minor bug fixes
 * hw/misc: Add dummy ZYNQ DDR controller
 * hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d
 * hw/dma/omap_dma: Remove unused ifdeffed out code

----------------------------------------------------------------
Jason Wright (2):
      target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS
      target/arm: advertise FEAT_RNG_TRAP on cortex-max

Peter Maydell (5):
      target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault
      target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors"
      hw/dma/omap_dma: Remove unused ifdeffed out code
      hw/dma/omap_dma: Fix coding style in omap_dma_transfer_setup()
      hw/dma/omap_dma: Fix indentation after ifdef removal

Richard Henderson (5):
      target/arm: Enable REVD for SVE2.1
      target/arm: Add feature predicate for FEAT_CMPBR
      target/arm: Implement CB, CBB, CBH
      target/arm: Implement CB (immediate)
      target/arm: Enable FEAT_CMPBR for -cpu max

YannickV (9):
      hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff
      hw/arm/zynq-devcfg: Prevent unintended unlock during initialization
      hw/dma/zynq: Ensure PCFG_DONE bit remains set to indicate PL is in user mode
      hw/dma/zynq-devcfg: Simulate dummy PL reset
      hw/dma/zynq-devcfg: Indicate power-up status of PL
      hw/misc: Add dummy ZYNQ DDR controller
      hw/misc/zynq_slcr: Add logic for DCI configuration
      hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d
      hw/arm/xilinx_zynq: Split xilinx_zynq into header and implementation files

 MAINTAINERS                      |   2 +
 docs/system/arm/emulation.rst    |   2 +
 hw/arm/Kconfig                   |   1 +
 hw/arm/xilinx_zynq.c             |  29 ++-
 hw/block/m25p80.c                |   3 +-
 hw/dma/omap_dma.c                | 247 ++++++++---------------
 hw/dma/xlnx-zynq-devcfg.c        |  27 ++-
 hw/misc/Kconfig                  |   3 +
 hw/misc/meson.build              |   1 +
 hw/misc/xlnx-zynq-ddrc.c         | 421 +++++++++++++++++++++++++++++++++++++++
 hw/misc/zynq_slcr.c              |  31 +++
 include/hw/arm/xilinx_zynq.h     |  30 +++
 include/hw/misc/xlnx-zynq-ddrc.h | 147 ++++++++++++++
 linux-user/aarch64/elfload.c     |   1 +
 target/arm/cpu-features.h        |  10 +
 target/arm/helper.c              |  58 +++++-
 target/arm/internals.h           |  10 +
 target/arm/tcg/a64.decode        |  11 +
 target/arm/tcg/cpu64.c           |   3 +-
 target/arm/tcg/translate-a64.c   |  86 ++++++++
 target/arm/tcg/translate-sme.c   |   4 +-
 target/arm/tcg/translate-sve.c   |   3 +-
 22 files changed, 939 insertions(+), 191 deletions(-)
 create mode 100644 hw/misc/xlnx-zynq-ddrc.c
 create mode 100644 include/hw/arm/xilinx_zynq.h
 create mode 100644 include/hw/misc/xlnx-zynq-ddrc.h


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

* [PULL 01/21] target/arm: Enable REVD for SVE2.1
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 02/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff Peter Maydell
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: Richard Henderson <richard.henderson@linaro.org>

Cc: qemu-stable@nongnu.org
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260522220408.235438-1-richard.henderson@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/tcg/translate-sve.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c
index d04ef2dcfc..fb9d379184 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -2993,7 +2993,8 @@ TRANS_FEAT(REVH, aa64_sme_or_sve, gen_gvec_ool_arg_zpz, revh_fns[a->esz], a, 0)
 TRANS_FEAT(REVW, aa64_sme_or_sve, gen_gvec_ool_arg_zpz,
            a->esz == 3 ? gen_helper_sve_revw_d : NULL, a, 0)
 
-TRANS_FEAT(REVD, aa64_sme, gen_gvec_ool_arg_zpz, gen_helper_sme_revd_q, a, 0)
+TRANS_FEAT(REVD, aa64_sme_or_sve2p1, gen_gvec_ool_arg_zpz,
+           gen_helper_sme_revd_q, a, 0)
 
 TRANS_FEAT(SPLICE, aa64_sme_or_sve, gen_gvec_ool_arg_zpzz,
            gen_helper_sve_splice, a, a->esz)
-- 
2.43.0



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

* [PULL 02/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
  2026-05-29 11:47 ` [PULL 01/21] target/arm: Enable REVD for SVE2.1 Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 03/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization Peter Maydell
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: YannickV <Y.Vossen@beckhoff.com>

A DMA transfer to destination address `0xffffffff` should trigger a
bitstream load via the PCAP interface. Currently, this case is not
intercepted, causing loaders to enter an infinite loop when polling
the status register.

This commit adds a check for `0xffffffff` as the destination address.
If detected, the relevant status register bits (`DMA_DONE`,
`DMA_P_DONE`, and `PCFG_DONE`) are set to indicate a successful
bitstream load. If the address is different, the DMA transfer proceeds
as usual. A successful load is indicated but nothing is actually
done. Guests relying on FPGA functions are still known to fail.

This feature is required for the integration of the Beckhoff
CX7200 model.

Signed-off-by: YannickV <Y.Vossen@beckhoff.com>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Message-id: 20260518073401.11279-2-corvin.koehne@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/dma/xlnx-zynq-devcfg.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index cf00aa863d..9708200760 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -247,7 +247,14 @@ static uint64_t r_lock_pre_write(RegisterInfo *reg, uint64_t val)
 static void r_dma_dst_len_post_write(RegisterInfo *reg, uint64_t val)
 {
     XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque);
-
+    if ((s->regs[R_DMA_DST_ADDR]) == 0xffffffff) {
+        DB_PRINT("bitstream loading detected\n");
+        s->regs[R_INT_STS] |= R_INT_STS_DMA_DONE_MASK |
+                                R_INT_STS_DMA_P_DONE_MASK |
+                                R_INT_STS_PCFG_DONE_MASK;
+        xlnx_zynq_devcfg_update_ixr(s);
+        return;
+    }
     s->dma_cmd_fifo[s->dma_cmd_fifo_num] = (XlnxZynqDevcfgDMACmd) {
             .src_addr = s->regs[R_DMA_SRC_ADDR] & ~0x3UL,
             .dest_addr = s->regs[R_DMA_DST_ADDR] & ~0x3UL,
-- 
2.43.0



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

* [PULL 03/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
  2026-05-29 11:47 ` [PULL 01/21] target/arm: Enable REVD for SVE2.1 Peter Maydell
  2026-05-29 11:47 ` [PULL 02/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 04/21] hw/dma/zynq: Ensure PCFG_DONE bit remains set to indicate PL is in user mode Peter Maydell
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: YannickV <Y.Vossen@beckhoff.com>

During the emulation startup, all registers are reset, which triggers the
`r_unlock_post_write` function with a value of 0. This led to an
unintended memory access disable, making the devcfg unusable.

During startup, the memory space no longer gets locked.

Signed-off-by: YannickV <Y.Vossen@beckhoff.com>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Message-id: 20260518073401.11279-3-corvin.koehne@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/dma/xlnx-zynq-devcfg.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index 9708200760..afe6ffd326 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -221,7 +221,9 @@ static void r_unlock_post_write(RegisterInfo *reg, uint64_t val)
 {
     XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque);
     const char *device_prefix = object_get_typename(OBJECT(s));
-
+    if (device_is_in_reset(DEVICE(s))) {
+        return;
+    }
     if (val == R_UNLOCK_MAGIC) {
         DB_PRINT("successful unlock\n");
         s->regs[R_CTRL] |= R_CTRL_PCAP_PR_MASK;
-- 
2.43.0



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

* [PULL 04/21] hw/dma/zynq: Ensure PCFG_DONE bit remains set to indicate PL is in user mode
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (2 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 03/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 05/21] hw/dma/zynq-devcfg: Simulate dummy PL reset Peter Maydell
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: YannickV <Y.Vossen@beckhoff.com>

All register bits are clear on write by writing 1s to those bits, however
the register bits will only be cleared if the condition that sets the
interrupt flag is no longer true. Since we can assume that programming
is always done, the `PCFG_DONE` flag is always set to 1, so it will not
never be cleared.

Signed-off-by: YannickV <Y.Vossen@beckhoff.com>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Message-id: 20260518073401.11279-4-corvin.koehne@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/dma/xlnx-zynq-devcfg.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index afe6ffd326..7370ab941f 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -188,6 +188,8 @@ static void r_ixr_post_write(RegisterInfo *reg, uint64_t val)
 {
     XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque);
 
+    s->regs[R_INT_STS] |= R_INT_STS_PCFG_DONE_MASK;
+
     xlnx_zynq_devcfg_update_ixr(s);
 }
 
-- 
2.43.0



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

* [PULL 05/21] hw/dma/zynq-devcfg: Simulate dummy PL reset
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (3 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 04/21] hw/dma/zynq: Ensure PCFG_DONE bit remains set to indicate PL is in user mode Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 06/21] hw/dma/zynq-devcfg: Indicate power-up status of PL Peter Maydell
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: YannickV <Y.Vossen@beckhoff.com>

Setting PCFG_PROG_B should reset the PL. After a reset PCFG_INIT
should indicate that the reset is finished successfully.

In order to add a MMIO-Device as part of the PL in the Zynq, the
reset logic must succeed. The PCFG_INIT flag is now set when the
PL reset is triggered by PCFG_PROG_B. Indicating the reset was
successful.

Signed-off-by: YannickV <Y.Vossen@beckhoff.com>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Message-id: 20260518073401.11279-5-corvin.koehne@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/dma/xlnx-zynq-devcfg.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index 7370ab941f..6b1d96ff80 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -49,6 +49,7 @@
 
 REG32(CTRL, 0x00)
     FIELD(CTRL,     FORCE_RST,          31,  1) /* Not supported, wr ignored */
+    FIELD(CTRL,     PCFG_PROG_B,        30,  1)
     FIELD(CTRL,     PCAP_PR,            27,  1) /* Forced to 0 on bad unlock */
     FIELD(CTRL,     PCAP_MODE,          26,  1)
     FIELD(CTRL,     MULTIBOOT_EN,       24,  1)
@@ -116,6 +117,7 @@ REG32(STATUS, 0x14)
     FIELD(STATUS,   PSS_GTS_USR_B,      11,  1)
     FIELD(STATUS,   PSS_FST_CFG_B,      10,  1)
     FIELD(STATUS,   PSS_CFG_RESET_B,     5,  1)
+    FIELD(STATUS,   PCFG_INIT,           4,  1)
 
 REG32(DMA_SRC_ADDR, 0x18)
 REG32(DMA_DST_ADDR, 0x1C)
@@ -204,6 +206,13 @@ static uint64_t r_ctrl_pre_write(RegisterInfo *reg, uint64_t val)
             val |= lock_ctrl_map[i] & s->regs[R_CTRL];
         }
     }
+
+    if (FIELD_EX32(val, CTRL, PCFG_PROG_B)) {
+        s->regs[R_STATUS] |= R_STATUS_PCFG_INIT_MASK;
+    } else {
+        s->regs[R_STATUS] &= ~R_STATUS_PCFG_INIT_MASK;
+    }
+
     return val;
 }
 
-- 
2.43.0



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

* [PULL 06/21] hw/dma/zynq-devcfg: Indicate power-up status of PL
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (4 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 05/21] hw/dma/zynq-devcfg: Simulate dummy PL reset Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 07/21] hw/misc: Add dummy ZYNQ DDR controller Peter Maydell
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: YannickV <Y.Vossen@beckhoff.com>

It is assumed, that the programmable logic (PL) is always powered
during emulation. Therefor the PCFG_POR_B bit in the MCTRL register
is set.

Signed-off-by: YannickV <Y.Vossen@beckhoff.com>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Message-id: 20260518073401.11279-6-corvin.koehne@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/dma/xlnx-zynq-devcfg.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index 6b1d96ff80..5608460dc7 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -333,7 +333,8 @@ static const RegisterAccessInfo xlnx_zynq_devcfg_regs_info[] = {
        /* Silicon 3.0 for version field, the mysterious reserved bit 23
         * and QEMU platform identifier.
         */
-       .reset = 0x2 << R_MCTRL_PS_VERSION_SHIFT | 1 << 23 | R_MCTRL_QEMU_MASK,
+       .reset = 0x2 << R_MCTRL_PS_VERSION_SHIFT | 1 << 23 |
+                R_MCTRL_PCFG_POR_B_MASK | R_MCTRL_QEMU_MASK,
        .ro = ~R_MCTRL_INT_PCAP_LPBK_MASK,
        .rsvd = 0x00f00303,
     },
-- 
2.43.0



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

* [PULL 07/21] hw/misc: Add dummy ZYNQ DDR controller
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (5 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 06/21] hw/dma/zynq-devcfg: Indicate power-up status of PL Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 08/21] hw/misc/zynq_slcr: Add logic for DCI configuration Peter Maydell
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: YannickV <Y.Vossen@beckhoff.com>

A dummy DDR controller for ZYNQ has been added. While all registers are present,
not all are functional. Read and write access is validated, and the user mode
can be set. This provides a basic DDR controller initialization, preventing
system hangs due to endless polling or similar issues.

Signed-off-by: YannickV <Y.Vossen@beckhoff.com>
Message-id: 20260518073401.11279-7-corvin.koehne@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 MAINTAINERS                      |   2 +
 hw/arm/Kconfig                   |   1 +
 hw/arm/xilinx_zynq.c             |  16 +-
 hw/misc/Kconfig                  |   3 +
 hw/misc/meson.build              |   1 +
 hw/misc/xlnx-zynq-ddrc.c         | 421 +++++++++++++++++++++++++++++++
 include/hw/misc/xlnx-zynq-ddrc.h | 147 +++++++++++
 7 files changed, 588 insertions(+), 3 deletions(-)
 create mode 100644 hw/misc/xlnx-zynq-ddrc.c
 create mode 100644 include/hw/misc/xlnx-zynq-ddrc.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 7eb5823da6..580a8ff12b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1144,8 +1144,10 @@ L: qemu-arm@nongnu.org
 S: Maintained
 F: hw/*/xilinx_*
 F: hw/*/cadence_*
+F: hw/misc/xlnx-zynq-ddrc.c
 F: hw/misc/zynq_slcr.c
 F: hw/adc/zynq-xadc.c
+F: include/hw/misc/xlnx-zynq-ddrc.h
 F: include/hw/misc/zynq_slcr.h
 F: include/hw/adc/zynq-xadc.h
 X: hw/ssi/xilinx_*
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 5b198402d5..fb798ccbee 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -289,6 +289,7 @@ config ZYNQ
     select XILINX_AXI
     select XILINX_SPI
     select XILINX_SPIPS
+    select XLNX_ZYNQ_DDRC
     select ZYNQ_DEVCFG
 
 config ARM_V7M
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 9dcded9219..66a4480cc8 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -201,6 +201,17 @@ static void zynq_set_boot_mode(Object *obj, const char *str,
     m->boot_mode = mode;
 }
 
+static void ddr_ctrl_init(uint32_t base)
+{
+    DeviceState *dev;
+    SysBusDevice *busdev;
+
+    dev = qdev_new("zynq.ddr-ctlr");
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_realize_and_unref(busdev, &error_fatal);
+    sysbus_mmio_map(busdev, 0, base);
+}
+
 static void zynq_init(MachineState *machine)
 {
     ZynqMachineState *zynq_machine = ZYNQ_MACHINE(machine);
@@ -312,6 +323,8 @@ static void zynq_init(MachineState *machine)
     sysbus_create_varargs("cadence_ttc", 0xF8002000,
             pic[69-GIC_INTERNAL], pic[70-GIC_INTERNAL], pic[71-GIC_INTERNAL], NULL);
 
+    ddr_ctrl_init(0xF8006000);
+
     gem_init(0xE000B000, pic[54 - GIC_INTERNAL]);
     gem_init(0xE000C000, pic[77 - GIC_INTERNAL]);
 
@@ -393,9 +406,6 @@ static void zynq_init(MachineState *machine)
     /* System Watchdog Timer Registers */
     create_unimplemented_device("zynq.swdt", 0xF8005000, 4 * KiB);
 
-    /* DDR memory controller */
-    create_unimplemented_device("zynq.ddrc", 0xF8006000, 4 * KiB);
-
     /* AXI_HP Interface (AFI) */
     create_unimplemented_device("zynq.axi_hp0", 0xF8008000, 0x28);
     create_unimplemented_device("zynq.axi_hp1", 0xF8009000, 0x28);
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 99bdf09219..1543ee6653 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -254,4 +254,7 @@ config IOSB
 config XLNX_VERSAL_TRNG
     bool
 
+config XLNX_ZYNQ_DDRC
+    bool
+
 source macio/Kconfig
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index fa6a961ac9..23265f6035 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -97,6 +97,7 @@ system_ss.add(when: 'CONFIG_RASPI', if_true: files(
 ))
 system_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c'))
 system_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c'))
+system_ss.add(when: 'CONFIG_XLNX_ZYNQ_DDRC', if_true: files('xlnx-zynq-ddrc.c'))
 system_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-crf.c'))
 system_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-apu-ctrl.c'))
 system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files(
diff --git a/hw/misc/xlnx-zynq-ddrc.c b/hw/misc/xlnx-zynq-ddrc.c
new file mode 100644
index 0000000000..9e4f2f37a8
--- /dev/null
+++ b/hw/misc/xlnx-zynq-ddrc.c
@@ -0,0 +1,421 @@
+/*
+ * QEMU model of the Xilinx Zynq Double Data Rate Controller
+ *
+ * Copyright (c) Beckhoff Automation GmbH. & Co. KG
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/sysbus.h"
+#include "hw/core/register.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/core/registerfields.h"
+#include "system/block-backend.h"
+#include "system/address-spaces.h"
+#include "system/memory.h"
+#include "system/dma.h"
+#include "hw/misc/xlnx-zynq-ddrc.h"
+#include "migration/vmstate.h"
+
+#ifndef DDRCTRL_ERR_DEBUG
+#define DDRCTRL_ERR_DEBUG 0
+#endif
+
+static void zynq_ddrctrl_post_write(RegisterInfo *reg, uint64_t val)
+{
+    DDRCTRLState *s = DDRCTRL(reg->opaque);
+    if (reg->access->addr == A_DDRC_CTRL) {
+        if (val & 0x1) {
+            s->reg[R_MODE_STS_REG] |=
+                (R_MODE_STS_REG_DDR_REG_OPERATING_MODE_MASK & 0x1);
+        } else {
+            s->reg[R_MODE_STS_REG] &=
+                ~R_MODE_STS_REG_DDR_REG_OPERATING_MODE_MASK;
+        }
+    }
+}
+
+static const RegisterAccessInfo xlnx_zynq_ddrc_regs_info[] = {
+    /* 0x00 - 0x3C: Basic DDRC control and config */
+    { .name = "DDRC_CTRL",
+      .addr = A_DDRC_CTRL,
+      .reset = 0x00000200,
+      .post_write = zynq_ddrctrl_post_write },
+    { .name = "TWO_RANK_CFG",
+      .addr = A_TWO_RANK_CFG,
+      .reset = 0x000C1076 },
+    { .name = "HPR_REG",
+      .addr = A_HPR_REG,
+      .reset = 0x03C0780F },
+    { .name = "LPR_REG",
+      .addr = A_LPR_REG,
+      .reset = 0x03C0780F },
+    { .name = "WR_REG",
+      .addr = A_WR_REG,
+      .reset = 0x0007F80F },
+    { .name = "DRAM_PARAM_REG0",
+      .addr = A_DRAM_PARAM_REG0,
+      .reset = 0x00041016 },
+    { .name = "DRAM_PARAM_REG1",
+      .addr = A_DRAM_PARAM_REG1,
+      .reset = 0x351B48D9 },
+    { .name = "DRAM_PARAM_REG2",
+      .addr = A_DRAM_PARAM_REG2,
+      .reset = 0x83015904 },
+    { .name = "DRAM_PARAM_REG3",
+      .addr = A_DRAM_PARAM_REG3,
+      .reset = 0x250882D0 },
+    { .name = "DRAM_PARAM_REG4",
+      .addr = A_DRAM_PARAM_REG4,
+      .reset = 0x0000003C },
+    { .name = "DRAM_INIT_PARAM",
+      .addr = A_DRAM_INIT_PARAM,
+      .reset = 0x00002007 },
+    { .name = "DRAM_EMR_REG",
+      .addr = A_DRAM_EMR_REG,
+      .reset = 0x00000008 },
+    { .name = "DRAM_EMR_MR_REG",
+      .addr = A_DRAM_EMR_MR_REG,
+      .reset = 0x00000940 },
+    { .name = "DRAM_BURST8_RDWR",
+      .addr = A_DRAM_BURST8_RDWR,
+      .reset = 0x00020034 },
+    { .name = "DRAM_DISABLE_DQ",
+      .addr = A_DRAM_DISABLE_DQ },
+    { .name = "DRAM_ADDR_MAP_BANK",
+      .addr = A_DRAM_ADDR_MAP_BANK,
+      .reset = 0x00000F77 },
+    { .name = "DRAM_ADDR_MAP_COL",
+      .addr = A_DRAM_ADDR_MAP_COL,
+      .reset = 0xFFF00000 },
+    { .name = "DRAM_ADDR_MAP_ROW",
+      .addr = A_DRAM_ADDR_MAP_ROW,
+      .reset = 0x0FF55555 },
+    { .name = "DRAM_ODT_REG",
+      .addr = A_DRAM_ODT_REG,
+      .reset = 0x00000249 },
+
+    /* 0x4C - 0x5C: PHY and DLL */
+    { .name = "PHY_DBG_REG",
+      .addr = A_PHY_DBG_REG },
+    { .name = "PHY_CMD_TIMEOUT_RDDATA_CPT",
+      .addr = A_PHY_CMD_TIMEOUT_RDDATA_CPT,
+      .reset = 0x00010200 },
+    { .name = "MODE_STS_REG",
+      .addr = A_MODE_STS_REG },
+    { .name = "DLL_CALIB",
+      .addr = A_DLL_CALIB,
+      .reset = 0x00000101 },
+    { .name = "ODT_DELAY_HOLD",
+      .addr = A_ODT_DELAY_HOLD,
+      .reset = 0x00000023 },
+
+    /* 0x60 - 0x7C: Control registers */
+    { .name = "CTRL_REG1",
+      .addr = A_CTRL_REG1,
+      .reset = 0x0000003E },
+    { .name = "CTRL_REG2",
+      .addr = A_CTRL_REG2,
+      .reset = 0x00020000 },
+    { .name = "CTRL_REG3",
+      .addr = A_CTRL_REG3,
+      .reset = 0x00284027 },
+    { .name = "CTRL_REG4",
+      .addr = A_CTRL_REG4,
+      .reset = 0x00001610 },
+    { .name = "CTRL_REG5",
+      .addr = A_CTRL_REG5,
+      .reset = 0x00455111 },
+    { .name = "CTRL_REG6",
+      .addr = A_CTRL_REG6,
+      .reset = 0x00032222 },
+
+    /* 0xA0 - 0xB4: Refresh, ZQ, powerdown, misc */
+    { .name = "CHE_REFRESH_TIMER0",
+      .addr = A_CHE_REFRESH_TIMER0,
+      .reset = 0x00008000 },
+    { .name = "CHE_T_ZQ",
+      .addr = A_CHE_T_ZQ,
+      .reset = 0x10300802 },
+    { .name = "CHE_T_ZQ_SHORT_INTERVAL_REG",
+      .addr = A_CHE_T_ZQ_SHORT_INTERVAL_REG,
+      .reset = 0x0020003A },
+    { .name = "DEEP_PWRDWN_REG",
+      .addr = A_DEEP_PWRDWN_REG },
+    { .name = "REG_2C",
+      .addr = A_REG_2C },
+    { .name = "REG_2D",
+      .addr = A_REG_2D,
+      .reset = 0x00000200 },
+
+    /* 0xB8 - 0xF8: ECC, DFI, etc. */
+    { .name = "DFI_TIMING",
+      .addr = A_DFI_TIMING,
+      .reset = 0x00200067 },
+    { .name = "CHE_ECC_CONTROL_REG_OFFSET",
+      .addr = A_CHE_ECC_CONTROL_REG_OFFSET },
+    { .name = "CHE_CORR_ECC_LOG_REG_OFFSET",
+      .addr = A_CHE_CORR_ECC_LOG_REG_OFFSET },
+    { .name = "CHE_CORR_ECC_ADDR_REG_OFFSET",
+      .addr = A_CHE_CORR_ECC_ADDR_REG_OFFSET },
+    { .name = "CHE_CORR_ECC_DATA_31_0_REG_OFFSET",
+      .addr = A_CHE_CORR_ECC_DATA_31_0_REG_OFFSET },
+    { .name = "CHE_CORR_ECC_DATA_63_32_REG_OFFSET",
+      .addr = A_CHE_CORR_ECC_DATA_63_32_REG_OFFSET },
+    { .name = "CHE_CORR_ECC_DATA_71_64_REG_OFFSET",
+      .addr = A_CHE_CORR_ECC_DATA_71_64_REG_OFFSET },
+    { .name = "CHE_UNCORR_ECC_LOG_REG_OFFSET",
+      .addr = A_CHE_UNCORR_ECC_LOG_REG_OFFSET },
+    { .name = "CHE_UNCORR_ECC_ADDR_REG_OFFSET",
+      .addr = A_CHE_UNCORR_ECC_ADDR_REG_OFFSET },
+    { .name = "CHE_UNCORR_ECC_DATA_31_0_REG_OFFSET",
+      .addr = A_CHE_UNCORR_ECC_DATA_31_0_REG_OFFSET },
+    { .name = "CHE_UNCORR_ECC_DATA_63_32_REG_OFFSET",
+      .addr = A_CHE_UNCORR_ECC_DATA_63_32_REG_OFFSET },
+    { .name = "CHE_UNCORR_ECC_DATA_71_64_REG_OFFSET",
+      .addr = A_CHE_UNCORR_ECC_DATA_71_64_REG_OFFSET },
+    { .name = "CHE_ECC_STATS_REG_OFFSET",
+      .addr = A_CHE_ECC_STATS_REG_OFFSET },
+    { .name = "ECC_SCRUB",
+      .addr = A_ECC_SCRUB,
+      .reset = 0x00000008 },
+    { .name = "CHE_ECC_CORR_BIT_MASK_31_0_REG_OFFSET",
+      .addr = A_CHE_ECC_CORR_BIT_MASK_31_0_REG_OFFSET },
+    { .name = "CHE_ECC_CORR_BIT_MASK_63_32_REG_OFFSET",
+      .addr = A_CHE_ECC_CORR_BIT_MASK_63_32_REG_OFFSET },
+
+    /* 0x114 - 0x174: PHY config, ratios, DQS, WE */
+    { .name = "PHY_RCVER_ENABLE",
+      .addr = A_PHY_RCVER_ENABLE },
+    { .name = "PHY_CONFIG0",
+      .addr = A_PHY_CONFIG0,
+      .reset = 0x40000001 },
+    { .name = "PHY_CONFIG1",
+      .addr = A_PHY_CONFIG1,
+      .reset = 0x40000001 },
+    { .name = "PHY_CONFIG2",
+      .addr = A_PHY_CONFIG2,
+      .reset = 0x40000001 },
+    { .name = "PHY_CONFIG3",
+      .addr = A_PHY_CONFIG3,
+      .reset = 0x40000001 },
+    { .name = "PHY_INIT_RATIO0",
+      .addr = A_PHY_INIT_RATIO0 },
+    { .name = "PHY_INIT_RATIO1",
+      .addr = A_PHY_INIT_RATIO1 },
+    { .name = "PHY_INIT_RATIO2",
+      .addr = A_PHY_INIT_RATIO2 },
+    { .name = "PHY_INIT_RATIO3",
+      .addr = A_PHY_INIT_RATIO3 },
+    { .name = "PHY_RD_DQS_CFG0",
+      .addr = A_PHY_RD_DQS_CFG0,
+      .reset = 0x00000040 },
+    { .name = "PHY_RD_DQS_CFG1",
+      .addr = A_PHY_RD_DQS_CFG1,
+      .reset = 0x00000040 },
+    { .name = "PHY_RD_DQS_CFG2",
+      .addr = A_PHY_RD_DQS_CFG2,
+      .reset = 0x00000040 },
+    { .name = "PHY_RD_DQS_CFG3",
+      .addr = A_PHY_RD_DQS_CFG3,
+      .reset = 0x00000040 },
+    { .name = "PHY_WR_DQS_CFG0",
+      .addr = A_PHY_WR_DQS_CFG0 },
+    { .name = "PHY_WR_DQS_CFG1",
+      .addr = A_PHY_WR_DQS_CFG1 },
+    { .name = "PHY_WR_DQS_CFG2",
+      .addr = A_PHY_WR_DQS_CFG2 },
+    { .name = "PHY_WR_DQS_CFG3",
+      .addr = A_PHY_WR_DQS_CFG3 },
+    { .name = "PHY_WE_CFG0",
+      .addr = A_PHY_WE_CFG0,
+      .reset = 0x00000040 },
+    { .name = "PHY_WE_CFG1",
+      .addr = A_PHY_WE_CFG1,
+      .reset = 0x00000040 },
+    { .name = "PHY_WE_CFG2",
+      .addr = A_PHY_WE_CFG2,
+      .reset = 0x00000040 },
+    { .name = "PHY_WE_CFG3",
+      .addr = A_PHY_WE_CFG3,
+      .reset = 0x00000040 },
+
+    /* 0x17C - 0x194: Write data slaves, misc */
+    { .name = "WR_DATA_SLV0",
+      .addr = A_WR_DATA_SLV0,
+      .reset = 0x00000080 },
+    { .name = "WR_DATA_SLV1",
+      .addr = A_WR_DATA_SLV1,
+      .reset = 0x00000080 },
+    { .name = "WR_DATA_SLV2",
+      .addr = A_WR_DATA_SLV2,
+      .reset = 0x00000080 },
+    { .name = "WR_DATA_SLV3",
+      .addr = A_WR_DATA_SLV3,
+      .reset = 0x00000080 },
+    { .name = "REG_64",
+      .addr = A_REG_64,
+      .reset = 0x10020000 },
+    { .name = "REG_65",
+      .addr = A_REG_65 },
+
+    /* 0x1A4 - 0x1C4: Misc registers */
+    { .name = "REG69_6A0",
+      .addr = A_REG69_6A0 },
+    { .name = "REG69_6A1",
+      .addr = A_REG69_6A1 },
+    { .name = "REG6C_6D2",
+      .addr = A_REG6C_6D2 },
+    { .name = "REG6C_6D3",
+      .addr = A_REG6C_6D3 },
+    { .name = "REG6E_710",
+      .addr = A_REG6E_710 },
+    { .name = "REG6E_711",
+      .addr = A_REG6E_711 },
+    { .name = "REG6E_712",
+      .addr = A_REG6E_712 },
+    { .name = "REG6E_713",
+      .addr = A_REG6E_713 },
+
+    /* 0x1CC - 0x1E8: DLL, PHY status */
+    { .name = "PHY_DLL_STS0",
+      .addr = A_PHY_DLL_STS0 },
+    { .name = "PHY_DLL_STS1",
+      .addr = A_PHY_DLL_STS1 },
+    { .name = "PHY_DLL_STS2",
+      .addr = A_PHY_DLL_STS2 },
+    { .name = "PHY_DLL_STS3",
+      .addr = A_PHY_DLL_STS3 },
+    { .name = "DLL_LOCK_STS",
+      .addr = A_DLL_LOCK_STS },
+    { .name = "PHY_CTRL_STS",
+      .addr = A_PHY_CTRL_STS },
+    { .name = "PHY_CTRL_STS_REG2",
+      .addr = A_PHY_CTRL_STS_REG2 },
+
+    /* 0x200 - 0x2B4: AXI, LPDDR, misc */
+    { .name = "AXI_ID",
+      .addr = A_AXI_ID },
+    { .name = "PAGE_MASK",
+      .addr = A_PAGE_MASK },
+    { .name = "AXI_PRIORITY_WR_PORT0",
+      .addr = A_AXI_PRIORITY_WR_PORT0,
+      .reset = 0x000803FF },
+    { .name = "AXI_PRIORITY_WR_PORT1",
+      .addr = A_AXI_PRIORITY_WR_PORT1,
+      .reset = 0x000803FF },
+    { .name = "AXI_PRIORITY_WR_PORT2",
+      .addr = A_AXI_PRIORITY_WR_PORT2,
+      .reset = 0x000803FF },
+    { .name = "AXI_PRIORITY_WR_PORT3",
+      .addr = A_AXI_PRIORITY_WR_PORT3,
+      .reset = 0x000803FF },
+    { .name = "AXI_PRIORITY_RD_PORT0",
+      .addr = A_AXI_PRIORITY_RD_PORT0,
+      .reset = 0x000003FF },
+    { .name = "AXI_PRIORITY_RD_PORT1",
+      .addr = A_AXI_PRIORITY_RD_PORT1,
+      .reset = 0x000003FF },
+    { .name = "AXI_PRIORITY_RD_PORT2",
+      .addr = A_AXI_PRIORITY_RD_PORT2,
+      .reset = 0x000003FF },
+    { .name = "AXI_PRIORITY_RD_PORT3",
+      .addr = A_AXI_PRIORITY_RD_PORT3,
+      .reset = 0x000003FF },
+    { .name = "EXCL_ACCESS_CFG0",
+      .addr = A_EXCL_ACCESS_CFG0 },
+    { .name = "EXCL_ACCESS_CFG1",
+      .addr = A_EXCL_ACCESS_CFG1 },
+    { .name = "EXCL_ACCESS_CFG2",
+      .addr = A_EXCL_ACCESS_CFG2 },
+    { .name = "EXCL_ACCESS_CFG3",
+      .addr = A_EXCL_ACCESS_CFG3 },
+    { .name = "MODE_REG_READ",
+      .addr = A_MODE_REG_READ },
+    { .name = "LPDDR_CTRL0",
+      .addr = A_LPDDR_CTRL0 },
+    { .name = "LPDDR_CTRL1",
+      .addr = A_LPDDR_CTRL1 },
+    { .name = "LPDDR_CTRL2",
+      .addr = A_LPDDR_CTRL2,
+      .reset = 0x003C0015 },
+    { .name = "LPDDR_CTRL3",
+      .addr = A_LPDDR_CTRL3,
+      .reset = 0x00000601 },
+};
+
+static void zynq_ddrctrl_reset(DeviceState *dev)
+{
+    DDRCTRLState *s = DDRCTRL(dev);
+    int i;
+
+    for (i = 0; i < ZYNQ_DDRCTRL_NUM_REG; ++i) {
+        register_reset(&s->regs_info[i]);
+    }
+}
+
+static const MemoryRegionOps ddrctrl_ops = {
+    .read = register_read_memory,
+    .write = register_write_memory,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const VMStateDescription vmstate_zynq_ddrctrl = {
+    .name = "zynq_ddrc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(reg, DDRCTRLState, ZYNQ_DDRCTRL_NUM_REG),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void zynq_ddrctrl_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    DDRCTRLState *s = DDRCTRL(obj);
+
+    s->reg_array =
+        register_init_block32(DEVICE(obj), xlnx_zynq_ddrc_regs_info,
+                              ARRAY_SIZE(xlnx_zynq_ddrc_regs_info),
+                              s->regs_info, s->reg,
+                              &ddrctrl_ops,
+                              DDRCTRL_ERR_DEBUG,
+                              ZYNQ_DDRCTRL_MMIO_SIZE);
+
+    sysbus_init_mmio(sbd, &s->reg_array->mem);
+}
+
+static void zynq_ddrctrl_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    device_class_set_legacy_reset(dc, zynq_ddrctrl_reset);
+    dc->vmsd = &vmstate_zynq_ddrctrl;
+}
+
+static const TypeInfo ddrctrl_info = {
+    .name = TYPE_DDRCTRL,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(DDRCTRLState),
+    .instance_init = zynq_ddrctrl_init,
+    .class_init = zynq_ddrctrl_class_init,
+};
+
+static void ddrctrl_register_types(void)
+{
+    type_register_static(&ddrctrl_info);
+}
+
+type_init(ddrctrl_register_types)
diff --git a/include/hw/misc/xlnx-zynq-ddrc.h b/include/hw/misc/xlnx-zynq-ddrc.h
new file mode 100644
index 0000000000..124bff27ac
--- /dev/null
+++ b/include/hw/misc/xlnx-zynq-ddrc.h
@@ -0,0 +1,147 @@
+/*
+ * QEMU model of the Xilinx Zynq Double Data Rate Controller
+ *
+ * Copyright (c) Beckhoff Automation GmbH. & Co. KG
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef XLNX_ZYNQ_DDRC_H
+#define XLNX_ZYNQ_DDRC_H
+
+#include "hw/core/sysbus.h"
+#include "hw/core/register.h"
+
+#define TYPE_DDRCTRL "zynq.ddr-ctlr"
+OBJECT_DECLARE_SIMPLE_TYPE(DDRCTRLState, DDRCTRL)
+
+REG32(DDRC_CTRL, 0x00)
+REG32(TWO_RANK_CFG, 0x04)
+REG32(HPR_REG, 0x08)
+REG32(LPR_REG, 0x0C)
+REG32(WR_REG, 0x10)
+REG32(DRAM_PARAM_REG0, 0x14)
+REG32(DRAM_PARAM_REG1, 0x18)
+REG32(DRAM_PARAM_REG2, 0x1C)
+REG32(DRAM_PARAM_REG3, 0x20)
+REG32(DRAM_PARAM_REG4, 0x24)
+REG32(DRAM_INIT_PARAM, 0x28)
+REG32(DRAM_EMR_REG, 0x2C)
+REG32(DRAM_EMR_MR_REG, 0x30)
+REG32(DRAM_BURST8_RDWR, 0x34)
+REG32(DRAM_DISABLE_DQ, 0x38)
+REG32(DRAM_ADDR_MAP_BANK, 0x3C)
+REG32(DRAM_ADDR_MAP_COL, 0x40)
+REG32(DRAM_ADDR_MAP_ROW, 0x44)
+REG32(DRAM_ODT_REG, 0x48)
+REG32(PHY_DBG_REG, 0x4C)
+REG32(PHY_CMD_TIMEOUT_RDDATA_CPT, 0x50)
+REG32(MODE_STS_REG, 0x54)
+    FIELD(MODE_STS_REG, DDR_REG_DBG_STALL, 3, 3)
+    FIELD(MODE_STS_REG, DDR_REG_OPERATING_MODE, 0, 2)
+REG32(DLL_CALIB, 0x58)
+REG32(ODT_DELAY_HOLD, 0x5C)
+REG32(CTRL_REG1, 0x60)
+REG32(CTRL_REG2, 0x64)
+REG32(CTRL_REG3, 0x68)
+REG32(CTRL_REG4, 0x6C)
+REG32(CTRL_REG5, 0x78)
+REG32(CTRL_REG6, 0x7C)
+REG32(CHE_REFRESH_TIMER0, 0xA0)
+REG32(CHE_T_ZQ, 0xA4)
+REG32(CHE_T_ZQ_SHORT_INTERVAL_REG, 0xA8)
+REG32(DEEP_PWRDWN_REG, 0xAC)
+REG32(REG_2C, 0xB0)
+REG32(REG_2D, 0xB4)
+REG32(DFI_TIMING, 0xB8)
+REG32(CHE_ECC_CONTROL_REG_OFFSET, 0xC4)
+REG32(CHE_CORR_ECC_LOG_REG_OFFSET, 0xC8)
+REG32(CHE_CORR_ECC_ADDR_REG_OFFSET, 0xCC)
+REG32(CHE_CORR_ECC_DATA_31_0_REG_OFFSET, 0xD0)
+REG32(CHE_CORR_ECC_DATA_63_32_REG_OFFSET, 0xD4)
+REG32(CHE_CORR_ECC_DATA_71_64_REG_OFFSET, 0xD8)
+REG32(CHE_UNCORR_ECC_LOG_REG_OFFSET, 0xDC)
+REG32(CHE_UNCORR_ECC_ADDR_REG_OFFSET, 0xE0)
+REG32(CHE_UNCORR_ECC_DATA_31_0_REG_OFFSET, 0xE4)
+REG32(CHE_UNCORR_ECC_DATA_63_32_REG_OFFSET, 0xE8)
+REG32(CHE_UNCORR_ECC_DATA_71_64_REG_OFFSET, 0xEC)
+REG32(CHE_ECC_STATS_REG_OFFSET, 0xF0)
+REG32(ECC_SCRUB, 0xF4)
+REG32(CHE_ECC_CORR_BIT_MASK_31_0_REG_OFFSET, 0xF8)
+REG32(CHE_ECC_CORR_BIT_MASK_63_32_REG_OFFSET, 0xFC)
+REG32(PHY_RCVER_ENABLE, 0x114)
+REG32(PHY_CONFIG0, 0x118)
+REG32(PHY_CONFIG1, 0x11C)
+REG32(PHY_CONFIG2, 0x120)
+REG32(PHY_CONFIG3, 0x124)
+REG32(PHY_INIT_RATIO0, 0x12C)
+REG32(PHY_INIT_RATIO1, 0x130)
+REG32(PHY_INIT_RATIO2, 0x134)
+REG32(PHY_INIT_RATIO3, 0x138)
+REG32(PHY_RD_DQS_CFG0, 0x140)
+REG32(PHY_RD_DQS_CFG1, 0x144)
+REG32(PHY_RD_DQS_CFG2, 0x148)
+REG32(PHY_RD_DQS_CFG3, 0x14C)
+REG32(PHY_WR_DQS_CFG0, 0x154)
+REG32(PHY_WR_DQS_CFG1, 0x158)
+REG32(PHY_WR_DQS_CFG2, 0x15C)
+REG32(PHY_WR_DQS_CFG3, 0x160)
+REG32(PHY_WE_CFG0, 0x168)
+REG32(PHY_WE_CFG1, 0x16C)
+REG32(PHY_WE_CFG2, 0x170)
+REG32(PHY_WE_CFG3, 0x174)
+REG32(WR_DATA_SLV0, 0x17C)
+REG32(WR_DATA_SLV1, 0x180)
+REG32(WR_DATA_SLV2, 0x184)
+REG32(WR_DATA_SLV3, 0x188)
+REG32(REG_64, 0x190)
+REG32(REG_65, 0x194)
+REG32(REG69_6A0, 0x1A4)
+REG32(REG69_6A1, 0x1A8)
+REG32(REG6C_6D2, 0x1B0)
+REG32(REG6C_6D3, 0x1B4)
+REG32(REG6E_710, 0x1B8)
+REG32(REG6E_711, 0x1BC)
+REG32(REG6E_712, 0x1C0)
+REG32(REG6E_713, 0x1C4)
+REG32(PHY_DLL_STS0, 0x1CC)
+REG32(PHY_DLL_STS1, 0x1D0)
+REG32(PHY_DLL_STS2, 0x1D4)
+REG32(PHY_DLL_STS3, 0x1D8)
+REG32(DLL_LOCK_STS, 0x1E0)
+REG32(PHY_CTRL_STS, 0x1E4)
+REG32(PHY_CTRL_STS_REG2, 0x1E8)
+REG32(AXI_ID, 0x200)
+REG32(PAGE_MASK, 0x204)
+REG32(AXI_PRIORITY_WR_PORT0, 0x208)
+REG32(AXI_PRIORITY_WR_PORT1, 0x20C)
+REG32(AXI_PRIORITY_WR_PORT2, 0x210)
+REG32(AXI_PRIORITY_WR_PORT3, 0x214)
+REG32(AXI_PRIORITY_RD_PORT0, 0x218)
+REG32(AXI_PRIORITY_RD_PORT1, 0x21C)
+REG32(AXI_PRIORITY_RD_PORT2, 0x220)
+REG32(AXI_PRIORITY_RD_PORT3, 0x224)
+REG32(EXCL_ACCESS_CFG0, 0x294)
+REG32(EXCL_ACCESS_CFG1, 0x298)
+REG32(EXCL_ACCESS_CFG2, 0x29C)
+REG32(EXCL_ACCESS_CFG3, 0x2A0)
+REG32(MODE_REG_READ, 0x2A4)
+REG32(LPDDR_CTRL0, 0x2A8)
+REG32(LPDDR_CTRL1, 0x2AC)
+REG32(LPDDR_CTRL2, 0x2B0)
+REG32(LPDDR_CTRL3, 0x2B4)
+
+
+#define ZYNQ_DDRCTRL_MMIO_SIZE      0x400
+#define ZYNQ_DDRCTRL_NUM_REG        (ZYNQ_DDRCTRL_MMIO_SIZE / 4)
+
+typedef struct DDRCTRLState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion iomem;
+
+    RegisterInfoArray *reg_array;
+    uint32_t reg[ZYNQ_DDRCTRL_NUM_REG];
+    RegisterInfo regs_info[ZYNQ_DDRCTRL_NUM_REG];
+} DDRCTRLState;
+#endif
-- 
2.43.0



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

* [PULL 08/21] hw/misc/zynq_slcr: Add logic for DCI configuration
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (6 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 07/21] hw/misc: Add dummy ZYNQ DDR controller Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 09/21] hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d Peter Maydell
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: YannickV <Y.Vossen@beckhoff.com>

The registers for the digitally controlled impedance (DCI) clock are
part of the system level control registers (SLCR). The DONE bit in
the status register indicates a successfull DCI calibration. An
description of the calibration process can be found here:
https://docs.amd.com/r/en-US/ug585-zynq-7000-SoC-TRM/DDR-IOB-Impedance-Calibration

The DCI control register and status register have been added. As soon
as the ENABLE and RESET bit are set, the RESET bit has also been toggled
to 0 before and the UPDATE_CONTROL is not set, the DONE bit in the status
register is set. If these bits change the DONE bit is reset. Note that the
option bits are not taken into consideration.

Signed-off-by: YannickV <Y.Vossen@beckhoff.com>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Message-id: 20260518073401.11279-8-corvin.koehne@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/misc/zynq_slcr.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
index faae98fa02..0ae5d607be 100644
--- a/hw/misc/zynq_slcr.c
+++ b/hw/misc/zynq_slcr.c
@@ -180,6 +180,12 @@ REG32(GPIOB_CFG_HSTL, 0xb14)
 REG32(GPIOB_DRVR_BIAS_CTRL, 0xb18)
 
 REG32(DDRIOB, 0xb40)
+REG32(DDRIOB_DCI_CTRL, 0xb70)
+    FIELD(DDRIOB_DCI_CTRL, RESET, 0, 1)
+    FIELD(DDRIOB_DCI_CTRL, ENABLE, 1, 1)
+    FIELD(DDRIOB_DCI_CTRL, UPDATE_CONTROL, 20, 1)
+REG32(DDRIOB_DCI_STATUS, 0xb74)
+    FIELD(DDRIOB_DCI_STATUS, DONE, 13, 1)
 #define DDRIOB_LENGTH 14
 
 #define ZYNQ_SLCR_MMIO_SIZE     0x1000
@@ -193,6 +199,8 @@ struct ZynqSLCRState {
 
     MemoryRegion iomem;
 
+    bool ddriob_dci_ctrl_reset_toggled;
+
     uint32_t regs[ZYNQ_SLCR_NUM_REGS];
 
     Clock *ps_clk;
@@ -331,6 +339,8 @@ static void zynq_slcr_reset_init(Object *obj, ResetType type)
 
     DB_PRINT("RESET\n");
 
+    s->ddriob_dci_ctrl_reset_toggled = false;
+
     s->regs[R_LOCKSTA] = 1;
     /* 0x100 - 0x11C */
     s->regs[R_ARM_PLL_CTRL]   = 0x0001A008;
@@ -418,6 +428,8 @@ static void zynq_slcr_reset_init(Object *obj, ResetType type)
     s->regs[R_DDRIOB + 4] = s->regs[R_DDRIOB + 5] = s->regs[R_DDRIOB + 6]
                           = 0x00000e00;
     s->regs[R_DDRIOB + 12] = 0x00000021;
+
+    s->regs[R_DDRIOB_DCI_CTRL] = 0x00000020;
 }
 
 static void zynq_slcr_reset_hold(Object *obj, ResetType type)
@@ -554,6 +566,25 @@ static void zynq_slcr_write(void *opaque, hwaddr offset,
                 (int)offset, (unsigned)val & 0xFFFF);
         }
         return;
+
+    case R_DDRIOB_DCI_CTRL:
+        if (!FIELD_EX32(val, DDRIOB_DCI_CTRL, RESET) &&
+            FIELD_EX32(s->regs[R_DDRIOB_DCI_CTRL], DDRIOB_DCI_CTRL, RESET)) {
+
+            s->ddriob_dci_ctrl_reset_toggled = true;
+            DB_PRINT("DDRIOB DCI CTRL RESET was toggled\n");
+        }
+
+        if (FIELD_EX32(val, DDRIOB_DCI_CTRL, ENABLE) &&
+            FIELD_EX32(val, DDRIOB_DCI_CTRL, RESET) &&
+            !FIELD_EX32(val, DDRIOB_DCI_CTRL, UPDATE_CONTROL) &&
+            s->ddriob_dci_ctrl_reset_toggled) {
+
+            s->regs[R_DDRIOB_DCI_STATUS] |= R_DDRIOB_DCI_STATUS_DONE_MASK;
+        } else {
+            s->regs[R_DDRIOB_DCI_STATUS] &= ~R_DDRIOB_DCI_STATUS_DONE_MASK;
+        }
+        break;
     }
 
     if (s->regs[R_LOCKSTA]) {
-- 
2.43.0



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

* [PULL 09/21] hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (7 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 08/21] hw/misc/zynq_slcr: Add logic for DCI configuration Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 10/21] hw/arm/xilinx_zynq: Split xilinx_zynq into header and implementation files Peter Maydell
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: YannickV <Y.Vossen@beckhoff.com>

The is25lp016d has 4 Block Write Protect Bits. BP3 specifies
whether the upper or lower range should be protected. Therefore,
we add the HAS_SR_TB flag to the is25lp016d flags.

Signed-off-by: YannickV <Y.Vossen@beckhoff.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260518073401.11279-10-corvin.koehne@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/block/m25p80.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index b8a2543c0b..4a4cda6602 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -217,7 +217,8 @@ static const FlashPartInfo known_devices[] = {
     /* ISSI */
     { INFO("is25lq040b",  0x9d4013,      0,  64 << 10,   8, ER_4K) },
     { INFO("is25lp080d",  0x9d6014,      0,  64 << 10,  16, ER_4K) },
-    { INFO("is25lp016d",  0x9d6015,      0,  64 << 10,  32, ER_4K) },
+    { INFO("is25lp016d",  0x9d6015,      0,  64 << 10,  32,
+           ER_4K | HAS_SR_TB) },
     { INFO("is25lp032",   0x9d6016,      0,  64 << 10,  64, ER_4K) },
     { INFO("is25lp064",   0x9d6017,      0,  64 << 10, 128, ER_4K) },
     { INFO("is25lp128",   0x9d6018,      0,  64 << 10, 256, ER_4K) },
-- 
2.43.0



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

* [PULL 10/21] hw/arm/xilinx_zynq: Split xilinx_zynq into header and implementation files
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (8 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 09/21] hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 11/21] target/arm: Add feature predicate for FEAT_CMPBR Peter Maydell
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: YannickV <Y.Vossen@beckhoff.com>

Create xilinx_zynq.h header file to expose ZynqMachineState and
related definitions for machine inheritance. This enables creation
of derived machines based on the Zynq platform.

Signed-off-by: YannickV <Y.Vossen@beckhoff.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260518073401.11279-11-corvin.koehne@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/xilinx_zynq.c         | 13 +------------
 include/hw/arm/xilinx_zynq.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 12 deletions(-)
 create mode 100644 include/hw/arm/xilinx_zynq.h

diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 66a4480cc8..6c83439017 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -41,9 +41,7 @@
 #include "exec/tswap.h"
 #include "target/arm/cpu-qom.h"
 #include "qapi/visitor.h"
-
-#define TYPE_ZYNQ_MACHINE MACHINE_TYPE_NAME("xilinx-zynq-a9")
-OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE)
+#include "hw/arm/xilinx_zynq.h"
 
 /* board base frequency: 33.333333 MHz */
 #define PS_CLK_FREQUENCY (100 * 1000 * 1000 / 3)
@@ -87,15 +85,6 @@ static const int dma_irqs[8] = {
     0xe3401000 + ARMV7_IMM16(extract32((val), 16, 16)), /* movt r1 ... */ \
     0xe5801000 + (addr)
 
-#define ZYNQ_MAX_CPUS 2
-
-struct ZynqMachineState {
-    MachineState parent;
-    Clock *ps_clk;
-    ARMCPU *cpu[ZYNQ_MAX_CPUS];
-    uint8_t boot_mode;
-};
-
 static void zynq_write_board_setup(ARMCPU *cpu,
                                    const struct arm_boot_info *info)
 {
diff --git a/include/hw/arm/xilinx_zynq.h b/include/hw/arm/xilinx_zynq.h
new file mode 100644
index 0000000000..cefb7789ff
--- /dev/null
+++ b/include/hw/arm/xilinx_zynq.h
@@ -0,0 +1,30 @@
+/*
+ * Xilinx Zynq Baseboard System emulation.
+ *
+ * Copyright (c) 2010 Xilinx.
+ * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com)
+ * Copyright (c) 2012 Petalogix Pty Ltd.
+ * Written by Haibing Ma
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_ARM_ZYNQ_H
+#define QEMU_ARM_ZYNQ_H
+
+#include "target/arm/cpu-qom.h"
+#include "hw/core/qdev-clock.h"
+
+#define TYPE_ZYNQ_MACHINE MACHINE_TYPE_NAME("xilinx-zynq-a9")
+OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE)
+
+#define ZYNQ_MAX_CPUS 2
+
+struct ZynqMachineState {
+    MachineState parent;
+    Clock *ps_clk;
+    ARMCPU *cpu[ZYNQ_MAX_CPUS];
+    uint8_t boot_mode;
+};
+
+#endif /* QEMU_ARM_ZYNQ_H */
-- 
2.43.0



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

* [PULL 11/21] target/arm: Add feature predicate for FEAT_CMPBR
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (9 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 10/21] hw/arm/xilinx_zynq: Split xilinx_zynq into header and implementation files Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 12/21] target/arm: Implement CB, CBB, CBH Peter Maydell
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: Richard Henderson <richard.henderson@linaro.org>

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260518174750.660258-2-richard.henderson@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu-features.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index f9c979d20b..4e8d844fea 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1061,6 +1061,11 @@ static inline bool isar_feature_aa64_cssc(const ARMISARegisters *id)
     return FIELD_EX64_IDREG(id, ID_AA64ISAR2, CSSC) != 0;
 }
 
+static inline bool isar_feature_aa64_cmpbr(const ARMISARegisters *id)
+{
+    return FIELD_EX64_IDREG(id, ID_AA64ISAR2, CSSC) >= 2;
+}
+
 static inline bool isar_feature_aa64_lut(const ARMISARegisters *id)
 {
     return FIELD_EX64_IDREG(id, ID_AA64ISAR2, LUT);
-- 
2.43.0



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

* [PULL 12/21] target/arm: Implement CB, CBB, CBH
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (10 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 11/21] target/arm: Add feature predicate for FEAT_CMPBR Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 13/21] target/arm: Implement CB (immediate) Peter Maydell
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: Richard Henderson <richard.henderson@linaro.org>

Compare and branch instructions, with various operand widths.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260518174750.660258-3-richard.henderson@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
[PMM: move var decl to top of function]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/tcg/a64.decode      |  9 +++++++
 target/arm/tcg/translate-a64.c | 43 ++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
index 02c7264cb9..a5a2a45a2f 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -208,6 +208,15 @@ TBZ             . 011011 nz:1 ..... .............. rt:5 &tbz  imm=%imm14 bitpos=
 # B.cond and BC.cond
 B_cond          0101010 0 ................... c:1 cond:4 imm=%imm19
 
+# CB, CBB, CBH
+%imm9           5:s9   !function=times_4
+&cb             cc rt rm imm esz
+@cb             . ....... cc:3 rm:5 .. ......... rt:5       &cb imm=%imm9
+CB_cond         0 1110100 ... ..... 00 ......... .....      @cb esz=2
+CB_cond         1 1110100 ... ..... 00 ......... .....      @cb esz=3
+CB_cond         0 1110100 ... ..... 10 ......... .....      @cb esz=0  # CBB
+CB_cond         0 1110100 ... ..... 11 ......... .....      @cb esz=1  # CBH
+
 BR              1101011 0000 11111 000000 rn:5 00000 &r
 BLR             1101011 0001 11111 000000 rn:5 00000 &r
 RET             1101011 0010 11111 000000 rn:5 00000 &r
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 15b40090c0..94dad693eb 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -1774,6 +1774,49 @@ static bool trans_B_cond(DisasContext *s, arg_B_cond *a)
     return true;
 }
 
+static bool trans_CB_cond(DisasContext *s, arg_CB_cond *a)
+{
+    static const TCGCond cb_cond[8] = {
+        [0] = TCG_COND_GT,
+        [1] = TCG_COND_GE,
+        [2] = TCG_COND_GTU,
+        [3] = TCG_COND_GEU,
+        [4] = TCG_COND_NEVER,  /* reserved */
+        [5] = TCG_COND_NEVER,  /* reserved */
+        [6] = TCG_COND_EQ,
+        [7] = TCG_COND_NE,
+    };
+    TCGCond cond = cb_cond[a->cc];
+    TCGv_i64 t, m;
+    DisasLabel match;
+
+    if (!dc_isar_feature(aa64_cmpbr, s) || cond == TCG_COND_NEVER) {
+        return false;
+    }
+
+    t = cpu_reg(s, a->rt);
+    m = cpu_reg(s, a->rm);
+    if (a->esz != MO_64) {
+        MemOp mop = a->esz | (is_signed_cond(cond) ? MO_SIGN : 0);
+        TCGv_i64 tt = tcg_temp_new_i64();
+        TCGv_i64 tm = tcg_temp_new_i64();
+
+        tcg_gen_ext_i64(tt, t, mop);
+        tcg_gen_ext_i64(tm, m, mop);
+        t = tt;
+        m = tm;
+    }
+
+    reset_btype(s);
+    match = gen_disas_label(s);
+
+    tcg_gen_brcond_i64(cond, t, m, match.label);
+    gen_goto_tb(s, 0, 4);
+    set_disas_label(s, match);
+    gen_goto_tb(s, 1, a->imm);
+    return true;
+}
+
 static void set_btype_for_br(DisasContext *s, int rn)
 {
     if (dc_isar_feature(aa64_bti, s)) {
-- 
2.43.0



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

* [PULL 13/21] target/arm: Implement CB (immediate)
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (11 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 12/21] target/arm: Implement CB, CBB, CBH Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 14/21] target/arm: Enable FEAT_CMPBR for -cpu max Peter Maydell
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: Richard Henderson <richard.henderson@linaro.org>

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260518174750.660258-4-richard.henderson@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
[PMM: var decl at top of function; add comment]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/tcg/a64.decode      |  2 ++
 target/arm/tcg/translate-a64.c | 43 ++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
index a5a2a45a2f..d8a3269573 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -217,6 +217,8 @@ CB_cond         1 1110100 ... ..... 00 ......... .....      @cb esz=3
 CB_cond         0 1110100 ... ..... 10 ......... .....      @cb esz=0  # CBB
 CB_cond         0 1110100 ... ..... 11 ......... .....      @cb esz=1  # CBH
 
+CB_cond_imm     sf:1 1110101 cc:3 imm6:6 0 ......... rt:5   %imm9
+
 BR              1101011 0000 11111 000000 rn:5 00000 &r
 BLR             1101011 0001 11111 000000 rn:5 00000 &r
 RET             1101011 0010 11111 000000 rn:5 00000 &r
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 94dad693eb..765bc3f0b0 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -1817,6 +1817,49 @@ static bool trans_CB_cond(DisasContext *s, arg_CB_cond *a)
     return true;
 }
 
+static bool trans_CB_cond_imm(DisasContext *s, arg_CB_cond_imm *a)
+{
+    /* Note that CB imm and CB encode the condition differently */
+    static const TCGCond cb_cond[8] = {
+        [0] = TCG_COND_GT,
+        [1] = TCG_COND_LT,
+        [2] = TCG_COND_GTU,
+        [3] = TCG_COND_LTU,
+        [4] = TCG_COND_NEVER,  /* reserved */
+        [5] = TCG_COND_NEVER,  /* reserved */
+        [6] = TCG_COND_EQ,
+        [7] = TCG_COND_NE,
+    };
+    TCGCond cond = cb_cond[a->cc];
+    TCGv_i64 t;
+    DisasLabel match;
+
+    if (!dc_isar_feature(aa64_cmpbr, s) || cond == TCG_COND_NEVER) {
+        return false;
+    }
+
+    t = cpu_reg(s, a->rt);
+    if (!a->sf) {
+        TCGv_i64 tt = tcg_temp_new_i64();
+
+        if (is_signed_cond(cond)) {
+            tcg_gen_ext32s_i64(tt, t);
+        } else {
+            tcg_gen_ext32u_i64(tt, t);
+        }
+        t = tt;
+    }
+
+    reset_btype(s);
+    match = gen_disas_label(s);
+
+    tcg_gen_brcondi_i64(cond, t, a->imm6, match.label);
+    gen_goto_tb(s, 0, 4);
+    set_disas_label(s, match);
+    gen_goto_tb(s, 1, a->imm9);
+    return true;
+}
+
 static void set_btype_for_br(DisasContext *s, int rn)
 {
     if (dc_isar_feature(aa64_bti, s)) {
-- 
2.43.0



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

* [PULL 14/21] target/arm: Enable FEAT_CMPBR for -cpu max
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (12 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 13/21] target/arm: Implement CB (immediate) Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 15/21] target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault Peter Maydell
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: Richard Henderson <richard.henderson@linaro.org>

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260518174750.660258-5-richard.henderson@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 docs/system/arm/emulation.rst | 1 +
 linux-user/aarch64/elfload.c  | 1 +
 target/arm/tcg/cpu64.c        | 2 +-
 3 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index e44b3016be..37ca4e47b8 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -35,6 +35,7 @@ the following architecture extensions:
 - FEAT_CCIDX (Extended cache index)
 - FEAT_CHK (Check Feature Status)
 - FEAT_CMOW (Control for cache maintenance permission)
+- FEAT_CMPBR (Compare and Branch instructions)
 - FEAT_CRC32 (CRC32 instructions)
 - FEAT_Crypto (Cryptographic Extension)
 - FEAT_CSSC (Common Short Sequence Compression instructions)
diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c
index ceeeee5315..228b593316 100644
--- a/linux-user/aarch64/elfload.c
+++ b/linux-user/aarch64/elfload.c
@@ -170,6 +170,7 @@ abi_ulong get_elf_hwcap(CPUState *cs)
     GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
     GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
     GET_FEATURE_ID(aa64_gcs, ARM_HWCAP_A64_GCS);
+    GET_FEATURE_ID(aa64_cmpbr, ARM_HWCAP_A64_CMPBR);
 
     return hwcaps;
 }
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index a377f67b9c..ce76e09d52 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1262,7 +1262,7 @@ void aarch64_max_tcg_initfn(Object *obj)
     t = FIELD_DP64(t, ID_AA64ISAR2, MOPS, 1);     /* FEAT_MOPS */
     t = FIELD_DP64(t, ID_AA64ISAR2, BC, 1);       /* FEAT_HBC */
     t = FIELD_DP64(t, ID_AA64ISAR2, WFXT, 2);     /* FEAT_WFxT */
-    t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 1);     /* FEAT_CSSC */
+    t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 2);     /* FEAT_CSSC, FEAT_CMPBR */
     t = FIELD_DP64(t, ID_AA64ISAR2, ATS1A, 1);    /* FEAT_ATS1A */
     SET_IDREG(isar, ID_AA64ISAR2, t);
 
-- 
2.43.0



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

* [PULL 15/21] target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (13 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 14/21] target/arm: Enable FEAT_CMPBR for -cpu max Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 16/21] target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors" Peter Maydell
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

The Domain fault type can only happen for 32-bit short-format
descriptors.  This means that it almost never needs to be encoded in
a long-format fault status code.  However, there is one corner case
where we do need to report it as a long-format FSC: if a 64-bit EL2
does an AT insn on an AArch32 EL1&0 translation regime that is using
short-descriptors and that translation operation hits a Domain fault,
then this is reported in the PAR_EL1 in long-format.

The PAR_EL1 register description defines that this should be reported
as 0b111101 for a level 1 Domain fault or 0b111110 for a level 2
Domain fault.

The Arm ARM pseudocode special cases this in the function
AArch64_PARFaultStatus() (because no other "fault to LFSC" code path
can be a Domain fault).  For QEMU, implement it in arm_fi_to_lfsc().

Cc: qemu-stable@nongnu.org
Fixes: 1fa498fe0de97 ("target/arm: Provide fault type enum and FSR conversion functions")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3512
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260526174155.2491217-1-peter.maydell@linaro.org
---
 target/arm/internals.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/target/arm/internals.h b/target/arm/internals.h
index ae5afc5362..f39a992012 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -893,6 +893,16 @@ static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi)
         assert(fi->level >= 0 && fi->level <= 3);
         fsc = 0b001100 | fi->level;
         break;
+    case ARMFault_Domain:
+        /*
+         * This can only happen when doing an AT insn at EL2 for an AArch32
+         * stage 1 EL1&0 translation regime using short-descriptors, and
+         * the translation hits a Domain fault. This needs to be reported in
+         * the long-format PAR. Compare pseudocode AArch64_PARFaultStatus().
+         */
+        assert(fi->level == 1 || fi->level == 2);
+        fsc = 0b111100 | fi->level;
+        break;
     case ARMFault_Translation:
         assert(fi->level >= -1 && fi->level <= 3);
         if (fi->level < 0) {
-- 
2.43.0



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

* [PULL 16/21] target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors"
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (14 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 15/21] target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS Peter Maydell
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

The Arm ARM A1.5.10 notes that some instructions have "Alternate
Bfloat16 behaviors" when FPCR.AH == 1.  We implement these using the
FPST_AH and FPST_AH_F16 fp_status words.  The list includes the SME
BFVCT (single-precision to BFloat16) and BFCVTN, but we forgot to
make those use FPST_AH_F16 when we implemented them. (We get the
ASIMD and SVE insns on the list right.)

Add the missing logic to select the right FPST.

Cc: qemu-stable@nongnu.org
Fixes: 465d36db0e1 ("target/arm: Implement SME2 BFCVT, BFCVTN, FCVT, FCVTN")
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20260521180854.1744788-1-peter.maydell@linaro.org
---
 target/arm/tcg/translate-sme.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c
index e2d17de165..82aa14131b 100644
--- a/target/arm/tcg/translate-sme.c
+++ b/target/arm/tcg/translate-sme.c
@@ -1449,9 +1449,9 @@ static bool do_zz_fpst(DisasContext *s, arg_zz_n *a, int data,
 }
 
 TRANS_FEAT(BFCVT, aa64_sme2, do_zz_fpst, a, 0,
-           FPST_A64, gen_helper_sme2_bfcvt)
+           s->fpcr_ah ? FPST_AH : FPST_A64, gen_helper_sme2_bfcvt)
 TRANS_FEAT(BFCVTN, aa64_sme2, do_zz_fpst, a, 0,
-           FPST_A64, gen_helper_sme2_bfcvtn)
+           s->fpcr_ah ? FPST_AH : FPST_A64, gen_helper_sme2_bfcvtn)
 TRANS_FEAT(FCVT_n, aa64_sme2, do_zz_fpst, a, 0,
            FPST_A64, gen_helper_sme2_fcvt_n)
 TRANS_FEAT(FCVTN, aa64_sme2, do_zz_fpst, a, 0,
-- 
2.43.0



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

* [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (15 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 16/21] target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors" Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-06-07 10:42   ` Zenghui Yu
  2026-05-29 11:47 ` [PULL 18/21] target/arm: advertise FEAT_RNG_TRAP on cortex-max Peter Maydell
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: Jason Wright <wrigjl@proton.me>

Add an .accessfn to the RNDR and RNDRRS system registers that traps
reads to EL3 when SCR_EL3.TRNDR is set, as required by FEAT_RNG_TRAP.
Mark SCR_EL3.TRNDR (bit 40) as a writable field in scr_write() when
the CPU advertises the feature. The pseudocode in DDI0487 revision M.b
shows the trap firing from EL0, EL1, EL2, and EL3, so there is no
check of arm_current_el().

When FEAT_RNG_TRAP is implemented without FEAT_RNG, an RNDR/RNDRRS read
with SCR_EL3.TRNDR=0 should UNDEF rather than succeed; handle that case
in access_rndr(). Register the rndr_reginfo CP reg entries whenever either
FEAT_RNG or FEAT_RNG_TRAP is implemented, so the accessfn fires even on a
FEAT_RNG_TRAP-only CPU.

When SCR_EL3.TRNDR is set, ID_AA64ISAR0_EL1.RNDR reads as 1 regardless
of whether FEAT_RNG is implemented; give ID_AA64ISAR0_EL1 a readfn so it
reports this at runtime, as we already do for ID_AA64PFR0_EL1.

Suggested-by: Richard Henderson <richard.henderson@linaro.org>
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Jason Wright <wrigjl@proton.me>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu-features.h |  5 ++++
 target/arm/helper.c       | 58 +++++++++++++++++++++++++++++++++++----
 2 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index 4e8d844fea..38a695ded7 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -908,6 +908,11 @@ static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id)
     return FIELD_EX64_IDREG(id, ID_AA64ISAR0, RNDR) != 0;
 }
 
+static inline bool isar_feature_aa64_rng_trap(const ARMISARegisters *id)
+{
+    return FIELD_EX64_IDREG(id, ID_AA64PFR1, RNDR_TRAP) != 0;
+}
+
 static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id)
 {
     return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TLB) == 2;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 34487eeaa3..9dd8fdfa41 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -790,6 +790,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
         if (cpu_isar_feature(aa64_fpmr, cpu)) {
             valid_mask |= SCR_ENFPM;
         }
+        if (cpu_isar_feature(aa64_rng_trap, cpu)) {
+            valid_mask |= SCR_TRNDR;
+        }
     } else {
         valid_mask &= ~(SCR_RW | SCR_ST);
         if (cpu_isar_feature(aa32_ras, cpu)) {
@@ -5170,6 +5173,21 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
     }
     return pfr0;
 }
+
+static uint64_t id_aa64isar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    ARMCPU *cpu = env_archcpu(env);
+    uint64_t isar0 = GET_IDREG(&cpu->isar, ID_AA64ISAR0);
+
+    /*
+     * When FEAT_RNG_TRAP is active (SCR_EL3.TRNDR set), ID_AA64ISAR0_EL1.RNDR
+     * reads as 1 regardless of whether FEAT_RNG is implemented.
+     */
+    if (env->cp15.scr_el3 & SCR_TRNDR) {
+        isar0 = FIELD_DP64(isar0, ID_AA64ISAR0, RNDR, 1);
+    }
+    return isar0;
+}
 #endif
 
 /*
@@ -5304,6 +5322,22 @@ static const ARMCPRegInfo pauth_reginfo[] = {
       .fieldoffset = offsetof(CPUARMState, keys.apib.hi) },
 };
 
+static CPAccessResult access_rndr(CPUARMState *env, const ARMCPRegInfo *ri,
+                                  bool isread)
+{
+    if (env->cp15.scr_el3 & SCR_TRNDR) {
+        return CP_ACCESS_TRAP_EL3;
+    }
+    /*
+     * Note that FEAT_RNG_TRAP may be implemented without FEAT_RNG.
+     * In that case, if the trap is not enabled, the read undefs.
+     */
+    if (!cpu_isar_feature(aa64_rndr, env_archcpu(env))) {
+        return CP_ACCESS_UNDEFINED;
+    }
+    return CP_ACCESS_OK;
+}
+
 static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
 {
     Error *err = NULL;
@@ -5335,11 +5369,11 @@ static const ARMCPRegInfo rndr_reginfo[] = {
     { .name = "RNDR", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
       .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 0,
-      .access = PL0_R, .readfn = rndr_readfn },
+      .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
     { .name = "RNDRRS", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
       .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1,
-      .access = PL0_R, .readfn = rndr_readfn },
+      .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
 };
 
 static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -6522,11 +6556,24 @@ void register_cp_regs_for_features(ARMCPU *cpu)
               .access = PL1_R, .type = ARM_CP_CONST,
               .accessfn = access_tid3,
               .resetvalue = 0 },
+            /*
+             * ID_AA64ISAR0_EL1 is not a plain ARM_CP_CONST in system
+             * emulation because the RNDR field depends on SCR_EL3.TRNDR
+             * at read time when FEAT_RNG_TRAP is implemented.
+             */
             { .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64,
               .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0,
-              .access = PL1_R, .type = ARM_CP_CONST,
+              .access = PL1_R,
+#ifdef CONFIG_USER_ONLY
+              .type = ARM_CP_CONST,
+              .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)
+#else
+              .type = ARM_CP_NO_RAW,
               .accessfn = access_tid3,
-              .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)},
+              .readfn = id_aa64isar0_read,
+              .writefn = arm_cp_write_ignore
+#endif
+            },
             { .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64,
               .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1,
               .access = PL1_R, .type = ARM_CP_CONST,
@@ -7454,7 +7501,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
     if (cpu_isar_feature(aa64_pauth, cpu)) {
         define_arm_cp_regs(cpu, pauth_reginfo);
     }
-    if (cpu_isar_feature(aa64_rndr, cpu)) {
+    if (cpu_isar_feature(aa64_rndr, cpu) ||
+        cpu_isar_feature(aa64_rng_trap, cpu)) {
         define_arm_cp_regs(cpu, rndr_reginfo);
     }
     /* Data Cache clean instructions up to PoP */
-- 
2.43.0



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

* [PULL 18/21] target/arm: advertise FEAT_RNG_TRAP on cortex-max
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (16 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 19/21] hw/dma/omap_dma: Remove unused ifdeffed out code Peter Maydell
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

From: Jason Wright <wrigjl@proton.me>

Set ID_AA64PFR1.RNDR_TRAP=1 on the max CPU model so guests and
firmware detect FEAT_RNG_TRAP, per the Arm Architecture Reference
Manual for A-profile architecture (DDI 0487), and document the feature
as emulated in docs/system/arm/emulation.rst.

Signed-off-by: Jason Wright <wrigjl@proton.me>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 docs/system/arm/emulation.rst | 1 +
 target/arm/tcg/cpu64.c        | 1 +
 2 files changed, 2 insertions(+)

diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index 37ca4e47b8..18c6355967 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -136,6 +136,7 @@ the following architecture extensions:
 - FEAT_RME (Realm Management Extension) (NB: support status in QEMU is experimental)
 - FEAT_RME_GPC2 (RME Granule Protection Check 2 Extension)
 - FEAT_RNG (Random number generator)
+- FEAT_RNG_TRAP (Trapping support for RNDR/RNDRRS)
 - FEAT_RPRES (Increased precision of FRECPE and FRSQRTE)
 - FEAT_S1PIE (Stage 1 permission indirections)
 - FEAT_S2PIE (Stage 2 permission indirections)
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index ce76e09d52..1a4f50486d 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1292,6 +1292,7 @@ void aarch64_max_tcg_initfn(Object *obj)
     t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3);       /* FEAT_MTE3 */
     t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0);  /* FEAT_RASv1p1 + FEAT_DoubleFault */
     t = FIELD_DP64(t, ID_AA64PFR1, SME, 2);       /* FEAT_SME2 */
+    t = FIELD_DP64(t, ID_AA64PFR1, RNDR_TRAP, 1); /* FEAT_RNG_TRAP */
     t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_3 */
     t = FIELD_DP64(t, ID_AA64PFR1, NMI, 1);       /* FEAT_NMI */
     t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1);       /* FEAT_GCS */
-- 
2.43.0



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

* [PULL 19/21] hw/dma/omap_dma: Remove unused ifdeffed out code
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (17 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 18/21] target/arm: advertise FEAT_RNG_TRAP on cortex-max Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 20/21] hw/dma/omap_dma: Fix coding style in omap_dma_transfer_setup() Peter Maydell
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

The OMAP DMA device includes a lot of code which has been disabled
via ifdefs for over a decade. Whatever this unfinished development
work was, all knowledge of it is long gone, and we're unlikely to
be doing any serious work on this device model in future. If we
did, we'd likely have to start from scratch.

Remove all the ifdeffed out code. We will fix up the indentation
in a followup commit that has only whitespace changes.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260528152852.3349928-2-peter.maydell@linaro.org
---
 hw/dma/omap_dma.c | 94 -----------------------------------------------
 1 file changed, 94 deletions(-)

diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c
index b042e7c59c..a93d9ad196 100644
--- a/hw/dma/omap_dma.c
+++ b/hw/dma/omap_dma.c
@@ -343,9 +343,6 @@ static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma)
     struct omap_dma_channel_s *ch = dma->opaque;
     struct omap_dma_reg_set_s *a = &ch->active_set;
     int bytes = dma->bytes;
-#ifdef MULTI_REQ
-    uint16_t status = ch->status;
-#endif
 
     do {
         /* Transfer a single element */
@@ -362,7 +359,6 @@ static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma)
         a->dest += a->elem_delta[1];
         a->element ++;
 
-#ifndef MULTI_REQ
         if (a->element == a->elements) {
             /* End of Frame */
             a->element = 0;
@@ -375,78 +371,6 @@ static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma)
                 ch->cpc = a->dest & 0xffff;
         }
     } while ((bytes -= ch->data_type));
-#else
-        /* If the channel is element synchronized, deactivate it */
-        if (ch->sync && !ch->fs && !ch->bs)
-            omap_dma_deactivate_channel(s, ch);
-
-        /* If it is the last frame, set the LAST_FRAME interrupt */
-        if (a->element == 1 && a->frame == a->frames - 1)
-            if (ch->interrupts & LAST_FRAME_INTR)
-                ch->status |= LAST_FRAME_INTR;
-
-        /* If the half of the frame was reached, set the HALF_FRAME
-           interrupt */
-        if (a->element == (a->elements >> 1))
-            if (ch->interrupts & HALF_FRAME_INTR)
-                ch->status |= HALF_FRAME_INTR;
-
-        if (ch->fs && ch->bs) {
-            a->pck_element ++;
-            /* Check if a full packet has been transferred.  */
-            if (a->pck_element == a->pck_elements) {
-                a->pck_element = 0;
-
-                /* Set the END_PKT interrupt */
-                if ((ch->interrupts & END_PKT_INTR) && !ch->src_sync)
-                    ch->status |= END_PKT_INTR;
-
-                /* If the channel is packet-synchronized, deactivate it */
-                if (ch->sync)
-                    omap_dma_deactivate_channel(s, ch);
-            }
-        }
-
-        if (a->element == a->elements) {
-            /* End of Frame */
-            a->element = 0;
-            a->src += a->frame_delta[0];
-            a->dest += a->frame_delta[1];
-            a->frame ++;
-
-            /* If the channel is frame synchronized, deactivate it */
-            if (ch->sync && ch->fs && !ch->bs)
-                omap_dma_deactivate_channel(s, ch);
-
-            /* If the channel is async, update cpc */
-            if (!ch->sync)
-                ch->cpc = a->dest & 0xffff;
-
-            /* Set the END_FRAME interrupt */
-            if (ch->interrupts & END_FRAME_INTR)
-                ch->status |= END_FRAME_INTR;
-
-            if (a->frame == a->frames) {
-                /* End of Block */
-                /* Disable the channel */
-
-                if (!ch->auto_init)
-                    omap_dma_disable_channel(s, ch);
-                else if (ch->repeat || ch->end_prog)
-                    omap_dma_channel_load(ch);
-                else {
-                    ch->waiting_end_prog = 1;
-                    omap_dma_deactivate_channel(s, ch);
-                }
-
-                if (ch->interrupts & END_BLOCK_INTR)
-                    ch->status |= END_BLOCK_INTR;
-            }
-        }
-    } while (status == ch->status && ch->active);
-
-    omap_dma_interrupts_update(s);
-#endif
 }
 
 enum {
@@ -475,13 +399,6 @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
     dest_p = &s->mpu->port[ch->port[1]];
     if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) ||
                     (!dest_p->addr_valid(s->mpu, a->dest))) {
-#if 0
-        /* Bus time-out */
-        if (ch->interrupts & TIMEOUT_INTR)
-            ch->status |= TIMEOUT_INTR;
-        omap_dma_deactivate_channel(s, ch);
-        continue;
-#endif
         printf("%s: Bus time-out in DMA%i operation\n",
                         __func__, dma->num);
     }
@@ -552,11 +469,6 @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
 
     /* Set appropriate interrupts and/or deactivate channels */
 
-#ifdef MULTI_REQ
-    /* TODO: should all of this only be done if dma->update, and otherwise
-     * inside omap_dma_transfer_generic below - check what's faster.  */
-    if (dma->update) {
-#endif
 
         /* If the channel is element synchronized, deactivate it */
         if (min_elems == elements[omap_dma_intr_element_sync])
@@ -612,9 +524,7 @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
 
         /* TODO: check if we really need to update anything here or perhaps we
          * can skip part of this.  */
-#ifndef MULTI_REQ
         if (dma->update) {
-#endif
             a->element += min_elems;
 
             frames = a->element / a->elements;
@@ -629,11 +539,7 @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
 
             /* TODO: if the destination port is IMIF or EMIFF, set the dirty
              * bits on it.  */
-#ifndef MULTI_REQ
         }
-#else
-    }
-#endif
 
     omap_dma_interrupts_update(s);
 }
-- 
2.43.0



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

* [PULL 20/21] hw/dma/omap_dma: Fix coding style in omap_dma_transfer_setup()
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (18 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 19/21] hw/dma/omap_dma: Remove unused ifdeffed out code Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 11:47 ` [PULL 21/21] hw/dma/omap_dma: Fix indentation after ifdef removal Peter Maydell
  2026-05-29 19:49 ` [PULL 00/21] target-arm queue Stefan Hajnoczi
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

We're about to fix indent in a section of the
omap_dma_transfer_setup() function, which will make checkpatch
complain.  Since we're touching the code anyway, fix the uses of if()
with no braces and wrongly formatted multiline comments.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20260528152852.3349928-3-peter.maydell@linaro.org
---
 hw/dma/omap_dma.c | 51 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c
index a93d9ad196..b8bbb707c4 100644
--- a/hw/dma/omap_dma.c
+++ b/hw/dma/omap_dma.c
@@ -471,49 +471,59 @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
 
 
         /* If the channel is element synchronized, deactivate it */
-        if (min_elems == elements[omap_dma_intr_element_sync])
+        if (min_elems == elements[omap_dma_intr_element_sync]) {
             omap_dma_deactivate_channel(s, ch);
+        }
 
         /* If it is the last frame, set the LAST_FRAME interrupt */
-        if (min_elems == elements[omap_dma_intr_last_frame])
+        if (min_elems == elements[omap_dma_intr_last_frame]) {
             ch->status |= LAST_FRAME_INTR;
+        }
 
-        /* If exactly half of the frame was reached, set the HALF_FRAME
-           interrupt */
-        if (min_elems == elements[omap_dma_intr_half_frame])
+        /*
+         * If exactly half of the frame was reached, set the HALF_FRAME
+         * interrupt
+         */
+        if (min_elems == elements[omap_dma_intr_half_frame]) {
             ch->status |= HALF_FRAME_INTR;
+        }
 
         /* If a full packet has been transferred, set the END_PKT interrupt */
-        if (min_elems == elements[omap_dma_intr_packet])
+        if (min_elems == elements[omap_dma_intr_packet]) {
             ch->status |= END_PKT_INTR;
+        }
 
         /* If the channel is packet-synchronized, deactivate it */
-        if (min_elems == elements[omap_dma_intr_packet_sync])
+        if (min_elems == elements[omap_dma_intr_packet_sync]) {
             omap_dma_deactivate_channel(s, ch);
+        }
 
         /* If the channel is frame synchronized, deactivate it */
-        if (min_elems == elements[omap_dma_intr_frame_sync])
+        if (min_elems == elements[omap_dma_intr_frame_sync]) {
             omap_dma_deactivate_channel(s, ch);
+        }
 
         /* Set the END_FRAME interrupt */
-        if (min_elems == elements[omap_dma_intr_frame])
+        if (min_elems == elements[omap_dma_intr_frame]) {
             ch->status |= END_FRAME_INTR;
+        }
 
         if (min_elems == elements[omap_dma_intr_block]) {
             /* End of Block */
             /* Disable the channel */
 
-            if (!ch->auto_init)
+            if (!ch->auto_init) {
                 omap_dma_disable_channel(s, ch);
-            else if (ch->repeat || ch->end_prog)
+            } else if (ch->repeat || ch->end_prog) {
                 omap_dma_channel_load(ch);
-            else {
+            } else {
                 ch->waiting_end_prog = 1;
                 omap_dma_deactivate_channel(s, ch);
             }
 
-            if (ch->interrupts & END_BLOCK_INTR)
+            if (ch->interrupts & END_BLOCK_INTR) {
                 ch->status |= END_BLOCK_INTR;
+            }
         }
 
         /* Update packet number */
@@ -522,8 +532,10 @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
             a->pck_element %= a->pck_elements;
         }
 
-        /* TODO: check if we really need to update anything here or perhaps we
-         * can skip part of this.  */
+        /*
+         * TODO: check if we really need to update anything here or perhaps we
+         * can skip part of this.
+         */
         if (dma->update) {
             a->element += min_elems;
 
@@ -534,11 +546,14 @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
             a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1];
 
             /* If the channel is async, update cpc */
-            if (!ch->sync && frames)
+            if (!ch->sync && frames) {
                 ch->cpc = a->dest & 0xffff;
+            }
 
-            /* TODO: if the destination port is IMIF or EMIFF, set the dirty
-             * bits on it.  */
+            /*
+             * TODO: if the destination port is IMIF or EMIFF, set the dirty
+             * bits on it.
+             */
         }
 
     omap_dma_interrupts_update(s);
-- 
2.43.0



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

* [PULL 21/21] hw/dma/omap_dma: Fix indentation after ifdef removal
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (19 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 20/21] hw/dma/omap_dma: Fix coding style in omap_dma_transfer_setup() Peter Maydell
@ 2026-05-29 11:47 ` Peter Maydell
  2026-05-29 19:49 ` [PULL 00/21] target-arm queue Stefan Hajnoczi
  21 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-05-29 11:47 UTC (permalink / raw)
  To: qemu-devel

Some of the ifdefs in omap_dma_transfer_setup() which we just
removed had if() blocks in them. Now that the code inside them
is always unconditional it has an extra unnecessary layer of
indentation; fix this, as a whitespace only change.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20260528152852.3349928-4-peter.maydell@linaro.org
---
 hw/dma/omap_dma.c | 156 +++++++++++++++++++++++-----------------------
 1 file changed, 78 insertions(+), 78 deletions(-)

diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c
index b8bbb707c4..668fc49054 100644
--- a/hw/dma/omap_dma.c
+++ b/hw/dma/omap_dma.c
@@ -470,91 +470,91 @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
     /* Set appropriate interrupts and/or deactivate channels */
 
 
-        /* If the channel is element synchronized, deactivate it */
-        if (min_elems == elements[omap_dma_intr_element_sync]) {
+    /* If the channel is element synchronized, deactivate it */
+    if (min_elems == elements[omap_dma_intr_element_sync]) {
+        omap_dma_deactivate_channel(s, ch);
+    }
+
+    /* If it is the last frame, set the LAST_FRAME interrupt */
+    if (min_elems == elements[omap_dma_intr_last_frame]) {
+        ch->status |= LAST_FRAME_INTR;
+    }
+
+    /*
+     * If exactly half of the frame was reached, set the HALF_FRAME
+     * interrupt
+     */
+    if (min_elems == elements[omap_dma_intr_half_frame]) {
+        ch->status |= HALF_FRAME_INTR;
+    }
+
+    /* If a full packet has been transferred, set the END_PKT interrupt */
+    if (min_elems == elements[omap_dma_intr_packet]) {
+        ch->status |= END_PKT_INTR;
+    }
+
+    /* If the channel is packet-synchronized, deactivate it */
+    if (min_elems == elements[omap_dma_intr_packet_sync]) {
+        omap_dma_deactivate_channel(s, ch);
+    }
+
+    /* If the channel is frame synchronized, deactivate it */
+    if (min_elems == elements[omap_dma_intr_frame_sync]) {
+        omap_dma_deactivate_channel(s, ch);
+    }
+
+    /* Set the END_FRAME interrupt */
+    if (min_elems == elements[omap_dma_intr_frame]) {
+        ch->status |= END_FRAME_INTR;
+    }
+
+    if (min_elems == elements[omap_dma_intr_block]) {
+        /* End of Block */
+        /* Disable the channel */
+
+        if (!ch->auto_init) {
+            omap_dma_disable_channel(s, ch);
+        } else if (ch->repeat || ch->end_prog) {
+            omap_dma_channel_load(ch);
+        } else {
+            ch->waiting_end_prog = 1;
             omap_dma_deactivate_channel(s, ch);
         }
 
-        /* If it is the last frame, set the LAST_FRAME interrupt */
-        if (min_elems == elements[omap_dma_intr_last_frame]) {
-            ch->status |= LAST_FRAME_INTR;
+        if (ch->interrupts & END_BLOCK_INTR) {
+            ch->status |= END_BLOCK_INTR;
+        }
+    }
+
+    /* Update packet number */
+    if (ch->fs && ch->bs) {
+        a->pck_element += min_elems;
+        a->pck_element %= a->pck_elements;
+    }
+
+    /*
+     * TODO: check if we really need to update anything here or perhaps we
+     * can skip part of this.
+     */
+    if (dma->update) {
+        a->element += min_elems;
+
+        frames = a->element / a->elements;
+        a->element = a->element % a->elements;
+        a->frame += frames;
+        a->src += min_elems * a->elem_delta[0] + frames * a->frame_delta[0];
+        a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1];
+
+        /* If the channel is async, update cpc */
+        if (!ch->sync && frames) {
+            ch->cpc = a->dest & 0xffff;
         }
 
         /*
-         * If exactly half of the frame was reached, set the HALF_FRAME
-         * interrupt
+         * TODO: if the destination port is IMIF or EMIFF, set the dirty
+         * bits on it.
          */
-        if (min_elems == elements[omap_dma_intr_half_frame]) {
-            ch->status |= HALF_FRAME_INTR;
-        }
-
-        /* If a full packet has been transferred, set the END_PKT interrupt */
-        if (min_elems == elements[omap_dma_intr_packet]) {
-            ch->status |= END_PKT_INTR;
-        }
-
-        /* If the channel is packet-synchronized, deactivate it */
-        if (min_elems == elements[omap_dma_intr_packet_sync]) {
-            omap_dma_deactivate_channel(s, ch);
-        }
-
-        /* If the channel is frame synchronized, deactivate it */
-        if (min_elems == elements[omap_dma_intr_frame_sync]) {
-            omap_dma_deactivate_channel(s, ch);
-        }
-
-        /* Set the END_FRAME interrupt */
-        if (min_elems == elements[omap_dma_intr_frame]) {
-            ch->status |= END_FRAME_INTR;
-        }
-
-        if (min_elems == elements[omap_dma_intr_block]) {
-            /* End of Block */
-            /* Disable the channel */
-
-            if (!ch->auto_init) {
-                omap_dma_disable_channel(s, ch);
-            } else if (ch->repeat || ch->end_prog) {
-                omap_dma_channel_load(ch);
-            } else {
-                ch->waiting_end_prog = 1;
-                omap_dma_deactivate_channel(s, ch);
-            }
-
-            if (ch->interrupts & END_BLOCK_INTR) {
-                ch->status |= END_BLOCK_INTR;
-            }
-        }
-
-        /* Update packet number */
-        if (ch->fs && ch->bs) {
-            a->pck_element += min_elems;
-            a->pck_element %= a->pck_elements;
-        }
-
-        /*
-         * TODO: check if we really need to update anything here or perhaps we
-         * can skip part of this.
-         */
-        if (dma->update) {
-            a->element += min_elems;
-
-            frames = a->element / a->elements;
-            a->element = a->element % a->elements;
-            a->frame += frames;
-            a->src += min_elems * a->elem_delta[0] + frames * a->frame_delta[0];
-            a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1];
-
-            /* If the channel is async, update cpc */
-            if (!ch->sync && frames) {
-                ch->cpc = a->dest & 0xffff;
-            }
-
-            /*
-             * TODO: if the destination port is IMIF or EMIFF, set the dirty
-             * bits on it.
-             */
-        }
+    }
 
     omap_dma_interrupts_update(s);
 }
-- 
2.43.0



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

* Re: [PULL 00/21] target-arm queue
  2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
                   ` (20 preceding siblings ...)
  2026-05-29 11:47 ` [PULL 21/21] hw/dma/omap_dma: Fix indentation after ifdef removal Peter Maydell
@ 2026-05-29 19:49 ` Stefan Hajnoczi
  21 siblings, 0 replies; 30+ messages in thread
From: Stefan Hajnoczi @ 2026-05-29 19:49 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 116 bytes --]

Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/11.1 for any user-visible changes.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS
  2026-05-29 11:47 ` [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS Peter Maydell
@ 2026-06-07 10:42   ` Zenghui Yu
  2026-06-07 18:04     ` Jason L. Wright'
  2026-06-07 18:22     ` [PATCH] target/arm/hvf: manually sync ID_AA64ISAR0_EL1 on vCPU init Jason Wright
  0 siblings, 2 replies; 30+ messages in thread
From: Zenghui Yu @ 2026-06-07 10:42 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-devel, Alexander Graf, qemu-arm

+ Alexander and qemu-arm (for HVF/arm),

On 5/29/26 7:47 PM, Peter Maydell wrote:
> From: Jason Wright <wrigjl@proton.me>
> 
> Add an .accessfn to the RNDR and RNDRRS system registers that traps
> reads to EL3 when SCR_EL3.TRNDR is set, as required by FEAT_RNG_TRAP.
> Mark SCR_EL3.TRNDR (bit 40) as a writable field in scr_write() when
> the CPU advertises the feature. The pseudocode in DDI0487 revision M.b
> shows the trap firing from EL0, EL1, EL2, and EL3, so there is no
> check of arm_current_el().
> 
> When FEAT_RNG_TRAP is implemented without FEAT_RNG, an RNDR/RNDRRS read
> with SCR_EL3.TRNDR=0 should UNDEF rather than succeed; handle that case
> in access_rndr(). Register the rndr_reginfo CP reg entries whenever either
> FEAT_RNG or FEAT_RNG_TRAP is implemented, so the accessfn fires even on a
> FEAT_RNG_TRAP-only CPU.
> 
> When SCR_EL3.TRNDR is set, ID_AA64ISAR0_EL1.RNDR reads as 1 regardless
> of whether FEAT_RNG is implemented; give ID_AA64ISAR0_EL1 a readfn so it
> reports this at runtime, as we already do for ID_AA64PFR0_EL1.
> 
> Suggested-by: Richard Henderson <richard.henderson@linaro.org>
> Suggested-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Jason Wright <wrigjl@proton.me>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target/arm/cpu-features.h |  5 ++++
>  target/arm/helper.c       | 58 +++++++++++++++++++++++++++++++++++----
>  2 files changed, 58 insertions(+), 5 deletions(-)
> 
> diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
> index 4e8d844fea..38a695ded7 100644
> --- a/target/arm/cpu-features.h
> +++ b/target/arm/cpu-features.h
> @@ -908,6 +908,11 @@ static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id)
>      return FIELD_EX64_IDREG(id, ID_AA64ISAR0, RNDR) != 0;
>  }
>  
> +static inline bool isar_feature_aa64_rng_trap(const ARMISARegisters *id)
> +{
> +    return FIELD_EX64_IDREG(id, ID_AA64PFR1, RNDR_TRAP) != 0;
> +}
> +
>  static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id)
>  {
>      return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TLB) == 2;
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 34487eeaa3..9dd8fdfa41 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -790,6 +790,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>          if (cpu_isar_feature(aa64_fpmr, cpu)) {
>              valid_mask |= SCR_ENFPM;
>          }
> +        if (cpu_isar_feature(aa64_rng_trap, cpu)) {
> +            valid_mask |= SCR_TRNDR;
> +        }
>      } else {
>          valid_mask &= ~(SCR_RW | SCR_ST);
>          if (cpu_isar_feature(aa32_ras, cpu)) {
> @@ -5170,6 +5173,21 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
>      }
>      return pfr0;
>  }
> +
> +static uint64_t id_aa64isar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    ARMCPU *cpu = env_archcpu(env);
> +    uint64_t isar0 = GET_IDREG(&cpu->isar, ID_AA64ISAR0);
> +
> +    /*
> +     * When FEAT_RNG_TRAP is active (SCR_EL3.TRNDR set), ID_AA64ISAR0_EL1.RNDR
> +     * reads as 1 regardless of whether FEAT_RNG is implemented.
> +     */
> +    if (env->cp15.scr_el3 & SCR_TRNDR) {
> +        isar0 = FIELD_DP64(isar0, ID_AA64ISAR0, RNDR, 1);
> +    }
> +    return isar0;
> +}
>  #endif
>  
>  /*
> @@ -5304,6 +5322,22 @@ static const ARMCPRegInfo pauth_reginfo[] = {
>        .fieldoffset = offsetof(CPUARMState, keys.apib.hi) },
>  };
>  
> +static CPAccessResult access_rndr(CPUARMState *env, const ARMCPRegInfo *ri,
> +                                  bool isread)
> +{
> +    if (env->cp15.scr_el3 & SCR_TRNDR) {
> +        return CP_ACCESS_TRAP_EL3;
> +    }
> +    /*
> +     * Note that FEAT_RNG_TRAP may be implemented without FEAT_RNG.
> +     * In that case, if the trap is not enabled, the read undefs.
> +     */
> +    if (!cpu_isar_feature(aa64_rndr, env_archcpu(env))) {
> +        return CP_ACCESS_UNDEFINED;
> +    }
> +    return CP_ACCESS_OK;
> +}
> +
>  static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
>  {
>      Error *err = NULL;
> @@ -5335,11 +5369,11 @@ static const ARMCPRegInfo rndr_reginfo[] = {
>      { .name = "RNDR", .state = ARM_CP_STATE_AA64,
>        .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
>        .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 0,
> -      .access = PL0_R, .readfn = rndr_readfn },
> +      .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
>      { .name = "RNDRRS", .state = ARM_CP_STATE_AA64,
>        .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
>        .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1,
> -      .access = PL0_R, .readfn = rndr_readfn },
> +      .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
>  };
>  
>  static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *ri,
> @@ -6522,11 +6556,24 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>                .access = PL1_R, .type = ARM_CP_CONST,
>                .accessfn = access_tid3,
>                .resetvalue = 0 },
> +            /*
> +             * ID_AA64ISAR0_EL1 is not a plain ARM_CP_CONST in system
> +             * emulation because the RNDR field depends on SCR_EL3.TRNDR
> +             * at read time when FEAT_RNG_TRAP is implemented.
> +             */
>              { .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64,
>                .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0,
> -              .access = PL1_R, .type = ARM_CP_CONST,
> +              .access = PL1_R,
> +#ifdef CONFIG_USER_ONLY
> +              .type = ARM_CP_CONST,
> +              .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)
> +#else
> +              .type = ARM_CP_NO_RAW,
>                .accessfn = access_tid3,
> -              .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)},
> +              .readfn = id_aa64isar0_read,
> +              .writefn = arm_cp_write_ignore
> +#endif
> +            },

A new assert() was triggered when booting guest on M1 since this change:

Assertion failed: (!(ri->type & ARM_CP_NO_RAW)), function hvf_arch_init_vcpu, file hvf.c, line 1442.

Thanks,
Zenghui

>              { .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64,
>                .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1,
>                .access = PL1_R, .type = ARM_CP_CONST,
> @@ -7454,7 +7501,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>      if (cpu_isar_feature(aa64_pauth, cpu)) {
>          define_arm_cp_regs(cpu, pauth_reginfo);
>      }
> -    if (cpu_isar_feature(aa64_rndr, cpu)) {
> +    if (cpu_isar_feature(aa64_rndr, cpu) ||
> +        cpu_isar_feature(aa64_rng_trap, cpu)) {
>          define_arm_cp_regs(cpu, rndr_reginfo);
>      }
>      /* Data Cache clean instructions up to PoP */


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

* Re: [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS
  2026-06-07 10:42   ` Zenghui Yu
@ 2026-06-07 18:04     ` Jason L. Wright'
  2026-06-08  8:57       ` Alex Bennée
  2026-06-07 18:22     ` [PATCH] target/arm/hvf: manually sync ID_AA64ISAR0_EL1 on vCPU init Jason Wright
  1 sibling, 1 reply; 30+ messages in thread
From: Jason L. Wright' @ 2026-06-07 18:04 UTC (permalink / raw)
  To: Zenghui Yu; +Cc: Peter Maydell, qemu-devel, Alexander Graf, qemu-arm

On Sun, Jun 07, 2026 at 06:42:30PM +0800, Zenghui Yu wrote:
> + Alexander and qemu-arm (for HVF/arm),
> 
> On 5/29/26 7:47 PM, Peter Maydell wrote:
> > From: Jason Wright <wrigjl@proton.me>
> >
> > Add an .accessfn to the RNDR and RNDRRS system registers that traps
> > reads to EL3 when SCR_EL3.TRNDR is set, as required by FEAT_RNG_TRAP.
> > Mark SCR_EL3.TRNDR (bit 40) as a writable field in scr_write() when
> > the CPU advertises the feature. The pseudocode in DDI0487 revision M.b
> > shows the trap firing from EL0, EL1, EL2, and EL3, so there is no
> > check of arm_current_el().
> >
> > When FEAT_RNG_TRAP is implemented without FEAT_RNG, an RNDR/RNDRRS read
> > with SCR_EL3.TRNDR=0 should UNDEF rather than succeed; handle that case
> > in access_rndr(). Register the rndr_reginfo CP reg entries whenever either
> > FEAT_RNG or FEAT_RNG_TRAP is implemented, so the accessfn fires even on a
> > FEAT_RNG_TRAP-only CPU.
> >
> > When SCR_EL3.TRNDR is set, ID_AA64ISAR0_EL1.RNDR reads as 1 regardless
> > of whether FEAT_RNG is implemented; give ID_AA64ISAR0_EL1 a readfn so it
> > reports this at runtime, as we already do for ID_AA64PFR0_EL1.
> >
> > Suggested-by: Richard Henderson <richard.henderson@linaro.org>
> > Suggested-by: Peter Maydell <peter.maydell@linaro.org>
> > Signed-off-by: Jason Wright <wrigjl@proton.me>
> > Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> > ---
> >  target/arm/cpu-features.h |  5 ++++
> >  target/arm/helper.c       | 58 +++++++++++++++++++++++++++++++++++----
> >  2 files changed, 58 insertions(+), 5 deletions(-)
> >
> > diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
> > index 4e8d844fea..38a695ded7 100644
> > --- a/target/arm/cpu-features.h
> > +++ b/target/arm/cpu-features.h
> > @@ -908,6 +908,11 @@ static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id)
> >      return FIELD_EX64_IDREG(id, ID_AA64ISAR0, RNDR) != 0;
> >  }
> >
> > +static inline bool isar_feature_aa64_rng_trap(const ARMISARegisters *id)
> > +{
> > +    return FIELD_EX64_IDREG(id, ID_AA64PFR1, RNDR_TRAP) != 0;
> > +}
> > +
> >  static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id)
> >  {
> >      return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TLB) == 2;
> > diff --git a/target/arm/helper.c b/target/arm/helper.c
> > index 34487eeaa3..9dd8fdfa41 100644
> > --- a/target/arm/helper.c
> > +++ b/target/arm/helper.c
> > @@ -790,6 +790,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
> >          if (cpu_isar_feature(aa64_fpmr, cpu)) {
> >              valid_mask |= SCR_ENFPM;
> >          }
> > +        if (cpu_isar_feature(aa64_rng_trap, cpu)) {
> > +            valid_mask |= SCR_TRNDR;
> > +        }
> >      } else {
> >          valid_mask &= ~(SCR_RW | SCR_ST);
> >          if (cpu_isar_feature(aa32_ras, cpu)) {
> > @@ -5170,6 +5173,21 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
> >      }
> >      return pfr0;
> >  }
> > +
> > +static uint64_t id_aa64isar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
> > +{
> > +    ARMCPU *cpu = env_archcpu(env);
> > +    uint64_t isar0 = GET_IDREG(&cpu->isar, ID_AA64ISAR0);
> > +
> > +    /*
> > +     * When FEAT_RNG_TRAP is active (SCR_EL3.TRNDR set), ID_AA64ISAR0_EL1.RNDR
> > +     * reads as 1 regardless of whether FEAT_RNG is implemented.
> > +     */
> > +    if (env->cp15.scr_el3 & SCR_TRNDR) {
> > +        isar0 = FIELD_DP64(isar0, ID_AA64ISAR0, RNDR, 1);
> > +    }
> > +    return isar0;
> > +}
> >  #endif
> >
> >  /*
> > @@ -5304,6 +5322,22 @@ static const ARMCPRegInfo pauth_reginfo[] = {
> >        .fieldoffset = offsetof(CPUARMState, keys.apib.hi) },
> >  };
> >
> > +static CPAccessResult access_rndr(CPUARMState *env, const ARMCPRegInfo *ri,
> > +                                  bool isread)
> > +{
> > +    if (env->cp15.scr_el3 & SCR_TRNDR) {
> > +        return CP_ACCESS_TRAP_EL3;
> > +    }
> > +    /*
> > +     * Note that FEAT_RNG_TRAP may be implemented without FEAT_RNG.
> > +     * In that case, if the trap is not enabled, the read undefs.
> > +     */
> > +    if (!cpu_isar_feature(aa64_rndr, env_archcpu(env))) {
> > +        return CP_ACCESS_UNDEFINED;
> > +    }
> > +    return CP_ACCESS_OK;
> > +}
> > +
> >  static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
> >  {
> >      Error *err = NULL;
> > @@ -5335,11 +5369,11 @@ static const ARMCPRegInfo rndr_reginfo[] = {
> >      { .name = "RNDR", .state = ARM_CP_STATE_AA64,
> >        .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
> >        .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 0,
> > -      .access = PL0_R, .readfn = rndr_readfn },
> > +      .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
> >      { .name = "RNDRRS", .state = ARM_CP_STATE_AA64,
> >        .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
> >        .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1,
> > -      .access = PL0_R, .readfn = rndr_readfn },
> > +      .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
> >  };
> >
> >  static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *ri,
> > @@ -6522,11 +6556,24 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> >                .access = PL1_R, .type = ARM_CP_CONST,
> >                .accessfn = access_tid3,
> >                .resetvalue = 0 },
> > +            /*
> > +             * ID_AA64ISAR0_EL1 is not a plain ARM_CP_CONST in system
> > +             * emulation because the RNDR field depends on SCR_EL3.TRNDR
> > +             * at read time when FEAT_RNG_TRAP is implemented.
> > +             */
> >              { .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64,
> >                .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0,
> > -              .access = PL1_R, .type = ARM_CP_CONST,
> > +              .access = PL1_R,
> > +#ifdef CONFIG_USER_ONLY
> > +              .type = ARM_CP_CONST,
> > +              .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)
> > +#else
> > +              .type = ARM_CP_NO_RAW,
> >                .accessfn = access_tid3,
> > -              .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)},
> > +              .readfn = id_aa64isar0_read,
> > +              .writefn = arm_cp_write_ignore
> > +#endif
> > +            },
> 
> A new assert() was triggered when booting guest on M1 since this change:
> 
> Assertion failed: (!(ri->type & ARM_CP_NO_RAW)), function hvf_arch_init_vcpu, file hvf.c, line 1442.
> 
> Thanks,
> Zenghui
> 
Thanks for the report and the bisect, Zenghui. I can reproduce on M1 with:

qemu-system-aarch64 -M virt,accel=hvf -cpu host \
                      -nographic -display none -bios /dev/null

ID_AA64PFR0_EL1 has the same NO_RAW + readfn shape that the FEAT_RNG_TRAP
change gave ID_AA64ISAR0_EL1, and HVF already accommodates it by listing
the cpreg in the SYNC_NO_RAW_REGS block in target/arm/hvf/sysreg.c.inc
(so the assert loop skips it) and pushing QEMU's value to the vCPU at
init time. Mirroring that pattern for ID_AA64ISAR0_EL1 clears the assert
without disturbing the readfn semantics that the spec requires if a
FEAT_RNG_TRAP-only CPU eventually appears.

I'll send a fix-up as [PATCH] target/arm/hvf shortly.



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

* [PATCH] target/arm/hvf: manually sync ID_AA64ISAR0_EL1 on vCPU init
  2026-06-07 10:42   ` Zenghui Yu
  2026-06-07 18:04     ` Jason L. Wright'
@ 2026-06-07 18:22     ` Jason Wright
  2026-06-08 13:07       ` Peter Maydell
  1 sibling, 1 reply; 30+ messages in thread
From: Jason Wright @ 2026-06-07 18:22 UTC (permalink / raw)
  To: agraf, peter.maydell; +Cc: qemu-arm, qemu-devel, zenghui.yu, richard.henderson

Commit 887eaa8a29 ("target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS")
gave ID_AA64ISAR0_EL1 a readfn so the RNDR field can reflect SCR_EL3.TRNDR
at read time, and marked the cpreg ARM_CP_NO_RAW in the system-emulation
path.  HVF then trips its hvf_arch_init_vcpu() assertion that no ID
register in hvf_sreg_list[] is NO_RAW, aborting on boot on Apple Silicon:

  Assertion failed: (!(ri->type & ARM_CP_NO_RAW)),
  function hvf_arch_init_vcpu, file hvf.c, line 1442.

Reproduce with:

  qemu-system-aarch64 -M virt,accel=hvf -cpu host \
                      -nographic -display none -bios /dev/null

Mirror the existing treatment of ID_AA64PFR0_EL1: move
HV_SYS_REG_ID_AA64ISAR0_EL1 into the SYNC_NO_RAW_REGS block in
sysreg.c.inc so the assert loop skips it, and push QEMU's view of the
register to the vCPU at init time.  HVF does not expose EL3, so
SCR_EL3.TRNDR is never set and the readfn is functionally static there.

Reported-by: Zenghui Yu <zenghui.yu@linux.dev>
Fixes: 887eaa8a29 ("target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS")
Signed-off-by: Jason Wright <wrigjl@proton.me>
---
 target/arm/hvf/hvf.c        | 4 ++++
 target/arm/hvf/sysreg.c.inc | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index d88cbe7c82..afa1120c8a 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1485,6 +1485,10 @@ int hvf_arch_init_vcpu(CPUState *cpu)
     ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64PFR0_EL1, pfr);
     assert_hvf_ok(ret);
 
+    ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64ISAR0_EL1,
+                              GET_IDREG(&arm_cpu->isar, ID_AA64ISAR0));
+    assert_hvf_ok(ret);
+
     /* We're limited to underlying hardware caps, override internal versions */
     ret = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64MMFR0_EL1,
                               &arm_cpu->isar.idregs[ID_AA64MMFR0_EL1_IDX]);
diff --git a/target/arm/hvf/sysreg.c.inc b/target/arm/hvf/sysreg.c.inc
index c11dbf274e..acd5a41364 100644
--- a/target/arm/hvf/sysreg.c.inc
+++ b/target/arm/hvf/sysreg.c.inc
@@ -89,13 +89,13 @@ 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)
+DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0)
 #endif
 
 DEF_SYSREG(HV_SYS_REG_ID_AA64PFR1_EL1, 3, 0, 0, 4, 1)
 /* Add ID_AA64PFR2_EL1 here when HVF supports it */
 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
-- 
2.50.1 (Apple Git-155)




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

* Re: [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS
  2026-06-07 18:04     ` Jason L. Wright'
@ 2026-06-08  8:57       ` Alex Bennée
  0 siblings, 0 replies; 30+ messages in thread
From: Alex Bennée @ 2026-06-08  8:57 UTC (permalink / raw)
  To: Jason L. Wright'
  Cc: Zenghui Yu, Peter Maydell, qemu-devel, Alexander Graf, qemu-arm,
	Philippe Mathieu-Daudé, Mark Burton

"Jason L. Wright'" <wrigjl@proton.me> writes:

> On Sun, Jun 07, 2026 at 06:42:30PM +0800, Zenghui Yu wrote:
>> + Alexander and qemu-arm (for HVF/arm),
>> 
>> On 5/29/26 7:47 PM, Peter Maydell wrote:
>> > From: Jason Wright <wrigjl@proton.me>
>> >
>> > Add an .accessfn to the RNDR and RNDRRS system registers that traps
>> > reads to EL3 when SCR_EL3.TRNDR is set, as required by FEAT_RNG_TRAP.
>> > Mark SCR_EL3.TRNDR (bit 40) as a writable field in scr_write() when
>> > the CPU advertises the feature. The pseudocode in DDI0487 revision M.b
>> > shows the trap firing from EL0, EL1, EL2, and EL3, so there is no
>> > check of arm_current_el().
>> >
>> > When FEAT_RNG_TRAP is implemented without FEAT_RNG, an RNDR/RNDRRS read
>> > with SCR_EL3.TRNDR=0 should UNDEF rather than succeed; handle that case
>> > in access_rndr(). Register the rndr_reginfo CP reg entries whenever either
>> > FEAT_RNG or FEAT_RNG_TRAP is implemented, so the accessfn fires even on a
>> > FEAT_RNG_TRAP-only CPU.
>> >
>> > When SCR_EL3.TRNDR is set, ID_AA64ISAR0_EL1.RNDR reads as 1 regardless
>> > of whether FEAT_RNG is implemented; give ID_AA64ISAR0_EL1 a readfn so it
>> > reports this at runtime, as we already do for ID_AA64PFR0_EL1.
>> >
>> > Suggested-by: Richard Henderson <richard.henderson@linaro.org>
>> > Suggested-by: Peter Maydell <peter.maydell@linaro.org>
>> > Signed-off-by: Jason Wright <wrigjl@proton.me>
>> > Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
>> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> > ---
>> >  target/arm/cpu-features.h |  5 ++++
>> >  target/arm/helper.c       | 58 +++++++++++++++++++++++++++++++++++----
>> >  2 files changed, 58 insertions(+), 5 deletions(-)
>> >
>> > diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
>> > index 4e8d844fea..38a695ded7 100644
>> > --- a/target/arm/cpu-features.h
>> > +++ b/target/arm/cpu-features.h
>> > @@ -908,6 +908,11 @@ static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id)
>> >      return FIELD_EX64_IDREG(id, ID_AA64ISAR0, RNDR) != 0;
>> >  }
>> >
>> > +static inline bool isar_feature_aa64_rng_trap(const ARMISARegisters *id)
>> > +{
>> > +    return FIELD_EX64_IDREG(id, ID_AA64PFR1, RNDR_TRAP) != 0;
>> > +}
>> > +
>> >  static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id)
>> >  {
>> >      return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TLB) == 2;
>> > diff --git a/target/arm/helper.c b/target/arm/helper.c
>> > index 34487eeaa3..9dd8fdfa41 100644
>> > --- a/target/arm/helper.c
>> > +++ b/target/arm/helper.c
>> > @@ -790,6 +790,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>> >          if (cpu_isar_feature(aa64_fpmr, cpu)) {
>> >              valid_mask |= SCR_ENFPM;
>> >          }
>> > +        if (cpu_isar_feature(aa64_rng_trap, cpu)) {
>> > +            valid_mask |= SCR_TRNDR;
>> > +        }
>> >      } else {
>> >          valid_mask &= ~(SCR_RW | SCR_ST);
>> >          if (cpu_isar_feature(aa32_ras, cpu)) {
>> > @@ -5170,6 +5173,21 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
>> >      }
>> >      return pfr0;
>> >  }
>> > +
>> > +static uint64_t id_aa64isar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
>> > +{
>> > +    ARMCPU *cpu = env_archcpu(env);
>> > +    uint64_t isar0 = GET_IDREG(&cpu->isar, ID_AA64ISAR0);
>> > +
>> > +    /*
>> > +     * When FEAT_RNG_TRAP is active (SCR_EL3.TRNDR set), ID_AA64ISAR0_EL1.RNDR
>> > +     * reads as 1 regardless of whether FEAT_RNG is implemented.
>> > +     */
>> > +    if (env->cp15.scr_el3 & SCR_TRNDR) {
>> > +        isar0 = FIELD_DP64(isar0, ID_AA64ISAR0, RNDR, 1);
>> > +    }
>> > +    return isar0;
>> > +}
>> >  #endif
>> >
>> >  /*
>> > @@ -5304,6 +5322,22 @@ static const ARMCPRegInfo pauth_reginfo[] = {
>> >        .fieldoffset = offsetof(CPUARMState, keys.apib.hi) },
>> >  };
>> >
>> > +static CPAccessResult access_rndr(CPUARMState *env, const ARMCPRegInfo *ri,
>> > +                                  bool isread)
>> > +{
>> > +    if (env->cp15.scr_el3 & SCR_TRNDR) {
>> > +        return CP_ACCESS_TRAP_EL3;
>> > +    }
>> > +    /*
>> > +     * Note that FEAT_RNG_TRAP may be implemented without FEAT_RNG.
>> > +     * In that case, if the trap is not enabled, the read undefs.
>> > +     */
>> > +    if (!cpu_isar_feature(aa64_rndr, env_archcpu(env))) {
>> > +        return CP_ACCESS_UNDEFINED;
>> > +    }
>> > +    return CP_ACCESS_OK;
>> > +}
>> > +
>> >  static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
>> >  {
>> >      Error *err = NULL;
>> > @@ -5335,11 +5369,11 @@ static const ARMCPRegInfo rndr_reginfo[] = {
>> >      { .name = "RNDR", .state = ARM_CP_STATE_AA64,
>> >        .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
>> >        .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 0,
>> > -      .access = PL0_R, .readfn = rndr_readfn },
>> > +      .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
>> >      { .name = "RNDRRS", .state = ARM_CP_STATE_AA64,
>> >        .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
>> >        .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1,
>> > -      .access = PL0_R, .readfn = rndr_readfn },
>> > +      .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
>> >  };
>> >
>> >  static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *ri,
>> > @@ -6522,11 +6556,24 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>> >                .access = PL1_R, .type = ARM_CP_CONST,
>> >                .accessfn = access_tid3,
>> >                .resetvalue = 0 },
>> > +            /*
>> > +             * ID_AA64ISAR0_EL1 is not a plain ARM_CP_CONST in system
>> > +             * emulation because the RNDR field depends on SCR_EL3.TRNDR
>> > +             * at read time when FEAT_RNG_TRAP is implemented.
>> > +             */
>> >              { .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64,
>> >                .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0,
>> > -              .access = PL1_R, .type = ARM_CP_CONST,
>> > +              .access = PL1_R,
>> > +#ifdef CONFIG_USER_ONLY
>> > +              .type = ARM_CP_CONST,
>> > +              .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)
>> > +#else
>> > +              .type = ARM_CP_NO_RAW,
>> >                .accessfn = access_tid3,
>> > -              .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)},
>> > +              .readfn = id_aa64isar0_read,
>> > +              .writefn = arm_cp_write_ignore
>> > +#endif
>> > +            },
>> 
>> A new assert() was triggered when booting guest on M1 since this change:
>> 
>> Assertion failed: (!(ri->type & ARM_CP_NO_RAW)), function hvf_arch_init_vcpu, file hvf.c, line 1442.
>> 
>> Thanks,
>> Zenghui
>> 
> Thanks for the report and the bisect, Zenghui. I can reproduce on M1 with:
>
> qemu-system-aarch64 -M virt,accel=hvf -cpu host \
>                       -nographic -display none -bios /dev/null
>
> ID_AA64PFR0_EL1 has the same NO_RAW + readfn shape that the FEAT_RNG_TRAP
> change gave ID_AA64ISAR0_EL1, and HVF already accommodates it by listing
> the cpreg in the SYNC_NO_RAW_REGS block in target/arm/hvf/sysreg.c.inc
> (so the assert loop skips it) and pushing QEMU's value to the vCPU at
> init time. Mirroring that pattern for ID_AA64ISAR0_EL1 clears the assert
> without disturbing the readfn semantics that the spec requires if a
> FEAT_RNG_TRAP-only CPU eventually appears.
>
> I'll send a fix-up as [PATCH] target/arm/hvf shortly.

This highlights why we need some bare metal MacOS machines in the
CI to exercise this code path.

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


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

* Re: [PATCH] target/arm/hvf: manually sync ID_AA64ISAR0_EL1 on vCPU init
  2026-06-07 18:22     ` [PATCH] target/arm/hvf: manually sync ID_AA64ISAR0_EL1 on vCPU init Jason Wright
@ 2026-06-08 13:07       ` Peter Maydell
  2026-06-08 15:56         ` Jason L. Wright'
  0 siblings, 1 reply; 30+ messages in thread
From: Peter Maydell @ 2026-06-08 13:07 UTC (permalink / raw)
  To: Jason Wright; +Cc: agraf, qemu-arm, qemu-devel, zenghui.yu, richard.henderson

On Sun, 7 Jun 2026 at 19:22, Jason Wright <wrigjl@proton.me> wrote:
>
> Commit 887eaa8a29 ("target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS")
> gave ID_AA64ISAR0_EL1 a readfn so the RNDR field can reflect SCR_EL3.TRNDR
> at read time, and marked the cpreg ARM_CP_NO_RAW in the system-emulation
> path.  HVF then trips its hvf_arch_init_vcpu() assertion that no ID
> register in hvf_sreg_list[] is NO_RAW, aborting on boot on Apple Silicon:
>
>   Assertion failed: (!(ri->type & ARM_CP_NO_RAW)),
>   function hvf_arch_init_vcpu, file hvf.c, line 1442.
>
> Reproduce with:
>
>   qemu-system-aarch64 -M virt,accel=hvf -cpu host \
>                       -nographic -display none -bios /dev/null
>
> Mirror the existing treatment of ID_AA64PFR0_EL1: move
> HV_SYS_REG_ID_AA64ISAR0_EL1 into the SYNC_NO_RAW_REGS block in
> sysreg.c.inc so the assert loop skips it, and push QEMU's view of the
> register to the vCPU at init time.  HVF does not expose EL3, so
> SCR_EL3.TRNDR is never set and the readfn is functionally static there.
>
> Reported-by: Zenghui Yu <zenghui.yu@linux.dev>
> Fixes: 887eaa8a29 ("target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS")
> Signed-off-by: Jason Wright <wrigjl@proton.me>
> ---
>  target/arm/hvf/hvf.c        | 4 ++++
>  target/arm/hvf/sysreg.c.inc | 2 +-
>  2 files changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
> index d88cbe7c82..afa1120c8a 100644
> --- a/target/arm/hvf/hvf.c
> +++ b/target/arm/hvf/hvf.c
> @@ -1485,6 +1485,10 @@ int hvf_arch_init_vcpu(CPUState *cpu)
>      ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64PFR0_EL1, pfr);
>      assert_hvf_ok(ret);
>
> +    ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64ISAR0_EL1,
> +                              GET_IDREG(&arm_cpu->isar, ID_AA64ISAR0));
> +    assert_hvf_ok(ret);
> +

For ID_AA64PFR0_EL1, we do "read the value from hvf, update it,
write it back", and we do not either read or write the isar.idregs[]
entry for it.

For ID_AA64MMFR0_EL1, we read the hvf value into the isar.idregs[]
array entry, update it there, and write it back to hvf.

For ID_AA64ISAR0_EL1, we write whatever is in the isar.idregs[]
array entry into hvf.

Why do we do three different things for these three registers ?

thanks
-- PMM


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

* Re: [PATCH] target/arm/hvf: manually sync ID_AA64ISAR0_EL1 on vCPU init
  2026-06-08 13:07       ` Peter Maydell
@ 2026-06-08 15:56         ` Jason L. Wright'
  2026-06-08 16:05           ` Peter Maydell
  0 siblings, 1 reply; 30+ messages in thread
From: Jason L. Wright' @ 2026-06-08 15:56 UTC (permalink / raw)
  To: Peter Maydell; +Cc: agraf, qemu-arm, qemu-devel, zenghui.yu, richard.henderson

On Mon, Jun 08, 2026 at 02:07:03PM +0100, Peter Maydell wrote:
> On Sun, 7 Jun 2026 at 19:22, Jason Wright <wrigjl@proton.me> wrote:
> >
> > Commit 887eaa8a29 ("target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS")
> > gave ID_AA64ISAR0_EL1 a readfn so the RNDR field can reflect SCR_EL3.TRNDR
> > at read time, and marked the cpreg ARM_CP_NO_RAW in the system-emulation
> > path.  HVF then trips its hvf_arch_init_vcpu() assertion that no ID
> > register in hvf_sreg_list[] is NO_RAW, aborting on boot on Apple Silicon:
> >
> >   Assertion failed: (!(ri->type & ARM_CP_NO_RAW)),
> >   function hvf_arch_init_vcpu, file hvf.c, line 1442.
> >
> > Reproduce with:
> >
> >   qemu-system-aarch64 -M virt,accel=hvf -cpu host \
> >                       -nographic -display none -bios /dev/null
> >
> > Mirror the existing treatment of ID_AA64PFR0_EL1: move
> > HV_SYS_REG_ID_AA64ISAR0_EL1 into the SYNC_NO_RAW_REGS block in
> > sysreg.c.inc so the assert loop skips it, and push QEMU's view of the
> > register to the vCPU at init time.  HVF does not expose EL3, so
> > SCR_EL3.TRNDR is never set and the readfn is functionally static there.
> >
> > Reported-by: Zenghui Yu <zenghui.yu@linux.dev>
> > Fixes: 887eaa8a29 ("target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS")
> > Signed-off-by: Jason Wright <wrigjl@proton.me>
> > ---
> >  target/arm/hvf/hvf.c        | 4 ++++
> >  target/arm/hvf/sysreg.c.inc | 2 +-
> >  2 files changed, 5 insertions(+), 1 deletion(-)
> >
> > diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
> > index d88cbe7c82..afa1120c8a 100644
> > --- a/target/arm/hvf/hvf.c
> > +++ b/target/arm/hvf/hvf.c
> > @@ -1485,6 +1485,10 @@ int hvf_arch_init_vcpu(CPUState *cpu)
> >      ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64PFR0_EL1, pfr);
> >      assert_hvf_ok(ret);
> >
> > +    ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64ISAR0_EL1,
> > +                              GET_IDREG(&arm_cpu->isar, ID_AA64ISAR0));
> > +    assert_hvf_ok(ret);
> > +
> 
> For ID_AA64PFR0_EL1, we do "read the value from hvf, update it,
> write it back", and we do not either read or write the isar.idregs[]
> entry for it.
> 
> For ID_AA64MMFR0_EL1, we read the hvf value into the isar.idregs[]
> array entry, update it there, and write it back to hvf.
> 
> For ID_AA64ISAR0_EL1, we write whatever is in the isar.idregs[]
> array entry into hvf.
> 
> Why do we do three different things for these three registers ?
> 
I think it's each call doing the minimum work required for that
register.

MIDR_EL1 / MPIDR_EL1 are QEMU-defined identity values; HVF has
nothing useful to contribute, so we just write.

ID_AA64PFR0_EL1 needs HVF's value as the base (host feature set)
and then ORs in the GIC sysreg-iface bit, which depends on
env->gicv3state runtime overlay, hence the get/modify/set.

ID_AA64MMFR0_EL1 also needs HVF's value as the base, and the
modification (clamping PARANGE to the configured IPA size)
consults isar.idregs[], so we read into idregs[] before clamping
and then write back.

ID_AA64ISAR0_EL1 in this patch has no runtime overlay on the HVF
path: SCR_EL3.TRNDR is permanently 0 since HVF does not expose
EL3, so the readfn is a constant equal to
isar.idregs[ID_AA64ISAR0_EL1_IDX], which was already seeded from
the host during realize.

The three methods track different requirements, so I matched
the closest existing pattern for ID_AA64ISAR0_EL1 and left
the others alone.



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

* Re: [PATCH] target/arm/hvf: manually sync ID_AA64ISAR0_EL1 on vCPU init
  2026-06-08 15:56         ` Jason L. Wright'
@ 2026-06-08 16:05           ` Peter Maydell
  0 siblings, 0 replies; 30+ messages in thread
From: Peter Maydell @ 2026-06-08 16:05 UTC (permalink / raw)
  To: Jason L. Wright'
  Cc: agraf, qemu-arm, qemu-devel, zenghui.yu, richard.henderson

On Mon, 8 Jun 2026 at 16:56, Jason L. Wright' <wrigjl@proton.me> wrote:
>
> On Mon, Jun 08, 2026 at 02:07:03PM +0100, Peter Maydell wrote:
> > On Sun, 7 Jun 2026 at 19:22, Jason Wright <wrigjl@proton.me> wrote:
> > >
> > > Commit 887eaa8a29 ("target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS")
> > > gave ID_AA64ISAR0_EL1 a readfn so the RNDR field can reflect SCR_EL3.TRNDR
> > > at read time, and marked the cpreg ARM_CP_NO_RAW in the system-emulation
> > > path.  HVF then trips its hvf_arch_init_vcpu() assertion that no ID
> > > register in hvf_sreg_list[] is NO_RAW, aborting on boot on Apple Silicon:
> > >
> > >   Assertion failed: (!(ri->type & ARM_CP_NO_RAW)),
> > >   function hvf_arch_init_vcpu, file hvf.c, line 1442.
> > >
> > > Reproduce with:
> > >
> > >   qemu-system-aarch64 -M virt,accel=hvf -cpu host \
> > >                       -nographic -display none -bios /dev/null
> > >
> > > Mirror the existing treatment of ID_AA64PFR0_EL1: move
> > > HV_SYS_REG_ID_AA64ISAR0_EL1 into the SYNC_NO_RAW_REGS block in
> > > sysreg.c.inc so the assert loop skips it, and push QEMU's view of the
> > > register to the vCPU at init time.  HVF does not expose EL3, so
> > > SCR_EL3.TRNDR is never set and the readfn is functionally static there.
> > >
> > > Reported-by: Zenghui Yu <zenghui.yu@linux.dev>
> > > Fixes: 887eaa8a29 ("target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS")
> > > Signed-off-by: Jason Wright <wrigjl@proton.me>
> > > ---
> > >  target/arm/hvf/hvf.c        | 4 ++++
> > >  target/arm/hvf/sysreg.c.inc | 2 +-
> > >  2 files changed, 5 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
> > > index d88cbe7c82..afa1120c8a 100644
> > > --- a/target/arm/hvf/hvf.c
> > > +++ b/target/arm/hvf/hvf.c
> > > @@ -1485,6 +1485,10 @@ int hvf_arch_init_vcpu(CPUState *cpu)
> > >      ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64PFR0_EL1, pfr);
> > >      assert_hvf_ok(ret);
> > >
> > > +    ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64ISAR0_EL1,
> > > +                              GET_IDREG(&arm_cpu->isar, ID_AA64ISAR0));
> > > +    assert_hvf_ok(ret);
> > > +
> >
> > For ID_AA64PFR0_EL1, we do "read the value from hvf, update it,
> > write it back", and we do not either read or write the isar.idregs[]
> > entry for it.
> >
> > For ID_AA64MMFR0_EL1, we read the hvf value into the isar.idregs[]
> > array entry, update it there, and write it back to hvf.
> >
> > For ID_AA64ISAR0_EL1, we write whatever is in the isar.idregs[]
> > array entry into hvf.
> >
> > Why do we do three different things for these three registers ?
> >
> I think it's each call doing the minimum work required for that
> register.
>
> MIDR_EL1 / MPIDR_EL1 are QEMU-defined identity values; HVF has
> nothing useful to contribute, so we just write.

These don't have isar.idregs[] entries either, so it makes sense
that they're not quite the same.

> ID_AA64PFR0_EL1 needs HVF's value as the base (host feature set)
> and then ORs in the GIC sysreg-iface bit, which depends on
> env->gicv3state runtime overlay, hence the get/modify/set.

But why do we not update isar.idregs[] to match ?

> ID_AA64MMFR0_EL1 also needs HVF's value as the base, and the
> modification (clamping PARANGE to the configured IPA size)
> consults isar.idregs[], so we read into idregs[] before clamping
> and then write back.

But why does the modification consult isar.idregs[] rather than
taking a value that it's passed in as an argument ?

> ID_AA64ISAR0_EL1 in this patch has no runtime overlay on the HVF
> path: SCR_EL3.TRNDR is permanently 0 since HVF does not expose
> EL3, so the readfn is a constant equal to
> isar.idregs[ID_AA64ISAR0_EL1_IDX], which was already seeded from
> the host during realize.

But if the values in isar.idregs[] are seeded from HVF during
realize, why do we not trust the isar.idregs[] value when we're
handling ID_AA64PFR0_EL1?

> The three methods track different requirements, so I matched
> the closest existing pattern for ID_AA64ISAR0_EL1 and left
> the others alone.

It seems to me that you've added a third thing that's different
from either of the ways that we handle existing ID registers
with an isar.idregs[] field.

I think we need to figure out:

(1) can we trust that the isar.idregs[] values at this point
are the ones that hvf uses? If so we don't need to re-read
the hvf values. If we can't trust them we should consistently
read the hvf values.

(2) do we need to update the isar.idregs[] values when we
modify the values to write back to hvf? If so, we should
do it consistently for all these regs. If not, we should
not update any of them.

Currently ID_AA64PFR0_EL1 neither trusts isar.idregs[] nor
updates it; ID_AA64MMFR0_EL1 does not trust isar.idregs[]
but does update it; and ID_AA64ISAR0_EL1 trusts isar.idregs[]
and has no need to update it.

thanks
-- PMM


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

end of thread, other threads:[~2026-06-08 16:06 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-29 11:47 [PULL 00/21] target-arm queue Peter Maydell
2026-05-29 11:47 ` [PULL 01/21] target/arm: Enable REVD for SVE2.1 Peter Maydell
2026-05-29 11:47 ` [PULL 02/21] hw/dma/zynq-devcfg: Handle bitstream loading via DMA to 0xffffffff Peter Maydell
2026-05-29 11:47 ` [PULL 03/21] hw/arm/zynq-devcfg: Prevent unintended unlock during initialization Peter Maydell
2026-05-29 11:47 ` [PULL 04/21] hw/dma/zynq: Ensure PCFG_DONE bit remains set to indicate PL is in user mode Peter Maydell
2026-05-29 11:47 ` [PULL 05/21] hw/dma/zynq-devcfg: Simulate dummy PL reset Peter Maydell
2026-05-29 11:47 ` [PULL 06/21] hw/dma/zynq-devcfg: Indicate power-up status of PL Peter Maydell
2026-05-29 11:47 ` [PULL 07/21] hw/misc: Add dummy ZYNQ DDR controller Peter Maydell
2026-05-29 11:47 ` [PULL 08/21] hw/misc/zynq_slcr: Add logic for DCI configuration Peter Maydell
2026-05-29 11:47 ` [PULL 09/21] hw/block/m25p80: Add HAS_SR_TB flag for is25lp016d Peter Maydell
2026-05-29 11:47 ` [PULL 10/21] hw/arm/xilinx_zynq: Split xilinx_zynq into header and implementation files Peter Maydell
2026-05-29 11:47 ` [PULL 11/21] target/arm: Add feature predicate for FEAT_CMPBR Peter Maydell
2026-05-29 11:47 ` [PULL 12/21] target/arm: Implement CB, CBB, CBH Peter Maydell
2026-05-29 11:47 ` [PULL 13/21] target/arm: Implement CB (immediate) Peter Maydell
2026-05-29 11:47 ` [PULL 14/21] target/arm: Enable FEAT_CMPBR for -cpu max Peter Maydell
2026-05-29 11:47 ` [PULL 15/21] target/arm: Don't assert if 64-bit EL2 AT insn sees a Domain fault Peter Maydell
2026-05-29 11:47 ` [PULL 16/21] target/arm: SME BFCVT, BFCVTN have "Alternate BFloat16 behaviors" Peter Maydell
2026-05-29 11:47 ` [PULL 17/21] target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS Peter Maydell
2026-06-07 10:42   ` Zenghui Yu
2026-06-07 18:04     ` Jason L. Wright'
2026-06-08  8:57       ` Alex Bennée
2026-06-07 18:22     ` [PATCH] target/arm/hvf: manually sync ID_AA64ISAR0_EL1 on vCPU init Jason Wright
2026-06-08 13:07       ` Peter Maydell
2026-06-08 15:56         ` Jason L. Wright'
2026-06-08 16:05           ` Peter Maydell
2026-05-29 11:47 ` [PULL 18/21] target/arm: advertise FEAT_RNG_TRAP on cortex-max Peter Maydell
2026-05-29 11:47 ` [PULL 19/21] hw/dma/omap_dma: Remove unused ifdeffed out code Peter Maydell
2026-05-29 11:47 ` [PULL 20/21] hw/dma/omap_dma: Fix coding style in omap_dma_transfer_setup() Peter Maydell
2026-05-29 11:47 ` [PULL 21/21] hw/dma/omap_dma: Fix indentation after ifdef removal Peter Maydell
2026-05-29 19:49 ` [PULL 00/21] target-arm queue Stefan Hajnoczi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.