All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 00/83] riscv-to-apply queue
@ 2026-06-16 10:04 alistair23
  2026-06-16 10:04 ` [PULL 01/83] target/riscv/tcg: disable svpbmt if satp_mode < sv39 alistair23
                   ` (84 more replies)
  0 siblings, 85 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Alistair Francis

From: Alistair Francis <alistair.francis@wdc.com>

The following changes since commit 2f28d34ea0aead9830478cd1d3d0dd9d9191d82e:

  Merge tag 'pull-tcg-20260612' of https://gitlab.com/rth7680/qemu into staging (2026-06-13 14:02:34 -0400)

are available in the Git repository at:

  https://github.com/alistair23/qemu.git tags/pull-riscv-to-apply-20260616

for you to fetch changes up to e968e487acf082279118667f495a3f4275a59d59:

  hw/riscv: add create_fdt_socket_cpu_sifive() (2026-06-16 20:01:11 +1000)

----------------------------------------------------------------
RISC-V PR for 11.1

* Disable svpbmt if satp_mode is less then sv39
* Fix PMP address alignment
* Mstatus write bug fixes
* Add 'cbo' insns to disassembler
* Do not hide Sstc CSRs from gdbstub
* Reject Svinval instructions in U-mode
* Save opcode before zicbo helpers
* Fault with reserved PTE.PBMT val
* Allow LOAD_ADDR_MIS promotion to AMO fault
* Make riscv cpu.h target independent
* Add PMA access fault
* Disable svnapot if satp_mode is less then sv39
* Fix disassembler inst_length calculation
* Add RISC-V big-endian target support
* Add the implied rules for G and B extensions
* Print privilege level and ELP in riscv_cpu_dump_state
* Improve alignment in riscv_cpu_dump_state
* Mask vxrm csrw write to the low 2 bits
* Reorder Smrnmi CPU fields above CPU reset line
* Supplement cpu topology arguments
* Don't insert DDT cache in Bare mode
* Fix 'iommu-map' FDT entry
* Fix mstatus.FS dirty tracking for FP exception-raising instructions
* Enable `mnret` disassembly
* Add support for K230 board
* FDT creation helpers

----------------------------------------------------------------
Abhigyan Kumar (1):
      target/riscv: mask vxrm csrw write to the low 2 bits

Anton Blanchard (2):
      target/riscv: Print privilege level and ELP in riscv_cpu_dump_state
      target/riscv: Improve alignment in riscv_cpu_dump_state

Anton Johansson (27):
      target/riscv: Fix size of gpr and gprh
      target/riscv: Fix size of vector CSRs
      target/riscv: Fix size of pc, load_[val|res]
      target/riscv: Fix size of frm and fflags
      target/riscv: Fix size of badaddr and bins
      target/riscv: Fix size of guest_phys_fault_addr
      target/riscv: Fix size of priv_ver and vext_ver
      target/riscv: Fix size of retxh
      target/riscv: Fix size of ssp
      target/riscv: Fix size of excp_uw2
      target/riscv: Fix size of sw_check_code
      target/riscv: Fix size of priv
      target/riscv: Fix size of gei fields
      target/riscv: Fix size of [m|s|vs]iselect fields
      target/riscv: Fix arguments to board IMSIC emulation callbacks
      target/riscv: Fix size of irq_overflow_left
      target/riscv: Indent PMUFixedCtrState correctly
      target/riscv: Replace target_ulong in riscv_cpu_get_trap_name()
      target/riscv: Replace target_ulong in riscv_ctr_add_entry()
      target/riscv: Fix size of trigger data
      target/riscv: Fix size of mseccfg
      target/riscv: Move debug.h include away from cpu.h
      target/riscv: Move CSR declarations to separate csr.h header
      target/riscv: Introduce externally facing CSR access functions
      target/riscv: Make pmp.h target_ulong agnostic
      target/riscv: Pass address as uint64_t in cpu_set_exception_base()
      target/riscv: Fix pmp.h/cpu.h circular inclusion

Chao Liu (5):
      target/riscv: add thead-c908 cpu support
      hw/riscv: add k230 board initial support
      hw/watchdog: add k230 watchdog initial support
      tests/qtest: add test for K230 watchdog
      docs/system/riscv: add documentation for k230 machine

Daniel Henrique Barboza (24):
      target/riscv/tcg: disable svpbmt if satp_mode < sv39
      target/riscv/csr.c: do not allow mstatus MPV/GVA writes
      target/riscv/csr.c: fix mstatus.UXL reserved value
      disas/riscv.c: add 'cbo' insns to disassembler
      target/riscv/insn_trans/trans_rvzicbo.c.inc: save opcode before helpers
      target/riscv/cpu_helper.c: fault with reserved PTE.PBMT val
      target/riscv/cpu_helper.c: allow LOAD_ADDR_MIS promotion to AMO fault
      target/riscv/cpu_helper.c: add PMA access fault
      target/riscv/tcg: disable svnapot if satp_mode < sv39
      disas/riscv.c: fix inst_length()
      hw/riscv/virt.c: fix 'iommu-map' FDT entry
      hw/riscv/sifive_u.c: add a FDT phandle to cpu-intc
      hw/riscv: add fdt-common helper
      hw/riscv/numa: make numa_enabled() public
      hw/riscv: add create_fdt_socket_memory() helper
      hw/riscv/sifive_u.c: add intc_phandles array
      hw/riscv/spike.c: add intc_phandles array
      hw/riscv: add create_fdt_clint() helper
      hw/riscv/sifive_u.c: add cpu-map, cluster and core DTs
      hw/riscv: add fdt_create_cpu_socket_subnode() helper
      hw/riscv: add create_fdt_socket_cpus()
      hw/riscv/spike.c: use create_fdt_socket_cpus()
      hw/riscv/fdt_common.c: create create_fdt_socket_cpu_internal()
      hw/riscv: add create_fdt_socket_cpu_sifive()

Djordje Todorovic (6):
      target/riscv: Implement runtime data endianness via MSTATUS bits
      target/riscv: Fix page table walk endianness for big-endian harts
      target/riscv: Add big-endian CPU configuration field and reset logic
      hw/riscv/boot: Honour data endianness
      target/riscv: Expose and document the CPU 'big-endian' property
      tests/functional: Add RISC-V endianness test

Frank Chang (2):
      target/riscv: Add standard B extension implied rule
      target/riscv: Reorder Smrnmi CPU fields above CPU reset line

Jay Chang (4):
      target/riscv: Align pmp size to pmp-granularity
      target/riscv: Improve PMP address alignment readability
      hw/riscv: Don't insert DDT cache in Bare mode
      hw/riscv: Refactor riscv_iommu_ctx_put() for Bare mode handling

Jim Shu (1):
      target/riscv: Add the implied rule for G extension

Max Chou (2):
      target/riscv: Set mstatus.FS dirty when scalar FP raises exceptions
      target/riscv: rvv: Set mstatus.FS dirty when vector FP raises exceptions

Philippe Mathieu-Daudé (5):
      target/riscv: Initialize DisasContext::mo_endian once
      target/riscv: De-indent some code in get_physical_address()
      target/riscv: Remove target_ulong use in get_physical_address()
      hw/riscv/boot: Rewrite setup_rom_reset_vec() using load/store API
      hw/riscv/boot: Replace cpu_to_le32() -> const_le32()

Xuemei Liu (1):
      hw/riscv/numa.c: Supplement cpu topology arguments

Zephyr Li (2):
      target/riscv: Do not hide Sstc CSRs from gdbstub
      target/riscv: Reject Svinval instructions in U-mode

imaginos (1):
      disas/riscv: enable `mnret` disassembly

 MAINTAINERS                                    |  11 +
 docs/system/riscv/k230.rst                     | 113 ++++++
 docs/system/target-riscv.rst                   |  30 ++
 include/hw/riscv/fdt-common.h                  |  33 ++
 include/hw/riscv/k230.h                        | 149 +++++++
 include/hw/riscv/numa.h                        |   8 +
 include/hw/watchdog/k230_wdt.h                 | 121 ++++++
 target/riscv/cpu-qom.h                         |   2 +
 target/riscv/cpu.h                             | 287 +++++---------
 target/riscv/csr.h                             | 102 +++++
 target/riscv/debug.h                           |   2 -
 target/riscv/internals.h                       |  33 +-
 target/riscv/pmp.h                             |  23 +-
 target/riscv/pmu.h                             |   2 +-
 target/riscv/cpu_cfg_fields.h.inc              |   1 +
 target/riscv/insn32.decode                     |   2 +-
 disas/riscv.c                                  |  56 ++-
 hw/intc/riscv_imsic.c                          |  34 +-
 hw/riscv/boot.c                                |  95 ++---
 hw/riscv/fdt-common.c                          | 202 ++++++++++
 hw/riscv/k230.c                                | 526 +++++++++++++++++++++++++
 hw/riscv/numa.c                                |  32 +-
 hw/riscv/riscv-iommu.c                         |  34 +-
 hw/riscv/riscv_hart.c                          |   7 +-
 hw/riscv/sifive_u.c                            |  88 +----
 hw/riscv/spike.c                               | 123 ++----
 hw/riscv/virt.c                                | 185 ++-------
 hw/watchdog/k230_wdt.c                         | 296 ++++++++++++++
 linux-user/riscv/signal.c                      |   5 +-
 target/riscv/cpu.c                             | 140 ++++++-
 target/riscv/cpu_helper.c                      | 180 ++++++---
 target/riscv/csr.c                             | 116 ++++--
 target/riscv/debug.c                           |   1 +
 target/riscv/fpu_helper.c                      | 167 ++++++--
 target/riscv/gdbstub.c                         |   3 +-
 target/riscv/kvm/kvm-cpu.c                     |   1 +
 target/riscv/machine.c                         |  81 ++--
 target/riscv/mips_csr.c                        |   1 +
 target/riscv/monitor.c                         |   3 +-
 target/riscv/op_helper.c                       |  28 +-
 target/riscv/pmp.c                             |  34 +-
 target/riscv/pmu.c                             |   9 +-
 target/riscv/riscv-qmp-cmds.c                  |   1 +
 target/riscv/tcg/tcg-cpu.c                     |  63 ++-
 target/riscv/th_csr.c                          | 377 +++++++++++++++++-
 target/riscv/translate.c                       |  82 ++--
 target/riscv/vector_helper.c                   | 366 +++++++++--------
 tests/qtest/k230-wdt-test.c                    | 189 +++++++++
 target/riscv/insn_trans/trans_privileged.c.inc |   2 +-
 target/riscv/insn_trans/trans_rva.c.inc        |   4 +-
 target/riscv/insn_trans/trans_rvd.c.inc        |   4 +-
 target/riscv/insn_trans/trans_rvf.c.inc        |   4 +-
 target/riscv/insn_trans/trans_rvi.c.inc        |  24 +-
 target/riscv/insn_trans/trans_rvm.c.inc        |  16 +-
 target/riscv/insn_trans/trans_rvv.c.inc        |  22 +-
 target/riscv/insn_trans/trans_rvzacas.c.inc    |   4 +-
 target/riscv/insn_trans/trans_rvzalasr.c.inc   |   4 +-
 target/riscv/insn_trans/trans_rvzce.c.inc      |   4 +-
 target/riscv/insn_trans/trans_rvzfh.c.inc      |   4 +-
 target/riscv/insn_trans/trans_rvzicbo.c.inc    |   8 +
 target/riscv/insn_trans/trans_rvzicfiss.c.inc  |  26 +-
 target/riscv/insn_trans/trans_svinval.c.inc    |  12 +
 target/riscv/insn_trans/trans_xmips.c.inc      |   8 +-
 target/riscv/insn_trans/trans_xthead.c.inc     |  16 +-
 target/riscv/insn_trans/trans_zilsd.c.inc      |   4 +-
 hw/riscv/Kconfig                               |  11 +
 hw/riscv/meson.build                           |   3 +-
 hw/watchdog/Kconfig                            |   4 +
 hw/watchdog/meson.build                        |   1 +
 hw/watchdog/trace-events                       |   9 +
 tests/functional/riscv64/meson.build           |   1 +
 tests/functional/riscv64/test_endianness.py    |  57 +++
 tests/qtest/meson.build                        |   3 +-
 73 files changed, 3544 insertions(+), 1155 deletions(-)
 create mode 100644 docs/system/riscv/k230.rst
 create mode 100644 include/hw/riscv/fdt-common.h
 create mode 100644 include/hw/riscv/k230.h
 create mode 100644 include/hw/watchdog/k230_wdt.h
 create mode 100644 target/riscv/csr.h
 create mode 100644 hw/riscv/fdt-common.c
 create mode 100644 hw/riscv/k230.c
 create mode 100644 hw/watchdog/k230_wdt.c
 create mode 100644 tests/qtest/k230-wdt-test.c
 create mode 100644 tests/functional/riscv64/test_endianness.py


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

* [PULL 01/83] target/riscv/tcg: disable svpbmt if satp_mode < sv39
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 02/83] target/riscv: Align pmp size to pmp-granularity alistair23
                   ` (83 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Daniel Henrique Barboza, Chao Liu, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

Priv spec chapter "Svpbmt Extension for Page-Based Memory Types, Version
1.0" mentions that "The Svpbmt extension depends on the Sv39
extension.".

We're not doing any satp checks when enabling svpbmt.  This causes
problems with the riscv32 'max' CPU that happens to be enabling svpbmt
even though it doesn't support the required satp mode.  In fact all rv32
CPUs are allowing menvcfg.PBMTE writes, which doesn't make sense for
them in any circunstance since svpbmt is not possible for rv32 at this
moment [1].

This also impacts rv64 CPUs that are running in satp 'bare' mode and are
reporting svpbmt in the riscv,isa.

All these problems can be solved by disabling svpbmt if satp_mode is not
at least sv39.  The problem reported in [1] goes away because we'll
never enable MENVCFG_PBMTE write mask in write_menvcfgh().  We're also
become consistent with how svpbmt is enabled for rv64.

In case the user enables svpbmt in the command line using an invalid setup,
not just disable svpbmt but also throw a warning:

$ ./build/qemu-system-riscv64 -M virt,dumpdtb=fdt.dtb \
    -cpu max,sv39=off,sv48=off,sv57=off,sv64=off,svpbmt=on
qemu-system-riscv64: warning: svpbmt requires at least satp sv39, current satp mode: none

[1] https://gitlab.com/qemu-project/qemu/-/work_items/3473

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3473
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Message-ID: <20260519114858.316532-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/tcg/tcg-cpu.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 3e22e7ed53..f8b2f04a94 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -837,6 +837,17 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
         return;
     }
 
+#ifndef CONFIG_USER_ONLY
+    if (cpu->cfg.ext_svpbmt && cpu->cfg.max_satp_mode < VM_1_10_SV39) {
+        cpu->cfg.ext_svpbmt = false;
+        if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_svpbmt))) {
+            warn_report("svpbmt requires at least satp sv39, "
+                        "current satp mode: %s",
+                        satp_mode_str(cpu->cfg.max_satp_mode,
+                                     riscv_cpu_is_32bit(cpu)));
+        }
+    }
+#endif
     /*
      * Disable isa extensions based on priv spec after we
      * validated and set everything we need.
-- 
2.54.0



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

* [PULL 02/83] target/riscv: Align pmp size to pmp-granularity
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
  2026-06-16 10:04 ` [PULL 01/83] target/riscv/tcg: disable svpbmt if satp_mode < sv39 alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 03/83] target/riscv: Improve PMP address alignment readability alistair23
                   ` (82 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Jay Chang, Frank Chang, Daniel Henrique Barboza,
	Chao Liu, Alistair Francis

From: Jay Chang <jay.chang@sifive.com>

When configuring pmpcfg (TOR, NA4, or NAPOT) and pmpaddr, if the
value is smaller than the PMP granularity, it needs to be aligned
to the PMP granularity.

Signed-off-by: Jay Chang <jay.chang@sifive.com>
Reviewed-by: Frank Chang <frank.chang@sifive.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Message-ID: <20260520063606.36600-2-jay.chang@sifive.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/pmp.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index a71091a316..8adf7c9719 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -179,11 +179,12 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
             }
             /*
              * When granularity g >= 1 (i.e., granularity > 4 bytes),
-             * the NA4 (Naturally Aligned 4-byte) mode is not selectable
+             * the NA4 (Naturally Aligned 4-byte) mode is not selectable.
+             * In this case, an NA4 setting is reinterpreted as a NAPOT mode.
              */
             if ((riscv_cpu_cfg(env)->pmp_granularity >
                 MIN_RISCV_PMP_GRANULARITY) && (a_field == PMP_AMATCH_NA4)) {
-                    return false;
+                    val |= PMP_AMATCH;
             }
             env->pmp_state.pmp[pmp_index].cfg_reg = val;
             pmp_update_rule_addr(env, pmp_index);
@@ -263,6 +264,11 @@ void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index)
         break;
 
     case PMP_AMATCH_NAPOT:
+        /* Bits [g-2:0] need to be all one to align pmp granularity */
+        if (g >= 2) {
+            this_addr = deposit64(this_addr, 0, g - 1, -1ULL);
+        }
+
         pmp_decode_napot(this_addr, &sa, &ea);
         break;
 
-- 
2.54.0



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

* [PULL 03/83] target/riscv: Improve PMP address alignment readability
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
  2026-06-16 10:04 ` [PULL 01/83] target/riscv/tcg: disable svpbmt if satp_mode < sv39 alistair23
  2026-06-16 10:04 ` [PULL 02/83] target/riscv: Align pmp size to pmp-granularity alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 04/83] target/riscv/csr.c: do not allow mstatus MPV/GVA writes alistair23
                   ` (81 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Jay Chang, Chao Liu, Alistair Francis

From: Jay Chang <jay.chang@sifive.com>

Replace manual bit manipulation for better readability:

- TOR: Use ROUND_DOWN() to clear lower bits
- NAPOT: Use deposit64() to set lower bits

Signed-off-by: Jay Chang <jay.chang@sifive.com>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Message-ID: <20260520063606.36600-3-jay.chang@sifive.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/pmp.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 8adf7c9719..58a8923d0d 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -247,8 +247,9 @@ void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index)
     case PMP_AMATCH_TOR:
         /* Bits pmpaddr[G-1:0] do not affect the TOR address-matching logic. */
         if (g >= 1) {
-            prev_addr &= ~((1ULL << g) - 1ULL);
-            this_addr &= ~((1ULL << g) - 1ULL);
+            uint64_t granule = 1ULL << g;
+            prev_addr = ROUND_DOWN(prev_addr, granule);
+            this_addr = ROUND_DOWN(this_addr, granule);
         }
         if (prev_addr >= this_addr) {
             sa = ea = 0u;
@@ -641,13 +642,14 @@ target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
         case PMP_AMATCH_TOR:
             /* Bit [g-1:0] read all zero */
             if (g >= 1 && g < TARGET_LONG_BITS) {
-                val &= ~((1ULL << g) - 1ULL);
+                uint64_t granule = 1ULL << g;
+                val = ROUND_DOWN(val, granule);
             }
             break;
         case PMP_AMATCH_NAPOT:
             /* Bit [g-2:0] read all one */
             if (g >= 2 && g < TARGET_LONG_BITS) {
-                val |= ((1ULL << (g - 1)) - 1ULL);
+                val = deposit64(val, 0, g - 1, -1ULL);
             }
             break;
         default:
-- 
2.54.0



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

* [PULL 04/83] target/riscv/csr.c: do not allow mstatus MPV/GVA writes
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (2 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 03/83] target/riscv: Improve PMP address alignment readability alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 05/83] target/riscv/csr.c: fix mstatus.UXL reserved value alistair23
                   ` (80 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

The priv spec states the following about mstatus.MPV:

"The MPV bit (Machine Previous Virtualization Mode) is written by the
implementation whenever a trap is taken into M-mode."

And, about mstatus.GVA:

"Field GVA (Guest Virtual Address) is written by the implementation
whenever a trap is taken into M-mode."

Both are written during riscv_cpu_do_interrupt().  They're not supposed
to be written by userspace.  As far as write_mstatus goes these fields
are read only.  The same applies for mstatush.MPV/mstatush.GVA.

Fixes: 03dd405dd5 ("target/riscv: Support MSTATUS.MPV/GVA only when RVH is enabled")
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260514194537.2416243-2-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/csr.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 5514e0f455..83ca354bf0 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2044,9 +2044,6 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
     }
 
     if (xl != MXL_RV32 || env->debugger) {
-        if (riscv_has_ext(env, RVH)) {
-            mask |= MSTATUS_MPV | MSTATUS_GVA;
-        }
         if ((val & MSTATUS64_UXL) != 0) {
             mask |= MSTATUS64_UXL;
         }
@@ -2083,7 +2080,7 @@ static RISCVException write_mstatush(CPURISCVState *env, int csrno,
                                      target_ulong val, uintptr_t ra)
 {
     uint64_t valh = (uint64_t)val << 32;
-    uint64_t mask = riscv_has_ext(env, RVH) ? MSTATUS_MPV | MSTATUS_GVA : 0;
+    uint64_t mask = 0;
 
     if (riscv_cpu_cfg(env)->ext_smdbltrp) {
         mask |= MSTATUS_MDT;
-- 
2.54.0



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

* [PULL 05/83] target/riscv/csr.c: fix mstatus.UXL reserved value
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (3 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 04/83] target/riscv/csr.c: do not allow mstatus MPV/GVA writes alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 06/83] disas/riscv.c: add 'cbo' insns to disassembler alistair23
                   ` (79 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

By the priv spec the value "3" is marked as 'Reserved' for mstatus.UXL.
Handle a mstatus.UXL = 3 write by writing the current 'xl' instead.

Fixes: https://gitlab.com/qemu-project/qemu/-/work_items/3367
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260514194537.2416243-3-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/csr.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 83ca354bf0..d004a4bfb4 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2045,7 +2045,17 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
 
     if (xl != MXL_RV32 || env->debugger) {
         if ((val & MSTATUS64_UXL) != 0) {
+            uint64_t uxl = val & MSTATUS64_UXL >> 32;
             mask |= MSTATUS64_UXL;
+
+            /*
+             * uxl = 3 is reserved so write the current xl instead.
+             * In case xl = MXL_RV128 (3) write MXL_RV64.
+             */
+            if (uxl == 3) {
+                uxl = xl == MXL_RV128 ? MXL_RV64 : xl;
+                val = deposit64(val, 32, 2, uxl);
+            }
         }
     }
 
-- 
2.54.0



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

* [PULL 06/83] disas/riscv.c: add 'cbo' insns to disassembler
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (4 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 05/83] target/riscv/csr.c: fix mstatus.UXL reserved value alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 07/83] target/riscv: Do not hide Sstc CSRs from gdbstub alistair23
                   ` (78 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Daniel Henrique Barboza, Chao Liu, Richard Henderson,
	Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

We forgot to add 'cbo' insns to disas/riscv.c.  The result is that the
disassembler recognizes all of them as 'lq', an insn that happens to
share the same opcode space.

While we're at it reorder cbo_* entries in insn32.decode using opcode
order instead of insn name.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3480
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-ID: <20260519204714.1376551-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/insn32.decode |  2 +-
 disas/riscv.c              | 29 ++++++++++++++++++++++++++++-
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 6e35c4b1e6..21272fdb50 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -207,9 +207,9 @@ ldu      ............   ..... 111 ..... 0000011 @i
 {
   [
     # *** RV32 Zicbom Standard Extension ***
+    cbo_inval  0000000 00000 ..... 010 00000 0001111 @sfence_vm
     cbo_clean  0000000 00001 ..... 010 00000 0001111 @sfence_vm
     cbo_flush  0000000 00010 ..... 010 00000 0001111 @sfence_vm
-    cbo_inval  0000000 00000 ..... 010 00000 0001111 @sfence_vm
 
     # *** RV32 Zicboz Standard Extension ***
     cbo_zero   0000000 00100 ..... 010 00000 0001111 @sfence_vm
diff --git a/disas/riscv.c b/disas/riscv.c
index d416a4d6b3..36609efdf5 100644
--- a/disas/riscv.c
+++ b/disas/riscv.c
@@ -985,6 +985,10 @@ typedef enum {
     rv_op_ssamoswap_d = 953,
     rv_op_c_sspush = 954,
     rv_op_c_sspopchk = 955,
+    rv_op_cbo_inval = 956,
+    rv_op_cbo_clean = 957,
+    rv_op_cbo_flush = 958,
+    rv_op_cbo_zero = 959,
 } rv_op;
 
 /* register names */
@@ -2255,6 +2259,10 @@ const rv_opcode_data rvi_opcode_data[] = {
       rv_op_sspush, 0 },
     { "c.sspopchk", rv_codec_cmop_ss, rv_fmt_rs1, NULL, rv_op_sspopchk,
       rv_op_sspopchk, 0 },
+   { "cbo.inval", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
+   { "cbo.clean", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
+   { "cbo.flush", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
+   { "cbo.zero", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
 };
 
 /* CSR names */
@@ -2876,7 +2884,26 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
             switch ((inst >> 12) & 0b111) {
             case 0: op = rv_op_fence; break;
             case 1: op = rv_op_fence_i; break;
-            case 2: op = rv_op_lq; break;
+            case 2:
+               /*
+                * 'lq' shares the "(...) 010 ..... 0001111" opcode space
+                * with 'cbo' insns.  Check the next 5 bits to select
+                * what we want:
+                *
+                * cbo_inval  0000000 00000 ..... 010 00000 0001111
+                * cbo_clean  0000000 00001 ..... 010 00000 0001111
+                * cbo_flush  0000000 00010 ..... 010 00000 0001111
+                * cbo_zero   0000000 00100 ..... 010 00000 0001111
+                *
+                * Anything that doesn't match these will default to 'lq'.
+                */
+               switch ((inst >> 17) & 0b11111) {
+               case 0: op = rv_op_cbo_inval; break;
+               case 1: op = rv_op_cbo_clean; break;
+               case 2: op = rv_op_cbo_flush; break;
+               case 4: op = rv_op_cbo_zero; break;
+               default: op = rv_op_lq; break;
+               }
             }
             break;
         case 4:
-- 
2.54.0



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

* [PULL 07/83] target/riscv: Do not hide Sstc CSRs from gdbstub
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (5 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 06/83] disas/riscv.c: add 'cbo' insns to disassembler alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 08/83] target/riscv: Reject Svinval instructions in U-mode alistair23
                   ` (77 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Zephyr Li, Alistair Francis, Chao Liu

From: Zephyr Li <fritchleybohrer@gmail.com>

The Sstc predicate currently checks both ext_sstc and rdtime_fn. This
causes the gdbstub CSR XML generation to skip Sstc CSRs when rdtime_fn
has not been initialized yet, even if the CPU supports Sstc.

As a result, GDB reports $stimecmp as void with a CPU that exposes the
sstc extension.

Only use ext_sstc for the early existence check, and keep the rdtime_fn
check for non-debugger accesses.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3496
Signed-off-by: Zephyr Li <fritchleybohrer@gmail.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Message-ID: <20260525024220.39027-1-fritchleybohrer@gmail.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/csr.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index d004a4bfb4..2e81221b1d 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -590,7 +590,7 @@ static RISCVException sstc(CPURISCVState *env, int csrno)
 {
     bool hmode_check = false;
 
-    if (!riscv_cpu_cfg(env)->ext_sstc || !env->rdtime_fn) {
+    if (!riscv_cpu_cfg(env)->ext_sstc) {
         return RISCV_EXCP_ILLEGAL_INST;
     }
 
@@ -607,6 +607,10 @@ static RISCVException sstc(CPURISCVState *env, int csrno)
         return RISCV_EXCP_NONE;
     }
 
+    if (!env->rdtime_fn) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+
     if (env->priv == PRV_M) {
         return RISCV_EXCP_NONE;
     }
-- 
2.54.0



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

* [PULL 08/83] target/riscv: Reject Svinval instructions in U-mode
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (6 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 07/83] target/riscv: Do not hide Sstc CSRs from gdbstub alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 09/83] target/riscv/insn_trans/trans_rvzicbo.c.inc: save opcode before helpers alistair23
                   ` (76 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Zephyr Li, Daniel Henrique Barboza, Alistair Francis,
	Chao Liu

From: Zephyr Li <fritchleybohrer@gmail.com>

The RISC-V privileged specification requires SFENCE.W.INVAL and
SFENCE.INVAL.IR to raise an illegal instruction exception when executed
in U-mode. Check the current privilege mode during translation and reject these
instructions in U-mode, so they are reported as illegal instructions.

Add a helper to reject these instructions in U-mode during translation.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3493

Suggested-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

Signed-off-by: Zephyr Li <fritchleybohrer@gmail.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260522033145.17850-1-fritchleybohrer@gmail.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/insn_trans/trans_svinval.c.inc | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/target/riscv/insn_trans/trans_svinval.c.inc b/target/riscv/insn_trans/trans_svinval.c.inc
index a06c3b214f..4614c1489c 100644
--- a/target/riscv/insn_trans/trans_svinval.c.inc
+++ b/target/riscv/insn_trans/trans_svinval.c.inc
@@ -22,11 +22,19 @@
     }                                      \
 } while (0)
 
+/* Test if priv level is M or S. */
+#define REQUIRE_PRIV_MS(ctx) do {          \
+    if (ctx->priv == PRV_U) {              \
+        return false;                      \
+    }                                      \
+} while (0)
+
 static bool trans_sinval_vma(DisasContext *ctx, arg_sinval_vma *a)
 {
     REQUIRE_SVINVAL(ctx);
     /* Do the same as sfence.vma currently */
     REQUIRE_EXT(ctx, RVS);
+    REQUIRE_PRIV_MS(ctx);
 #ifndef CONFIG_USER_ONLY
     decode_save_opc(ctx, 0);
     gen_helper_tlb_flush(tcg_env);
@@ -39,6 +47,7 @@ static bool trans_sfence_w_inval(DisasContext *ctx, arg_sfence_w_inval *a)
 {
     REQUIRE_SVINVAL(ctx);
     REQUIRE_EXT(ctx, RVS);
+    REQUIRE_PRIV_MS(ctx);
     /* Do nothing currently */
     return true;
 }
@@ -47,6 +56,7 @@ static bool trans_sfence_inval_ir(DisasContext *ctx, arg_sfence_inval_ir *a)
 {
     REQUIRE_SVINVAL(ctx);
     REQUIRE_EXT(ctx, RVS);
+    REQUIRE_PRIV_MS(ctx);
     /* Do nothing currently */
     return true;
 }
@@ -56,6 +66,7 @@ static bool trans_hinval_vvma(DisasContext *ctx, arg_hinval_vvma *a)
     REQUIRE_SVINVAL(ctx);
     /* Do the same as hfence.vvma currently */
     REQUIRE_EXT(ctx, RVH);
+    REQUIRE_PRIV_MS(ctx);
 #ifndef CONFIG_USER_ONLY
     decode_save_opc(ctx, 0);
     gen_helper_hyp_tlb_flush(tcg_env);
@@ -69,6 +80,7 @@ static bool trans_hinval_gvma(DisasContext *ctx, arg_hinval_gvma *a)
     REQUIRE_SVINVAL(ctx);
     /* Do the same as hfence.gvma currently */
     REQUIRE_EXT(ctx, RVH);
+    REQUIRE_PRIV_MS(ctx);
 #ifndef CONFIG_USER_ONLY
     decode_save_opc(ctx, 0);
     gen_helper_hyp_gvma_tlb_flush(tcg_env);
-- 
2.54.0



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

* [PULL 09/83] target/riscv/insn_trans/trans_rvzicbo.c.inc: save opcode before helpers
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (7 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 08/83] target/riscv: Reject Svinval instructions in U-mode alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 10/83] target/riscv/cpu_helper.c: fault with reserved PTE.PBMT val alistair23
                   ` (75 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

All helpers from this file can trigger ILLEGAL_INSN exceptions via
check_zicbo_envcfg() directly, bypassing the usual exception code from
translate.c.   If we don't save the opcode before each helper,
riscv_raise_exception() is triggered and env->bins won't be unwind during
cpu_loop_exit_restore() (code path cpu_restore_state ->
cpu_restore_state_from_tb() -> restore_state_to_opc()).

And finally, in riscv_cpu_do_interrupt(), we will set (m)tval = 0 when we can,
instead, set it to the cbo opcode that generated the exception.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3380
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520214704.1943652-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/insn_trans/trans_rvzicbo.c.inc | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/target/riscv/insn_trans/trans_rvzicbo.c.inc b/target/riscv/insn_trans/trans_rvzicbo.c.inc
index 15711c3140..096f7dde27 100644
--- a/target/riscv/insn_trans/trans_rvzicbo.c.inc
+++ b/target/riscv/insn_trans/trans_rvzicbo.c.inc
@@ -33,6 +33,8 @@ static bool trans_cbo_clean(DisasContext *ctx, arg_cbo_clean *a)
     REQUIRE_ZICBOM(ctx);
     TCGv src = get_address(ctx, a->rs1, 0);
 
+    /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */
+    decode_save_opc(ctx, 0);
     gen_helper_cbo_clean_flush(tcg_env, src);
     return true;
 }
@@ -42,6 +44,8 @@ static bool trans_cbo_flush(DisasContext *ctx, arg_cbo_flush *a)
     REQUIRE_ZICBOM(ctx);
     TCGv src = get_address(ctx, a->rs1, 0);
 
+    /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */
+    decode_save_opc(ctx, 0);
     gen_helper_cbo_clean_flush(tcg_env, src);
     return true;
 }
@@ -51,6 +55,8 @@ static bool trans_cbo_inval(DisasContext *ctx, arg_cbo_inval *a)
     REQUIRE_ZICBOM(ctx);
     TCGv src = get_address(ctx, a->rs1, 0);
 
+    /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */
+    decode_save_opc(ctx, 0);
     gen_helper_cbo_inval(tcg_env, src);
     return true;
 }
@@ -60,6 +66,8 @@ static bool trans_cbo_zero(DisasContext *ctx, arg_cbo_zero *a)
     REQUIRE_ZICBOZ(ctx);
     TCGv src = get_address(ctx, a->rs1, 0);
 
+    /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */
+    decode_save_opc(ctx, 0);
     gen_helper_cbo_zero(tcg_env, src);
     return true;
 }
-- 
2.54.0



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

* [PULL 10/83] target/riscv/cpu_helper.c: fault with reserved PTE.PBMT val
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (8 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 09/83] target/riscv/insn_trans/trans_rvzicbo.c.inc: save opcode before helpers alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 11/83] target/riscv/cpu_helper.c: allow LOAD_ADDR_MIS promotion to AMO fault alistair23
                   ` (74 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

We need to fault during any access done while PTE bits 62-61 are both
set, according to the RISC-V priv spec.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3494
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260521130727.2311629-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 17305e1bb7..bc63713ddf 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1446,6 +1446,25 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
                 return TRANSLATE_FAIL;
             }
 
+            /*
+             * priv spec, "Svpbmt" chapter:
+             * "For non-leaf PTEs, bits 62-61 are reserved for future
+             * standard use.  Until their use is defined by a standard
+             * extension, they must be cleared by software for forward
+             * compatibility, or else a page-fault exception is raised."
+             *
+             * For leaf PTEs the same bits are also reserved but in that
+             * case the page-fault is mandatory.  Make both cases consistent
+             * by also page faulting here.
+             */
+            if ((pte & PTE_PBMT) == PTE_PBMT) {
+                qemu_log_mask(LOG_GUEST_ERROR, "%s: PBMT bits 62 and 61 are "
+                        "reserved but are set in PTE: "
+                        "addr: 0x%" HWADDR_PRIx " pte: 0x" TARGET_FMT_lx "\n",
+                        __func__, pte_addr, pte);
+                return TRANSLATE_FAIL;
+            }
+
             if (!riscv_cpu_cfg(env)->ext_svnapot && (pte & PTE_N)) {
                 /* Reserved without Svnapot extension */
                 qemu_log_mask(LOG_GUEST_ERROR, "%s: N bit set in PTE, "
@@ -1498,6 +1517,23 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
         return TRANSLATE_FAIL;
     }
 
+    /*
+     * priv spec, "Svpbmt" chapter:
+     * "For leaf PTEs, setting bits 62-61 to the value 3 is reserved
+     * for future standard use. Until this value is defined by a
+     * standard extension, using this reserved value in a leaf PTE
+     * raises a page-fault exception. "
+     *
+     * Raise a fault if 62-61 (i.e. PTE_PBMT) are set.
+     */
+    if ((pte & PTE_PBMT) == PTE_PBMT) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: PBMT bits 62 and 61 are "
+                      "reserved but are set in leaf PTE: "
+                      "addr: 0x%" HWADDR_PRIx " pte: 0x" TARGET_FMT_lx "\n",
+                      __func__, pte_addr, pte);
+        return TRANSLATE_FAIL;
+    }
+
     target_ulong rwx = pte & (PTE_R | PTE_W | PTE_X);
     /* Check for reserved combinations of RWX flags. */
     switch (rwx) {
-- 
2.54.0



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

* [PULL 11/83] target/riscv/cpu_helper.c: allow LOAD_ADDR_MIS promotion to AMO fault
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (9 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 10/83] target/riscv/cpu_helper.c: fault with reserved PTE.PBMT val alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 12/83] target/riscv: Fix size of gpr and gprh alistair23
                   ` (73 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Daniel Henrique Barboza, qemu-stable,
	Alistair Francis, Chao Liu

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

promote_load_fault() is missing the promotion of misaligned AMO load
addresses, i.e. RISCV_EXCP_LOAD_ADDR_MIS should be promoted to
RISCV_EXCP_STORE_AMO_ADDR_MIS when RISCV_UW2_ALWAYS_STORE_AMO (i.e.
always_storeamo is true).

All other load AMO faults are already being covered.

Cc: qemu-stable@nongnu.org
Fixes: 98f21c30f5 ("target/riscv: AMO operations always raise store/AMO fault")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3503
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Message-ID: <20260522181353.429782-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index bc63713ddf..c3745cee19 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -2210,6 +2210,9 @@ static target_ulong promote_load_fault(target_ulong orig_cause)
 
     case RISCV_EXCP_LOAD_PAGE_FAULT:
         return RISCV_EXCP_STORE_PAGE_FAULT;
+
+    case RISCV_EXCP_LOAD_ADDR_MIS:
+        return RISCV_EXCP_STORE_AMO_ADDR_MIS;
     }
 
     /* if no promotion, return original cause */
-- 
2.54.0



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

* [PULL 12/83] target/riscv: Fix size of gpr and gprh
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (10 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 11/83] target/riscv/cpu_helper.c: allow LOAD_ADDR_MIS promotion to AMO fault alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 13/83] target/riscv: Fix size of vector CSRs alistair23
                   ` (72 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Alistair Francis, Pierrick Bouvier

From: Anton Johansson <anjo@rev.ng>

gprh is only needed for TARGET_RISCV64 when modeling 128-bit registers,
fixing their size to 64 bits makes sense.

gpr is also fixed to 64 bits since all direct uses of env->gpr
correctly zero extend/truncate to/from target_ulong, meaning
!TARGET_RISCV64 will behave as expected.

We do however need to be a bit careful when mapping 64-bit fields to
32-bit TCGv globals on big endian hosts.

Note, the cpu/rv128 VMSTATE version is bumped, breaking migration from
older versions.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Message-ID: <20260520125406.28693-2-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h       |  4 ++--
 target/riscv/cpu.c       |  2 +-
 target/riscv/machine.c   |  8 ++++----
 target/riscv/monitor.c   |  2 +-
 target/riscv/translate.c | 16 ++++++++++++++--
 5 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index f7d8a08c08..a440b03071 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -214,8 +214,8 @@ typedef struct PMUFixedCtrState {
 } PMUFixedCtrState;
 
 struct CPUArchState {
-    target_ulong gpr[32];
-    target_ulong gprh[32]; /* 64 top bits of the 128-bit registers */
+    uint64_t gpr[32];
+    uint64_t gprh[32]; /* 64 top bits of the 128-bit registers */
 
     /* vector coprocessor state. */
     uint64_t vreg[32 * RV_VLEN_MAX / 64] QEMU_ALIGNED(16);
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5903df9954..a57884dbc9 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -612,7 +612,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 #endif
 
     for (i = 0; i < 32; i++) {
-        qemu_fprintf(f, " %-8s " TARGET_FMT_lx,
+        qemu_fprintf(f, " %-8s %" PRIx64,
                      riscv_int_regnames[i], env->gpr[i]);
         if ((i & 3) == 3) {
             qemu_fprintf(f, "\n");
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index b92e38b11a..358320a7fe 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -178,11 +178,11 @@ static bool rv128_needed(void *opaque)
 
 static const VMStateDescription vmstate_rv128 = {
     .name = "cpu/rv128",
-    .version_id = 1,
-    .minimum_version_id = 1,
+    .version_id = 2,
+    .minimum_version_id = 2,
     .needed = rv128_needed,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINTTL_ARRAY(env.gprh, RISCVCPU, 32),
+        VMSTATE_UINT64_ARRAY(env.gprh, RISCVCPU, 32),
         VMSTATE_UINT64(env.mscratchh, RISCVCPU),
         VMSTATE_UINT64(env.sscratchh, RISCVCPU),
         VMSTATE_END_OF_LIST()
@@ -449,7 +449,7 @@ const VMStateDescription vmstate_riscv_cpu = {
     .minimum_version_id = 11,
     .post_load = riscv_cpu_post_load,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
+        VMSTATE_UINT64_ARRAY(env.gpr, RISCVCPU, 32),
         VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
         VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
         VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c
index 6380600241..9edac0533c 100644
--- a/target/riscv/monitor.c
+++ b/target/riscv/monitor.c
@@ -248,7 +248,7 @@ static bool reg_is_ulong_integer(CPURISCVState *env, const char *name,
                                  target_ulong *val, bool is_gprh)
 {
     const char * const *reg_names;
-    target_ulong *vals;
+    uint64_t *vals;
 
     if (is_gprh) {
         reg_names = riscv_int_regnamesh;
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 1e4f340256..640691e1c5 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -1469,12 +1469,24 @@ void riscv_translate_init(void)
      */
     cpu_gpr[0] = NULL;
     cpu_gprh[0] = NULL;
+    /*
+     * Be careful with big endian hosts when mapping 64-bit CPUArchState fields
+     * to 32-bit TCGv globals.  An offset of 4 bytes is applied so the least
+     * significant bytes are correctly written to.
+     */
+#if HOST_BIG_ENDIAN && !defined(TARGET_RISCV64)
+    size_t field_offset = 4;
+#else
+    size_t field_offset = 0;
+#endif
 
     for (i = 1; i < 32; i++) {
         cpu_gpr[i] = tcg_global_mem_new(tcg_env,
-            offsetof(CPURISCVState, gpr[i]), riscv_int_regnames[i]);
+            offsetof(CPURISCVState, gpr[i]) + field_offset,
+            riscv_int_regnames[i]);
         cpu_gprh[i] = tcg_global_mem_new(tcg_env,
-            offsetof(CPURISCVState, gprh[i]), riscv_int_regnamesh[i]);
+            offsetof(CPURISCVState, gprh[i]) + field_offset,
+            riscv_int_regnamesh[i]);
     }
 
     for (i = 0; i < 32; i++) {
-- 
2.54.0



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

* [PULL 13/83] target/riscv: Fix size of vector CSRs
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (11 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 12/83] target/riscv: Fix size of gpr and gprh alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 14/83] target/riscv: Fix size of pc, load_[val|res] alistair23
                   ` (71 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Alistair Francis, Pierrick Bouvier,
	Philippe Mathieu-Daudé

From: Anton Johansson <anjo@rev.ng>

According to version 20250508 of the unprivileged specification:
- vtype: bits 0..7 used, bit XLEN-1 illegal, rest reserved
  => fix to 64-bits.

- vxsat: bit 0 used, vxrm which would occupy bits 1..2 is stored
  separately, and bits 3..31 are set to 0
  => fix to 8-bits.

- vxrm: 2 lowest bits are used for rounding mode, rest set to 0
  => fix to 8-bits.

- vstart: maximum value of VLMAX-1, where VLMAX is at most 2^16
  => fix to 32-bits as vstart is mapped to a TCG global.

- vl: maximum value of VLEN which is at most 2^16
  => fix to 32-bits as vl is mapped to a TCG global.

Fields are shuffled for reduced padding.

Note, the cpu/vector VMSTATE version is bumped, breaking migration from
older versions.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20260520125406.28693-3-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h                      |  12 +--
 target/riscv/machine.c                  |  14 +--
 target/riscv/translate.c                |  12 ++-
 target/riscv/vector_helper.c            | 125 ++++++++++++++----------
 target/riscv/insn_trans/trans_rvv.c.inc |  22 ++---
 5 files changed, 103 insertions(+), 82 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index a440b03071..981073021f 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -193,7 +193,7 @@ FIELD(VTYPE, VSEW, 3, 3)
 FIELD(VTYPE, VTA, 6, 1)
 FIELD(VTYPE, VMA, 7, 1)
 FIELD(VTYPE, ALTFMT, 8, 1)
-FIELD(VTYPE, RESERVED, 9, sizeof(target_ulong) * 8 - 10)
+FIELD(VTYPE, RESERVED, 9, sizeof(uint64_t) * 8 - 10)
 
 typedef struct PMUCTRState {
     /* Current value of a counter */
@@ -219,11 +219,11 @@ struct CPUArchState {
 
     /* vector coprocessor state. */
     uint64_t vreg[32 * RV_VLEN_MAX / 64] QEMU_ALIGNED(16);
-    target_ulong vxrm;
-    target_ulong vxsat;
-    target_ulong vl;
-    target_ulong vstart;
-    target_ulong vtype;
+    uint64_t vtype;
+    uint32_t vl;
+    uint32_t vstart;
+    uint8_t vxrm;
+    uint8_t vxsat;
     bool vill;
 
     target_ulong pc;
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 358320a7fe..45e13a0105 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -138,16 +138,16 @@ static bool vector_needed(void *opaque)
 
 static const VMStateDescription vmstate_vector = {
     .name = "cpu/vector",
-    .version_id = 2,
-    .minimum_version_id = 2,
+    .version_id = 3,
+    .minimum_version_id = 3,
     .needed = vector_needed,
     .fields = (const VMStateField[]) {
         VMSTATE_UINT64_ARRAY(env.vreg, RISCVCPU, 32 * RV_VLEN_MAX / 64),
-        VMSTATE_UINTTL(env.vxrm, RISCVCPU),
-        VMSTATE_UINTTL(env.vxsat, RISCVCPU),
-        VMSTATE_UINTTL(env.vl, RISCVCPU),
-        VMSTATE_UINTTL(env.vstart, RISCVCPU),
-        VMSTATE_UINTTL(env.vtype, RISCVCPU),
+        VMSTATE_UINT64(env.vtype, RISCVCPU),
+        VMSTATE_UINT32(env.vl, RISCVCPU),
+        VMSTATE_UINT32(env.vstart, RISCVCPU),
+        VMSTATE_UINT8(env.vxrm, RISCVCPU),
+        VMSTATE_UINT8(env.vxsat, RISCVCPU),
         VMSTATE_BOOL(env.vill, RISCVCPU),
         VMSTATE_END_OF_LIST()
     }
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 640691e1c5..4a557b4907 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -38,8 +38,9 @@
 #include "tcg/tcg-cpu.h"
 
 /* global register indices */
-static TCGv cpu_gpr[32], cpu_gprh[32], cpu_pc, cpu_vl, cpu_vstart;
+static TCGv cpu_gpr[32], cpu_gprh[32], cpu_pc;
 static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */
+static TCGv_i32 cpu_vl, cpu_vstart;
 static TCGv load_res;
 static TCGv load_val;
 
@@ -1480,6 +1481,10 @@ void riscv_translate_init(void)
     size_t field_offset = 0;
 #endif
 
+    /* 32 bits in size, no offset needed */
+    size_t vl_offset = offsetof(CPURISCVState, vl);
+    size_t vstart_offset = offsetof(CPURISCVState, vstart);
+
     for (i = 1; i < 32; i++) {
         cpu_gpr[i] = tcg_global_mem_new(tcg_env,
             offsetof(CPURISCVState, gpr[i]) + field_offset,
@@ -1495,9 +1500,8 @@ void riscv_translate_init(void)
     }
 
     cpu_pc = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, pc), "pc");
-    cpu_vl = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, vl), "vl");
-    cpu_vstart = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, vstart),
-                            "vstart");
+    cpu_vl = tcg_global_mem_new_i32(tcg_env, vl_offset, "vl");
+    cpu_vstart = tcg_global_mem_new_i32(tcg_env, vstart_offset, "vstart");
     load_res = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, load_res),
                              "load_res");
     load_val = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, load_val),
diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
index 954a85c03a..89012fccb3 100644
--- a/target/riscv/vector_helper.c
+++ b/target/riscv/vector_helper.c
@@ -285,7 +285,7 @@ vext_continuous_ldst_host(CPURISCVState *env, vext_ldst_elem_fn_host *ldst_host,
     }
 }
 
-static void vext_set_tail_elems_1s(target_ulong vl, void *vd,
+static void vext_set_tail_elems_1s(uint32_t vl, void *vd,
                                    uint32_t desc, uint32_t nf,
                                    uint32_t esz, uint32_t max_elems)
 {
@@ -388,6 +388,12 @@ vext_page_ldst_us(CPURISCVState *env, void *vd, target_ulong addr,
     uint32_t evl = env->vstart + elems;
     MMUAccessType access_type = is_load ? MMU_DATA_LOAD : MMU_DATA_STORE;
 
+    /*
+     * Maximum vector length is VLMAX == 2^16 == LMUL * VL / SEW, and
+     * occurs for LMUL == 8, SEW == 8, VL == 2^16.
+     */
+    g_assert(env->vstart < UINT16_MAX && UINT16_MAX - env->vstart >= elems);
+
     /* Check page permission/pmp/watchpoint/etc. */
     probe_pages(env, addr, size, ra, access_type, mmu_index, &host, &flags,
                 true);
@@ -2224,12 +2230,12 @@ GEN_VEXT_VMERGE_VX(vmerge_vxm_d, int64_t, H8)
  * define common macros for fixed point here.
  */
 typedef void opivv2_rm_fn(void *vd, void *vs1, void *vs2, int i,
-                          CPURISCVState *env, int vxrm);
+                          CPURISCVState *env, uint8_t vxrm);
 
 #define OPIVV2_RM(NAME, TD, T1, T2, TX1, TX2, HD, HS1, HS2, OP)     \
 static inline void                                                  \
 do_##NAME(void *vd, void *vs1, void *vs2, int i,                    \
-          CPURISCVState *env, int vxrm)                             \
+          CPURISCVState *env, uint8_t vxrm)                         \
 {                                                                   \
     TX1 s1 = *((T1 *)vs1 + HS1(i));                                 \
     TX2 s2 = *((T2 *)vs2 + HS2(i));                                 \
@@ -2239,7 +2245,7 @@ do_##NAME(void *vd, void *vs1, void *vs2, int i,                    \
 static inline void
 vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2,
              CPURISCVState *env,
-             uint32_t vl, uint32_t vm, int vxrm,
+             uint32_t vl, uint32_t vm, uint8_t vxrm,
              opivv2_rm_fn *fn, uint32_t vma, uint32_t esz)
 {
     for (uint32_t i = env->vstart; i < vl; i++) {
@@ -2298,7 +2304,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2,     \
                  do_##NAME, ESZ);                               \
 }
 
-static inline uint8_t saddu8(CPURISCVState *env, int vxrm, uint8_t a,
+static inline uint8_t saddu8(CPURISCVState *env, uint8_t vxrm, uint8_t a,
                              uint8_t b)
 {
     uint8_t res = a + b;
@@ -2309,7 +2315,7 @@ static inline uint8_t saddu8(CPURISCVState *env, int vxrm, uint8_t a,
     return res;
 }
 
-static inline uint16_t saddu16(CPURISCVState *env, int vxrm, uint16_t a,
+static inline uint16_t saddu16(CPURISCVState *env, uint8_t vxrm, uint16_t a,
                                uint16_t b)
 {
     uint16_t res = a + b;
@@ -2320,7 +2326,7 @@ static inline uint16_t saddu16(CPURISCVState *env, int vxrm, uint16_t a,
     return res;
 }
 
-static inline uint32_t saddu32(CPURISCVState *env, int vxrm, uint32_t a,
+static inline uint32_t saddu32(CPURISCVState *env, uint8_t vxrm, uint32_t a,
                                uint32_t b)
 {
     uint32_t res = a + b;
@@ -2331,7 +2337,7 @@ static inline uint32_t saddu32(CPURISCVState *env, int vxrm, uint32_t a,
     return res;
 }
 
-static inline uint64_t saddu64(CPURISCVState *env, int vxrm, uint64_t a,
+static inline uint64_t saddu64(CPURISCVState *env, uint8_t vxrm, uint64_t a,
                                uint64_t b)
 {
     uint64_t res = a + b;
@@ -2352,12 +2358,12 @@ GEN_VEXT_VV_RM(vsaddu_vv_w, 4)
 GEN_VEXT_VV_RM(vsaddu_vv_d, 8)
 
 typedef void opivx2_rm_fn(void *vd, target_long s1, void *vs2, int i,
-                          CPURISCVState *env, int vxrm);
+                          CPURISCVState *env, uint8_t vxrm);
 
 #define OPIVX2_RM(NAME, TD, T1, T2, TX1, TX2, HD, HS2, OP)          \
 static inline void                                                  \
 do_##NAME(void *vd, target_long s1, void *vs2, int i,               \
-          CPURISCVState *env, int vxrm)                             \
+          CPURISCVState *env, uint8_t vxrm)                         \
 {                                                                   \
     TX2 s2 = *((T2 *)vs2 + HS2(i));                                 \
     *((TD *)vd + HD(i)) = OP(env, vxrm, s2, (TX1)(T1)s1);           \
@@ -2366,7 +2372,7 @@ do_##NAME(void *vd, target_long s1, void *vs2, int i,               \
 static inline void
 vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2,
              CPURISCVState *env,
-             uint32_t vl, uint32_t vm, int vxrm,
+             uint32_t vl, uint32_t vm, uint8_t vxrm,
              opivx2_rm_fn *fn, uint32_t vma, uint32_t esz)
 {
     for (uint32_t i = env->vstart; i < vl; i++) {
@@ -2435,7 +2441,8 @@ GEN_VEXT_VX_RM(vsaddu_vx_h, 2)
 GEN_VEXT_VX_RM(vsaddu_vx_w, 4)
 GEN_VEXT_VX_RM(vsaddu_vx_d, 8)
 
-static inline int8_t sadd8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
+static inline int8_t sadd8(CPURISCVState *env, uint8_t vxrm, int8_t a,
+                           int8_t b)
 {
     int8_t res = a + b;
     if ((res ^ a) & (res ^ b) & INT8_MIN) {
@@ -2445,7 +2452,7 @@ static inline int8_t sadd8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
     return res;
 }
 
-static inline int16_t sadd16(CPURISCVState *env, int vxrm, int16_t a,
+static inline int16_t sadd16(CPURISCVState *env, uint8_t vxrm, int16_t a,
                              int16_t b)
 {
     int16_t res = a + b;
@@ -2456,7 +2463,7 @@ static inline int16_t sadd16(CPURISCVState *env, int vxrm, int16_t a,
     return res;
 }
 
-static inline int32_t sadd32(CPURISCVState *env, int vxrm, int32_t a,
+static inline int32_t sadd32(CPURISCVState *env, uint8_t vxrm, int32_t a,
                              int32_t b)
 {
     int32_t res = a + b;
@@ -2467,7 +2474,7 @@ static inline int32_t sadd32(CPURISCVState *env, int vxrm, int32_t a,
     return res;
 }
 
-static inline int64_t sadd64(CPURISCVState *env, int vxrm, int64_t a,
+static inline int64_t sadd64(CPURISCVState *env, uint8_t vxrm, int64_t a,
                              int64_t b)
 {
     int64_t res = a + b;
@@ -2496,7 +2503,7 @@ GEN_VEXT_VX_RM(vsadd_vx_h, 2)
 GEN_VEXT_VX_RM(vsadd_vx_w, 4)
 GEN_VEXT_VX_RM(vsadd_vx_d, 8)
 
-static inline uint8_t ssubu8(CPURISCVState *env, int vxrm, uint8_t a,
+static inline uint8_t ssubu8(CPURISCVState *env, uint8_t vxrm, uint8_t a,
                              uint8_t b)
 {
     uint8_t res = a - b;
@@ -2507,7 +2514,7 @@ static inline uint8_t ssubu8(CPURISCVState *env, int vxrm, uint8_t a,
     return res;
 }
 
-static inline uint16_t ssubu16(CPURISCVState *env, int vxrm, uint16_t a,
+static inline uint16_t ssubu16(CPURISCVState *env, uint8_t vxrm, uint16_t a,
                                uint16_t b)
 {
     uint16_t res = a - b;
@@ -2518,7 +2525,7 @@ static inline uint16_t ssubu16(CPURISCVState *env, int vxrm, uint16_t a,
     return res;
 }
 
-static inline uint32_t ssubu32(CPURISCVState *env, int vxrm, uint32_t a,
+static inline uint32_t ssubu32(CPURISCVState *env, uint8_t vxrm, uint32_t a,
                                uint32_t b)
 {
     uint32_t res = a - b;
@@ -2529,7 +2536,7 @@ static inline uint32_t ssubu32(CPURISCVState *env, int vxrm, uint32_t a,
     return res;
 }
 
-static inline uint64_t ssubu64(CPURISCVState *env, int vxrm, uint64_t a,
+static inline uint64_t ssubu64(CPURISCVState *env, uint8_t vxrm, uint64_t a,
                                uint64_t b)
 {
     uint64_t res = a - b;
@@ -2558,7 +2565,8 @@ GEN_VEXT_VX_RM(vssubu_vx_h, 2)
 GEN_VEXT_VX_RM(vssubu_vx_w, 4)
 GEN_VEXT_VX_RM(vssubu_vx_d, 8)
 
-static inline int8_t ssub8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
+static inline int8_t ssub8(CPURISCVState *env, uint8_t vxrm, int8_t a,
+                           int8_t b)
 {
     int8_t res = a - b;
     if ((res ^ a) & (a ^ b) & INT8_MIN) {
@@ -2568,7 +2576,7 @@ static inline int8_t ssub8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
     return res;
 }
 
-static inline int16_t ssub16(CPURISCVState *env, int vxrm, int16_t a,
+static inline int16_t ssub16(CPURISCVState *env, uint8_t vxrm, int16_t a,
                              int16_t b)
 {
     int16_t res = a - b;
@@ -2579,7 +2587,7 @@ static inline int16_t ssub16(CPURISCVState *env, int vxrm, int16_t a,
     return res;
 }
 
-static inline int32_t ssub32(CPURISCVState *env, int vxrm, int32_t a,
+static inline int32_t ssub32(CPURISCVState *env, uint8_t vxrm, int32_t a,
                              int32_t b)
 {
     int32_t res = a - b;
@@ -2590,7 +2598,7 @@ static inline int32_t ssub32(CPURISCVState *env, int vxrm, int32_t a,
     return res;
 }
 
-static inline int64_t ssub64(CPURISCVState *env, int vxrm, int64_t a,
+static inline int64_t ssub64(CPURISCVState *env, uint8_t vxrm, int64_t a,
                              int64_t b)
 {
     int64_t res = a - b;
@@ -2620,7 +2628,7 @@ GEN_VEXT_VX_RM(vssub_vx_w, 4)
 GEN_VEXT_VX_RM(vssub_vx_d, 8)
 
 /* Vector Single-Width Averaging Add and Subtract */
-static inline uint8_t get_round(int vxrm, uint64_t v, uint8_t shift)
+static inline uint8_t get_round(uint8_t vxrm, uint64_t v, uint8_t shift)
 {
     uint8_t d = extract64(v, shift, 1);
     uint8_t d1;
@@ -2632,22 +2640,30 @@ static inline uint8_t get_round(int vxrm, uint64_t v, uint8_t shift)
 
     d1 = extract64(v, shift - 1, 1);
     D1 = extract64(v, 0, shift);
-    if (vxrm == 0) { /* round-to-nearest-up (add +0.5 LSB) */
+    switch (vxrm) {
+    case 0:
+        /* round-to-nearest-up (add +0.5 LSB) */
         return d1;
-    } else if (vxrm == 1) { /* round-to-nearest-even */
+    case 1:
+        /* round-to-nearest-even */
         if (shift > 1) {
             D2 = extract64(v, 0, shift - 1);
             return d1 & ((D2 != 0) | d);
         } else {
             return d1 & d;
         }
-    } else if (vxrm == 3) { /* round-to-odd (OR bits into LSB, aka "jam") */
+    case 2:
+        /* round-down (truncate) */
+        return 0;
+    case 3:
+        /* round-to-odd (OR bits into LSB, aka "jam") */
         return !d & (D1 != 0);
+    default:
+        g_assert_not_reached();
     }
-    return 0; /* round-down (truncate) */
 }
 
-static inline int32_t aadd32(CPURISCVState *env, int vxrm, int32_t a,
+static inline int32_t aadd32(CPURISCVState *env, uint8_t vxrm, int32_t a,
                              int32_t b)
 {
     int64_t res = (int64_t)a + b;
@@ -2656,7 +2672,7 @@ static inline int32_t aadd32(CPURISCVState *env, int vxrm, int32_t a,
     return (res >> 1) + round;
 }
 
-static inline int64_t aadd64(CPURISCVState *env, int vxrm, int64_t a,
+static inline int64_t aadd64(CPURISCVState *env, uint8_t vxrm, int64_t a,
                              int64_t b)
 {
     int64_t res = a + b;
@@ -2685,7 +2701,7 @@ GEN_VEXT_VX_RM(vaadd_vx_h, 2)
 GEN_VEXT_VX_RM(vaadd_vx_w, 4)
 GEN_VEXT_VX_RM(vaadd_vx_d, 8)
 
-static inline uint32_t aaddu32(CPURISCVState *env, int vxrm,
+static inline uint32_t aaddu32(CPURISCVState *env, uint8_t vxrm,
                                uint32_t a, uint32_t b)
 {
     uint64_t res = (uint64_t)a + b;
@@ -2694,7 +2710,7 @@ static inline uint32_t aaddu32(CPURISCVState *env, int vxrm,
     return (res >> 1) + round;
 }
 
-static inline uint64_t aaddu64(CPURISCVState *env, int vxrm,
+static inline uint64_t aaddu64(CPURISCVState *env, uint8_t vxrm,
                                uint64_t a, uint64_t b)
 {
     uint64_t res = a + b;
@@ -2722,7 +2738,7 @@ GEN_VEXT_VX_RM(vaaddu_vx_h, 2)
 GEN_VEXT_VX_RM(vaaddu_vx_w, 4)
 GEN_VEXT_VX_RM(vaaddu_vx_d, 8)
 
-static inline int32_t asub32(CPURISCVState *env, int vxrm, int32_t a,
+static inline int32_t asub32(CPURISCVState *env, uint8_t vxrm, int32_t a,
                              int32_t b)
 {
     int64_t res = (int64_t)a - b;
@@ -2731,7 +2747,7 @@ static inline int32_t asub32(CPURISCVState *env, int vxrm, int32_t a,
     return (res >> 1) + round;
 }
 
-static inline int64_t asub64(CPURISCVState *env, int vxrm, int64_t a,
+static inline int64_t asub64(CPURISCVState *env, uint8_t vxrm, int64_t a,
                              int64_t b)
 {
     int64_t res = (int64_t)a - b;
@@ -2760,7 +2776,7 @@ GEN_VEXT_VX_RM(vasub_vx_h, 2)
 GEN_VEXT_VX_RM(vasub_vx_w, 4)
 GEN_VEXT_VX_RM(vasub_vx_d, 8)
 
-static inline uint32_t asubu32(CPURISCVState *env, int vxrm,
+static inline uint32_t asubu32(CPURISCVState *env, uint8_t vxrm,
                                uint32_t a, uint32_t b)
 {
     int64_t res = (int64_t)a - b;
@@ -2769,7 +2785,7 @@ static inline uint32_t asubu32(CPURISCVState *env, int vxrm,
     return (res >> 1) + round;
 }
 
-static inline uint64_t asubu64(CPURISCVState *env, int vxrm,
+static inline uint64_t asubu64(CPURISCVState *env, uint8_t vxrm,
                                uint64_t a, uint64_t b)
 {
     uint64_t res = (uint64_t)a - b;
@@ -2798,7 +2814,8 @@ GEN_VEXT_VX_RM(vasubu_vx_w, 4)
 GEN_VEXT_VX_RM(vasubu_vx_d, 8)
 
 /* Vector Single-Width Fractional Multiply with Rounding and Saturation */
-static inline int8_t vsmul8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
+static inline int8_t vsmul8(CPURISCVState *env, uint8_t vxrm, int8_t a,
+                            int8_t b)
 {
     uint8_t round;
     int16_t res;
@@ -2818,7 +2835,7 @@ static inline int8_t vsmul8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
     }
 }
 
-static int16_t vsmul16(CPURISCVState *env, int vxrm, int16_t a, int16_t b)
+static int16_t vsmul16(CPURISCVState *env, uint8_t vxrm, int16_t a, int16_t b)
 {
     uint8_t round;
     int32_t res;
@@ -2838,7 +2855,7 @@ static int16_t vsmul16(CPURISCVState *env, int vxrm, int16_t a, int16_t b)
     }
 }
 
-static int32_t vsmul32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
+static int32_t vsmul32(CPURISCVState *env, uint8_t vxrm, int32_t a, int32_t b)
 {
     uint8_t round;
     int64_t res;
@@ -2858,7 +2875,7 @@ static int32_t vsmul32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
     }
 }
 
-static int64_t vsmul64(CPURISCVState *env, int vxrm, int64_t a, int64_t b)
+static int64_t vsmul64(CPURISCVState *env, uint8_t vxrm, int64_t a, int64_t b)
 {
     uint8_t round;
     uint64_t hi_64, lo_64;
@@ -2906,7 +2923,7 @@ GEN_VEXT_VX_RM(vsmul_vx_d, 8)
 
 /* Vector Single-Width Scaling Shift Instructions */
 static inline uint8_t
-vssrl8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b)
+vssrl8(CPURISCVState *env, uint8_t vxrm, uint8_t a, uint8_t b)
 {
     uint8_t round, shift = b & 0x7;
     uint8_t res;
@@ -2916,7 +2933,7 @@ vssrl8(CPURISCVState *env, int vxrm, uint8_t a, uint8_t b)
     return res;
 }
 static inline uint16_t
-vssrl16(CPURISCVState *env, int vxrm, uint16_t a, uint16_t b)
+vssrl16(CPURISCVState *env, uint8_t vxrm, uint16_t a, uint16_t b)
 {
     uint8_t round, shift = b & 0xf;
 
@@ -2924,7 +2941,7 @@ vssrl16(CPURISCVState *env, int vxrm, uint16_t a, uint16_t b)
     return (a >> shift) + round;
 }
 static inline uint32_t
-vssrl32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b)
+vssrl32(CPURISCVState *env, uint8_t vxrm, uint32_t a, uint32_t b)
 {
     uint8_t round, shift = b & 0x1f;
 
@@ -2932,7 +2949,7 @@ vssrl32(CPURISCVState *env, int vxrm, uint32_t a, uint32_t b)
     return (a >> shift) + round;
 }
 static inline uint64_t
-vssrl64(CPURISCVState *env, int vxrm, uint64_t a, uint64_t b)
+vssrl64(CPURISCVState *env, uint8_t vxrm, uint64_t a, uint64_t b)
 {
     uint8_t round, shift = b & 0x3f;
 
@@ -2958,7 +2975,7 @@ GEN_VEXT_VX_RM(vssrl_vx_w, 4)
 GEN_VEXT_VX_RM(vssrl_vx_d, 8)
 
 static inline int8_t
-vssra8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
+vssra8(CPURISCVState *env, uint8_t vxrm, int8_t a, int8_t b)
 {
     uint8_t round, shift = b & 0x7;
 
@@ -2966,7 +2983,7 @@ vssra8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
     return (a >> shift) + round;
 }
 static inline int16_t
-vssra16(CPURISCVState *env, int vxrm, int16_t a, int16_t b)
+vssra16(CPURISCVState *env, uint8_t vxrm, int16_t a, int16_t b)
 {
     uint8_t round, shift = b & 0xf;
 
@@ -2974,7 +2991,7 @@ vssra16(CPURISCVState *env, int vxrm, int16_t a, int16_t b)
     return (a >> shift) + round;
 }
 static inline int32_t
-vssra32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
+vssra32(CPURISCVState *env, uint8_t vxrm, int32_t a, int32_t b)
 {
     uint8_t round, shift = b & 0x1f;
 
@@ -2982,7 +2999,7 @@ vssra32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
     return (a >> shift) + round;
 }
 static inline int64_t
-vssra64(CPURISCVState *env, int vxrm, int64_t a, int64_t b)
+vssra64(CPURISCVState *env, uint8_t vxrm, int64_t a, int64_t b)
 {
     uint8_t round, shift = b & 0x3f;
 
@@ -3010,7 +3027,7 @@ GEN_VEXT_VX_RM(vssra_vx_d, 8)
 
 /* Vector Narrowing Fixed-Point Clip Instructions */
 static inline int8_t
-vnclip8(CPURISCVState *env, int vxrm, int16_t a, int8_t b)
+vnclip8(CPURISCVState *env, uint8_t vxrm, int16_t a, int8_t b)
 {
     uint8_t round, shift = b & 0xf;
     int16_t res;
@@ -3029,7 +3046,7 @@ vnclip8(CPURISCVState *env, int vxrm, int16_t a, int8_t b)
 }
 
 static inline int16_t
-vnclip16(CPURISCVState *env, int vxrm, int32_t a, int16_t b)
+vnclip16(CPURISCVState *env, uint8_t vxrm, int32_t a, int16_t b)
 {
     uint8_t round, shift = b & 0x1f;
     int32_t res;
@@ -3048,7 +3065,7 @@ vnclip16(CPURISCVState *env, int vxrm, int32_t a, int16_t b)
 }
 
 static inline int32_t
-vnclip32(CPURISCVState *env, int vxrm, int64_t a, int32_t b)
+vnclip32(CPURISCVState *env, uint8_t vxrm, int64_t a, int32_t b)
 {
     uint8_t round, shift = b & 0x3f;
     int64_t res;
@@ -3081,7 +3098,7 @@ GEN_VEXT_VX_RM(vnclip_wx_h, 2)
 GEN_VEXT_VX_RM(vnclip_wx_w, 4)
 
 static inline uint8_t
-vnclipu8(CPURISCVState *env, int vxrm, uint16_t a, uint8_t b)
+vnclipu8(CPURISCVState *env, uint8_t vxrm, uint16_t a, uint8_t b)
 {
     uint8_t round, shift = b & 0xf;
     uint16_t res;
@@ -3097,7 +3114,7 @@ vnclipu8(CPURISCVState *env, int vxrm, uint16_t a, uint8_t b)
 }
 
 static inline uint16_t
-vnclipu16(CPURISCVState *env, int vxrm, uint32_t a, uint16_t b)
+vnclipu16(CPURISCVState *env, uint8_t vxrm, uint32_t a, uint16_t b)
 {
     uint8_t round, shift = b & 0x1f;
     uint32_t res;
@@ -3113,7 +3130,7 @@ vnclipu16(CPURISCVState *env, int vxrm, uint32_t a, uint16_t b)
 }
 
 static inline uint32_t
-vnclipu32(CPURISCVState *env, int vxrm, uint64_t a, uint32_t b)
+vnclipu32(CPURISCVState *env, uint8_t vxrm, uint64_t a, uint32_t b)
 {
     uint8_t round, shift = b & 0x3f;
     uint64_t res;
diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc
index 9a86c6dcd4..23262b1d03 100644
--- a/target/riscv/insn_trans/trans_rvv.c.inc
+++ b/target/riscv/insn_trans/trans_rvv.c.inc
@@ -203,7 +203,7 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2)
 
     if (rd == 0 && rs1 == 0) {
         s1 = tcg_temp_new();
-        tcg_gen_mov_tl(s1, cpu_vl);
+        tcg_gen_ext_i32_tl(s1, cpu_vl);
     } else if (rs1 == 0) {
         /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
         s1 = tcg_constant_tl(RV_VLEN_MAX);
@@ -1213,9 +1213,9 @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf,
                 tcg_gen_qemu_st_i64(t8, addr, s->mem_idx, MO_LEUQ | atomicity);
             }
             if (i == size - 8) {
-                tcg_gen_movi_tl(cpu_vstart, 0);
+                tcg_gen_movi_i32(cpu_vstart, 0);
             } else {
-                tcg_gen_addi_tl(cpu_vstart, cpu_vstart, 8 >> log2_esz);
+                tcg_gen_addi_i32(cpu_vstart, cpu_vstart, 8 >> log2_esz);
             }
         }
     } else {
@@ -2426,7 +2426,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                  \
                            s->cfg_ptr->vlenb, data,                     \
                            (s->altfmt ? gen_helper_##BFA_HELPER :       \
                                         fns[s->sew - 1]));              \
-        tcg_gen_movi_tl(cpu_vstart, 0);                                 \
+        tcg_gen_movi_i32(cpu_vstart, 0);                                \
         finalize_rvv_inst(s);                                           \
                                                                         \
         return true;                                                    \
@@ -3641,7 +3641,7 @@ static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a)
         vec_element_loadi(s, t1, a->rs2, 0, true);
         tcg_gen_trunc_i64_tl(dest, t1);
         gen_set_gpr(s, a->rd, dest);
-        tcg_gen_movi_tl(cpu_vstart, 0);
+        tcg_gen_movi_i32(cpu_vstart, 0);
         finalize_rvv_inst(s);
         return true;
     }
@@ -3658,7 +3658,7 @@ static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
         TCGv s1;
         TCGLabel *over = gen_new_label();
 
-        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
+        tcg_gen_brcond_i32(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
 
         t1 = tcg_temp_new_i64();
 
@@ -3670,7 +3670,7 @@ static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
         tcg_gen_ext_tl_i64(t1, s1);
         vec_element_storei_tail(s, a->rd, t1);
         gen_set_label(over);
-        tcg_gen_movi_tl(cpu_vstart, 0);
+        tcg_gen_movi_i32(cpu_vstart, 0);
         finalize_rvv_inst(s);
         return true;
     }
@@ -3698,7 +3698,7 @@ static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
         }
 
         mark_fs_dirty(s);
-        tcg_gen_movi_tl(cpu_vstart, 0);
+        tcg_gen_movi_i32(cpu_vstart, 0);
         finalize_rvv_inst(s);
         return true;
     }
@@ -3719,7 +3719,7 @@ static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
         TCGLabel *over = gen_new_label();
 
         /* if vstart >= vl, skip vector register write back */
-        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
+        tcg_gen_brcond_i32(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
 
         /* NaN-box f[rs1] */
         t1 = tcg_temp_new_i64();
@@ -3728,7 +3728,7 @@ static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
         vec_element_storei_tail(s, a->rd, t1);
 
         gen_set_label(over);
-        tcg_gen_movi_tl(cpu_vstart, 0);
+        tcg_gen_movi_i32(cpu_vstart, 0);
         finalize_rvv_inst(s);
         return true;
     }
@@ -3793,7 +3793,7 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                  \
                                                                         \
         fns[s->sew](dest, mask, src1, src2, tcg_env, desc);             \
                                                                         \
-        tcg_gen_movi_tl(cpu_vstart, 0);                                 \
+        tcg_gen_movi_i32(cpu_vstart, 0);                                \
         finalize_rvv_inst(s);                                           \
                                                                         \
         return true;                                                    \
-- 
2.54.0



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

* [PULL 14/83] target/riscv: Fix size of pc, load_[val|res]
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (12 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 13/83] target/riscv: Fix size of vector CSRs alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 15/83] target/riscv: Fix size of frm and fflags alistair23
                   ` (70 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Fix to 64 bits in size and as these are mapped to TCG globals, be
careful with host endianness when allocating globals.  Casts are
added to logging expressions to retain the correct size for
TARGET_RISCV32.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-4-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        |  6 +++---
 target/riscv/cpu.c        |  2 +-
 target/riscv/cpu_helper.c |  6 +++---
 target/riscv/machine.c    |  6 +++---
 target/riscv/translate.c  | 12 +++++++-----
 5 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 981073021f..8f0e73b6b5 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -226,9 +226,9 @@ struct CPUArchState {
     uint8_t vxsat;
     bool vill;
 
-    target_ulong pc;
-    target_ulong load_res;
-    target_ulong load_val;
+    uint64_t pc;
+    uint64_t load_res;
+    uint64_t load_val;
 
     /* Floating-Point state */
     uint64_t fpr[32]; /* assume both F and D extensions */
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index a57884dbc9..c0b6218421 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -585,7 +585,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
         qemu_fprintf(f, " %s %d\n", "V      =  ", env->virt_enabled);
     }
 #endif
-    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
+    qemu_fprintf(f, " %s %" PRIx64 "\n", "pc      ", env->pc);
 #ifndef CONFIG_USER_ONLY
     for (i = 0; i < ARRAY_SIZE(csr_ops); i++) {
         int csrno = i;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index c3745cee19..f81354c90d 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -2373,9 +2373,9 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 
     qemu_log_mask(CPU_LOG_INT,
                   "%s: hart:%"PRIu64", async:%d, cause:"TARGET_FMT_lx", "
-                  "epc:0x"TARGET_FMT_lx", tval:0x"TARGET_FMT_lx", desc=%s\n",
-                  __func__, env->mhartid, async, cause, env->pc, tval,
-                  riscv_cpu_get_trap_name(cause, async));
+                  "epc:0x%"PRIx64", tval:0x"TARGET_FMT_lx", desc=%s\n",
+                  __func__, env->mhartid, async, cause, env->pc,
+                  tval, riscv_cpu_get_trap_name(cause, async));
 
     mode = env->priv <= PRV_S && cause < 64 &&
         (((deleg >> cause) & 1) || s_injected || vs_injected) ? PRV_S : PRV_M;
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 45e13a0105..a0376c7564 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -453,9 +453,9 @@ const VMStateDescription vmstate_riscv_cpu = {
         VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
         VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
         VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
-        VMSTATE_UINTTL(env.pc, RISCVCPU),
-        VMSTATE_UINTTL(env.load_res, RISCVCPU),
-        VMSTATE_UINTTL(env.load_val, RISCVCPU),
+        VMSTATE_UINT64(env.pc, RISCVCPU),
+        VMSTATE_UINT64(env.load_res, RISCVCPU),
+        VMSTATE_UINT64(env.load_val, RISCVCPU),
         VMSTATE_UINTTL(env.frm, RISCVCPU),
         VMSTATE_UINTTL(env.badaddr, RISCVCPU),
         VMSTATE_UINTTL(env.guest_phys_fault_addr, RISCVCPU),
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 4a557b4907..b444fde3ef 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -1484,6 +1484,10 @@ void riscv_translate_init(void)
     /* 32 bits in size, no offset needed */
     size_t vl_offset = offsetof(CPURISCVState, vl);
     size_t vstart_offset = offsetof(CPURISCVState, vstart);
+    /* 64 bits in size mapped to TCGv, needs offset */
+    size_t pc_offset     = offsetof(CPURISCVState, pc) + field_offset;
+    size_t res_offset    = offsetof(CPURISCVState, load_res) + field_offset;
+    size_t val_offset    = offsetof(CPURISCVState, load_val) + field_offset;
 
     for (i = 1; i < 32; i++) {
         cpu_gpr[i] = tcg_global_mem_new(tcg_env,
@@ -1499,11 +1503,9 @@ void riscv_translate_init(void)
             offsetof(CPURISCVState, fpr[i]), riscv_fpr_regnames[i]);
     }
 
-    cpu_pc = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, pc), "pc");
+    cpu_pc = tcg_global_mem_new(tcg_env, pc_offset, "pc");
     cpu_vl = tcg_global_mem_new_i32(tcg_env, vl_offset, "vl");
     cpu_vstart = tcg_global_mem_new_i32(tcg_env, vstart_offset, "vstart");
-    load_res = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, load_res),
-                             "load_res");
-    load_val = tcg_global_mem_new(tcg_env, offsetof(CPURISCVState, load_val),
-                             "load_val");
+    load_res = tcg_global_mem_new(tcg_env, res_offset, "load_res");
+    load_val = tcg_global_mem_new(tcg_env, val_offset, "load_val");
 }
-- 
2.54.0



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

* [PULL 15/83] target/riscv: Fix size of frm and fflags
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (13 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 14/83] target/riscv: Fix size of pc, load_[val|res] alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 16/83] target/riscv: Fix size of badaddr and bins alistair23
                   ` (69 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

According to version 20250508 of the unprivileged specification the frm
field of fcsr is 3-bits in size, fix it to 8-bits.  Similarly fflags is
5 bits, fix to 8.  Uses of frm is restricted to uint8_t where sensible,
helpers still need 32-bit arguments and the DisasContext field is kept
as int to represent -1 for an unknown rm.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-5-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        |  6 +++---
 target/riscv/csr.c        |  4 ++++
 target/riscv/fpu_helper.c | 10 +++++-----
 target/riscv/machine.c    |  2 +-
 target/riscv/translate.c  |  4 ++--
 5 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 8f0e73b6b5..6692bff456 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -232,7 +232,7 @@ struct CPUArchState {
 
     /* Floating-Point state */
     uint64_t fpr[32]; /* assume both F and D extensions */
-    target_ulong frm;
+    uint8_t frm;
     float_status fp_status;
 
     target_ulong badaddr;
@@ -667,8 +667,8 @@ G_NORETURN void riscv_raise_exception(CPURISCVState *env,
                                       RISCVException exception,
                                       uintptr_t pc);
 
-target_ulong riscv_cpu_get_fflags(CPURISCVState *env);
-void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong);
+uint8_t riscv_cpu_get_fflags(CPURISCVState *env);
+void riscv_cpu_set_fflags(CPURISCVState *env, uint8_t);
 
 #ifndef CONFIG_USER_ONLY
 void cpu_set_exception_base(int vp_index, target_ulong address);
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 2e81221b1d..8c2dcbeca4 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -918,6 +918,10 @@ static RISCVException write_frm(CPURISCVState *env, int csrno,
 static RISCVException read_fcsr(CPURISCVState *env, int csrno,
                                 target_ulong *val)
 {
+    /*
+     * This is an 8-bit operation, fflags make up the lower 5 bits and
+     * frm the upper 3 bits of fcsr.
+     */
     *val = (riscv_cpu_get_fflags(env) << FSR_AEXC_SHIFT)
         | (env->frm << FSR_RD_SHIFT);
     return RISCV_EXCP_NONE;
diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c
index af40561b31..e6d1ffb1d6 100644
--- a/target/riscv/fpu_helper.c
+++ b/target/riscv/fpu_helper.c
@@ -23,10 +23,10 @@
 #include "fpu/softfloat.h"
 #include "internals.h"
 
-target_ulong riscv_cpu_get_fflags(CPURISCVState *env)
+uint8_t riscv_cpu_get_fflags(CPURISCVState *env)
 {
     int soft = get_float_exception_flags(&env->fp_status);
-    target_ulong hard = 0;
+    uint8_t hard = 0;
 
     hard |= (soft & float_flag_inexact) ? FPEXC_NX : 0;
     hard |= (soft & float_flag_underflow) ? FPEXC_UF : 0;
@@ -37,7 +37,7 @@ target_ulong riscv_cpu_get_fflags(CPURISCVState *env)
     return hard;
 }
 
-void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong hard)
+void riscv_cpu_set_fflags(CPURISCVState *env, uint8_t hard)
 {
     int soft = 0;
 
@@ -52,7 +52,7 @@ void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong hard)
 
 void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm)
 {
-    int softrm;
+    FloatRoundMode softrm;
 
     if (rm == RISCV_FRM_DYN) {
         rm = env->frm;
@@ -82,7 +82,7 @@ void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm)
 
 void helper_set_rounding_mode_chkfrm(CPURISCVState *env, uint32_t rm)
 {
-    int softrm;
+    FloatRoundMode softrm;
 
     /* Always validate frm, even if rm != DYN. */
     if (unlikely(env->frm >= 5)) {
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index a0376c7564..5c692e0fe6 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -456,7 +456,7 @@ const VMStateDescription vmstate_riscv_cpu = {
         VMSTATE_UINT64(env.pc, RISCVCPU),
         VMSTATE_UINT64(env.load_res, RISCVCPU),
         VMSTATE_UINT64(env.load_val, RISCVCPU),
-        VMSTATE_UINTTL(env.frm, RISCVCPU),
+        VMSTATE_UINT8(env.frm, RISCVCPU),
         VMSTATE_UINTTL(env.badaddr, RISCVCPU),
         VMSTATE_UINTTL(env.guest_phys_fault_addr, RISCVCPU),
         VMSTATE_UINTTL(env.priv_ver, RISCVCPU),
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index b444fde3ef..7c23996271 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -753,7 +753,7 @@ static void finalize_rvv_inst(DisasContext *ctx)
     ctx->vstart_eq_zero = true;
 }
 
-static void gen_set_rm(DisasContext *ctx, int rm)
+static void gen_set_rm(DisasContext *ctx, uint8_t rm)
 {
     if (ctx->frm == rm) {
         return;
@@ -770,7 +770,7 @@ static void gen_set_rm(DisasContext *ctx, int rm)
     gen_helper_set_rounding_mode(tcg_env, tcg_constant_i32(rm));
 }
 
-static void gen_set_rm_chkfrm(DisasContext *ctx, int rm)
+static void gen_set_rm_chkfrm(DisasContext *ctx, uint8_t rm)
 {
     if (ctx->frm == rm && ctx->frm_valid) {
         return;
-- 
2.54.0



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

* [PULL 16/83] target/riscv: Fix size of badaddr and bins
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (14 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 15/83] target/riscv: Fix size of frm and fflags alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 17/83] target/riscv: Fix size of guest_phys_fault_addr alistair23
                   ` (68 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Fix these fields to 64 bits as they cannot be made smaller. Also make
sure stores to these fields from TCG are 64 bits in size to avoid
incorrect values on big endian hosts.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-6-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h                             | 4 ++--
 target/riscv/machine.c                         | 2 +-
 target/riscv/translate.c                       | 6 ++++--
 target/riscv/insn_trans/trans_privileged.c.inc | 2 +-
 4 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 6692bff456..2cc1b68f34 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -235,8 +235,8 @@ struct CPUArchState {
     uint8_t frm;
     float_status fp_status;
 
-    target_ulong badaddr;
-    target_ulong bins;
+    uint64_t badaddr;
+    uint64_t bins;
 
     target_ulong guest_phys_fault_addr;
 
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 5c692e0fe6..b7790c14d0 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -457,7 +457,7 @@ const VMStateDescription vmstate_riscv_cpu = {
         VMSTATE_UINT64(env.load_res, RISCVCPU),
         VMSTATE_UINT64(env.load_val, RISCVCPU),
         VMSTATE_UINT8(env.frm, RISCVCPU),
-        VMSTATE_UINTTL(env.badaddr, RISCVCPU),
+        VMSTATE_UINT64(env.badaddr, RISCVCPU),
         VMSTATE_UINTTL(env.guest_phys_fault_addr, RISCVCPU),
         VMSTATE_UINTTL(env.priv_ver, RISCVCPU),
         VMSTATE_UINTTL(env.vext_ver, RISCVCPU),
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 7c23996271..1ea7faea4c 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -273,7 +273,7 @@ static void generate_exception(DisasContext *ctx, RISCVException excp)
 
 static void gen_exception_illegal(DisasContext *ctx)
 {
-    tcg_gen_st_i32(tcg_constant_i32(ctx->opcode), tcg_env,
+    tcg_gen_st_i64(tcg_constant_i64(ctx->opcode), tcg_env,
                    offsetof(CPURISCVState, bins));
     if (ctx->virt_inst_excp) {
         generate_exception(ctx, RISCV_EXCP_VIRT_INSTRUCTION_FAULT);
@@ -284,7 +284,9 @@ static void gen_exception_illegal(DisasContext *ctx)
 
 static void gen_exception_inst_addr_mis(DisasContext *ctx, TCGv target)
 {
-    tcg_gen_st_tl(target, tcg_env, offsetof(CPURISCVState, badaddr));
+    TCGv_i64 ext = tcg_temp_new_i64();
+    tcg_gen_extu_tl_i64(ext, target);
+    tcg_gen_st_i64(ext, tcg_env, offsetof(CPURISCVState, badaddr));
     generate_exception(ctx, RISCV_EXCP_INST_ADDR_MIS);
 }
 
diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc
index 8a62b4cfcd..a8eaccef67 100644
--- a/target/riscv/insn_trans/trans_privileged.c.inc
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
@@ -68,7 +68,7 @@ static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
     if (pre == 0x01f01013 && ebreak == 0x00100073 && post == 0x40705013) {
         generate_exception(ctx, RISCV_EXCP_SEMIHOST);
     } else {
-        tcg_gen_st_tl(tcg_constant_tl(ebreak_addr), tcg_env,
+        tcg_gen_st_i64(tcg_constant_i64(ebreak_addr), tcg_env,
                       offsetof(CPURISCVState, badaddr));
         generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
     }
-- 
2.54.0



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

* [PULL 17/83] target/riscv: Fix size of guest_phys_fault_addr
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (15 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 16/83] target/riscv: Fix size of badaddr and bins alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 18/83] target/riscv: Fix size of priv_ver and vext_ver alistair23
                   ` (67 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Widen to 64 bits, and use hwaddr as argument to get_physical_address().

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-7-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        | 2 +-
 target/riscv/cpu_helper.c | 3 +--
 target/riscv/machine.c    | 2 +-
 3 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 2cc1b68f34..50f9ce1f86 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -238,7 +238,7 @@ struct CPUArchState {
     uint64_t badaddr;
     uint64_t bins;
 
-    target_ulong guest_phys_fault_addr;
+    uint64_t guest_phys_fault_addr;
 
     target_ulong priv_ver;
     target_ulong vext_ver;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index f81354c90d..a25727b0da 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1236,7 +1236,7 @@ static bool check_svukte_addr(CPURISCVState *env, vaddr addr)
  */
 static int get_physical_address(CPURISCVState *env, hwaddr *physical,
                                 int *ret_prot, vaddr addr,
-                                target_ulong *fault_pte_addr,
+                                hwaddr *fault_pte_addr,
                                 int access_type, int mmu_idx,
                                 bool first_stage, bool two_stage,
                                 bool is_debug, bool is_probe)
@@ -1876,7 +1876,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
         ret = get_physical_address(env, &pa, &prot, address,
                                    &env->guest_phys_fault_addr, access_type,
                                    mmu_idx, true, true, false, probe);
-
         /*
          * A G-stage exception may be triggered during two state lookup.
          * And the env->guest_phys_fault_addr has already been set in
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index b7790c14d0..a4d337c27a 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -458,7 +458,7 @@ const VMStateDescription vmstate_riscv_cpu = {
         VMSTATE_UINT64(env.load_val, RISCVCPU),
         VMSTATE_UINT8(env.frm, RISCVCPU),
         VMSTATE_UINT64(env.badaddr, RISCVCPU),
-        VMSTATE_UINTTL(env.guest_phys_fault_addr, RISCVCPU),
+        VMSTATE_UINT64(env.guest_phys_fault_addr, RISCVCPU),
         VMSTATE_UINTTL(env.priv_ver, RISCVCPU),
         VMSTATE_UINTTL(env.vext_ver, RISCVCPU),
         VMSTATE_UINT32(env.misa_mxl, RISCVCPU),
-- 
2.54.0



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

* [PULL 18/83] target/riscv: Fix size of priv_ver and vext_ver
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (16 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 17/83] target/riscv: Fix size of guest_phys_fault_addr alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 19/83] target/riscv: Fix size of retxh alistair23
                   ` (66 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Fix these fields to 32 bits, also update corresponding priv_ver field
in DisasContext as well as function arguments. 32 bits was chosen
since it's large enough to fit all stored values and int/int32_t is
used in RISCVCPUDef and a few functions.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-8-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h       | 6 +++---
 target/riscv/machine.c   | 4 ++--
 target/riscv/translate.c | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 50f9ce1f86..5336344cba 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -240,8 +240,8 @@ struct CPUArchState {
 
     uint64_t guest_phys_fault_addr;
 
-    target_ulong priv_ver;
-    target_ulong vext_ver;
+    uint32_t priv_ver;
+    uint32_t vext_ver;
 
     /* RISCVMXL, but uint32_t for vmstate migration */
     uint32_t misa_mxl;      /* current mxl */
@@ -846,7 +846,7 @@ bool riscv_cpu_eff_priv(CPURISCVState *env, int *priv, bool *virt)
 }
 
 static inline bool riscv_cpu_allow_16bit_insn(const RISCVCPUConfig *cfg,
-                                              target_long priv_ver,
+                                              uint32_t priv_ver,
                                               uint32_t misa_ext)
 {
     /* In priv spec version 1.12 or newer, C always implies Zca */
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index a4d337c27a..b6a85ccd3e 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -459,8 +459,8 @@ const VMStateDescription vmstate_riscv_cpu = {
         VMSTATE_UINT8(env.frm, RISCVCPU),
         VMSTATE_UINT64(env.badaddr, RISCVCPU),
         VMSTATE_UINT64(env.guest_phys_fault_addr, RISCVCPU),
-        VMSTATE_UINTTL(env.priv_ver, RISCVCPU),
-        VMSTATE_UINTTL(env.vext_ver, RISCVCPU),
+        VMSTATE_UINT32(env.priv_ver, RISCVCPU),
+        VMSTATE_UINT32(env.vext_ver, RISCVCPU),
         VMSTATE_UINT32(env.misa_mxl, RISCVCPU),
         VMSTATE_UINT32(env.misa_ext, RISCVCPU),
         VMSTATE_UNUSED(4),
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 1ea7faea4c..18a1e0ae99 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -59,7 +59,7 @@ typedef struct DisasContext {
     DisasContextBase base;
     target_ulong cur_insn_len;
     target_ulong pc_save;
-    target_ulong priv_ver;
+    uint32_t priv_ver;
     RISCVMXL misa_mxl_max;
     RISCVMXL xl;
     RISCVMXL address_xl;
-- 
2.54.0



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

* [PULL 19/83] target/riscv: Fix size of retxh
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (17 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 18/83] target/riscv: Fix size of priv_ver and vext_ver alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 20/83] target/riscv: Fix size of ssp alistair23
                   ` (65 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

128-bit helpers only make sense for MXL_RV128, TARGET_RISCV64,
and TCGv == TCGv_i64, therefore fix retxh to 64 bits.

For the sake of being pedandic, update 128-bit instructions to access
retxh via 64 bit TCG ops, even if they only make sense when TCGv ==
TCGv_i64.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-9-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h                      |  2 +-
 target/riscv/insn_trans/trans_rvi.c.inc |  8 ++++++--
 target/riscv/insn_trans/trans_rvm.c.inc | 16 ++++++++++++----
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 5336344cba..0a684f146f 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -250,7 +250,7 @@ struct CPUArchState {
     uint32_t xl;            /* current xlen */
 
     /* 128-bit helpers upper part return value */
-    target_ulong retxh;
+    uint64_t retxh;
 
     uint64_t jvt;
 
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index 2c82ae41a7..ff450d46f8 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -1030,10 +1030,12 @@ static bool do_csrr_i128(DisasContext *ctx, int rd, int rc)
     TCGv destl = dest_gpr(ctx, rd);
     TCGv desth = dest_gprh(ctx, rd);
     TCGv_i32 csr = tcg_constant_i32(rc);
+    TCGv_i64 wide_desth = tcg_temp_new_i64();
 
     translator_io_start(&ctx->base);
     gen_helper_csrr_i128(destl, tcg_env, csr);
-    tcg_gen_ld_tl(desth, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_ld_i64(wide_desth, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_trunc_i64_tl(desth, wide_desth);
     gen_set_gpr128(ctx, rd, destl, desth);
     return do_csr_post(ctx);
 }
@@ -1053,10 +1055,12 @@ static bool do_csrrw_i128(DisasContext *ctx, int rd, int rc,
     TCGv destl = dest_gpr(ctx, rd);
     TCGv desth = dest_gprh(ctx, rd);
     TCGv_i32 csr = tcg_constant_i32(rc);
+    TCGv_i64 wide_desth = tcg_temp_new_i64();
 
     translator_io_start(&ctx->base);
     gen_helper_csrrw_i128(destl, tcg_env, csr, srcl, srch, maskl, maskh);
-    tcg_gen_ld_tl(desth, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_ld_i64(wide_desth, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_trunc_i64_tl(desth, wide_desth);
     gen_set_gpr128(ctx, rd, destl, desth);
     return do_csr_post(ctx);
 }
diff --git a/target/riscv/insn_trans/trans_rvm.c.inc b/target/riscv/insn_trans/trans_rvm.c.inc
index 795f0ccf14..0e2da5bed2 100644
--- a/target/riscv/insn_trans/trans_rvm.c.inc
+++ b/target/riscv/insn_trans/trans_rvm.c.inc
@@ -169,8 +169,10 @@ static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a)
 static void gen_div_i128(TCGv rdl, TCGv rdh,
                          TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
 {
+    TCGv_i64 wide_rdh = tcg_temp_new_i64();
     gen_helper_divs_i128(rdl, tcg_env, rs1l, rs1h, rs2l, rs2h);
-    tcg_gen_ld_tl(rdh, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_ld_i64(wide_rdh, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_trunc_i64_tl(rdh, wide_rdh);
 }
 
 static void gen_div(TCGv ret, TCGv source1, TCGv source2)
@@ -212,8 +214,10 @@ static bool trans_div(DisasContext *ctx, arg_div *a)
 static void gen_divu_i128(TCGv rdl, TCGv rdh,
                           TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
 {
+    TCGv_i64 wide_rdh = tcg_temp_new_i64();
     gen_helper_divu_i128(rdl, tcg_env, rs1l, rs1h, rs2l, rs2h);
-    tcg_gen_ld_tl(rdh, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_ld_i64(wide_rdh, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_trunc_i64_tl(rdh, wide_rdh);
 }
 
 static void gen_divu(TCGv ret, TCGv source1, TCGv source2)
@@ -244,8 +248,10 @@ static bool trans_divu(DisasContext *ctx, arg_divu *a)
 static void gen_rem_i128(TCGv rdl, TCGv rdh,
                          TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
 {
+    TCGv_i64 wide_rdh = tcg_temp_new_i64();
     gen_helper_rems_i128(rdl, tcg_env, rs1l, rs1h, rs2l, rs2h);
-    tcg_gen_ld_tl(rdh, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_ld_i64(wide_rdh, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_trunc_i64_tl(rdh, wide_rdh);
 }
 
 static void gen_rem(TCGv ret, TCGv source1, TCGv source2)
@@ -289,8 +295,10 @@ static bool trans_rem(DisasContext *ctx, arg_rem *a)
 static void gen_remu_i128(TCGv rdl, TCGv rdh,
                           TCGv rs1l, TCGv rs1h, TCGv rs2l, TCGv rs2h)
 {
+    TCGv_i64 wide_rdh = tcg_temp_new_i64();
     gen_helper_remu_i128(rdl, tcg_env, rs1l, rs1h, rs2l, rs2h);
-    tcg_gen_ld_tl(rdh, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_ld_i64(wide_rdh, tcg_env, offsetof(CPURISCVState, retxh));
+    tcg_gen_trunc_i64_tl(rdh, wide_rdh);
 }
 
 static void gen_remu(TCGv ret, TCGv source1, TCGv source2)
-- 
2.54.0



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

* [PULL 20/83] target/riscv: Fix size of ssp
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (18 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 19/83] target/riscv: Fix size of retxh alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 21/83] target/riscv: Fix size of excp_uw2 alistair23
                   ` (64 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

As ssp holds a pointer, fix to 64 bits in size and make sure stores from
TCG use the correct size to avoid problems on big endian hosts.

Note, the cpu/ssp VMSTATE version is bumped, breaking migration from
older versions.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-10-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h                            |  2 +-
 target/riscv/machine.c                        |  6 +++---
 target/riscv/insn_trans/trans_rvzicfiss.c.inc | 18 +++++++++++++-----
 3 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0a684f146f..ae75f9f33f 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -257,7 +257,7 @@ struct CPUArchState {
     /* elp state for zicfilp extension */
     bool      elp;
     /* shadow stack register for zicfiss extension */
-    target_ulong ssp;
+    uint64_t ssp;
     /* env place holder for extra word 2 during unwind */
     target_ulong excp_uw2;
     /* sw check code for sw check exception */
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index b6a85ccd3e..7ab62ebc82 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -391,11 +391,11 @@ static bool ssp_needed(void *opaque)
 
 static const VMStateDescription vmstate_ssp = {
     .name = "cpu/ssp",
-    .version_id = 1,
-    .minimum_version_id = 1,
+    .version_id = 2,
+    .minimum_version_id = 2,
     .needed = ssp_needed,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINTTL(env.ssp, RISCVCPU),
+        VMSTATE_UINT64(env.ssp, RISCVCPU),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/target/riscv/insn_trans/trans_rvzicfiss.c.inc b/target/riscv/insn_trans/trans_rvzicfiss.c.inc
index 0b6ad57965..40e5a1b7df 100644
--- a/target/riscv/insn_trans/trans_rvzicfiss.c.inc
+++ b/target/riscv/insn_trans/trans_rvzicfiss.c.inc
@@ -32,7 +32,9 @@ static bool trans_sspopchk(DisasContext *ctx, arg_sspopchk *a)
     TCGLabel *skip = gen_new_label();
     uint32_t tmp = (get_xl(ctx) == MXL_RV64) ? 8 : 4;
     TCGv data = tcg_temp_new();
-    tcg_gen_ld_tl(addr, tcg_env, offsetof(CPURISCVState, ssp));
+    TCGv_i64 wide_addr = tcg_temp_new_i64();
+    tcg_gen_ld_i64(wide_addr, tcg_env, offsetof(CPURISCVState, ssp));
+    tcg_gen_trunc_i64_tl(addr, wide_addr);
     decode_save_opc(ctx, RISCV_UW2_ALWAYS_STORE_AMO);
     tcg_gen_qemu_ld_tl(data, addr, SS_MMU_INDEX(ctx),
                        mxl_memop(ctx) | MO_ALIGN);
@@ -45,7 +47,8 @@ static bool trans_sspopchk(DisasContext *ctx, arg_sspopchk *a)
                   tcg_constant_i32(RISCV_EXCP_SW_CHECK));
     gen_set_label(skip);
     tcg_gen_addi_tl(addr, addr, tmp);
-    tcg_gen_st_tl(addr, tcg_env, offsetof(CPURISCVState, ssp));
+    tcg_gen_ext_tl_i64(wide_addr, addr);
+    tcg_gen_st_i64(wide_addr, tcg_env, offsetof(CPURISCVState, ssp));
 
     return true;
 }
@@ -59,12 +62,15 @@ static bool trans_sspush(DisasContext *ctx, arg_sspush *a)
     TCGv addr = tcg_temp_new();
     int tmp = (get_xl(ctx) == MXL_RV64) ? -8 : -4;
     TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
+    TCGv_i64 wide_addr = tcg_temp_new_i64();
     decode_save_opc(ctx, RISCV_UW2_ALWAYS_STORE_AMO);
-    tcg_gen_ld_tl(addr, tcg_env, offsetof(CPURISCVState, ssp));
+    tcg_gen_ld_i64(wide_addr, tcg_env, offsetof(CPURISCVState, ssp));
+    tcg_gen_trunc_i64_tl(addr, wide_addr);
     tcg_gen_addi_tl(addr, addr, tmp);
     tcg_gen_qemu_st_tl(data, addr, SS_MMU_INDEX(ctx),
                        mxl_memop(ctx) | MO_ALIGN);
-    tcg_gen_st_tl(addr, tcg_env, offsetof(CPURISCVState, ssp));
+    tcg_gen_ext_tl_i64(wide_addr, addr);
+    tcg_gen_st_i64(wide_addr, tcg_env, offsetof(CPURISCVState, ssp));
 
     return true;
 }
@@ -76,7 +82,9 @@ static bool trans_ssrdp(DisasContext *ctx, arg_ssrdp *a)
     }
 
     TCGv dest = dest_gpr(ctx, a->rd);
-    tcg_gen_ld_tl(dest, tcg_env, offsetof(CPURISCVState, ssp));
+    TCGv_i64 wide_addr = tcg_temp_new_i64();
+    tcg_gen_ld_i64(wide_addr, tcg_env, offsetof(CPURISCVState, ssp));
+    tcg_gen_trunc_i64_tl(dest, wide_addr);
     gen_set_gpr(ctx, a->rd, dest);
 
     return true;
-- 
2.54.0



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

* [PULL 21/83] target/riscv: Fix size of excp_uw2
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (19 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 20/83] target/riscv: Fix size of ssp alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 22/83] target/riscv: Fix size of sw_check_code alistair23
                   ` (63 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Fix to 64 bits to match size of instruction start words.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-11-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h       | 2 +-
 target/riscv/translate.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index ae75f9f33f..ef21972615 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -259,7 +259,7 @@ struct CPUArchState {
     /* shadow stack register for zicfiss extension */
     uint64_t ssp;
     /* env place holder for extra word 2 during unwind */
-    target_ulong excp_uw2;
+    uint64_t excp_uw2;
     /* sw check code for sw check exception */
     target_ulong sw_check_code;
 #ifdef CONFIG_USER_ONLY
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 18a1e0ae99..9a0fd700d2 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -231,7 +231,7 @@ static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in)
     tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan);
 }
 
-static void decode_save_opc(DisasContext *ctx, target_ulong excp_uw2)
+static void decode_save_opc(DisasContext *ctx, uint64_t excp_uw2)
 {
     assert(!ctx->insn_start_updated);
     ctx->insn_start_updated = true;
-- 
2.54.0



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

* [PULL 22/83] target/riscv: Fix size of sw_check_code
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (20 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 21/83] target/riscv: Fix size of excp_uw2 alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 23/83] target/riscv: Fix size of priv alistair23
                   ` (62 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

The field only holds values of 2 and 3, fix its size to 8 bits and
update stores from TCG.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-12-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h                            | 2 +-
 target/riscv/translate.c                      | 4 ++--
 target/riscv/insn_trans/trans_rvi.c.inc       | 8 ++++----
 target/riscv/insn_trans/trans_rvzicfiss.c.inc | 4 ++--
 4 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index ef21972615..4794489ec3 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -261,7 +261,7 @@ struct CPUArchState {
     /* env place holder for extra word 2 during unwind */
     uint64_t excp_uw2;
     /* sw check code for sw check exception */
-    target_ulong sw_check_code;
+    uint8_t sw_check_code;
 #ifdef CONFIG_USER_ONLY
     uint32_t elf_flags;
 #endif
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 9a0fd700d2..6a1ae92e5a 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -1400,8 +1400,8 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
     if (ctx->fcfi_lp_expected) {
         /* Emit after insn_start, i.e. before the op following insn_start. */
         tcg_ctx->emit_before_op = QTAILQ_NEXT(ctx->base.insn_start, link);
-        tcg_gen_st_tl(tcg_constant_tl(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
-                      tcg_env, offsetof(CPURISCVState, sw_check_code));
+        tcg_gen_st8_i32(tcg_constant_i32(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
+                        tcg_env, offsetof(CPURISCVState, sw_check_code));
         gen_helper_raise_exception(tcg_env,
                       tcg_constant_i32(RISCV_EXCP_SW_CHECK));
         tcg_ctx->emit_before_op = NULL;
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index ff450d46f8..fea05d02cc 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -53,8 +53,8 @@ static bool trans_lpad(DisasContext *ctx, arg_lpad *a)
         /*
          * misaligned, according to spec we should raise sw check exception
          */
-        tcg_gen_st_tl(tcg_constant_tl(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
-                      tcg_env, offsetof(CPURISCVState, sw_check_code));
+        tcg_gen_st8_i32(tcg_constant_i32(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
+                        tcg_env, offsetof(CPURISCVState, sw_check_code));
         gen_helper_raise_exception(tcg_env,
                       tcg_constant_i32(RISCV_EXCP_SW_CHECK));
         return true;
@@ -66,8 +66,8 @@ static bool trans_lpad(DisasContext *ctx, arg_lpad *a)
         TCGv tmp = tcg_temp_new();
         tcg_gen_extract_tl(tmp, get_gpr(ctx, xT2, EXT_NONE), 12, 20);
         tcg_gen_brcondi_tl(TCG_COND_EQ, tmp, a->label, skip);
-        tcg_gen_st_tl(tcg_constant_tl(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
-                      tcg_env, offsetof(CPURISCVState, sw_check_code));
+        tcg_gen_st8_i32(tcg_constant_i32(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
+                        tcg_env, offsetof(CPURISCVState, sw_check_code));
         gen_helper_raise_exception(tcg_env,
                       tcg_constant_i32(RISCV_EXCP_SW_CHECK));
         gen_set_label(skip);
diff --git a/target/riscv/insn_trans/trans_rvzicfiss.c.inc b/target/riscv/insn_trans/trans_rvzicfiss.c.inc
index 40e5a1b7df..cb9c5419fa 100644
--- a/target/riscv/insn_trans/trans_rvzicfiss.c.inc
+++ b/target/riscv/insn_trans/trans_rvzicfiss.c.inc
@@ -40,8 +40,8 @@ static bool trans_sspopchk(DisasContext *ctx, arg_sspopchk *a)
                        mxl_memop(ctx) | MO_ALIGN);
     TCGv rs1 = get_gpr(ctx, a->rs1, EXT_NONE);
     tcg_gen_brcond_tl(TCG_COND_EQ, data, rs1, skip);
-    tcg_gen_st_tl(tcg_constant_tl(RISCV_EXCP_SW_CHECK_BCFI_TVAL),
-                  tcg_env, offsetof(CPURISCVState, sw_check_code));
+    tcg_gen_st8_i32(tcg_constant_i32(RISCV_EXCP_SW_CHECK_BCFI_TVAL),
+                    tcg_env, offsetof(CPURISCVState, sw_check_code));
     gen_update_pc(ctx, 0);
     gen_helper_raise_exception(tcg_env,
                   tcg_constant_i32(RISCV_EXCP_SW_CHECK));
-- 
2.54.0



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

* [PULL 23/83] target/riscv: Fix size of priv
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (21 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 22/83] target/riscv: Fix size of sw_check_code alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 24/83] target/riscv: Fix size of gei fields alistair23
                   ` (61 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

The priv field of CPUArchState only stores values in the range [0,3],
fix to 8 bits in size and update relevant function arguments.  Introduce
a new privilege_mode_t typedef for passing around the privilege mode.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-13-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        | 27 +++++++++++++++++----------
 target/riscv/internals.h  |  4 ++--
 target/riscv/pmu.h        |  2 +-
 target/riscv/cpu_helper.c | 37 ++++++++++++++++++++-----------------
 target/riscv/csr.c        | 10 ++++++----
 target/riscv/gdbstub.c    |  2 +-
 target/riscv/machine.c    |  2 +-
 target/riscv/op_helper.c  | 27 ++++++++++++++-------------
 target/riscv/pmu.c        |  9 ++++++---
 target/riscv/translate.c  |  2 +-
 10 files changed, 69 insertions(+), 53 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 4794489ec3..a57e28f40e 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -110,6 +110,12 @@ typedef struct riscv_cpu_profile {
 
 extern RISCVCPUProfile *riscv_profiles[];
 
+/*
+ * Type large enough to hold all PRV_* fields, update CPUArchState::priv
+ * migration field if changing this type.
+ */
+typedef uint8_t privilege_mode_t;
+
 /* Privileged specification version */
 #define PRIV_VER_1_10_0_STR "v1.10.0"
 #define PRIV_VER_1_11_0_STR "v1.11.0"
@@ -266,7 +272,7 @@ struct CPUArchState {
     uint32_t elf_flags;
 #endif
 
-    target_ulong priv;
+    privilege_mode_t priv;
     /* CSRs for execution environment configuration */
     uint64_t menvcfg;
     uint64_t senvcfg;
@@ -642,7 +648,7 @@ void riscv_cpu_interrupt(CPURISCVState *env);
 #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
 void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *),
                              void *arg);
-void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
+void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, privilege_mode_t priv,
                                    int (*rmw_fn)(void *arg,
                                                  target_ulong reg,
                                                  target_ulong *val,
@@ -653,10 +659,11 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
 RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
 #endif /* !CONFIG_USER_ONLY */
 
-void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool virt_en);
+void riscv_cpu_set_mode(CPURISCVState *env, privilege_mode_t newpriv,
+                        bool virt_en);
 
 void riscv_ctr_add_entry(CPURISCVState *env, target_long src, target_long dst,
-    enum CTRType type, target_ulong prev_priv, bool prev_virt);
+    enum CTRType type, privilege_mode_t prev_priv, bool prev_virt);
 void riscv_ctr_clear(CPURISCVState *env);
 
 void riscv_translate_init(void);
@@ -724,9 +731,9 @@ static inline const RISCVCPUConfig *riscv_cpu_cfg(CPURISCVState *env)
 }
 
 #if !defined(CONFIG_USER_ONLY)
-static inline int cpu_address_mode(CPURISCVState *env)
+static inline privilege_mode_t cpu_address_mode(CPURISCVState *env)
 {
-    int mode = env->priv;
+    privilege_mode_t mode = env->priv;
 
     if (mode == PRV_M && get_field(env->mstatus, MSTATUS_MPRV)) {
         mode = get_field(env->mstatus, MSTATUS_MPP);
@@ -734,7 +741,7 @@ static inline int cpu_address_mode(CPURISCVState *env)
     return mode;
 }
 
-static inline RISCVMXL cpu_get_xl(CPURISCVState *env, target_ulong mode)
+static inline RISCVMXL cpu_get_xl(CPURISCVState *env, privilege_mode_t mode)
 {
     RISCVMXL xl = env->misa_mxl;
     /*
@@ -780,7 +787,7 @@ static inline RISCVMXL cpu_address_xl(CPURISCVState *env)
 #ifdef CONFIG_USER_ONLY
     return env->xl;
 #else
-    int mode = cpu_address_mode(env);
+    privilege_mode_t mode = cpu_address_mode(env);
 
     return cpu_get_xl(env, mode);
 #endif
@@ -818,9 +825,9 @@ static inline RISCVMXL riscv_cpu_sxl(CPURISCVState *env)
  * Returns true if the effective privilege mode is modified.
  */
 static inline QEMU_ALWAYS_INLINE
-bool riscv_cpu_eff_priv(CPURISCVState *env, int *priv, bool *virt)
+bool riscv_cpu_eff_priv(CPURISCVState *env, privilege_mode_t *priv, bool *virt)
 {
-    int mode = env->priv;
+    privilege_mode_t mode = env->priv;
     bool virt_enabled = false;
     bool mode_modified = false;
 
diff --git a/target/riscv/internals.h b/target/riscv/internals.h
index 8c24af0d85..e143a86f97 100644
--- a/target/riscv/internals.h
+++ b/target/riscv/internals.h
@@ -43,9 +43,9 @@
 #define MMU_2STAGE_BIT      (1 << 2)
 #define MMU_IDX_SS_WRITE    (1 << 3)
 
-static inline int mmuidx_priv(int mmu_idx)
+static inline privilege_mode_t mmuidx_priv(int mmu_idx)
 {
-    int ret = mmu_idx & 3;
+    privilege_mode_t ret = mmu_idx & 3;
     if (ret == MMUIdx_S_SUM) {
         ret = PRV_S;
     }
diff --git a/target/riscv/pmu.h b/target/riscv/pmu.h
index 3853d0e262..b4f1e469a2 100644
--- a/target/riscv/pmu.h
+++ b/target/riscv/pmu.h
@@ -34,7 +34,7 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx);
 void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char *pmu_name);
 int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value,
                           uint32_t ctr_idx);
-void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, target_ulong newpriv,
+void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, privilege_mode_t newpriv,
                                  bool new_virt);
 RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val,
                                   bool upper_half, uint32_t ctr_idx);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index a25727b0da..9ffcc6fa51 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -44,7 +44,7 @@ int riscv_env_mmu_index(CPURISCVState *env, bool ifetch)
     return 0;
 #else
     bool virt = env->virt_enabled;
-    int mode = env->priv;
+    privilege_mode_t mode = env->priv;
     bool mode_modified = false;
 
     /* All priv -> mmu_idx mapping are here */
@@ -165,7 +165,7 @@ bool riscv_env_smode_dbltrp_enabled(CPURISCVState *env, bool virt)
 RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env)
 {
 #ifndef CONFIG_USER_ONLY
-    int priv_mode;
+    privilege_mode_t priv_mode;
     bool virt;
 
     riscv_cpu_eff_priv(env, &priv_mode, &virt);
@@ -217,7 +217,7 @@ RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env)
 RISCVPmPmm riscv_pm_get_vm_ldst_pmm(CPURISCVState *env)
 {
 #ifndef CONFIG_USER_ONLY
-    int priv_mode;
+    privilege_mode_t priv_mode;
 
     if (!riscv_cpu_cfg(env)->ext_ssnpm ||
         get_field(env->mstatus, MSTATUS_MXR) ||
@@ -245,7 +245,7 @@ bool riscv_cpu_virt_mem_enabled(CPURISCVState *env, bool is_vm_ldst)
 #ifndef CONFIG_USER_ONLY
     int satp_mode = 0;
     uint64_t satp;
-    int priv_mode;
+    privilege_mode_t priv_mode;
     bool virt = false;
 
     if (!is_vm_ldst) {
@@ -816,7 +816,7 @@ void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *),
     env->rdtime_fn_arg = arg;
 }
 
-void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
+void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, privilege_mode_t priv,
                                    int (*rmw_fn)(void *arg,
                                                  target_ulong reg,
                                                  target_ulong *val,
@@ -849,7 +849,7 @@ void riscv_ctr_clear(CPURISCVState *env)
     memset(env->ctr_data, 0x0, sizeof(env->ctr_data));
 }
 
-static uint64_t riscv_ctr_priv_to_mask(target_ulong priv, bool virt)
+static uint64_t riscv_ctr_priv_to_mask(privilege_mode_t priv, bool virt)
 {
     switch (priv) {
     case PRV_M:
@@ -869,7 +869,8 @@ static uint64_t riscv_ctr_priv_to_mask(target_ulong priv, bool virt)
     g_assert_not_reached();
 }
 
-static uint64_t riscv_ctr_get_control(CPURISCVState *env, target_long priv,
+static uint64_t riscv_ctr_get_control(CPURISCVState *env,
+                                      privilege_mode_t priv,
                                       bool virt)
 {
     switch (priv) {
@@ -891,10 +892,11 @@ static uint64_t riscv_ctr_get_control(CPURISCVState *env, target_long priv,
  * and src privilege is less than target privilege. This includes the virtual
  * state as well.
  */
-static bool riscv_ctr_check_xte(CPURISCVState *env, target_long src_prv,
+static bool riscv_ctr_check_xte(CPURISCVState *env,
+                                privilege_mode_t src_prv,
                                 bool src_virt)
 {
-    target_long tgt_prv = env->priv;
+    privilege_mode_t tgt_prv = env->priv;
     bool res = true;
 
     /*
@@ -980,7 +982,7 @@ static bool riscv_ctr_check_xte(CPURISCVState *env, target_long src_prv,
  *    idx = (sctrstatus.WRPTR - entry - 1) & (depth - 1);
  */
 void riscv_ctr_add_entry(CPURISCVState *env, target_long src, target_long dst,
-    enum CTRType type, target_ulong src_priv, bool src_virt)
+    enum CTRType type, privilege_mode_t src_priv, bool src_virt)
 {
     bool tgt_virt = env->virt_enabled;
     uint64_t src_mask = riscv_ctr_priv_to_mask(src_priv, src_virt);
@@ -1078,7 +1080,8 @@ void riscv_ctr_add_entry(CPURISCVState *env, target_long src, target_long dst,
     env->sctrstatus = set_field(env->sctrstatus, SCTRSTATUS_WRPTR_MASK, head);
 }
 
-void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool virt_en)
+void riscv_cpu_set_mode(CPURISCVState *env, privilege_mode_t newpriv,
+                        bool virt_en)
 {
     g_assert(newpriv <= PRV_M && newpriv != PRV_RESERVED);
 
@@ -1141,7 +1144,7 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool virt_en)
  */
 static int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
                                     int size, MMUAccessType access_type,
-                                    int mode)
+                                    privilege_mode_t mode)
 {
     pmp_priv_t pmp_priv;
     bool pmp_has_privs;
@@ -1165,7 +1168,7 @@ static int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
 
 /* Returns 'true' if a svukte address check is needed */
 static bool do_svukte_check(CPURISCVState *env, bool first_stage,
-                             int mode, bool virt)
+                            privilege_mode_t mode, bool virt)
 {
     /* Svukte extension depends on Sv39. */
     if (!(env_archcpu(env)->cfg.ext_svukte ||
@@ -1248,7 +1251,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
      */
     MemTxResult res;
     MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
-    int mode = mmuidx_priv(mmu_idx);
+    privilege_mode_t mode = mmuidx_priv(mmu_idx);
     bool virt = mmuidx_2stage(mmu_idx);
     bool use_background = false;
     hwaddr ppn;
@@ -1861,7 +1864,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     bool two_stage_lookup = mmuidx_2stage(mmu_idx);
     bool two_stage_indirect_error = false;
     int ret = TRANSLATE_FAIL;
-    int mode = mmuidx_priv(mmu_idx);
+    privilege_mode_t mode = mmuidx_priv(mmu_idx);
     /* default TLB page size */
     hwaddr tlb_size = TARGET_PAGE_SIZE;
 
@@ -2250,7 +2253,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
     bool always_storeamo = (env->excp_uw2 & RISCV_UW2_ALWAYS_STORE_AMO);
     bool vsmode_exc;
     uint64_t s;
-    int mode;
+    privilege_mode_t mode;
 
     /*
      * cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide
@@ -2266,7 +2269,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
     bool smode_double_trap = false;
     uint64_t hdeleg = async ? env->hideleg : env->hedeleg;
     const bool prev_virt = env->virt_enabled;
-    const target_ulong prev_priv = env->priv;
+    const privilege_mode_t prev_priv = env->priv;
     uint64_t last_pc = env->pc;
     target_ulong tval = 0;
     target_ulong tinst = 0;
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 8c2dcbeca4..f885f5d4f7 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -374,7 +374,7 @@ static RISCVException aia_smode(CPURISCVState *env, int csrno)
 static RISCVException aia_smode32(CPURISCVState *env, int csrno)
 {
     int ret;
-    int csr_priv = get_field(csrno, 0x300);
+    privilege_mode_t csr_priv = get_field(csrno, 0x300);
 
     if (csr_priv == PRV_M && !riscv_cpu_cfg(env)->ext_smaia) {
         return RISCV_EXCP_ILLEGAL_INST;
@@ -2671,7 +2671,8 @@ static RISCVException rmw_xireg_aia(CPURISCVState *env, int csrno,
     bool virt = false, isel_reserved = false;
     int ret = -EINVAL;
     uint8_t *iprio;
-    target_ulong priv, vgein;
+    privilege_mode_t priv;
+    uint32_t vgein;
 
     /* VS-mode CSR number passed in has already been translated */
     switch (csrno) {
@@ -2956,7 +2957,8 @@ static RISCVException rmw_xtopei(CPURISCVState *env, int csrno,
 {
     bool virt;
     int ret = -EINVAL;
-    target_ulong priv, vgein;
+    privilege_mode_t priv;
+    uint32_t vgein;
 
     /* Translate CSR number for VS-mode */
     csrno = aia_xlate_vs_csrno(env, csrno);
@@ -5647,7 +5649,7 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
     }
 
 #if !defined(CONFIG_USER_ONLY)
-    int csr_priv, effective_priv = env->priv;
+    privilege_mode_t csr_priv, effective_priv = env->priv;
 
     if (riscv_has_ext(env, RVH) && env->priv == PRV_S &&
         !env->virt_enabled) {
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 2c6ccd4761..7abacd0e11 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -223,7 +223,7 @@ static int riscv_gdb_set_virtual(CPUState *cs, uint8_t *mem_buf, int n)
         const unsigned regsz = riscv_cpu_is_32bit(cpu) ? 4 : 8;
 #ifndef CONFIG_USER_ONLY
         CPURISCVState *env = &cpu->env;
-        uint64_t new_priv = ldn(env, mem_buf, regsz) & 0x3;
+        privilege_mode_t new_priv = ldn(env, mem_buf, regsz) & 0x3;
         bool new_virt = 0;
 
         if (new_priv == PRV_RESERVED) {
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 7ab62ebc82..045e830242 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -465,7 +465,7 @@ const VMStateDescription vmstate_riscv_cpu = {
         VMSTATE_UINT32(env.misa_ext, RISCVCPU),
         VMSTATE_UNUSED(4),
         VMSTATE_UINT32(env.misa_ext_mask, RISCVCPU),
-        VMSTATE_UINTTL(env.priv, RISCVCPU),
+        VMSTATE_UINT8(env.priv, RISCVCPU),
         VMSTATE_BOOL(env.virt_enabled, RISCVCPU),
         VMSTATE_UINT64(env.resetvec, RISCVCPU),
         VMSTATE_UINT64(env.mhartid, RISCVCPU),
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 81873014cb..c074b24bc9 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -286,8 +286,9 @@ void helper_sc_probe_write(CPURISCVState *env, target_ulong addr,
 target_ulong helper_sret(CPURISCVState *env)
 {
     uint64_t mstatus;
-    target_ulong prev_priv, prev_virt = env->virt_enabled;
-    const target_ulong src_priv = env->priv;
+    privilege_mode_t prev_priv;
+    bool prev_virt = env->virt_enabled;
+    const privilege_mode_t src_priv = env->priv;
     const bool src_virt = env->virt_enabled;
 
     if (!(env->priv >= PRV_S)) {
@@ -339,7 +340,7 @@ target_ulong helper_sret(CPURISCVState *env)
         /* We support Hypervisor extensions and virtulisation is disabled */
         target_ulong hstatus = env->hstatus;
 
-        prev_virt = get_field(hstatus, HSTATUS_SPV);
+        prev_virt = !!(get_field(hstatus, HSTATUS_SPV));
         hstatus = set_field(hstatus, HSTATUS_SPV, 0);
 
         env->hstatus = hstatus;
@@ -369,7 +370,7 @@ target_ulong helper_sret(CPURISCVState *env)
 }
 
 static void check_ret_from_m_mode(CPURISCVState *env, target_ulong retpc,
-                                  target_ulong prev_priv,
+                                  privilege_mode_t prev_priv,
                                   uintptr_t ra)
 {
     if (!(env->priv >= PRV_M)) {
@@ -388,8 +389,8 @@ static void check_ret_from_m_mode(CPURISCVState *env, target_ulong retpc,
     }
 }
 static target_ulong ssdbltrp_mxret(CPURISCVState *env, target_ulong mstatus,
-                                   target_ulong prev_priv,
-                                   target_ulong prev_virt)
+                                   privilege_mode_t prev_priv,
+                                   bool prev_virt)
 {
     /* If returning to U, VS or VU, sstatus.sdt = 0 */
     if (prev_priv == PRV_U || (prev_virt &&
@@ -408,13 +409,13 @@ target_ulong helper_mret(CPURISCVState *env)
 {
     target_ulong retpc = env->mepc & get_xepc_mask(env);
     uint64_t mstatus = env->mstatus;
-    target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
+    privilege_mode_t prev_priv = get_field(mstatus, MSTATUS_MPP);
     uintptr_t ra = GETPC();
 
     check_ret_from_m_mode(env, retpc, prev_priv, ra);
 
-    target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV) &&
-                             (prev_priv != PRV_M);
+    bool prev_virt = !!(get_field(env->mstatus, MSTATUS_MPV) &&
+                     (prev_priv != PRV_M));
     mstatus = set_field(mstatus, MSTATUS_MIE,
                         get_field(mstatus, MSTATUS_MPIE));
     mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
@@ -457,14 +458,14 @@ target_ulong helper_mret(CPURISCVState *env)
 target_ulong helper_mnret(CPURISCVState *env)
 {
     target_ulong retpc = env->mnepc;
-    target_ulong prev_priv = get_field(env->mnstatus, MNSTATUS_MNPP);
-    target_ulong prev_virt;
+    privilege_mode_t prev_priv = get_field(env->mnstatus, MNSTATUS_MNPP);
+    bool prev_virt;
     uintptr_t ra = GETPC();
 
     check_ret_from_m_mode(env, retpc, prev_priv, ra);
 
-    prev_virt = get_field(env->mnstatus, MNSTATUS_MNPV) &&
-                (prev_priv != PRV_M);
+    prev_virt = !!(get_field(env->mnstatus, MNSTATUS_MNPV) &&
+                (prev_priv != PRV_M));
     env->mnstatus = set_field(env->mnstatus, MNSTATUS_NMIE, true);
 
     /*
diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c
index 708f2ec7aa..3444400bd2 100644
--- a/target/riscv/pmu.c
+++ b/target/riscv/pmu.c
@@ -114,7 +114,8 @@ static bool riscv_pmu_counter_enabled(RISCVCPU *cpu, uint32_t ctr_idx)
  *  new priv and new virt values are passed in as arguments.
  */
 static void riscv_pmu_icount_update_priv(CPURISCVState *env,
-                                         target_ulong newpriv, bool new_virt)
+                                         privilege_mode_t newpriv,
+                                         bool new_virt)
 {
     uint64_t *snapshot_prev, *snapshot_new;
     uint64_t current_icount;
@@ -154,7 +155,8 @@ static void riscv_pmu_icount_update_priv(CPURISCVState *env,
 }
 
 static void riscv_pmu_cycle_update_priv(CPURISCVState *env,
-                                        target_ulong newpriv, bool new_virt)
+                                        privilege_mode_t newpriv,
+                                        bool new_virt)
 {
     uint64_t *snapshot_prev, *snapshot_new;
     uint64_t current_ticks;
@@ -189,7 +191,8 @@ static void riscv_pmu_cycle_update_priv(CPURISCVState *env,
     counter_arr[env->priv] += delta;
 }
 
-void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, target_ulong newpriv,
+void riscv_pmu_update_fixed_ctrs(CPURISCVState *env,
+                                 privilege_mode_t newpriv,
                                  bool new_virt)
 {
     riscv_pmu_cycle_update_priv(env, newpriv, new_virt);
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 6a1ae92e5a..3132386801 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -68,7 +68,7 @@ typedef struct DisasContext {
     RISCVExtStatus mstatus_fs;
     RISCVExtStatus mstatus_vs;
     uint32_t mem_idx;
-    uint32_t priv;
+    privilege_mode_t priv;
     /*
      * Remember the rounding mode encoded in the previous fp instruction,
      * which we have already installed into env->fp_status.  Or -1 for
-- 
2.54.0



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

* [PULL 24/83] target/riscv: Fix size of gei fields
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (22 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 23/83] target/riscv: Fix size of priv alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 25/83] target/riscv: Fix size of [m|s|vs]iselect fields alistair23
                   ` (60 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

geilen takes the values 31 or 63, fix it to 8 bits. hgeie and hgeip are
at most 64 bits in size, fix to 64.  Update relevant function arguments
and uses of hgeie and hgeip.  Note, masking is widened to 64-bit as
geilen is already verified to be smaller than the target long size, and
an out-of-bounds shift would be UB anyway.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-14-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        | 10 +++++-----
 target/riscv/cpu.c        |  4 ++--
 target/riscv/cpu_helper.c |  4 ++--
 target/riscv/csr.c        |  4 ++--
 target/riscv/machine.c    |  4 ++--
 5 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index a57e28f40e..2a4b7378f3 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -280,7 +280,7 @@ struct CPUArchState {
 #ifndef CONFIG_USER_ONLY
     /* This contains QEMU specific information about the virt state. */
     bool virt_enabled;
-    target_ulong geilen;
+    uint8_t geilen;
     uint64_t resetvec;
 
     uint64_t mhartid;
@@ -357,8 +357,8 @@ struct CPUArchState {
     uint64_t htval;
     uint64_t htinst;
     uint64_t hgatp;
-    target_ulong hgeie;
-    target_ulong hgeip;
+    uint64_t hgeie;
+    uint64_t hgeip;
     uint64_t htimedelta;
     uint64_t hvien;
 
@@ -611,8 +611,8 @@ int riscv_cpu_mirq_pending(CPURISCVState *env);
 int riscv_cpu_sirq_pending(CPURISCVState *env);
 int riscv_cpu_vsirq_pending(CPURISCVState *env);
 bool riscv_cpu_fp_enabled(CPURISCVState *env);
-target_ulong riscv_cpu_get_geilen(CPURISCVState *env);
-void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen);
+uint8_t riscv_cpu_get_geilen(CPURISCVState *env);
+void riscv_cpu_set_geilen(CPURISCVState *env, uint8_t geilen);
 bool riscv_cpu_vector_enabled(CPURISCVState *env);
 void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
 int riscv_env_mmu_index(CPURISCVState *env, bool ifetch);
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index c0b6218421..c063604298 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1084,9 +1084,9 @@ static void riscv_cpu_set_irq(void *opaque, int irq, int level)
         }
 
         /* Update HGEIP CSR */
-        env->hgeip &= ~((target_ulong)1 << irq);
+        env->hgeip &= ~(1ULL << irq);
         if (level) {
-            env->hgeip |= (target_ulong)1 << irq;
+            env->hgeip |= 1ULL << irq;
         }
 
         /* Update mip.SGEIP bit */
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 9ffcc6fa51..4529341696 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -712,7 +712,7 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
     }
 }
 
-target_ulong riscv_cpu_get_geilen(CPURISCVState *env)
+uint8_t riscv_cpu_get_geilen(CPURISCVState *env)
 {
     if (!riscv_has_ext(env, RVH)) {
         return 0;
@@ -721,7 +721,7 @@ target_ulong riscv_cpu_get_geilen(CPURISCVState *env)
     return env->geilen;
 }
 
-void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen)
+void riscv_cpu_set_geilen(CPURISCVState *env, uint8_t geilen)
 {
     if (!riscv_has_ext(env, RVH)) {
         return;
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index f885f5d4f7..0d0b2fca49 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -3786,7 +3786,7 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno,
 
     if (csrno != CSR_HVIP) {
         gin = get_field(env->hstatus, HSTATUS_VGEIN);
-        old_mip |= (env->hgeip & ((target_ulong)1 << gin)) ? MIP_VSEIP : 0;
+        old_mip |= (env->hgeip & (1ULL << gin)) ? MIP_VSEIP : 0;
         old_mip |= env->vstime_irq ? MIP_VSTIP : 0;
     }
 
@@ -4971,7 +4971,7 @@ static RISCVException write_hgeie(CPURISCVState *env, int csrno,
                                   target_ulong val, uintptr_t ra)
 {
     /* Only GEILEN:1 bits implemented and BIT0 is never implemented */
-    val &= ((((target_ulong)1) << env->geilen) - 1) << 1;
+    val &= ((1ULL << env->geilen) - 1) << 1;
     env->hgeie = val;
     /* Update mip.SGEIP bit */
     riscv_cpu_update_mip(env, MIP_SGEIP,
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 045e830242..eb57ab07dc 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -92,8 +92,8 @@ static const VMStateDescription vmstate_hyper = {
         VMSTATE_UINT64(env.htval, RISCVCPU),
         VMSTATE_UINT64(env.htinst, RISCVCPU),
         VMSTATE_UINT64(env.hgatp, RISCVCPU),
-        VMSTATE_UINTTL(env.hgeie, RISCVCPU),
-        VMSTATE_UINTTL(env.hgeip, RISCVCPU),
+        VMSTATE_UINT64(env.hgeie, RISCVCPU),
+        VMSTATE_UINT64(env.hgeip, RISCVCPU),
         VMSTATE_UINT64(env.hvien, RISCVCPU),
         VMSTATE_UINT64(env.hvip, RISCVCPU),
         VMSTATE_UINT64(env.htimedelta, RISCVCPU),
-- 
2.54.0



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

* [PULL 25/83] target/riscv: Fix size of [m|s|vs]iselect fields
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (23 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 24/83] target/riscv: Fix size of gei fields alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 26/83] target/riscv: Fix arguments to board IMSIC emulation callbacks alistair23
                   ` (59 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

[m|s|vs]iselect are defined in version 20250508 of the privileged
specification to be XLEN in size, however QEMU only ever uses at most
16 bits of these fields, so fix them to 16.  Update relevant function
arguments.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-15-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h     |  8 ++++----
 target/riscv/csr.c     | 32 ++++++++++++++++----------------
 target/riscv/machine.c |  6 +++---
 3 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 2a4b7378f3..c338df1598 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -344,8 +344,8 @@ struct CPUArchState {
     uint8_t siprio[64];
 
     /* AIA CSRs */
-    target_ulong miselect;
-    target_ulong siselect;
+    uint16_t miselect;
+    uint16_t siselect;
     uint64_t mvien;
     uint64_t mvip;
 
@@ -391,7 +391,7 @@ struct CPUArchState {
     uint64_t vsatp;
 
     /* AIA VS-mode CSRs */
-    target_ulong vsiselect;
+    uint16_t vsiselect;
 
     uint64_t mtval2;
     uint64_t mtinst;
@@ -794,7 +794,7 @@ static inline RISCVMXL cpu_address_xl(CPURISCVState *env)
 }
 #endif
 
-static inline int riscv_cpu_xlen(CPURISCVState *env)
+static inline uint16_t riscv_cpu_xlen(CPURISCVState *env)
 {
     return 16 << env->xl;
 }
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 0d0b2fca49..29db646589 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2440,7 +2440,7 @@ static RISCVException rmw_xiselect(CPURISCVState *env, int csrno,
                                    target_ulong *val, target_ulong new_val,
                                    target_ulong wr_mask)
 {
-    target_ulong *iselect;
+    uint16_t *iselect;
     int ret;
 
     ret = smstateen_acc_ok(env, 0, SMSTATEEN0_SVSLCT);
@@ -2483,18 +2483,18 @@ static RISCVException rmw_xiselect(CPURISCVState *env, int csrno,
     return RISCV_EXCP_NONE;
 }
 
-static bool xiselect_aia_range(target_ulong isel)
+static bool xiselect_aia_range(uint16_t isel)
 {
     return (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) ||
            (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST);
 }
 
-static bool xiselect_cd_range(target_ulong isel)
+static bool xiselect_cd_range(uint16_t isel)
 {
     return (ISELECT_CD_FIRST <= isel && isel <= ISELECT_CD_LAST);
 }
 
-static bool xiselect_ctr_range(int csrno, target_ulong isel)
+static bool xiselect_ctr_range(int csrno, uint16_t isel)
 {
     /* MIREG-MIREG6 for the range 0x200-0x2ff are not used by CTR. */
     return CTR_ENTRIES_FIRST <= isel && isel <= CTR_ENTRIES_LAST &&
@@ -2502,7 +2502,7 @@ static bool xiselect_ctr_range(int csrno, target_ulong isel)
 }
 
 static int rmw_iprio(target_ulong xlen,
-                     target_ulong iselect, uint8_t *iprio,
+                     uint16_t iselect, uint8_t *iprio,
                      target_ulong *val, target_ulong new_val,
                      target_ulong wr_mask, int ext_irq_no)
 {
@@ -2546,7 +2546,7 @@ static int rmw_iprio(target_ulong xlen,
     return 0;
 }
 
-static int rmw_ctrsource(CPURISCVState *env, int isel, target_ulong *val,
+static int rmw_ctrsource(CPURISCVState *env, uint16_t isel, target_ulong *val,
                           target_ulong new_val, target_ulong wr_mask)
 {
     /*
@@ -2585,7 +2585,7 @@ static int rmw_ctrsource(CPURISCVState *env, int isel, target_ulong *val,
     return 0;
 }
 
-static int rmw_ctrtarget(CPURISCVState *env, int isel, target_ulong *val,
+static int rmw_ctrtarget(CPURISCVState *env, uint16_t isel, target_ulong *val,
                           target_ulong new_val, target_ulong wr_mask)
 {
     /*
@@ -2624,7 +2624,7 @@ static int rmw_ctrtarget(CPURISCVState *env, int isel, target_ulong *val,
     return 0;
 }
 
-static int rmw_ctrdata(CPURISCVState *env, int isel, target_ulong *val,
+static int rmw_ctrdata(CPURISCVState *env, uint16_t isel, target_ulong *val,
                         target_ulong new_val, target_ulong wr_mask)
 {
     /*
@@ -2665,7 +2665,7 @@ static int rmw_ctrdata(CPURISCVState *env, int isel, target_ulong *val,
 }
 
 static RISCVException rmw_xireg_aia(CPURISCVState *env, int csrno,
-                         target_ulong isel, target_ulong *val,
+                         uint16_t isel, target_ulong *val,
                          target_ulong new_val, target_ulong wr_mask)
 {
     bool virt = false, isel_reserved = false;
@@ -2746,12 +2746,12 @@ done:
 }
 
 static int rmw_xireg_cd(CPURISCVState *env, int csrno,
-                        target_ulong isel, target_ulong *val,
+                        uint16_t isel, target_ulong *val,
                         target_ulong new_val, target_ulong wr_mask)
 {
     int ret = -EINVAL;
-    int ctr_index = isel - ISELECT_CD_FIRST;
-    int isel_hpm_start = ISELECT_CD_FIRST + 3;
+    uint16_t ctr_index = isel - ISELECT_CD_FIRST;
+    uint16_t isel_hpm_start = ISELECT_CD_FIRST + 3;
 
     if (!riscv_cpu_cfg(env)->ext_smcdeleg || !riscv_cpu_cfg(env)->ext_ssccfg) {
         ret = RISCV_EXCP_ILLEGAL_INST;
@@ -2818,7 +2818,7 @@ done:
 }
 
 static int rmw_xireg_ctr(CPURISCVState *env, int csrno,
-                        target_ulong isel, target_ulong *val,
+                        uint16_t isel, target_ulong *val,
                         target_ulong new_val, target_ulong wr_mask)
 {
     if (!riscv_cpu_cfg(env)->ext_smctr && !riscv_cpu_cfg(env)->ext_ssctr) {
@@ -2846,7 +2846,7 @@ static int rmw_xireg_ctr(CPURISCVState *env, int csrno,
  * extension using csrind should be implemented here.
  */
 static int rmw_xireg_csrind(CPURISCVState *env, int csrno,
-                              target_ulong isel, target_ulong *val,
+                              uint16_t isel, target_ulong *val,
                               target_ulong new_val, target_ulong wr_mask)
 {
     bool virt = csrno == CSR_VSIREG ? true : false;
@@ -2876,7 +2876,7 @@ static int rmw_xiregi(CPURISCVState *env, int csrno, target_ulong *val,
                       target_ulong new_val, target_ulong wr_mask)
 {
     int ret = -EINVAL;
-    target_ulong isel;
+    uint16_t isel;
 
     ret = smstateen_acc_ok(env, 0, SMSTATEEN0_SVSLCT);
     if (ret != RISCV_EXCP_NONE) {
@@ -2907,7 +2907,7 @@ static RISCVException rmw_xireg(CPURISCVState *env, int csrno,
                                 target_ulong wr_mask)
 {
     int ret = -EINVAL;
-    target_ulong isel;
+    uint16_t isel;
 
     ret = smstateen_acc_ok(env, 0, SMSTATEEN0_SVSLCT);
     if (ret != RISCV_EXCP_NONE) {
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index eb57ab07dc..45fd39994e 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -109,7 +109,7 @@ static const VMStateDescription vmstate_hyper = {
         VMSTATE_UINT64(env.vscause, RISCVCPU),
         VMSTATE_UINT64(env.vstval, RISCVCPU),
         VMSTATE_UINT64(env.vsatp, RISCVCPU),
-        VMSTATE_UINTTL(env.vsiselect, RISCVCPU),
+        VMSTATE_UINT16(env.vsiselect, RISCVCPU),
         VMSTATE_UINT64(env.vsie, RISCVCPU),
 
         VMSTATE_UINT64(env.mtval2, RISCVCPU),
@@ -487,8 +487,8 @@ const VMStateDescription vmstate_riscv_cpu = {
         VMSTATE_UINT64(env.mepc, RISCVCPU),
         VMSTATE_UINT64(env.mcause, RISCVCPU),
         VMSTATE_UINT64(env.mtval, RISCVCPU),
-        VMSTATE_UINTTL(env.miselect, RISCVCPU),
-        VMSTATE_UINTTL(env.siselect, RISCVCPU),
+        VMSTATE_UINT16(env.miselect, RISCVCPU),
+        VMSTATE_UINT16(env.siselect, RISCVCPU),
         VMSTATE_UINT32(env.scounteren, RISCVCPU),
         VMSTATE_UINT32(env.mcounteren, RISCVCPU),
         VMSTATE_UINT32(env.scountinhibit, RISCVCPU),
-- 
2.54.0



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

* [PULL 26/83] target/riscv: Fix arguments to board IMSIC emulation callbacks
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (24 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 25/83] target/riscv: Fix size of [m|s|vs]iselect fields alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 27/83] target/riscv: Fix size of irq_overflow_left alistair23
                   ` (58 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

In hw/ the relevant RISCVIMSICState fields
eidelivery, eithreshold, eistate are uint32_t.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-16-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        | 42 ++++++++++++++++++++-------------------
 hw/intc/riscv_imsic.c     | 34 +++++++++++++++----------------
 target/riscv/cpu_helper.c | 12 ++++-------
 target/riscv/csr.c        | 24 ++++++++++++----------
 4 files changed, 57 insertions(+), 55 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index c338df1598..380749f9a8 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -201,6 +201,24 @@ FIELD(VTYPE, VMA, 7, 1)
 FIELD(VTYPE, ALTFMT, 8, 1)
 FIELD(VTYPE, RESERVED, 9, sizeof(uint64_t) * 8 - 10)
 
+#ifndef CONFIG_USER_ONLY
+/* machine specific AIA ireg read-modify-write callback */
+#define AIA_MAKE_IREG(__isel, __priv, __virt, __vgein, __xlen)                 \
+    ((uint32_t)((((__xlen) & 0xff) << 24) |                                    \
+                (((__vgein) & 0x3f) << 20) |                                   \
+                (((__virt) & 0x1) << 18) |                                     \
+                (((__priv) & 0x3) << 16) |                                     \
+                  (__isel & 0xffff)))
+#define AIA_IREG_ISEL(__ireg) ((__ireg) & 0xffff)
+#define AIA_IREG_PRIV(__ireg) (((__ireg) >> 16) & 0x3)
+#define AIA_IREG_VIRT(__ireg) (((__ireg) >> 18) & 0x1)
+#define AIA_IREG_VGEIN(__ireg) (((__ireg) >> 20) & 0x3f)
+#define AIA_IREG_XLEN(__ireg) (((__ireg) >> 24) & 0xff)
+
+typedef int (*aia_ireg_rmw_fn)(void *arg, uint32_t reg, uint64_t *val,
+                               uint64_t new_val, uint64_t write_mask);
+#endif
+
 typedef struct PMUCTRState {
     /* Current value of a counter */
     uint64_t mhpmcounter_val;
@@ -466,20 +484,8 @@ struct CPUArchState {
     void *rdtime_fn_arg;
 
     /* machine specific AIA ireg read-modify-write callback */
-#define AIA_MAKE_IREG(__isel, __priv, __virt, __vgein, __xlen) \
-    ((((__xlen) & 0xff) << 24) | \
-     (((__vgein) & 0x3f) << 20) | \
-     (((__virt) & 0x1) << 18) | \
-     (((__priv) & 0x3) << 16) | \
-     (__isel & 0xffff))
-#define AIA_IREG_ISEL(__ireg)                  ((__ireg) & 0xffff)
-#define AIA_IREG_PRIV(__ireg)                  (((__ireg) >> 16) & 0x3)
-#define AIA_IREG_VIRT(__ireg)                  (((__ireg) >> 18) & 0x1)
-#define AIA_IREG_VGEIN(__ireg)                 (((__ireg) >> 20) & 0x3f)
-#define AIA_IREG_XLEN(__ireg)                  (((__ireg) >> 24) & 0xff)
-    int (*aia_ireg_rmw_fn[4])(void *arg, target_ulong reg,
-        target_ulong *val, target_ulong new_val, target_ulong write_mask);
-    void *aia_ireg_rmw_fn_arg[4];
+    aia_ireg_rmw_fn aia_ireg_rmw_cb[4];
+    void *aia_ireg_rmw_cb_arg[4];
 
     /* True if in debugger mode.  */
     bool debugger;
@@ -648,12 +654,8 @@ void riscv_cpu_interrupt(CPURISCVState *env);
 #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
 void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *),
                              void *arg);
-void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, privilege_mode_t priv,
-                                   int (*rmw_fn)(void *arg,
-                                                 target_ulong reg,
-                                                 target_ulong *val,
-                                                 target_ulong new_val,
-                                                 target_ulong write_mask),
+void riscv_cpu_set_aia_ireg_rmw_cb(CPURISCVState *env, privilege_mode_t priv,
+                                   aia_ireg_rmw_fn rmw_fn,
                                    void *rmw_fn_arg);
 
 RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c
index ac59496c22..1c86ecdb2c 100644
--- a/hw/intc/riscv_imsic.c
+++ b/hw/intc/riscv_imsic.c
@@ -88,11 +88,11 @@ static void riscv_imsic_update(RISCVIMSICState *imsic, uint32_t page)
 }
 
 static int riscv_imsic_eidelivery_rmw(RISCVIMSICState *imsic, uint32_t page,
-                                      target_ulong *val,
-                                      target_ulong new_val,
-                                      target_ulong wr_mask)
+                                      uint64_t *val,
+                                      uint64_t new_val,
+                                      uint64_t wr_mask)
 {
-    target_ulong old_val = imsic->eidelivery[page];
+    uint32_t old_val = imsic->eidelivery[page];
 
     if (val) {
         *val = old_val;
@@ -106,11 +106,11 @@ static int riscv_imsic_eidelivery_rmw(RISCVIMSICState *imsic, uint32_t page,
 }
 
 static int riscv_imsic_eithreshold_rmw(RISCVIMSICState *imsic, uint32_t page,
-                                      target_ulong *val,
-                                      target_ulong new_val,
-                                      target_ulong wr_mask)
+                                      uint64_t *val,
+                                      uint64_t new_val,
+                                      uint64_t wr_mask)
 {
-    target_ulong old_val = imsic->eithreshold[page];
+    uint32_t old_val = imsic->eithreshold[page];
 
     if (val) {
         *val = old_val;
@@ -124,8 +124,8 @@ static int riscv_imsic_eithreshold_rmw(RISCVIMSICState *imsic, uint32_t page,
 }
 
 static int riscv_imsic_topei_rmw(RISCVIMSICState *imsic, uint32_t page,
-                                 target_ulong *val, target_ulong new_val,
-                                 target_ulong wr_mask)
+                                 uint64_t *val, uint64_t new_val,
+                                 uint64_t wr_mask)
 {
     uint32_t base, topei = riscv_imsic_topei(imsic, page);
 
@@ -149,11 +149,11 @@ static int riscv_imsic_topei_rmw(RISCVIMSICState *imsic, uint32_t page,
 
 static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
                                uint32_t xlen, uint32_t page,
-                               uint32_t num, bool pend, target_ulong *val,
-                               target_ulong new_val, target_ulong wr_mask)
+                               uint32_t num, bool pend, uint64_t *val,
+                               uint64_t new_val, uint64_t wr_mask)
 {
     uint32_t i, base, prev;
-    target_ulong mask;
+    uint64_t mask;
     uint32_t state = (pend) ? IMSIC_EISTATE_PENDING : IMSIC_EISTATE_ENABLED;
 
     if (xlen != 32) {
@@ -178,7 +178,7 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
             continue;
         }
 
-        mask = (target_ulong)1 << i;
+        mask = 1ull << i;
         if (wr_mask & mask) {
             if (new_val & mask) {
                 prev = qatomic_fetch_or(&imsic->eistate[base + i], state);
@@ -197,8 +197,8 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
     return 0;
 }
 
-static int riscv_imsic_rmw(void *arg, target_ulong reg, target_ulong *val,
-                           target_ulong new_val, target_ulong wr_mask)
+static int riscv_imsic_rmw(void *arg, uint32_t reg, uint64_t *val,
+                           uint64_t new_val, uint64_t wr_mask)
 {
     RISCVIMSICState *imsic = arg;
     uint32_t isel, priv, virt, vgein, xlen, page;
@@ -400,7 +400,7 @@ static void riscv_imsic_realize(DeviceState *dev, Error **errp)
         }
 
         if (!kvm_irqchip_in_kernel()) {
-            riscv_cpu_set_aia_ireg_rmw_fn(env, (imsic->mmode) ? PRV_M : PRV_S,
+            riscv_cpu_set_aia_ireg_rmw_cb(env, (imsic->mmode) ? PRV_M : PRV_S,
                                           riscv_imsic_rmw, imsic);
         }
     }
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 4529341696..ae0490a086 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -816,17 +816,13 @@ void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *),
     env->rdtime_fn_arg = arg;
 }
 
-void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, privilege_mode_t priv,
-                                   int (*rmw_fn)(void *arg,
-                                                 target_ulong reg,
-                                                 target_ulong *val,
-                                                 target_ulong new_val,
-                                                 target_ulong write_mask),
+void riscv_cpu_set_aia_ireg_rmw_cb(CPURISCVState *env, privilege_mode_t priv,
+                                   aia_ireg_rmw_fn rmw_fn,
                                    void *rmw_fn_arg)
 {
     if (priv <= PRV_M) {
-        env->aia_ireg_rmw_fn[priv] = rmw_fn;
-        env->aia_ireg_rmw_fn_arg[priv] = rmw_fn_arg;
+        env->aia_ireg_rmw_cb[priv] = rmw_fn;
+        env->aia_ireg_rmw_cb_arg[priv] = rmw_fn_arg;
     }
 }
 
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 29db646589..4dd6c93e51 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2673,6 +2673,7 @@ static RISCVException rmw_xireg_aia(CPURISCVState *env, int csrno,
     uint8_t *iprio;
     privilege_mode_t priv;
     uint32_t vgein;
+    uint64_t wide_val;
 
     /* VS-mode CSR number passed in has already been translated */
     switch (csrno) {
@@ -2717,16 +2718,17 @@ static RISCVException rmw_xireg_aia(CPURISCVState *env, int csrno,
         }
     } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) {
         /* IMSIC registers only available when machine implements it. */
-        if (env->aia_ireg_rmw_fn[priv]) {
+        if (env->aia_ireg_rmw_cb[priv]) {
             /* Selected guest interrupt file should not be zero */
             if (virt && (!vgein || env->geilen < vgein)) {
                 goto done;
             }
             /* Call machine specific IMSIC register emulation */
-            ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv],
+            ret = env->aia_ireg_rmw_cb[priv](env->aia_ireg_rmw_cb_arg[priv],
                                     AIA_MAKE_IREG(isel, priv, virt, vgein,
                                                   riscv_cpu_mxl_bits(env)),
-                                    val, new_val, wr_mask);
+                                    &wide_val, new_val, wr_mask);
+            *val = wide_val;
         }
     } else {
         isel_reserved = true;
@@ -2959,6 +2961,7 @@ static RISCVException rmw_xtopei(CPURISCVState *env, int csrno,
     int ret = -EINVAL;
     privilege_mode_t priv;
     uint32_t vgein;
+    uint64_t wide_val;
 
     /* Translate CSR number for VS-mode */
     csrno = aia_xlate_vs_csrno(env, csrno);
@@ -2984,7 +2987,7 @@ static RISCVException rmw_xtopei(CPURISCVState *env, int csrno,
     };
 
     /* IMSIC CSRs only available when machine implements IMSIC. */
-    if (!env->aia_ireg_rmw_fn[priv]) {
+    if (!env->aia_ireg_rmw_cb[priv]) {
         goto done;
     }
 
@@ -2997,10 +3000,11 @@ static RISCVException rmw_xtopei(CPURISCVState *env, int csrno,
     }
 
     /* Call machine specific IMSIC register emulation for TOPEI */
-    ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv],
+    ret = env->aia_ireg_rmw_cb[priv](env->aia_ireg_rmw_cb_arg[priv],
                     AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, priv, virt, vgein,
                                   riscv_cpu_mxl_bits(env)),
-                    val, new_val, wr_mask);
+                    &wide_val, new_val, wr_mask);
+    *val = wide_val;
 
 done:
     if (ret) {
@@ -4504,7 +4508,7 @@ static RISCVException read_vstopi(CPURISCVState *env, int csrno,
                                   target_ulong *val)
 {
     int irq, ret;
-    target_ulong topei;
+    uint64_t topei = 0;
     uint64_t vseip, vsgein;
     uint32_t iid, iprio, hviid, hviprio, gein;
     uint32_t s, scount = 0, siid[VSTOPI_NUM_SRCS], siprio[VSTOPI_NUM_SRCS];
@@ -4519,13 +4523,13 @@ static RISCVException read_vstopi(CPURISCVState *env, int csrno,
         if (gein <= env->geilen && vseip) {
             siid[scount] = IRQ_S_EXT;
             siprio[scount] = IPRIO_MMAXIPRIO + 1;
-            if (env->aia_ireg_rmw_fn[PRV_S]) {
+            if (env->aia_ireg_rmw_cb[PRV_S]) {
                 /*
                  * Call machine specific IMSIC register emulation for
                  * reading TOPEI.
                  */
-                ret = env->aia_ireg_rmw_fn[PRV_S](
-                        env->aia_ireg_rmw_fn_arg[PRV_S],
+                ret = env->aia_ireg_rmw_cb[PRV_S](
+                        env->aia_ireg_rmw_cb_arg[PRV_S],
                         AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, PRV_S, true, gein,
                                       riscv_cpu_mxl_bits(env)),
                         &topei, 0, 0);
-- 
2.54.0



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

* [PULL 27/83] target/riscv: Fix size of irq_overflow_left
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (25 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 26/83] target/riscv: Fix arguments to board IMSIC emulation callbacks alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 28/83] target/riscv: Indent PMUFixedCtrState correctly alistair23
                   ` (57 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Fix to 64 bits to hold all relevant values.  Also update comment to
reflect that irq_overflow_left stores the ns beyond INT64_MAX until the
next overflow, this to account for the uint64_t/int64_t timer value
difference between RISCV/QEMU.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-17-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 380749f9a8..5d01672f12 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -224,8 +224,8 @@ typedef struct PMUCTRState {
     uint64_t mhpmcounter_val;
     /* Snapshot value of a counter */
     uint64_t mhpmcounter_prev;
-    /* Value beyond UINT32_MAX/UINT64_MAX before overflow interrupt trigger */
-    target_ulong irq_overflow_left;
+    /* Value beyond INT64_MAX before overflow interrupt trigger */
+    uint64_t irq_overflow_left;
 } PMUCTRState;
 
 typedef struct PMUFixedCtrState {
-- 
2.54.0



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

* [PULL 28/83] target/riscv: Indent PMUFixedCtrState correctly
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (26 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 27/83] target/riscv: Fix size of irq_overflow_left alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 29/83] target/riscv: Replace target_ulong in riscv_cpu_get_trap_name() alistair23
                   ` (56 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-18-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 5d01672f12..6477c7de99 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -229,12 +229,12 @@ typedef struct PMUCTRState {
 } PMUCTRState;
 
 typedef struct PMUFixedCtrState {
-        /* Track cycle and icount for each privilege mode */
-        uint64_t counter[4];
-        uint64_t counter_prev[4];
-        /* Track cycle and icount for each privilege mode when V = 1*/
-        uint64_t counter_virt[2];
-        uint64_t counter_virt_prev[2];
+    /* Track cycle and icount for each privilege mode */
+    uint64_t counter[4];
+    uint64_t counter_prev[4];
+    /* Track cycle and icount for each privilege mode when V = 1*/
+    uint64_t counter_virt[2];
+    uint64_t counter_virt_prev[2];
 } PMUFixedCtrState;
 
 struct CPUArchState {
-- 
2.54.0



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

* [PULL 29/83] target/riscv: Replace target_ulong in riscv_cpu_get_trap_name()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (27 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 28/83] target/riscv: Indent PMUFixedCtrState correctly alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 30/83] target/riscv: Replace target_ulong in riscv_ctr_add_entry() alistair23
                   ` (55 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Fix cause argument to 64 bit to match env->mcause.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-19-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h | 2 +-
 target/riscv/cpu.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 6477c7de99..a92cb249fa 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -603,7 +603,7 @@ extern const char * const riscv_int_regnamesh[];
 extern const char * const riscv_fpr_regnames[];
 extern const char * const riscv_rvv_regnames[];
 
-const char *riscv_cpu_get_trap_name(target_ulong cause, bool async);
+const char *riscv_cpu_get_trap_name(uint64_t cause, bool async);
 int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
                                int cpuid, DumpState *s);
 int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index c063604298..e792655cc2 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -386,7 +386,7 @@ static const char * const riscv_intr_names[] = {
     [IRQ_PMU_OVF] = "counter_overflow",
 };
 
-const char *riscv_cpu_get_trap_name(target_ulong cause, bool async)
+const char *riscv_cpu_get_trap_name(uint64_t cause, bool async)
 {
     if (async) {
         if ((cause < ARRAY_SIZE(riscv_intr_names)) && riscv_intr_names[cause]) {
-- 
2.54.0



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

* [PULL 30/83] target/riscv: Replace target_ulong in riscv_ctr_add_entry()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (28 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 29/83] target/riscv: Replace target_ulong in riscv_cpu_get_trap_name() alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 31/83] target/riscv: Fix size of trigger data alistair23
                   ` (54 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Widen to 64 bits in size to hold all relevant values.  Note: src and dst
arguments change from signed to unsigned but no functional change is
incurred.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-20-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        | 5 +++--
 target/riscv/cpu_helper.c | 5 +++--
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index a92cb249fa..48d5c769f1 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -664,8 +664,9 @@ RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
 void riscv_cpu_set_mode(CPURISCVState *env, privilege_mode_t newpriv,
                         bool virt_en);
 
-void riscv_ctr_add_entry(CPURISCVState *env, target_long src, target_long dst,
-    enum CTRType type, privilege_mode_t prev_priv, bool prev_virt);
+void riscv_ctr_add_entry(CPURISCVState *env, uint64_t src, uint64_t dst,
+                         enum CTRType type, privilege_mode_t prev_priv,
+                         bool prev_virt);
 void riscv_ctr_clear(CPURISCVState *env);
 
 void riscv_translate_init(void);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index ae0490a086..57e6f8217c 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -977,8 +977,9 @@ static bool riscv_ctr_check_xte(CPURISCVState *env,
  *    entry = isel - CTR_ENTRIES_FIRST;
  *    idx = (sctrstatus.WRPTR - entry - 1) & (depth - 1);
  */
-void riscv_ctr_add_entry(CPURISCVState *env, target_long src, target_long dst,
-    enum CTRType type, privilege_mode_t src_priv, bool src_virt)
+void riscv_ctr_add_entry(CPURISCVState *env, uint64_t src, uint64_t dst,
+                         enum CTRType type, privilege_mode_t src_priv,
+                         bool src_virt)
 {
     bool tgt_virt = env->virt_enabled;
     uint64_t src_mask = riscv_ctr_priv_to_mask(src_priv, src_virt);
-- 
2.54.0



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

* [PULL 31/83] target/riscv: Fix size of trigger data
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (29 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 30/83] target/riscv: Replace target_ulong in riscv_ctr_add_entry() alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 32/83] target/riscv: Fix size of mseccfg alistair23
                   ` (53 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

mcontext is at most 14 bits in size with the H extension, fix to 16
bits. trigger_cur indexes into tdata*[RV_MAX_TRIGGERS] which holds 2
elements, fix to 8 bits.

This patch also adds a migration entry for mcontext which is used in
tandem with other debug data that is already migrated.

Note, the cpu/debug VMSTATE version is bumped, breaking migration from
older versions.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-21-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h     | 10 +++++-----
 target/riscv/machine.c | 13 +++++++------
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 48d5c769f1..45dc0393f9 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -468,11 +468,11 @@ struct CPUArchState {
     target_ulong mseccfg;
 
     /* trigger module */
-    target_ulong trigger_cur;
-    target_ulong tdata1[RV_MAX_TRIGGERS];
-    target_ulong tdata2[RV_MAX_TRIGGERS];
-    target_ulong tdata3[RV_MAX_TRIGGERS];
-    target_ulong mcontext;
+    uint16_t mcontext;
+    uint8_t trigger_cur;
+    uint64_t tdata1[RV_MAX_TRIGGERS];
+    uint64_t tdata2[RV_MAX_TRIGGERS];
+    uint64_t tdata3[RV_MAX_TRIGGERS];
     struct CPUBreakpoint *cpu_breakpoint[RV_MAX_TRIGGERS];
     struct CPUWatchpoint *cpu_watchpoint[RV_MAX_TRIGGERS];
     QEMUTimer *itrigger_timer[RV_MAX_TRIGGERS];
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 45fd39994e..78ca607b48 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -240,15 +240,16 @@ static int debug_post_load(void *opaque, int version_id)
 
 static const VMStateDescription vmstate_debug = {
     .name = "cpu/debug",
-    .version_id = 2,
-    .minimum_version_id = 2,
+    .version_id = 3,
+    .minimum_version_id = 3,
     .needed = debug_needed,
     .post_load = debug_post_load,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINTTL(env.trigger_cur, RISCVCPU),
-        VMSTATE_UINTTL_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS),
-        VMSTATE_UINTTL_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS),
-        VMSTATE_UINTTL_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS),
+        VMSTATE_UINT16(env.mcontext, RISCVCPU),
+        VMSTATE_UINT8(env.trigger_cur, RISCVCPU),
+        VMSTATE_UINT64_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS),
+        VMSTATE_UINT64_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS),
+        VMSTATE_UINT64_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS),
         VMSTATE_END_OF_LIST()
     }
 };
-- 
2.54.0



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

* [PULL 32/83] target/riscv: Fix size of mseccfg
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (30 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 31/83] target/riscv: Fix size of trigger data alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 33/83] target/riscv: Move debug.h include away from cpu.h alistair23
                   ` (52 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

mseccfg is defined in version 20250508 of the privileged specification
to be 64 bits in size.  Update relevant function arguments.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-22-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h     | 2 +-
 target/riscv/pmp.h     | 4 ++--
 target/riscv/machine.c | 2 +-
 target/riscv/pmp.c     | 4 ++--
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 45dc0393f9..8726929bd3 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -465,7 +465,7 @@ struct CPUArchState {
 
     /* physical memory protection */
     pmp_table_t pmp_state;
-    target_ulong mseccfg;
+    uint64_t mseccfg;
 
     /* trigger module */
     uint16_t mcontext;
diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
index 17307ef88a..91130289d8 100644
--- a/target/riscv/pmp.h
+++ b/target/riscv/pmp.h
@@ -71,8 +71,8 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
                       target_ulong val);
 target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index);
 
-void mseccfg_csr_write(CPURISCVState *env, target_ulong val);
-target_ulong mseccfg_csr_read(CPURISCVState *env);
+void mseccfg_csr_write(CPURISCVState *env, uint64_t val);
+uint64_t mseccfg_csr_read(CPURISCVState *env);
 
 void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
                        target_ulong val);
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 78ca607b48..dad45f10c3 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -439,7 +439,7 @@ static const VMStateDescription vmstate_mseccfg = {
     .minimum_version_id = 1,
     .needed = mseccfg_needed,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINTTL(env.mseccfg, RISCVCPU),
+        VMSTATE_UINT64(env.mseccfg, RISCVCPU),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 58a8923d0d..211f5b3862 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -667,7 +667,7 @@ target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
 /*
  * Handle a write to a mseccfg CSR
  */
-void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
+void mseccfg_csr_write(CPURISCVState *env, uint64_t val)
 {
     int i;
     uint64_t mask = MSECCFG_MMWP | MSECCFG_MML;
@@ -713,7 +713,7 @@ void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
 /*
  * Handle a read from a mseccfg CSR
  */
-target_ulong mseccfg_csr_read(CPURISCVState *env)
+uint64_t mseccfg_csr_read(CPURISCVState *env)
 {
     trace_mseccfg_csr_read(env->mhartid, env->mseccfg);
     return env->mseccfg;
-- 
2.54.0



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

* [PULL 33/83] target/riscv: Move debug.h include away from cpu.h
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (31 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 32/83] target/riscv: Fix size of mseccfg alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 34/83] target/riscv: Move CSR declarations to separate csr.h header alistair23
                   ` (51 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis,
	Philippe Mathieu-Daudé

From: Anton Johansson <anjo@rev.ng>

All debug.h definitions except for RV_MAX_TRIGGERS are internal to
target/riscv.  Move RV_MAX_TRIGGERS to cpu.h and include debug.h from
all translation units which relied on the cpu.h include.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20260520125406.28693-23-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h         | 2 +-
 target/riscv/debug.h       | 2 --
 target/riscv/cpu.c         | 3 +++
 target/riscv/cpu_helper.c  | 2 +-
 target/riscv/csr.c         | 3 +++
 target/riscv/debug.c       | 1 +
 target/riscv/tcg/tcg-cpu.c | 1 +
 7 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 8726929bd3..644a08ea5a 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -187,12 +187,12 @@ extern RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[];
 
 #if !defined(CONFIG_USER_ONLY)
 #include "pmp.h"
-#include "debug.h"
 #endif
 
 #define RV_VLEN_MAX 1024
 #define RV_MAX_MHPMEVENTS 32
 #define RV_MAX_MHPMCOUNTERS 32
+#define RV_MAX_TRIGGERS 2
 
 FIELD(VTYPE, VLMUL, 0, 3)
 FIELD(VTYPE, VSEW, 3, 3)
diff --git a/target/riscv/debug.h b/target/riscv/debug.h
index 066e9c585f..55a3ac72e6 100644
--- a/target/riscv/debug.h
+++ b/target/riscv/debug.h
@@ -25,8 +25,6 @@
 #include "exec/breakpoint.h"
 #include "exec/target_long.h"
 
-#define RV_MAX_TRIGGERS         2
-
 /* register index of tdata CSRs */
 enum {
     TDATA1 = 0,
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e792655cc2..7fb426b697 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -38,6 +38,9 @@
 #include "kvm/kvm_riscv.h"
 #include "tcg/tcg-cpu.h"
 #include "tcg/tcg.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "target/riscv/debug.h"
+#endif
 
 /* RISC-V CPU definitions */
 static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH";
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 57e6f8217c..be36dca8f1 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -34,7 +34,7 @@
 #include "semihosting/common-semi.h"
 #include "exec/icount.h"
 #include "cpu_bits.h"
-#include "debug.h"
+#include "target/riscv/debug.h"
 #include "pmp.h"
 #include "qemu/plugin.h"
 
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 4dd6c93e51..8b1de77b7a 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -31,6 +31,9 @@
 #include "qapi/error.h"
 #include "tcg/insn-start-words.h"
 #include "internals.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "target/riscv/debug.h"
+#endif
 
 /* CSR function table public API */
 void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops)
diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index 5664466749..30d39ee5cd 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -27,6 +27,7 @@
 #include "qemu/log.h"
 #include "qapi/error.h"
 #include "cpu.h"
+#include "target/riscv/debug.h"
 #include "trace.h"
 #include "exec/helper-proto.h"
 #include "exec/watchpoint.h"
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index f8b2f04a94..21886e5d39 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -37,6 +37,7 @@
 #include "hw/core/boards.h"
 #include "system/tcg.h"
 #include "exec/icount.h"
+#include "target/riscv/debug.h"
 #endif
 
 /* Hash that stores user set extensions */
-- 
2.54.0



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

* [PULL 34/83] target/riscv: Move CSR declarations to separate csr.h header
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (32 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 33/83] target/riscv: Move debug.h include away from cpu.h alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 35/83] target/riscv: Introduce externally facing CSR access functions alistair23
                   ` (50 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Most of these definitions save riscv_csrr, riscv_csrrw, riscv_csr_read,
riscv_csr_write are only used in target/.  Move declarations to a
separate headers which will soon be made internal to target/.

csr.h is temporarily included from cpu.h to not break includes from
outside target/, this include will be removed in the following commit.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-24-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h            |  87 +---------------------------
 target/riscv/csr.h            | 103 ++++++++++++++++++++++++++++++++++
 target/riscv/cpu.c            |   1 +
 target/riscv/csr.c            |   1 +
 target/riscv/gdbstub.c        |   1 +
 target/riscv/kvm/kvm-cpu.c    |   1 +
 target/riscv/mips_csr.c       |   1 +
 target/riscv/monitor.c        |   1 +
 target/riscv/op_helper.c      |   1 +
 target/riscv/riscv-qmp-cmds.c |   1 +
 target/riscv/th_csr.c         |   1 +
 11 files changed, 113 insertions(+), 86 deletions(-)
 create mode 100644 target/riscv/csr.h

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 644a08ea5a..b751c9d348 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -905,75 +905,7 @@ RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env);
 RISCVPmPmm riscv_pm_get_vm_ldst_pmm(CPURISCVState *env);
 uint32_t riscv_pm_get_pmlen(RISCVPmPmm pmm);
 
-RISCVException riscv_csrr(CPURISCVState *env, int csrno,
-                          target_ulong *ret_value);
-
-RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
-                           target_ulong *ret_value, target_ulong new_value,
-                           target_ulong write_mask, uintptr_t ra);
-RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
-                                 target_ulong *ret_value,
-                                 target_ulong new_value,
-                                 target_ulong write_mask);
-
-static inline void riscv_csr_write(CPURISCVState *env, int csrno,
-                                   target_ulong val)
-{
-    riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0);
-}
-
-static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno)
-{
-    target_ulong val = 0;
-    riscv_csrr(env, csrno, &val);
-    return val;
-}
-
-typedef RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env,
-                                                 int csrno);
-typedef RISCVException (*riscv_csr_read_fn)(CPURISCVState *env, int csrno,
-                                            target_ulong *ret_value);
-typedef RISCVException (*riscv_csr_write_fn)(CPURISCVState *env, int csrno,
-                                             target_ulong new_value,
-                                             uintptr_t ra);
-typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
-                                          target_ulong *ret_value,
-                                          target_ulong new_value,
-                                          target_ulong write_mask);
-
-RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno,
-                               Int128 *ret_value);
-RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
-                                Int128 *ret_value, Int128 new_value,
-                                Int128 write_mask, uintptr_t ra);
-
-typedef RISCVException (*riscv_csr_read128_fn)(CPURISCVState *env, int csrno,
-                                               Int128 *ret_value);
-typedef RISCVException (*riscv_csr_write128_fn)(CPURISCVState *env, int csrno,
-                                             Int128 new_value);
-
-typedef struct {
-    const char *name;
-    riscv_csr_predicate_fn predicate;
-    riscv_csr_read_fn read;
-    riscv_csr_write_fn write;
-    riscv_csr_op_fn op;
-    riscv_csr_read128_fn read128;
-    riscv_csr_write128_fn write128;
-    /* The default priv spec version should be PRIV_VERSION_1_10_0 (i.e 0) */
-    uint32_t min_priv_ver;
-} riscv_csr_operations;
-
-struct RISCVCSR {
-    int csrno;
-    bool (*insertion_test)(RISCVCPU *cpu);
-    riscv_csr_operations csr_ops;
-};
-
-/* CSR function table constants */
-enum {
-    CSR_TABLE_SIZE = 0x1000
-};
+#include "target/riscv/csr.h"
 
 /*
  * The event id are encoded based on the encoding specified in the
@@ -1007,28 +939,11 @@ void riscv_cpu_finalize_features(RISCVCPU *cpu, Error **errp);
 void riscv_add_satp_mode_properties(Object *obj);
 bool riscv_cpu_accelerator_compatible(RISCVCPU *cpu);
 
-/* CSR function table */
-extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
-bool riscv_csr_is_fpu(int csrno);
-bool riscv_csr_is_vpu(int csrno);
-
 extern const bool valid_vm_1_10_32[], valid_vm_1_10_64[];
 
-void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
-void riscv_set_csr_ops(int csrno, const riscv_csr_operations *ops);
-
 void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
 
-target_ulong riscv_new_csr_seed(target_ulong new_value,
-                                target_ulong write_mask);
-
 const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit);
 
-/* In th_csr.c */
-extern const RISCVCSR th_csr_list[];
-
-/* Implemented in mips_csr.c */
-extern const RISCVCSR mips_csr_list[];
-
 const char *priv_spec_to_str(int priv_version);
 #endif /* RISCV_CPU_H */
diff --git a/target/riscv/csr.h b/target/riscv/csr.h
new file mode 100644
index 0000000000..f45f9912c5
--- /dev/null
+++ b/target/riscv/csr.h
@@ -0,0 +1,103 @@
+/*
+ * QEMU RISC-V CSRs
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef RISCV_CSR_H
+#define RISCV_CSR_H
+
+#include "exec/target_long.h"
+#include "cpu_bits.h"
+
+target_ulong riscv_new_csr_seed(target_ulong new_value,
+                                target_ulong write_mask);
+
+RISCVException riscv_csrr(CPURISCVState *env, int csrno,
+                          target_ulong *ret_value);
+
+RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
+                           target_ulong *ret_value, target_ulong new_value,
+                           target_ulong write_mask, uintptr_t ra);
+RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
+                                 target_ulong *ret_value,
+                                 target_ulong new_value,
+                                 target_ulong write_mask);
+
+static inline void riscv_csr_write(CPURISCVState *env, int csrno,
+                                   target_ulong val)
+{
+    riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0);
+}
+
+static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno)
+{
+    target_ulong val = 0;
+    riscv_csrr(env, csrno, &val);
+    return val;
+}
+
+typedef RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env,
+                                                 int csrno);
+typedef RISCVException (*riscv_csr_read_fn)(CPURISCVState *env, int csrno,
+                                            target_ulong *ret_value);
+typedef RISCVException (*riscv_csr_write_fn)(CPURISCVState *env, int csrno,
+                                             target_ulong new_value,
+                                             uintptr_t ra);
+typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
+                                          target_ulong *ret_value,
+                                          target_ulong new_value,
+                                          target_ulong write_mask);
+
+RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno,
+                               Int128 *ret_value);
+RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
+                                Int128 *ret_value, Int128 new_value,
+                                Int128 write_mask, uintptr_t ra);
+
+typedef RISCVException (*riscv_csr_read128_fn)(CPURISCVState *env, int csrno,
+                                               Int128 *ret_value);
+typedef RISCVException (*riscv_csr_write128_fn)(CPURISCVState *env, int csrno,
+                                             Int128 new_value);
+
+typedef struct {
+    const char *name;
+    riscv_csr_predicate_fn predicate;
+    riscv_csr_read_fn read;
+    riscv_csr_write_fn write;
+    riscv_csr_op_fn op;
+    riscv_csr_read128_fn read128;
+    riscv_csr_write128_fn write128;
+    /* The default priv spec version should be PRIV_VERSION_1_10_0 (i.e 0) */
+    uint32_t min_priv_ver;
+} riscv_csr_operations;
+
+struct RISCVCSR {
+    int csrno;
+    bool (*insertion_test)(RISCVCPU *cpu);
+    riscv_csr_operations csr_ops;
+};
+
+/* CSR function table constants */
+enum {
+    CSR_TABLE_SIZE = 0x1000
+};
+
+/* CSR function table */
+extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
+
+bool riscv_csr_is_fpu(int csrno);
+bool riscv_csr_is_vpu(int csrno);
+
+void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
+void riscv_set_csr_ops(int csrno, const riscv_csr_operations *ops);
+
+/* In th_csr.c */
+extern const RISCVCSR th_csr_list[];
+
+/* Implemented in mips_csr.c */
+extern const RISCVCSR mips_csr_list[];
+
+#endif /* RISCV_CSR_H */
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 7fb426b697..bcc8a6bcb1 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -23,6 +23,7 @@
 #include "qemu/log.h"
 #include "cpu.h"
 #include "cpu_vendorid.h"
+#include "target/riscv/csr.h"
 #include "internals.h"
 #include "qapi/error.h"
 #include "qapi/visitor.h"
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 8b1de77b7a..e508985311 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -21,6 +21,7 @@
 #include "qemu/log.h"
 #include "qemu/timer.h"
 #include "cpu.h"
+#include "target/riscv/csr.h"
 #include "tcg/tcg-cpu.h"
 #include "pmu.h"
 #include "time_helper.h"
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 7abacd0e11..a2bbaf7f07 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -21,6 +21,7 @@
 #include "gdbstub/helpers.h"
 #include "cpu.h"
 #include "internals.h"
+#include "target/riscv/csr.h"
 
 struct TypeSize {
     const char *gdb_type;
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 53d88339c1..f0de5c3071 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -31,6 +31,7 @@
 #include "system/kvm.h"
 #include "system/kvm_int.h"
 #include "cpu.h"
+#include "target/riscv/csr.h"
 #include "trace.h"
 #include "accel/accel-cpu-target.h"
 #include "hw/pci/pci.h"
diff --git a/target/riscv/mips_csr.c b/target/riscv/mips_csr.c
index 822e25e346..609718f288 100644
--- a/target/riscv/mips_csr.c
+++ b/target/riscv/mips_csr.c
@@ -10,6 +10,7 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "cpu_vendorid.h"
+#include "target/riscv/csr.h"
 
 /* Static MIPS CSR state storage */
 static struct {
diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c
index 9edac0533c..3e89dcaf7c 100644
--- a/target/riscv/monitor.c
+++ b/target/riscv/monitor.c
@@ -22,6 +22,7 @@
 #include "qemu/ctype.h"
 #include "qemu/qemu-print.h"
 #include "cpu.h"
+#include "target/riscv/csr.h"
 #include "cpu_bits.h"
 #include "monitor/monitor.h"
 #include "monitor/hmp.h"
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index c074b24bc9..3dc8c4f6b3 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -20,6 +20,7 @@
 
 #include "qemu/osdep.h"
 #include "cpu.h"
+#include "target/riscv/csr.h"
 #include "internals.h"
 #include "exec/cputlb.h"
 #include "accel/tcg/cpu-ldst.h"
diff --git a/target/riscv/riscv-qmp-cmds.c b/target/riscv/riscv-qmp-cmds.c
index 93e6b7fa68..b94e8391ed 100644
--- a/target/riscv/riscv-qmp-cmds.c
+++ b/target/riscv/riscv-qmp-cmds.c
@@ -35,6 +35,7 @@
 #include "system/tcg.h"
 #include "cpu-qom.h"
 #include "cpu.h"
+#include "target/riscv/csr.h"
 
 static void riscv_cpu_add_definition(gpointer data, gpointer user_data)
 {
diff --git a/target/riscv/th_csr.c b/target/riscv/th_csr.c
index 49eb7bbab5..a4ea4ce391 100644
--- a/target/riscv/th_csr.c
+++ b/target/riscv/th_csr.c
@@ -19,6 +19,7 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "cpu_vendorid.h"
+#include "target/riscv/csr.h"
 
 #define CSR_TH_SXSTATUS 0x5c0
 
-- 
2.54.0



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

* [PULL 35/83] target/riscv: Introduce externally facing CSR access functions
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (33 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 34/83] target/riscv: Move CSR declarations to separate csr.h header alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 36/83] target/riscv: Make pmp.h target_ulong agnostic alistair23
                   ` (49 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

Convert riscv_csr_[read|write]() into target_ulong angnostic CSR access
functions that can be safely used from outside of target/ without
knowledge of the target register size.  Replace the 4 existing CSR
accesses in hw/ and linux-user/.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-25-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        |  7 ++++++-
 target/riscv/csr.h        | 13 -------------
 hw/riscv/riscv_hart.c     |  7 +++----
 linux-user/riscv/signal.c |  5 +++--
 target/riscv/csr.c        | 15 +++++++++++++++
 5 files changed, 27 insertions(+), 20 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index b751c9d348..e7ecc02b64 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -905,7 +905,12 @@ RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env);
 RISCVPmPmm riscv_pm_get_vm_ldst_pmm(CPURISCVState *env);
 uint32_t riscv_pm_get_pmlen(RISCVPmPmm pmm);
 
-#include "target/riscv/csr.h"
+/*
+ * Externally facing CSR access functions, wrappers around riscv_csr*().
+ */
+
+RISCVException riscv_csr_write_i64(CPURISCVState *env, int csrno, uint64_t val);
+RISCVException riscv_csr_read_i64(CPURISCVState *env, int csrn, uint64_t *res);
 
 /*
  * The event id are encoded based on the encoding specified in the
diff --git a/target/riscv/csr.h b/target/riscv/csr.h
index f45f9912c5..4cca3a000a 100644
--- a/target/riscv/csr.h
+++ b/target/riscv/csr.h
@@ -26,19 +26,6 @@ RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
                                  target_ulong new_value,
                                  target_ulong write_mask);
 
-static inline void riscv_csr_write(CPURISCVState *env, int csrno,
-                                   target_ulong val)
-{
-    riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0);
-}
-
-static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno)
-{
-    target_ulong val = 0;
-    riscv_csrr(env, csrno, &val);
-    return val;
-}
-
 typedef RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env,
                                                  int csrno);
 typedef RISCVException (*riscv_csr_read_fn)(CPURISCVState *env, int csrno,
diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c
index e675358e1a..d1c7188369 100644
--- a/hw/riscv/riscv_hart.c
+++ b/hw/riscv/riscv_hart.c
@@ -67,12 +67,11 @@ static void csr_call(char *cmd, uint64_t cpu_num, int csrno, uint64_t *val)
     RISCVCPU *cpu = RISCV_CPU(cpu_by_arch_id(cpu_num));
     CPURISCVState *env = &cpu->env;
 
-    int ret = RISCV_EXCP_NONE;
+    RISCVException ret = RISCV_EXCP_NONE;
     if (strcmp(cmd, "get_csr") == 0) {
-        ret = riscv_csrr(env, csrno, (target_ulong *)val);
+        ret = riscv_csr_read_i64(env, csrno, val);
     } else if (strcmp(cmd, "set_csr") == 0) {
-        ret = riscv_csrrw(env, csrno, NULL, *(target_ulong *)val,
-                          MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0);
+        ret = riscv_csr_write_i64(env, csrno, *val);
     }
 
     g_assert(ret == RISCV_EXCP_NONE);
diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c
index 358fa1d82d..9d5ba300e4 100644
--- a/linux-user/riscv/signal.c
+++ b/linux-user/riscv/signal.c
@@ -90,7 +90,8 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPURISCVState *env)
         __put_user(env->fpr[i], &sc->fpr[i]);
     }
 
-    uint32_t fcsr = riscv_csr_read(env, CSR_FCSR);
+    uint64_t fcsr;
+    riscv_csr_read_i64(env, CSR_FCSR, &fcsr);
     __put_user(fcsr, &sc->fcsr);
 }
 
@@ -159,7 +160,7 @@ static void restore_sigcontext(CPURISCVState *env, struct target_sigcontext *sc)
 
     uint32_t fcsr;
     __get_user(fcsr, &sc->fcsr);
-    riscv_csr_write(env, CSR_FCSR, fcsr);
+    riscv_csr_write_i64(env, CSR_FCSR, fcsr);
 }
 
 static void restore_ucontext(CPURISCVState *env, struct target_ucontext *uc)
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index e508985311..19d5a55b54 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -5751,6 +5751,21 @@ RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
     return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask, ra);
 }
 
+RISCVException riscv_csr_write_i64(CPURISCVState *env, int csrno, uint64_t val)
+{
+    return riscv_csrrw(env, csrno, NULL, val,
+                       MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0);
+}
+
+RISCVException riscv_csr_read_i64(CPURISCVState *env, int csrno, uint64_t *res)
+{
+    RISCVException ret;
+    target_ulong val = 0;
+    ret = riscv_csrr(env, csrno, &val);
+    *res = val;
+    return ret;
+}
+
 static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno,
                                         Int128 *ret_value,
                                         Int128 new_value,
-- 
2.54.0



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

* [PULL 36/83] target/riscv: Make pmp.h target_ulong agnostic
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (34 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 35/83] target/riscv: Introduce externally facing CSR access functions alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 37/83] target/riscv: Pass address as uint64_t in cpu_set_exception_base() alistair23
                   ` (48 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

The pmp.h header is exposed through cpu.h.  pmp_table_t is also used in
CPUArchState.  CSR declarations are only used in target/ and are moved to
csr.h.  In pmp.h, addr_reg is widened to 64 bits and the privilege mode
parameter is fixed to 8 bits, similar to previous commits.

Note, the cpu/pmp/entry and cpu/pmp VMSTATE versions are bumped, breaking
migration from older versions.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-26-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/csr.h     | 12 ++++++++++++
 target/riscv/pmp.h     | 19 +++++--------------
 target/riscv/machine.c | 10 +++++-----
 target/riscv/pmp.c     | 10 ++++++----
 4 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/target/riscv/csr.h b/target/riscv/csr.h
index 4cca3a000a..c791260f83 100644
--- a/target/riscv/csr.h
+++ b/target/riscv/csr.h
@@ -87,4 +87,16 @@ extern const RISCVCSR th_csr_list[];
 /* Implemented in mips_csr.c */
 extern const RISCVCSR mips_csr_list[];
 
+/* PMP CSRs, defined in pmp.c */
+void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
+                      target_ulong val);
+target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index);
+
+void mseccfg_csr_write(CPURISCVState *env, uint64_t val);
+uint64_t mseccfg_csr_read(CPURISCVState *env);
+
+void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
+                       target_ulong val);
+target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index);
+
 #endif /* RISCV_CSR_H */
diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
index 91130289d8..eae305ac6f 100644
--- a/target/riscv/pmp.h
+++ b/target/riscv/pmp.h
@@ -22,7 +22,6 @@
 #ifndef RISCV_PMP_H
 #define RISCV_PMP_H
 
-#include "exec/target_long.h"
 #include "cpu.h"
 
 typedef enum {
@@ -52,7 +51,7 @@ typedef enum {
 } mseccfg_field_t;
 
 typedef struct {
-    target_ulong addr_reg;
+    uint64_t addr_reg;
     uint8_t  cfg_reg;
 } pmp_entry_t;
 
@@ -67,21 +66,13 @@ typedef struct {
     uint32_t num_rules;
 } pmp_table_t;
 
-void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
-                      target_ulong val);
-target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index);
+typedef struct CPUArchState CPURISCVState;
 
-void mseccfg_csr_write(CPURISCVState *env, uint64_t val);
-uint64_t mseccfg_csr_read(CPURISCVState *env);
-
-void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
-                       target_ulong val);
-target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index);
 bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
-                        target_ulong size, pmp_priv_t privs,
+                        int size, pmp_priv_t privs,
                         pmp_priv_t *allowed_privs,
-                        target_ulong mode);
-target_ulong pmp_get_tlb_size(CPURISCVState *env, hwaddr addr);
+                        privilege_mode_t mode);
+uint64_t pmp_get_tlb_size(CPURISCVState *env, hwaddr addr);
 void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index);
 void pmp_update_rule_nums(CPURISCVState *env);
 uint32_t pmp_get_num_rules(CPURISCVState *env);
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index dad45f10c3..6e70b145a5 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -49,10 +49,10 @@ static int pmp_post_load(void *opaque, int version_id)
 
 static const VMStateDescription vmstate_pmp_entry = {
     .name = "cpu/pmp/entry",
-    .version_id = 1,
-    .minimum_version_id = 1,
+    .version_id = 2,
+    .minimum_version_id = 2,
     .fields = (const VMStateField[]) {
-        VMSTATE_UINTTL(addr_reg, pmp_entry_t),
+        VMSTATE_UINT64(addr_reg, pmp_entry_t),
         VMSTATE_UINT8(cfg_reg, pmp_entry_t),
         VMSTATE_END_OF_LIST()
     }
@@ -60,8 +60,8 @@ static const VMStateDescription vmstate_pmp_entry = {
 
 static const VMStateDescription vmstate_pmp = {
     .name = "cpu/pmp",
-    .version_id = 1,
-    .minimum_version_id = 1,
+    .version_id = 2,
+    .minimum_version_id = 2,
     .needed = pmp_needed,
     .post_load = pmp_post_load,
     .fields = (const VMStateField[]) {
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 211f5b3862..d93563c36b 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -23,6 +23,7 @@
 #include "qemu/log.h"
 #include "qapi/error.h"
 #include "cpu.h"
+#include "target/riscv/csr.h"
 #include "trace.h"
 #include "exec/cputlb.h"
 #include "exec/page-protection.h"
@@ -317,7 +318,7 @@ static int pmp_is_in_range(CPURISCVState *env, int pmp_index, hwaddr addr)
  */
 static bool pmp_hart_has_privs_default(CPURISCVState *env, pmp_priv_t privs,
                                        pmp_priv_t *allowed_privs,
-                                       target_ulong mode)
+                                       privilege_mode_t mode)
 {
     bool ret;
 
@@ -380,8 +381,9 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, pmp_priv_t privs,
  * have no functional impact in QEMU emulation.
  */
 bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
-                        target_ulong size, pmp_priv_t privs,
-                        pmp_priv_t *allowed_privs, target_ulong mode)
+                        int size, pmp_priv_t privs,
+                        pmp_priv_t *allowed_privs,
+                        privilege_mode_t mode)
 {
     int i = 0;
     int pmp_size = 0;
@@ -732,7 +734,7 @@ uint64_t mseccfg_csr_read(CPURISCVState *env)
  * To avoid this we return a size of 1 (which means no caching) if the PMP
  * region only covers partial of the TLB page.
  */
-target_ulong pmp_get_tlb_size(CPURISCVState *env, hwaddr addr)
+uint64_t pmp_get_tlb_size(CPURISCVState *env, hwaddr addr)
 {
     hwaddr pmp_sa;
     hwaddr pmp_ea;
-- 
2.54.0



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

* [PULL 37/83] target/riscv: Pass address as uint64_t in cpu_set_exception_base()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (35 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 36/83] target/riscv: Make pmp.h target_ulong agnostic alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 38/83] target/riscv: Fix pmp.h/cpu.h circular inclusion alistair23
                   ` (47 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

The corresponding field CPUArchState::resetvec is uint64_t anyway, no
need to use target_ulong.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-27-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h | 2 +-
 target/riscv/cpu.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index e7ecc02b64..3e33efdc60 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -681,7 +681,7 @@ uint8_t riscv_cpu_get_fflags(CPURISCVState *env);
 void riscv_cpu_set_fflags(CPURISCVState *env, uint8_t);
 
 #ifndef CONFIG_USER_ONLY
-void cpu_set_exception_base(int vp_index, target_ulong address);
+void cpu_set_exception_base(int vp_index, uint64_t address);
 #endif
 
 FIELD(TB_FLAGS, MEM_IDX, 0, 3)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index bcc8a6bcb1..65bf931296 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -76,7 +76,7 @@ bool riscv_cpu_option_set(RISCVCPU *cpu, const char *optname)
 
 #ifndef CONFIG_USER_ONLY
 /* This is used in runtime only. */
-void cpu_set_exception_base(int vp_index, target_ulong address)
+void cpu_set_exception_base(int vp_index, uint64_t address)
 {
     RISCVCPU *cpu;
     CPUState *cs = qemu_get_cpu(vp_index);
-- 
2.54.0



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

* [PULL 38/83] target/riscv: Fix pmp.h/cpu.h circular inclusion
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (36 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 37/83] target/riscv: Pass address as uint64_t in cpu_set_exception_base() alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 39/83] target/riscv/cpu_helper.c: add PMA access fault alistair23
                   ` (46 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Johansson, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Alistair Francis

From: Anton Johansson <anjo@rev.ng>

pmp.h is only needed and included for system mode, however relevant
macros (MAX_RISCV_PMPS, OLD_MAX_RISCV_PMPS, MIN_RISCV_PMP_GRANULARITY)
are required unconditionally by cpu.c, and so are defined in cpu.h.
pmp.h then defines pmp_table_t depending on these macros and so requires
cpu.h, and cpu.h in turn uses pmp_table_t resulting in circular
inclusion.

Move PMP macros to pmp.h and only expose PMP properties in system mode.

Signed-off-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260520125406.28693-28-anjo@rev.ng>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h | 4 ----
 target/riscv/pmp.h | 4 +++-
 target/riscv/cpu.c | 6 ++++++
 3 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 3e33efdc60..68e1ec37b4 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -181,10 +181,6 @@ extern RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[];
 
 #define MMU_USER_IDX 3
 
-#define MAX_RISCV_PMPS (64)
-#define OLD_MAX_RISCV_PMPS (16)
-#define MIN_RISCV_PMP_GRANULARITY 4
-
 #if !defined(CONFIG_USER_ONLY)
 #include "pmp.h"
 #endif
diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
index eae305ac6f..4c95c2767a 100644
--- a/target/riscv/pmp.h
+++ b/target/riscv/pmp.h
@@ -22,7 +22,9 @@
 #ifndef RISCV_PMP_H
 #define RISCV_PMP_H
 
-#include "cpu.h"
+#define MAX_RISCV_PMPS (64)
+#define OLD_MAX_RISCV_PMPS (16)
+#define MIN_RISCV_PMP_GRANULARITY 4
 
 typedef enum {
     PMP_READ  = 1 << 0,
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 65bf931296..1d9e575bb2 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1147,7 +1147,9 @@ static void riscv_cpu_init(Object *obj)
     cpu->cfg.cbop_blocksize = 64;
     cpu->cfg.cboz_blocksize = 64;
     cpu->cfg.pmp_regions = 16;
+#ifndef CONFIG_USER_ONLY
     cpu->cfg.pmp_granularity = MIN_RISCV_PMP_GRANULARITY;
+#endif
     cpu->env.vext_ver = VEXT_VERSION_1_00_0;
     cpu->cfg.max_satp_mode = -1;
 
@@ -1385,6 +1387,7 @@ static const PropertyInfo prop_mmu = {
     .set = prop_mmu_set,
 };
 
+#ifndef CONFIG_USER_ONLY
 static void prop_pmp_set(Object *obj, Visitor *v, const char *name,
                          void *opaque, Error **errp)
 {
@@ -1493,6 +1496,7 @@ static const PropertyInfo prop_pmp_granularity = {
     .get = prop_pmp_granularity_get,
     .set = prop_pmp_granularity_set,
 };
+#endif /* !CONFIG_USER_ONLY */
 
 static int priv_spec_from_str(const char *priv_spec_str)
 {
@@ -2522,9 +2526,11 @@ static const Property riscv_cpu_properties[] = {
     {.name = "pmu-num", .info = &prop_pmu_num}, /* Deprecated */
 
     {.name = "mmu", .info = &prop_mmu},
+#ifndef CONFIG_USER_ONLY
     {.name = "pmp", .info = &prop_pmp},
     {.name = "num-pmp-regions", .info = &prop_num_pmp_regions},
     {.name = "pmp-granularity", .info = &prop_pmp_granularity},
+#endif
 
     {.name = "priv_spec", .info = &prop_priv_spec},
     {.name = "vext_spec", .info = &prop_vext_spec},
-- 
2.54.0



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

* [PULL 39/83] target/riscv/cpu_helper.c: add PMA access fault
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (37 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 38/83] target/riscv: Fix pmp.h/cpu.h circular inclusion alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 40/83] target/riscv/tcg: disable svnapot if satp_mode < sv39 alistair23
                   ` (45 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Daniel Henrique Barboza, Alistair Francis, Chao Liu

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

We're not doing anything special w.r.t PMA (Physical Memory Access)
related faults, handling them like regular faults that will eventually
turn to be regular page faults.

Turns out we can't do that.  Priv spec section "Virtual Address
Translation Process" mentions:

"If a store to the PTE at address a+va.vpn[i]×PTESIZE would violate a
PMA or PMP check, raise an access-fault exception corresponding to the
original access type."

This means that we should handle PMA violations with access faults, like
we're already doing with PMP.  One clear code path where we should throw
a PMA failure, exposed by [1], is the error return from
address_space_ld* call.

There's a separated issue with the error code being returned by them (it
always return DECODE_ERROR even with 'rejected' reads) that we're going
to work around it by assuming that we did a good job with the PTE
address sanitization beforehand, and interpret that the error here is
related to PMA.  This is of course not ideal but fixing this QEMU API is
out of scope for this work.

All this said, we'll set the new pmp_pma_violation flag when we have
either a PMP or a PMA fault, and everything else shall fall into place.

[1] https://gitlab.com/qemu-project/qemu/-/work_items/3502

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3502
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Message-ID: <20260522172502.320529-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        |  3 ++-
 target/riscv/cpu_helper.c | 34 +++++++++++++++++++++++++---------
 2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 68e1ec37b4..1805aa8dfd 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -137,7 +137,8 @@ enum {
     TRANSLATE_SUCCESS,
     TRANSLATE_FAIL,
     TRANSLATE_PMP_FAIL,
-    TRANSLATE_G_STAGE_FAIL
+    TRANSLATE_G_STAGE_FAIL,
+    TRANSLATE_PMA_FAIL,
 };
 
 /* Extension context status */
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index be36dca8f1..dc78fc1192 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1424,7 +1424,22 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
         }
 
         if (res != MEMTX_OK) {
-            return TRANSLATE_FAIL;
+            /*
+             * The result of address_space_* APIs above does not take into
+             * consideration reject reads, putting all errors in the same
+             * cathegory (DECODE_ERROR), although there's a clear
+             * distinction between a rejected read versus other errors
+             * (see memory_region_dispatch_read() ->
+             * memory_region_access_valid()).  This is something that
+             * we might have to deal with core QEMU logic some other
+             * day.
+             *
+             * For this particular error path, given that we made checks
+             * w.r.t legal PTE address before calling those APIs, we'll
+             * assume that anything != MEMTX_OK means a rejected read,
+             * i.e. a PMA error.
+             */
+            return TRANSLATE_PMA_FAIL;
         }
 
         if (riscv_cpu_sxl(env) == MXL_RV32) {
@@ -1704,7 +1719,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
 }
 
 static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
-                                MMUAccessType access_type, bool pmp_violation,
+                                MMUAccessType access_type,
+                                bool pmp_pma_violation,
                                 bool first_stage, bool two_stage,
                                 bool two_stage_indirect)
 {
@@ -1712,7 +1728,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
 
     switch (access_type) {
     case MMU_INST_FETCH:
-        if (pmp_violation) {
+        if (pmp_pma_violation) {
             cs->exception_index = RISCV_EXCP_INST_ACCESS_FAULT;
         } else if (env->virt_enabled && !first_stage) {
             cs->exception_index = RISCV_EXCP_INST_GUEST_PAGE_FAULT;
@@ -1721,7 +1737,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
         }
         break;
     case MMU_DATA_LOAD:
-        if (pmp_violation) {
+        if (pmp_pma_violation) {
             cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT;
         } else if (two_stage && !first_stage) {
             cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT;
@@ -1730,7 +1746,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
         }
         break;
     case MMU_DATA_STORE:
-        if (pmp_violation) {
+        if (pmp_pma_violation) {
             cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
         } else if (two_stage && !first_stage) {
             cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT;
@@ -1856,7 +1872,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     vaddr im_address;
     hwaddr pa = 0;
     int prot, prot2, prot_pmp;
-    bool pmp_violation = false;
+    bool pmp_pma_violation = false;
     bool first_stage_error = true;
     bool two_stage_lookup = mmuidx_2stage(mmu_idx);
     bool two_stage_indirect_error = false;
@@ -1956,8 +1972,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
         }
     }
 
-    if (ret == TRANSLATE_PMP_FAIL) {
-        pmp_violation = true;
+    if (ret == TRANSLATE_PMP_FAIL || ret == TRANSLATE_PMA_FAIL) {
+        pmp_pma_violation = true;
     }
 
     if (ret == TRANSLATE_SUCCESS) {
@@ -1984,7 +2000,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
         cpu_check_watchpoint(cs, address, size, MEMTXATTRS_UNSPECIFIED,
                              wp_access, retaddr);
 
-        raise_mmu_exception(env, address, access_type, pmp_violation,
+        raise_mmu_exception(env, address, access_type, pmp_pma_violation,
                             first_stage_error, two_stage_lookup,
                             two_stage_indirect_error);
         cpu_loop_exit_restore(cs, retaddr);
-- 
2.54.0



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

* [PULL 40/83] target/riscv/tcg: disable svnapot if satp_mode < sv39
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (38 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 39/83] target/riscv/cpu_helper.c: add PMA access fault alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 41/83] disas/riscv.c: fix inst_length() alistair23
                   ` (44 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

We did a recent change to disable svpbmt if satp_mode < sv39 that was
discovered via a gitlab report.

This time we don't have an opened bug but the problem is similar: RISC-V
privileged ISA, chapter '"Svnapot" Extension for NAPOT Translation
Contiguity, Version 1.0' states:

"The Svnapot extension depends on the Sv39 extension."

Do the same thing with svnapot, including the user warning in case we
try to enable it without the required satp_mode:

$ ./build/qemu-system-riscv64 -M virt,dumpdtb=fdt.dtb \
     -cpu max,sv39=off,sv48=off,sv57=off,sv64=off,svnapot=on
qemu-system-riscv64: warning: svnapot requires at least satp sv39, current satp mode: none

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260527213034.2094103-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/tcg/tcg-cpu.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 21886e5d39..7e964e8f1a 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -848,6 +848,16 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
                                      riscv_cpu_is_32bit(cpu)));
         }
     }
+
+    if (cpu->cfg.ext_svnapot && cpu->cfg.max_satp_mode < VM_1_10_SV39) {
+        cpu->cfg.ext_svnapot = false;
+        if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_svnapot))) {
+            warn_report("svnapot requires at least satp sv39, "
+                        "current satp mode: %s",
+                        satp_mode_str(cpu->cfg.max_satp_mode,
+                                      riscv_cpu_is_32bit(cpu)));
+        }
+    }
 #endif
     /*
      * Disable isa extensions based on priv spec after we
-- 
2.54.0



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

* [PULL 41/83] disas/riscv.c: fix inst_length()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (39 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 40/83] target/riscv/tcg: disable svnapot if satp_mode < sv39 alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 42/83] target/riscv: Initialize DisasContext::mo_endian once alistair23
                   ` (43 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

inst_length() can return 0 if 'inst' happens to not match any known
encoding (like [1]).  Returning 0 is not desirable, even for unknown
encodings, given that it will cause a loop in target_disas() later on.

The most recent version of the RISC-V unpriv spec ditched the
sophisticated instruction-length encoding.  We're now supporting only
16-bit and 32-bit length instructions, where:

"All the 32-bit instructions in the base ISA have their lowest two bits
set to 11.  The optional compressed 16-bit instruction-set extensions
have their lowest two bits equal to 00, 01, or 10."

So the code is now simpler, never returning 0, and in fact it's the same
thing we're already doing in insn_len() from target/riscv/internals.h.
Due to include shenarigans we can't use that function in disas/riscv.c,
but I believe we can cut ourselves some slack this time and not lose
sleep over a 1 line of duplicated logic.  We're documenting it though!

[1] https://gitlab.com/qemu-project/qemu/-/work_items/3479

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3479
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260527200355.2068879-2-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 disas/riscv.c | 20 ++------------------
 1 file changed, 2 insertions(+), 18 deletions(-)

diff --git a/disas/riscv.c b/disas/riscv.c
index 36609efdf5..b8ec546883 100644
--- a/disas/riscv.c
+++ b/disas/riscv.c
@@ -5084,26 +5084,10 @@ static bool check_constraints(rv_decode *dec, const rvc_constraint *c)
     return true;
 }
 
-/* instruction length */
-
+/* Same as insn_len() from target/riscv/internals.h */
 static size_t inst_length(rv_inst inst)
 {
-    /* NOTE: supports maximum instruction size of 64-bits */
-
-    /*
-     * instruction length coding
-     *
-     *      aa - 16 bit aa != 11
-     *   bbb11 - 32 bit bbb != 111
-     *  011111 - 48 bit
-     * 0111111 - 64 bit
-     */
-
-    return (inst &      0b11) != 0b11      ? 2
-         : (inst &   0b11100) != 0b11100   ? 4
-         : (inst &  0b111111) == 0b011111  ? 6
-         : (inst & 0b1111111) == 0b0111111 ? 8
-         : 0;
+    return (inst & 3) == 3 ? 4 : 2;
 }
 
 /* format instruction */
-- 
2.54.0



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

* [PULL 42/83] target/riscv: Initialize DisasContext::mo_endian once
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (40 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 41/83] disas/riscv.c: fix inst_length() alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 43/83] target/riscv: Implement runtime data endianness via MSTATUS bits alistair23
                   ` (42 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Philippe Mathieu-Daudé, Djordje Todorovic,
	Alistair Francis, Pierrick Bouvier

From: Philippe Mathieu-Daudé <philmd@linaro.org>

The data access endianness is constant during a translation
block; rather than calling the mo_endian() method each time,
initialize the DisasContext::mo_endianness field once in
TranslatorOps::init_disas_context().

Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-2-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/translate.c                      |  9 ++++++---
 target/riscv/insn_trans/trans_rva.c.inc       |  4 ++--
 target/riscv/insn_trans/trans_rvd.c.inc       |  4 ++--
 target/riscv/insn_trans/trans_rvf.c.inc       |  4 ++--
 target/riscv/insn_trans/trans_rvi.c.inc       |  8 ++++----
 target/riscv/insn_trans/trans_rvzacas.c.inc   |  4 ++--
 target/riscv/insn_trans/trans_rvzalasr.c.inc  |  4 ++--
 target/riscv/insn_trans/trans_rvzce.c.inc     |  4 ++--
 target/riscv/insn_trans/trans_rvzfh.c.inc     |  4 ++--
 target/riscv/insn_trans/trans_rvzicfiss.c.inc |  4 ++--
 target/riscv/insn_trans/trans_xmips.c.inc     |  8 ++++----
 target/riscv/insn_trans/trans_xthead.c.inc    | 16 ++++++++--------
 target/riscv/insn_trans/trans_zilsd.c.inc     |  4 ++--
 13 files changed, 40 insertions(+), 37 deletions(-)

diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 3132386801..5405db9ea5 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -121,6 +121,8 @@ typedef struct DisasContext {
     bool fcfi_lp_expected;
     /* zicfiss extension, if shadow stack was enabled during TB gen */
     bool bcfi_enabled;
+    /* Data endianness from MSTATUS UBE/SBE/MBE */
+    MemOp mo_endianness;
 } DisasContext;
 
 static inline bool has_ext(DisasContext *ctx, uint32_t ext)
@@ -156,7 +158,7 @@ static inline MemOp mo_endian(DisasContext *ctx)
 #define get_address_xl(ctx)    ((ctx)->address_xl)
 #endif
 
-#define mxl_memop(ctx) ((get_xl(ctx) + 1) | mo_endian(ctx))
+#define mxl_memop(ctx) ((get_xl(ctx) + 1) | (ctx)->mo_endianness)
 
 /* The word size for this machine mode. */
 static inline int __attribute__((unused)) get_xlen(DisasContext *ctx)
@@ -1159,7 +1161,7 @@ static bool gen_amo(DisasContext *ctx, arg_atomic *a,
     TCGv src1, src2 = get_gpr(ctx, a->rs2, EXT_NONE);
     MemOp size = mop & MO_SIZE;
 
-    mop |= mo_endian(ctx);
+    mop |= ctx->mo_endianness;
     if (ctx->cfg_ptr->ext_zama16b && size >= MO_32) {
         mop |= MO_ATOM_WITHIN16;
     } else {
@@ -1180,7 +1182,7 @@ static bool gen_cmpxchg(DisasContext *ctx, arg_atomic *a, MemOp mop)
     TCGv src1 = get_address(ctx, a->rs1, 0);
     TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
 
-    mop |= mo_endian(ctx);
+    mop |= ctx->mo_endianness;
     decode_save_opc(ctx, RISCV_UW2_ALWAYS_STORE_AMO);
     tcg_gen_atomic_cmpxchg_tl(dest, src1, dest, src2, ctx->mem_idx, mop);
 
@@ -1363,6 +1365,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
     ctx->zero = tcg_constant_tl(0);
     ctx->virt_inst_excp = false;
     ctx->decoders = cpu->decoders;
+    ctx->mo_endianness = mo_endian(ctx);
 }
 
 static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc
index 62c0fe673d..44c1696fe4 100644
--- a/target/riscv/insn_trans/trans_rva.c.inc
+++ b/target/riscv/insn_trans/trans_rva.c.inc
@@ -35,7 +35,7 @@ static bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop)
     TCGv src1;
 
     mop |= MO_ALIGN;
-    mop |= mo_endian(ctx);
+    mop |= ctx->mo_endianness;
 
     decode_save_opc(ctx, 0);
     src1 = get_address(ctx, a->rs1, 0);
@@ -65,7 +65,7 @@ static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
     TCGLabel *l2 = gen_new_label();
 
     mop |= MO_ALIGN;
-    mop |= mo_endian(ctx);
+    mop |= ctx->mo_endianness;
 
     decode_save_opc(ctx, 0);
     src1 = get_address(ctx, a->rs1, 0);
diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc
index ffea0c2a1f..3b9a745520 100644
--- a/target/riscv/insn_trans/trans_rvd.c.inc
+++ b/target/riscv/insn_trans/trans_rvd.c.inc
@@ -60,7 +60,7 @@ static bool trans_fld(DisasContext *ctx, arg_fld *a)
     } else {
         memop |= MO_ATOM_IFALIGN;
     }
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
 
     decode_save_opc(ctx, 0);
     addr = get_address(ctx, a->rs1, a->imm);
@@ -85,7 +85,7 @@ static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
     } else {
         memop |= MO_ATOM_IFALIGN;
     }
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
 
     decode_save_opc(ctx, 0);
     addr = get_address(ctx, a->rs1, a->imm);
diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc
index 89fb0f604a..e935523c93 100644
--- a/target/riscv/insn_trans/trans_rvf.c.inc
+++ b/target/riscv/insn_trans/trans_rvf.c.inc
@@ -48,7 +48,7 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a)
     REQUIRE_FPU;
     REQUIRE_EXT(ctx, RVF);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     if (ctx->cfg_ptr->ext_zama16b) {
         memop |= MO_ATOM_WITHIN16;
     }
@@ -71,7 +71,7 @@ static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
     REQUIRE_FPU;
     REQUIRE_EXT(ctx, RVF);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     if (ctx->cfg_ptr->ext_zama16b) {
         memop |= MO_ATOM_WITHIN16;
     }
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index fea05d02cc..e47b16a7fa 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -392,7 +392,7 @@ static bool gen_load_i128(DisasContext *ctx, arg_lb *a, MemOp memop)
         }
     } else {
         tcg_gen_qemu_ld_i128(t16, addrl, ctx->mem_idx, memop);
-        if (mo_endian(ctx) == MO_LE) {
+        if (ctx->mo_endianness == MO_LE) {
             tcg_gen_extr_i128_i64(tl, th, t16);
         } else {
             tcg_gen_extr_i128_i64(th, tl, t16);
@@ -409,7 +409,7 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
 {
     bool out;
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     if (ctx->cfg_ptr->ext_zama16b) {
         memop |= MO_ATOM_WITHIN16;
     }
@@ -508,7 +508,7 @@ static bool gen_store_i128(DisasContext *ctx, arg_sb *a, MemOp memop)
         tcg_gen_ext_tl_i64(tl, src2l);
         tcg_gen_ext_tl_i64(th, src2h);
 
-        if (mo_endian(ctx) == MO_LE) {
+        if (ctx->mo_endianness == MO_LE) {
             tcg_gen_concat_i64_i128(t16, tl, th);
         } else {
             tcg_gen_concat_i64_i128(t16, th, tl);
@@ -520,7 +520,7 @@ static bool gen_store_i128(DisasContext *ctx, arg_sb *a, MemOp memop)
 
 static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
 {
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     if (ctx->cfg_ptr->ext_zama16b) {
         memop |= MO_ATOM_WITHIN16;
     }
diff --git a/target/riscv/insn_trans/trans_rvzacas.c.inc b/target/riscv/insn_trans/trans_rvzacas.c.inc
index 8d94b83ce9..79bca1e957 100644
--- a/target/riscv/insn_trans/trans_rvzacas.c.inc
+++ b/target/riscv/insn_trans/trans_rvzacas.c.inc
@@ -76,7 +76,7 @@ static bool gen_cmpxchg64(DisasContext *ctx, arg_atomic *a, MemOp mop)
     TCGv src1 = get_address(ctx, a->rs1, 0);
     TCGv_i64 src2 = get_gpr_pair(ctx, a->rs2);
 
-    mop |= mo_endian(ctx);
+    mop |= ctx->mo_endianness;
     decode_save_opc(ctx, RISCV_UW2_ALWAYS_STORE_AMO);
     tcg_gen_atomic_cmpxchg_i64(dest, src1, dest, src2, ctx->mem_idx, mop);
 
@@ -121,7 +121,7 @@ static bool trans_amocas_q(DisasContext *ctx, arg_amocas_q *a)
     TCGv_i64 desth = get_gpr(ctx, a->rd == 0 ? 0 : a->rd + 1, EXT_NONE);
     MemOp memop = MO_ALIGN | MO_UO;
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_concat_i64_i128(src2, src2l, src2h);
     tcg_gen_concat_i64_i128(dest, destl, desth);
     decode_save_opc(ctx, RISCV_UW2_ALWAYS_STORE_AMO);
diff --git a/target/riscv/insn_trans/trans_rvzalasr.c.inc b/target/riscv/insn_trans/trans_rvzalasr.c.inc
index 0f307affec..79b0b2c63b 100644
--- a/target/riscv/insn_trans/trans_rvzalasr.c.inc
+++ b/target/riscv/insn_trans/trans_rvzalasr.c.inc
@@ -29,7 +29,7 @@ static bool gen_load_acquire(DisasContext *ctx, arg_lb_aqrl *a, MemOp memop)
         return false;
     }
 
-    memop |= MO_ALIGN | mo_endian(ctx);
+    memop |= MO_ALIGN | ctx->mo_endianness;
     memop |= (ctx->cfg_ptr->ext_zama16b) ? MO_ATOM_WITHIN16 : 0;
 
     tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop);
@@ -79,7 +79,7 @@ static bool gen_store_release(DisasContext *ctx, arg_sb_aqrl *a, MemOp memop)
         return false;
     }
 
-    memop |= MO_ALIGN | mo_endian(ctx);
+    memop |= MO_ALIGN | ctx->mo_endianness;
     memop |= (ctx->cfg_ptr->ext_zama16b) ? MO_ATOM_WITHIN16 : 0;
 
     /* Add a memory barrier implied by RL (mandatory) and AQ (optional) */
diff --git a/target/riscv/insn_trans/trans_rvzce.c.inc b/target/riscv/insn_trans/trans_rvzce.c.inc
index 0d3ba40e52..71b4ca5473 100644
--- a/target/riscv/insn_trans/trans_rvzce.c.inc
+++ b/target/riscv/insn_trans/trans_rvzce.c.inc
@@ -185,7 +185,7 @@ static bool gen_pop(DisasContext *ctx, arg_cmpp *a, bool ret, bool ret_val)
 
     tcg_gen_addi_tl(addr, sp, stack_adj - reg_size);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     for (i = X_Sn + 11; i >= 0; i--) {
         if (reg_bitmap & (1 << i)) {
             TCGv dest = dest_gpr(ctx, i);
@@ -239,7 +239,7 @@ static bool trans_cm_push(DisasContext *ctx, arg_cm_push *a)
 
     tcg_gen_subi_tl(addr, sp, reg_size);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     for (i = X_Sn + 11; i >= 0; i--) {
         if (reg_bitmap & (1 << i)) {
             TCGv val = get_gpr(ctx, i, EXT_NONE);
diff --git a/target/riscv/insn_trans/trans_rvzfh.c.inc b/target/riscv/insn_trans/trans_rvzfh.c.inc
index 791ee51f65..f36b46c211 100644
--- a/target/riscv/insn_trans/trans_rvzfh.c.inc
+++ b/target/riscv/insn_trans/trans_rvzfh.c.inc
@@ -49,7 +49,7 @@ static bool trans_flh(DisasContext *ctx, arg_flh *a)
     REQUIRE_FPU;
     REQUIRE_ZFHMIN_OR_ZFBFMIN(ctx);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     decode_save_opc(ctx, 0);
     t0 = get_gpr(ctx, a->rs1, EXT_NONE);
     if (a->imm) {
@@ -74,7 +74,7 @@ static bool trans_fsh(DisasContext *ctx, arg_fsh *a)
     REQUIRE_FPU;
     REQUIRE_ZFHMIN_OR_ZFBFMIN(ctx);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     decode_save_opc(ctx, 0);
     t0 = get_gpr(ctx, a->rs1, EXT_NONE);
     if (a->imm) {
diff --git a/target/riscv/insn_trans/trans_rvzicfiss.c.inc b/target/riscv/insn_trans/trans_rvzicfiss.c.inc
index cb9c5419fa..a813232887 100644
--- a/target/riscv/insn_trans/trans_rvzicfiss.c.inc
+++ b/target/riscv/insn_trans/trans_rvzicfiss.c.inc
@@ -113,7 +113,7 @@ static bool trans_ssamoswap_w(DisasContext *ctx, arg_amoswap_w *a)
     decode_save_opc(ctx, RISCV_UW2_ALWAYS_STORE_AMO);
     src1 = get_address(ctx, a->rs1, 0);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_atomic_xchg_tl(dest, src1, src2, SS_MMU_INDEX(ctx), memop);
     gen_set_gpr(ctx, a->rd, dest);
     return true;
@@ -143,7 +143,7 @@ static bool trans_ssamoswap_d(DisasContext *ctx, arg_amoswap_w *a)
     decode_save_opc(ctx, RISCV_UW2_ALWAYS_STORE_AMO);
     src1 = get_address(ctx, a->rs1, 0);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_atomic_xchg_tl(dest, src1, src2, SS_MMU_INDEX(ctx), memop);
     gen_set_gpr(ctx, a->rd, dest);
     return true;
diff --git a/target/riscv/insn_trans/trans_xmips.c.inc b/target/riscv/insn_trans/trans_xmips.c.inc
index c1a30156d3..1b9993a9b0 100644
--- a/target/riscv/insn_trans/trans_xmips.c.inc
+++ b/target/riscv/insn_trans/trans_xmips.c.inc
@@ -47,7 +47,7 @@ static bool trans_ccmov(DisasContext *ctx, arg_ccmov *a)
 /* Load Doubleword Pair. */
 static bool trans_ldp(DisasContext *ctx, arg_ldp *a)
 {
-    MemOp memop = MO_SQ | mo_endian(ctx);
+    MemOp memop = MO_SQ | ctx->mo_endianness;
 
     REQUIRE_XMIPSLSP(ctx);
     REQUIRE_64_OR_128BIT(ctx);
@@ -71,7 +71,7 @@ static bool trans_ldp(DisasContext *ctx, arg_ldp *a)
 /* Load Word Pair. */
 static bool trans_lwp(DisasContext *ctx, arg_lwp *a)
 {
-    MemOp memop = MO_SL | mo_endian(ctx);
+    MemOp memop = MO_SL | ctx->mo_endianness;
 
     REQUIRE_XMIPSLSP(ctx);
 
@@ -94,7 +94,7 @@ static bool trans_lwp(DisasContext *ctx, arg_lwp *a)
 /* Store Doubleword Pair. */
 static bool trans_sdp(DisasContext *ctx, arg_sdp *a)
 {
-    MemOp memop = MO_UQ | mo_endian(ctx);
+    MemOp memop = MO_UQ | ctx->mo_endianness;
 
     REQUIRE_XMIPSLSP(ctx);
     REQUIRE_64_OR_128BIT(ctx);
@@ -116,7 +116,7 @@ static bool trans_sdp(DisasContext *ctx, arg_sdp *a)
 /* Store Word Pair. */
 static bool trans_swp(DisasContext *ctx, arg_swp *a)
 {
-    MemOp memop = MO_SL | mo_endian(ctx);
+    MemOp memop = MO_SL | ctx->mo_endianness;
 
     REQUIRE_XMIPSLSP(ctx);
 
diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc
index f8b95c6498..f4e3051000 100644
--- a/target/riscv/insn_trans/trans_xthead.c.inc
+++ b/target/riscv/insn_trans/trans_xthead.c.inc
@@ -349,7 +349,7 @@ static bool gen_fload_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
     TCGv_i64 rd = cpu_fpr[a->rd];
     TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_qemu_ld_i64(rd, addr, ctx->mem_idx, memop);
     if ((memop & MO_SIZE) == MO_32) {
         gen_nanbox_s(rd, rd);
@@ -370,7 +370,7 @@ static bool gen_fstore_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
     TCGv_i64 rd = cpu_fpr[a->rd];
     TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_qemu_st_i64(rd, addr, ctx->mem_idx, memop);
 
     return true;
@@ -570,7 +570,7 @@ static bool gen_load_inc(DisasContext *ctx, arg_th_meminc *a, MemOp memop,
     TCGv rd = dest_gpr(ctx, a->rd);
     TCGv rs1 = get_gpr(ctx, a->rs1, EXT_NONE);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_qemu_ld_tl(rd, addr, ctx->mem_idx, memop);
     tcg_gen_addi_tl(rs1, rs1, imm);
     gen_set_gpr(ctx, a->rd, rd);
@@ -591,7 +591,7 @@ static bool gen_store_inc(DisasContext *ctx, arg_th_meminc *a, MemOp memop,
     TCGv data = get_gpr(ctx, a->rd, EXT_NONE);
     TCGv rs1 = get_gpr(ctx, a->rs1, EXT_NONE);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
     tcg_gen_addi_tl(rs1, rs1, imm);
     gen_set_gpr(ctx, a->rs1, rs1);
@@ -747,7 +747,7 @@ static bool gen_load_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
     TCGv rd = dest_gpr(ctx, a->rd);
     TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_qemu_ld_tl(rd, addr, ctx->mem_idx, memop);
     gen_set_gpr(ctx, a->rd, rd);
 
@@ -765,7 +765,7 @@ static bool gen_store_idx(DisasContext *ctx, arg_th_memidx *a, MemOp memop,
     TCGv data = get_gpr(ctx, a->rd, EXT_NONE);
     TCGv addr = get_th_address_indexed(ctx, a->rs1, a->rs2, a->imm2, zext_offs);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
 
     return true;
@@ -926,7 +926,7 @@ static bool gen_loadpair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop,
     addr1 = get_address(ctx, a->rs, imm);
     addr2 = get_address(ctx, a->rs, memop_size(memop) + imm);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_qemu_ld_tl(t1, addr1, ctx->mem_idx, memop);
     tcg_gen_qemu_ld_tl(t2, addr2, ctx->mem_idx, memop);
     gen_set_gpr(ctx, a->rd1, t1);
@@ -965,7 +965,7 @@ static bool gen_storepair_tl(DisasContext *ctx, arg_th_pair *a, MemOp memop,
     addr1 = get_address(ctx, a->rs, imm);
     addr2 = get_address(ctx, a->rs, memop_size(memop) + imm);
 
-    memop |= mo_endian(ctx);
+    memop |= ctx->mo_endianness;
     tcg_gen_qemu_st_tl(data1, addr1, ctx->mem_idx, memop);
     tcg_gen_qemu_st_tl(data2, addr2, ctx->mem_idx, memop);
     return true;
diff --git a/target/riscv/insn_trans/trans_zilsd.c.inc b/target/riscv/insn_trans/trans_zilsd.c.inc
index f50c52f22c..8068cc1aec 100644
--- a/target/riscv/insn_trans/trans_zilsd.c.inc
+++ b/target/riscv/insn_trans/trans_zilsd.c.inc
@@ -30,7 +30,7 @@ static bool gen_load_i64(DisasContext *ctx, arg_ld *a)
     TCGv addr = get_address(ctx, a->rs1, a->imm);
     TCGv_i64 tmp = tcg_temp_new_i64();
 
-    tcg_gen_qemu_ld_i64(tmp, addr, ctx->mem_idx, MO_SQ | mo_endian(ctx));
+    tcg_gen_qemu_ld_i64(tmp, addr, ctx->mem_idx, MO_SQ | ctx->mo_endianness);
 
     if (a->rd == 0) {
         return true;
@@ -85,7 +85,7 @@ static bool gen_store_i64(DisasContext *ctx, arg_sd *a)
     } else {
         tcg_gen_concat_tl_i64(tmp, data_low, data_high);
     }
-    tcg_gen_qemu_st_i64(tmp, addr, ctx->mem_idx, MO_SQ | mo_endian(ctx));
+    tcg_gen_qemu_st_i64(tmp, addr, ctx->mem_idx, MO_SQ | ctx->mo_endianness);
 
     return true;
 }
-- 
2.54.0



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

* [PULL 43/83] target/riscv: Implement runtime data endianness via MSTATUS bits
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (41 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 42/83] target/riscv: Initialize DisasContext::mo_endian once alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 44/83] target/riscv: De-indent some code in get_physical_address() alistair23
                   ` (41 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Djordje Todorovic, Djordje Todorovic,
	Philippe Mathieu-Daudé, Alistair Francis, Pierrick Bouvier

From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com>

Make data accesses honour the MSTATUS MBE/SBE/UBE endianness bits
instead of being hardcoded to little-endian. Update mo_endian_env()
to pick the bit corresponding to the current privilege level (MBE
for M, SBE for S, UBE for U). Remove the now unused mo_endian()
helper.

Note, TB_FLAGS has no free bits, so the data endianness is carried
in the extended RISC-V TB flags stored in cs_base. It uses
EXT_TB_FLAGS.BIG_ENDIAN at bit 33, leaving bit 32 for
EXT_TB_FLAGS.ALTFMT. This keys TBs correctly on the current data
endianness.

Instruction fetches remain MO_LE unconditionally; RISC-V instructions
are always little-endian per the ISA specification. Update the
disassembler comment to clarify that BFD_ENDIAN_LITTLE is correct.

Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com>
Co-developed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-3-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h         |  1 +
 target/riscv/internals.h   | 29 +++++++++++++++++++++--------
 target/riscv/cpu.c         |  7 ++-----
 target/riscv/tcg/tcg-cpu.c |  2 ++
 target/riscv/translate.c   | 15 ++-------------
 5 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 1805aa8dfd..febd905389 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -714,6 +714,7 @@ FIELD(TB_FLAGS, PM_SIGNEXTEND, 31, 1)
 
 FIELD(EXT_TB_FLAGS, MISA_EXT, 0, 32)
 FIELD(EXT_TB_FLAGS, ALTFMT, 32, 1)
+FIELD(EXT_TB_FLAGS, BIG_ENDIAN, 33, 1)
 
 #ifdef TARGET_RISCV32
 #define riscv_cpu_mxl(env)  ((void)(env), MXL_RV32)
diff --git a/target/riscv/internals.h b/target/riscv/internals.h
index e143a86f97..5d84e4de96 100644
--- a/target/riscv/internals.h
+++ b/target/riscv/internals.h
@@ -62,16 +62,29 @@ static inline bool mmuidx_2stage(int mmu_idx)
     return mmu_idx & MMU_2STAGE_BIT;
 }
 
+/*
+ * Return the endianness for the current privilege
+ * level, based on the MSTATUS MBE/SBE/UBE bits.
+ */
 static inline MemOp mo_endian_env(CPURISCVState *env)
 {
-    /*
-     * A couple of bits in MSTATUS set the endianness:
-     *  - MSTATUS_UBE (User-mode),
-     *  - MSTATUS_SBE (Supervisor-mode),
-     *  - MSTATUS_MBE (Machine-mode)
-     * but we don't implement that yet.
-     */
-    return MO_LE;
+    bool be = false;
+#if !defined(CONFIG_USER_ONLY)
+    switch (env->priv) {
+    case PRV_M:
+        be = env->mstatus & MSTATUS_MBE;
+        break;
+    case PRV_S:
+        be = env->mstatus & MSTATUS_SBE;
+        break;
+    case PRV_U:
+        be = env->mstatus & MSTATUS_UBE;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+#endif
+    return be ? MO_BE : MO_LE;
 }
 
 /* share data between vector helpers and decode code */
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 1d9e575bb2..ee74cc5b20 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -831,11 +831,8 @@ static void riscv_cpu_disas_set_info(const CPUState *s, disassemble_info *info)
     info->target_info = &cpu->cfg;
 
     /*
-     * A couple of bits in MSTATUS set the endianness:
-     *  - MSTATUS_UBE (User-mode),
-     *  - MSTATUS_SBE (Supervisor-mode),
-     *  - MSTATUS_MBE (Machine-mode)
-     * but we don't implement that yet.
+     * RISC-V instructions are always little-endian, regardless of the
+     * data endianness configured via MSTATUS UBE/SBE/MBE bits.
      */
     info->endian = BFD_ENDIAN_LITTLE;
 
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 7e964e8f1a..60afb4ccc2 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -194,6 +194,8 @@ static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs)
     flags = FIELD_DP32(flags, TB_FLAGS, PM_SIGNEXTEND, pm_signext);
 
     ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, MISA_EXT, env->misa_ext);
+    ext_flags = FIELD_DP64(ext_flags, EXT_TB_FLAGS, BIG_ENDIAN,
+                           mo_endian_env(env) == MO_BE);
 
     return (TCGTBCPUState){
         .pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc,
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 5405db9ea5..9684dbe752 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -130,18 +130,6 @@ static inline bool has_ext(DisasContext *ctx, uint32_t ext)
     return ctx->misa_ext & ext;
 }
 
-static inline MemOp mo_endian(DisasContext *ctx)
-{
-    /*
-     * A couple of bits in MSTATUS set the endianness:
-     *  - MSTATUS_UBE (User-mode),
-     *  - MSTATUS_SBE (Supervisor-mode),
-     *  - MSTATUS_MBE (Machine-mode)
-     * but we don't implement that yet.
-     */
-    return MO_LE;
-}
-
 #ifdef TARGET_RISCV32
 #define get_xl(ctx)    MXL_RV32
 #elif defined(CONFIG_USER_ONLY)
@@ -1365,7 +1353,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
     ctx->zero = tcg_constant_tl(0);
     ctx->virt_inst_excp = false;
     ctx->decoders = cpu->decoders;
-    ctx->mo_endianness = mo_endian(ctx);
+    ctx->mo_endianness = FIELD_EX64(ext_tb_flags, EXT_TB_FLAGS, BIG_ENDIAN)
+                         ? MO_BE : MO_LE;
 }
 
 static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
-- 
2.54.0



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

* [PULL 44/83] target/riscv: De-indent some code in get_physical_address()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (42 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 43/83] target/riscv: Implement runtime data endianness via MSTATUS bits alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 45/83] target/riscv: Remove target_ulong use " alistair23
                   ` (40 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Philippe Mathieu-Daudé, Alistair Francis,
	Pierrick Bouvier

From: Philippe Mathieu-Daudé <philmd@linaro.org>

get_physical_address() is quite complex already. In order
to make the two next commits simplers, de-indent one if()
ladder. No logical change intended.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-5-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index dc78fc1192..a8d4a1a4f4 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1667,27 +1667,30 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
         hwaddr l = sxlen_bytes, addr1;
         mr = address_space_translate(cs->as, pte_addr, &addr1, &l,
                                      false, MEMTXATTRS_UNSPECIFIED);
-        if (memory_region_is_ram(mr)) {
-            target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1);
-            target_ulong old_pte;
-            if (riscv_cpu_sxl(env) == MXL_RV32) {
-                old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, cpu_to_le32(pte), cpu_to_le32(updated_pte));
-                old_pte = le32_to_cpu(old_pte);
-            } else {
-                old_pte = qatomic_cmpxchg(pte_pa, cpu_to_le64(pte), cpu_to_le64(updated_pte));
-                old_pte = le64_to_cpu(old_pte);
-            }
-            if (old_pte != pte) {
-                goto restart;
-            }
-            pte = updated_pte;
-        } else {
+        if (!memory_region_is_ram(mr)) {
             /*
              * Misconfigured PTE in ROM (AD bits are not preset) or
              * PTE is in IO space and can't be updated atomically.
              */
             return TRANSLATE_FAIL;
         }
+
+        target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1);
+        target_ulong old_pte;
+
+        if (riscv_cpu_sxl(env) == MXL_RV32) {
+            old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, cpu_to_le32(pte),
+                                      cpu_to_le32(updated_pte));
+            old_pte = le32_to_cpu(old_pte);
+        } else {
+            old_pte = qatomic_cmpxchg(pte_pa, cpu_to_le64(pte),
+                                      cpu_to_le64(updated_pte));
+            old_pte = le64_to_cpu(old_pte);
+        }
+        if (old_pte != pte) {
+            goto restart;
+        }
+        pte = updated_pte;
     }
 
     /* For superpage mappings, make a fake leaf PTE for the TLB's benefit. */
-- 
2.54.0



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

* [PULL 45/83] target/riscv: Remove target_ulong use in get_physical_address()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (43 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 44/83] target/riscv: De-indent some code in get_physical_address() alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 46/83] target/riscv: Fix page table walk endianness for big-endian harts alistair23
                   ` (39 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Philippe Mathieu-Daudé, Alistair Francis,
	Pierrick Bouvier

From: Philippe Mathieu-Daudé <philmd@linaro.org>

Use uint32_t for RV32, uint64_t otherwise.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-6-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index a8d4a1a4f4..430378490f 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1675,16 +1675,18 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
             return TRANSLATE_FAIL;
         }
 
-        target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1);
-        target_ulong old_pte;
+        void *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1);
+        uint64_t old_pte;
 
         if (riscv_cpu_sxl(env) == MXL_RV32) {
-            old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, cpu_to_le32(pte),
-                                      cpu_to_le32(updated_pte));
+            uint32_t cmp = cpu_to_le32(pte);
+            uint32_t val = cpu_to_le32(updated_pte);
+            old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, cmp, val);
             old_pte = le32_to_cpu(old_pte);
         } else {
-            old_pte = qatomic_cmpxchg(pte_pa, cpu_to_le64(pte),
-                                      cpu_to_le64(updated_pte));
+            uint64_t cmp = cpu_to_le64(pte);
+            uint64_t val = cpu_to_le64(updated_pte);
+            old_pte = qatomic_cmpxchg((uint64_t *)pte_pa, cmp, val);
             old_pte = le64_to_cpu(old_pte);
         }
         if (old_pte != pte) {
-- 
2.54.0



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

* [PULL 46/83] target/riscv: Fix page table walk endianness for big-endian harts
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (44 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 45/83] target/riscv: Remove target_ulong use " alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 47/83] hw/riscv/boot: Rewrite setup_rom_reset_vec() using load/store API alistair23
                   ` (38 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Djordje Todorovic, Djordje Todorovic,
	Philippe Mathieu-Daudé, Alistair Francis, Pierrick Bouvier

From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com>

The page table walker reads PTEs using address_space_ldl/ldq which use
compile-time native endianness (always LE for RISC-V). However, when a
big-endian kernel writes PTEs via normal store instructions, they are
stored in big-endian byte order. The walker then misinterprets the PTE
values, causing page faults and a hang when the kernel enables the MMU.

The RISC-V privileged specification states that implicit data memory
accesses to supervisor-level memory management data structures follow
the hart's endianness setting (MSTATUS SBE/MBE bits).

Fix both PTE reads and atomic A/D bit updates to use the explicit _le
or _be memory access variants based on the hart's runtime endianness.

Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-7-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 430378490f..e5653a5730 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1370,6 +1370,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
     target_ulong pte;
     hwaddr pte_addr;
     const hwaddr base_root = base;
+    const bool be = mo_endian_env(env) == MO_BE;
     int i;
 
  restart:
@@ -1418,9 +1419,11 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
         }
 
         if (riscv_cpu_mxl(env) == MXL_RV32) {
-            pte = address_space_ldl_le(cs->as, pte_addr, attrs, &res);
+            pte = be ? address_space_ldl_be(cs->as, pte_addr, attrs, &res)
+                     : address_space_ldl_le(cs->as, pte_addr, attrs, &res);
         } else {
-            pte = address_space_ldq_le(cs->as, pte_addr, attrs, &res);
+            pte = be ? address_space_ldq_be(cs->as, pte_addr, attrs, &res)
+                     : address_space_ldq_le(cs->as, pte_addr, attrs, &res);
         }
 
         if (res != MEMTX_OK) {
@@ -1679,15 +1682,15 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
         uint64_t old_pte;
 
         if (riscv_cpu_sxl(env) == MXL_RV32) {
-            uint32_t cmp = cpu_to_le32(pte);
-            uint32_t val = cpu_to_le32(updated_pte);
+            uint32_t cmp = be ? cpu_to_be32(pte) : cpu_to_le32(pte);
+            uint32_t val = be ? cpu_to_be32(updated_pte) : cpu_to_le32(updated_pte);
             old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, cmp, val);
-            old_pte = le32_to_cpu(old_pte);
+            old_pte = be ? be32_to_cpu(old_pte) : le32_to_cpu(old_pte);
         } else {
-            uint64_t cmp = cpu_to_le64(pte);
-            uint64_t val = cpu_to_le64(updated_pte);
+            uint64_t cmp = be ? cpu_to_be64(pte) : cpu_to_le64(pte);
+            uint64_t val = be ? cpu_to_be64(updated_pte) : cpu_to_le64(updated_pte);
             old_pte = qatomic_cmpxchg((uint64_t *)pte_pa, cmp, val);
-            old_pte = le64_to_cpu(old_pte);
+            old_pte = be ? be64_to_cpu(old_pte) : le64_to_cpu(old_pte);
         }
         if (old_pte != pte) {
             goto restart;
-- 
2.54.0



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

* [PULL 47/83] hw/riscv/boot: Rewrite setup_rom_reset_vec() using load/store API
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (45 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 46/83] target/riscv: Fix page table walk endianness for big-endian harts alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 48/83] hw/riscv/boot: Replace cpu_to_le32() -> const_le32() alistair23
                   ` (37 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Philippe Mathieu-Daudé, Alistair Francis,
	Pierrick Bouvier

From: Philippe Mathieu-Daudé <philmd@linaro.org>

In order to make the following commits easier to review, do
not pre-initialize the reset_vec[] array, fill each word one
by one. Set the start and FDT load addresses using the load/
store APIs.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-8-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/boot.c | 55 ++++++++++++++++++++++---------------------------
 1 file changed, 25 insertions(+), 30 deletions(-)

diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index ae2f86c7ce..c6ab1cc8cf 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -18,6 +18,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/bswap.h"
 #include "qemu/datadir.h"
 #include "qemu/units.h"
 #include "qemu/error-report.h"
@@ -444,6 +445,9 @@ void riscv_rom_copy_firmware_info(MachineState *machine,
                            &address_space_memory);
 }
 
+#define CODE_WORDS 6
+#define DATA_WORDS 4
+
 void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts,
                                hwaddr start_addr,
                                hwaddr rom_base, hwaddr rom_size,
@@ -451,43 +455,34 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts
                                uint64_t fdt_load_addr)
 {
     int i;
-    uint32_t start_addr_hi32 = 0x00000000;
-    uint32_t fdt_load_addr_hi32 = 0x00000000;
-
-    if (!riscv_is_32bit(harts)) {
-        start_addr_hi32 = start_addr >> 32;
-        fdt_load_addr_hi32 = fdt_load_addr >> 32;
-    }
-    /* reset vector */
-    uint32_t reset_vec[10] = {
-        0x00000297,                  /* 1:  auipc  t0, %pcrel_hi(fw_dyn) */
-        0x02828613,                  /*     addi   a2, t0, %pcrel_lo(1b) */
-        0xf1402573,                  /*     csrr   a0, mhartid  */
-        0,
-        0,
-        0x00028067,                  /*     jr     t0 */
-        start_addr,                  /* start: .dword */
-        start_addr_hi32,
-        fdt_load_addr,               /* fdt_laddr: .dword */
-        fdt_load_addr_hi32,
-                                     /* fw_dyn: */
-    };
-    if (riscv_is_32bit(harts)) {
-        reset_vec[3] = 0x0202a583;   /*     lw     a1, 32(t0) */
-        reset_vec[4] = 0x0182a283;   /*     lw     t0, 24(t0) */
+    const bool rv32 = riscv_is_32bit(harts);
+    uint32_t reset_vec[CODE_WORDS + DATA_WORDS];
+
+    /* .text */
+    reset_vec[0] = 0x00000297;                  /* 1:  auipc  t0, %pcrel_hi(fw_dyn) */
+    reset_vec[1] = 0x02828613;                  /*     addi   a2, t0, %pcrel_lo(1b) */
+    if (harts->harts[0].cfg.ext_zicsr) {
+        reset_vec[2] = 0xf1402573;              /*     csrr   a0, mhartid  */
     } else {
-        reset_vec[3] = 0x0202b583;   /*     ld     a1, 32(t0) */
-        reset_vec[4] = 0x0182b283;   /*     ld     t0, 24(t0) */
-    }
-
-    if (!harts->harts[0].cfg.ext_zicsr) {
         /*
          * The Zicsr extension has been disabled, so let's ensure we don't
          * run the CSR instruction. Let's fill the address with a non
          * compressed nop.
          */
-        reset_vec[2] = 0x00000013;   /*     addi   x0, x0, 0 */
+        reset_vec[2] = 0x00000013;              /*     addi   x0, x0, 0 */
+    }
+    if (rv32) {
+        reset_vec[3] = 0x0202a583;              /*     lw     a1, 32(t0) */
+        reset_vec[4] = 0x0182a283;              /*     lw     t0, 24(t0) */
+    } else {
+        reset_vec[3] = 0x0202b583;              /*     ld     a1, 32(t0) */
+        reset_vec[4] = 0x0182b283;              /*     ld     t0, 24(t0) */
     }
+    reset_vec[5] = 0x00028067;                  /*     jr     t0 */
+
+    /* .data */
+    stq_p(&reset_vec[6], start_addr);           /* start:       .dword */
+    stq_p(&reset_vec[8], fdt_load_addr);        /* fdt_laddr:   .dword */
 
     /* copy in the reset vector in little_endian byte order */
     for (i = 0; i < ARRAY_SIZE(reset_vec); i++) {
-- 
2.54.0



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

* [PULL 48/83] hw/riscv/boot: Replace cpu_to_le32() -> const_le32()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (46 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 47/83] hw/riscv/boot: Rewrite setup_rom_reset_vec() using load/store API alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 49/83] target/riscv: Add big-endian CPU configuration field and reset logic alistair23
                   ` (36 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Philippe Mathieu-Daudé, Alistair Francis,
	Pierrick Bouvier

From: Philippe Mathieu-Daudé <philmd@linaro.org>

Rather than adapting the array endianness when it it
filled, directly initialize the CODE words with the
correct endianness.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-9-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/boot.c | 30 +++++++++++++-----------------
 1 file changed, 13 insertions(+), 17 deletions(-)

diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index c6ab1cc8cf..4297949f6b 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -454,40 +454,36 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts
                                uint64_t kernel_entry,
                                uint64_t fdt_load_addr)
 {
-    int i;
     const bool rv32 = riscv_is_32bit(harts);
     uint32_t reset_vec[CODE_WORDS + DATA_WORDS];
 
-    /* .text */
-    reset_vec[0] = 0x00000297;                  /* 1:  auipc  t0, %pcrel_hi(fw_dyn) */
-    reset_vec[1] = 0x02828613;                  /*     addi   a2, t0, %pcrel_lo(1b) */
+    /* .text (RISC-V instructions are always little-endian) */
+    reset_vec[0] = const_le32(0x00000297);      /* 1:  auipc  t0, %pcrel_hi(fw_dyn) */
+    reset_vec[1] = const_le32(0x02828613);      /*     addi   a2, t0, %pcrel_lo(1b) */
+    reset_vec[2] = const_le32(0xf1402573);      /*     csrr   a0, mhartid  */
     if (harts->harts[0].cfg.ext_zicsr) {
-        reset_vec[2] = 0xf1402573;              /*     csrr   a0, mhartid  */
+        reset_vec[2] = const_le32(0xf1402573);  /*     csrr   a0, mhartid  */
     } else {
         /*
          * The Zicsr extension has been disabled, so let's ensure we don't
          * run the CSR instruction. Let's fill the address with a non
          * compressed nop.
          */
-        reset_vec[2] = 0x00000013;              /*     addi   x0, x0, 0 */
+        reset_vec[2] = const_le32(0x00000013);  /*     addi   x0, x0, 0 */
     }
     if (rv32) {
-        reset_vec[3] = 0x0202a583;              /*     lw     a1, 32(t0) */
-        reset_vec[4] = 0x0182a283;              /*     lw     t0, 24(t0) */
+        reset_vec[3] = const_le32(0x0202a583);  /*     lw     a1, 32(t0) */
+        reset_vec[4] = const_le32(0x0182a283);  /*     lw     t0, 24(t0) */
     } else {
-        reset_vec[3] = 0x0202b583;              /*     ld     a1, 32(t0) */
-        reset_vec[4] = 0x0182b283;              /*     ld     t0, 24(t0) */
+        reset_vec[3] = const_le32(0x0202b583);  /*     ld     a1, 32(t0) */
+        reset_vec[4] = const_le32(0x0182b283);  /*     ld     t0, 24(t0) */
     }
-    reset_vec[5] = 0x00028067;                  /*     jr     t0 */
+    reset_vec[5] = const_le32(0x00028067);      /*     jr     t0 */
 
     /* .data */
-    stq_p(&reset_vec[6], start_addr);           /* start:       .dword */
-    stq_p(&reset_vec[8], fdt_load_addr);        /* fdt_laddr:   .dword */
+    stq_le_p(&reset_vec[6], start_addr);        /* start:       .dword */
+    stq_le_p(&reset_vec[8], fdt_load_addr);     /* fdt_laddr:   .dword */
 
-    /* copy in the reset vector in little_endian byte order */
-    for (i = 0; i < ARRAY_SIZE(reset_vec); i++) {
-        reset_vec[i] = cpu_to_le32(reset_vec[i]);
-    }
     rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
                           rom_base, &address_space_memory);
     riscv_rom_copy_firmware_info(machine, harts,
-- 
2.54.0



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

* [PULL 49/83] target/riscv: Add big-endian CPU configuration field and reset logic
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (47 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 48/83] hw/riscv/boot: Replace cpu_to_le32() -> const_le32() alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 50/83] hw/riscv/boot: Honour data endianness alistair23
                   ` (35 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Djordje Todorovic, Djordje Todorovic,
	Philippe Mathieu-Daudé, Alistair Francis, Pierrick Bouvier

From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com>

Add a big_endian field to RISCVCPUConfig and wire it into the CPU
reset path. When cfg.big_endian is set, riscv_cpu_reset_hold()
writes 1 into the MSTATUS MBE/SBE/UBE fields using set_field();
otherwise it writes 0. This makes the reset value deterministic on
both cold and warm reset.

This models fixed-endian harts, not mixed-endian implementations where
the guest can toggle MBE/SBE/UBE at runtime. The MBE/SBE/UBE bits are
not included in the writable mask of any mstatus/mstatush/sstatus CSR
write path (unchanged by this series), so the value chosen at reset is
effectively hardwired per section 3.1.6.5 of the RISC-V Privileged
Specification.

The user-facing property and documentation are added in a later patch,
once the full endianness support is in place.

Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-10-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_cfg_fields.h.inc | 1 +
 target/riscv/cpu.c                | 7 +++++++
 2 files changed, 8 insertions(+)

diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc
index 734fa079f2..9eb47af0a7 100644
--- a/target/riscv/cpu_cfg_fields.h.inc
+++ b/target/riscv/cpu_cfg_fields.h.inc
@@ -157,6 +157,7 @@ BOOL_FIELD(ext_xmipscmov)
 BOOL_FIELD(ext_xmipslsp)
 BOOL_FIELD(ext_xlrbr)
 
+BOOL_FIELD(big_endian)
 BOOL_FIELD(mmu)
 BOOL_FIELD(pmp)
 BOOL_FIELD(debug)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ee74cc5b20..cc793aef18 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -740,6 +740,13 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
             env->mstatus = set_field(env->mstatus, MSTATUS_MDT, 1);
         }
     }
+    /*
+     * Model fixed-endian harts: MBE/SBE/UBE are initialized from the
+     * CPU configuration and are intentionally not writable via status CSRs.
+     */
+    env->mstatus = set_field(env->mstatus, MSTATUS_MBE, cpu->cfg.big_endian);
+    env->mstatus = set_field(env->mstatus, MSTATUS_SBE, cpu->cfg.big_endian);
+    env->mstatus = set_field(env->mstatus, MSTATUS_UBE, cpu->cfg.big_endian);
     env->mcause = 0;
     env->miclaim = MIP_SGEIP;
     env->pc = env->resetvec;
-- 
2.54.0



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

* [PULL 50/83] hw/riscv/boot: Honour data endianness
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (48 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 49/83] target/riscv: Add big-endian CPU configuration field and reset logic alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 51/83] target/riscv: Expose and document the CPU 'big-endian' property alistair23
                   ` (34 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Djordje Todorovic, Djordje Todorovic,
	Philippe Mathieu-Daudé, Alistair Francis, Pierrick Bouvier

From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com>

Check the hart endianness property and use it throughout the boot code:

- ELF loading: pass ELFDATA2MSB or ELFDATA2LSB based on endianness
- Firmware dynamic info
- Reset vector: instructions (entries 0-5) remain always little-endian,
  data words (entries 6-9) use target data endianness.

Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com>
Co-developed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-11-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/boot.c | 40 ++++++++++++++++++++++++++++------------
 1 file changed, 28 insertions(+), 12 deletions(-)

diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index 4297949f6b..7c9cd61468 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -407,21 +407,31 @@ void riscv_rom_copy_firmware_info(MachineState *machine,
     struct fw_dynamic_info64 dinfo64;
     void *dinfo_ptr = NULL;
     size_t dinfo_len;
+    const bool rv32 = riscv_is_32bit(harts);
+    const bool be = harts->harts[0].cfg.big_endian;
 
-    if (riscv_is_32bit(harts)) {
-        dinfo32.magic = cpu_to_le32(FW_DYNAMIC_INFO_MAGIC_VALUE);
-        dinfo32.version = cpu_to_le32(FW_DYNAMIC_INFO_VERSION);
-        dinfo32.next_mode = cpu_to_le32(FW_DYNAMIC_INFO_NEXT_MODE_S);
-        dinfo32.next_addr = cpu_to_le32(kernel_entry);
+    if (rv32) {
+        dinfo32.magic = be ? cpu_to_be32(FW_DYNAMIC_INFO_MAGIC_VALUE)
+                           : cpu_to_le32(FW_DYNAMIC_INFO_MAGIC_VALUE);
+        dinfo32.version = be ? cpu_to_be32(FW_DYNAMIC_INFO_VERSION)
+                             : cpu_to_le32(FW_DYNAMIC_INFO_VERSION);
+        dinfo32.next_mode = be ? cpu_to_be32(FW_DYNAMIC_INFO_NEXT_MODE_S)
+                               : cpu_to_le32(FW_DYNAMIC_INFO_NEXT_MODE_S);
+        dinfo32.next_addr = be ? cpu_to_be32(kernel_entry)
+                               : cpu_to_le32(kernel_entry);
         dinfo32.options = 0;
         dinfo32.boot_hart = 0;
         dinfo_ptr = &dinfo32;
         dinfo_len = sizeof(dinfo32);
     } else {
-        dinfo64.magic = cpu_to_le64(FW_DYNAMIC_INFO_MAGIC_VALUE);
-        dinfo64.version = cpu_to_le64(FW_DYNAMIC_INFO_VERSION);
-        dinfo64.next_mode = cpu_to_le64(FW_DYNAMIC_INFO_NEXT_MODE_S);
-        dinfo64.next_addr = cpu_to_le64(kernel_entry);
+        dinfo64.magic = be ? cpu_to_be64(FW_DYNAMIC_INFO_MAGIC_VALUE)
+                           : cpu_to_le64(FW_DYNAMIC_INFO_MAGIC_VALUE);
+        dinfo64.version = be ? cpu_to_be64(FW_DYNAMIC_INFO_VERSION)
+                             : cpu_to_le64(FW_DYNAMIC_INFO_VERSION);
+        dinfo64.next_mode = be ? cpu_to_be64(FW_DYNAMIC_INFO_NEXT_MODE_S)
+                               : cpu_to_le64(FW_DYNAMIC_INFO_NEXT_MODE_S);
+        dinfo64.next_addr = be ? cpu_to_be64(kernel_entry)
+                               : cpu_to_le64(kernel_entry);
         dinfo64.options = 0;
         dinfo64.boot_hart = 0;
         dinfo_ptr = &dinfo64;
@@ -455,6 +465,7 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts
                                uint64_t fdt_load_addr)
 {
     const bool rv32 = riscv_is_32bit(harts);
+    const bool big_endian = harts->harts[0].cfg.big_endian;
     uint32_t reset_vec[CODE_WORDS + DATA_WORDS];
 
     /* .text (RISC-V instructions are always little-endian) */
@@ -480,9 +491,14 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts
     }
     reset_vec[5] = const_le32(0x00028067);      /*     jr     t0 */
 
-    /* .data */
-    stq_le_p(&reset_vec[6], start_addr);        /* start:       .dword */
-    stq_le_p(&reset_vec[8], fdt_load_addr);     /* fdt_laddr:   .dword */
+    /* .data (must match the firmware's data endianness) */
+    if (big_endian) {
+        stq_be_p(&reset_vec[6], start_addr);    /* start:       .dword */
+        stq_be_p(&reset_vec[8], fdt_load_addr); /* fdt_laddr:   .dword */
+    } else {
+        stq_le_p(&reset_vec[6], start_addr);
+        stq_le_p(&reset_vec[8], fdt_load_addr);
+    }
 
     rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
                           rom_base, &address_space_memory);
-- 
2.54.0



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

* [PULL 51/83] target/riscv: Expose and document the CPU 'big-endian' property
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (49 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 50/83] hw/riscv/boot: Honour data endianness alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 52/83] tests/functional: Add RISC-V endianness test alistair23
                   ` (33 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Djordje Todorovic, Djordje Todorovic,
	Philippe Mathieu-Daudé, Alistair Francis, Pierrick Bouvier

From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com>

Now that the full big-endian data path is in place (runtime MSTATUS
bits, boot code, and page-table walks), expose the "big-endian"
property to users via DEFINE_PROP_BOOL and document it in
docs/system/target-riscv.rst.

Document that the property models fixed-endian hardware: it selects
harts whose MBE/SBE/UBE fields are fixed to 1, and it does not model
a mixed-endian implementation where software can toggle those bits at
runtime.

The property can be enabled from the command line, e.g.:

    -cpu <cpu>,big-endian=on

Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-12-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 docs/system/target-riscv.rst | 29 +++++++++++++++++++++++++++++
 target/riscv/cpu.c           |  1 +
 2 files changed, 30 insertions(+)

diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
index 3ad5d1ddaf..afd86ca2ba 100644
--- a/docs/system/target-riscv.rst
+++ b/docs/system/target-riscv.rst
@@ -95,3 +95,32 @@ the images they need.
 * ``-bios <file>``
 
 Tells QEMU to load the specified file as the firmware.
+
+RISC-V CPU endianness
+---------------------
+
+The RISC-V ISA specifies that instruction fetches are always little-endian,
+while data accesses can be either little-endian or big-endian under control
+of the MSTATUS ``MBE``/``SBE``/``UBE`` bits (see section 3.1.6.5, "Memory
+Endianness", in the RISC-V Privileged Specification).
+
+QEMU implements the full data-endianness behaviour described by those bits.
+In addition, the RISC-V CPU object exposes a ``big-endian`` boolean property
+which models a big-endian-only hardware implementation, where the
+``MBE``/``SBE``/``UBE`` bits are hardwired to 1. When the property is set,
+the CPU is reset with all three bits initialised to 1, so the guest starts
+executing in big-endian data mode from the reset vector. The property is a
+static, per-CPU hardware configuration option and is not meant to be toggled
+at runtime.
+
+The property does not model a mixed-endian implementation where software can
+toggle ``MBE``/``SBE``/``UBE`` at runtime. QEMU's RISC-V CPUs treat these
+fields as fixed by the CPU configuration: they are reset to 0 by default and
+to 1 when ``big-endian`` is enabled.
+
+The property can be enabled from the command line, for example::
+
+    -cpu <cpu>,big-endian=on
+
+No upstream CPU model currently defaults to big-endian; the property is
+provided so that big-endian-only RISC-V CPU variants can be modelled.
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index cc793aef18..5a3560308f 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -2525,6 +2525,7 @@ RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[] = {
 
 static const Property riscv_cpu_properties[] = {
     DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true),
+    DEFINE_PROP_BOOL("big-endian", RISCVCPU, cfg.big_endian, false),
 
     {.name = "pmu-mask", .info = &prop_pmu_mask},
     {.name = "pmu-num", .info = &prop_pmu_num}, /* Deprecated */
-- 
2.54.0



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

* [PULL 52/83] tests/functional: Add RISC-V endianness test
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (50 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 51/83] target/riscv: Expose and document the CPU 'big-endian' property alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 53/83] target/riscv: Add the implied rule for G extension alistair23
                   ` (32 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Djordje Todorovic, Djordje Todorovic, Thomas Huth,
	Philippe Mathieu-Daudé, Alistair Francis, Pierrick Bouvier

From: Djordje Todorovic <Djordje.Todorovic@htecgroup.com>

Add functional test for the RISC-V 'big-endian' CPU property.

Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-ID: <20260527201348.29511-13-philmd@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 tests/functional/riscv64/meson.build        |  1 +
 tests/functional/riscv64/test_endianness.py | 57 +++++++++++++++++++++
 2 files changed, 58 insertions(+)
 create mode 100644 tests/functional/riscv64/test_endianness.py

diff --git a/tests/functional/riscv64/meson.build b/tests/functional/riscv64/meson.build
index b996c89d7d..5871211e89 100644
--- a/tests/functional/riscv64/meson.build
+++ b/tests/functional/riscv64/meson.build
@@ -11,6 +11,7 @@ tests_riscv64_system_quick = [
 ]
 
 tests_riscv64_system_thorough = [
+  'endianness',
   'boston',
   'sifive_u',
   'tuxrun',
diff --git a/tests/functional/riscv64/test_endianness.py b/tests/functional/riscv64/test_endianness.py
new file mode 100644
index 0000000000..9e0b3b7db5
--- /dev/null
+++ b/tests/functional/riscv64/test_endianness.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+#
+# Functional tests for RISC-V big-endian support
+#
+# Copyright (c) 2026 MIPS
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+
+
+class RiscvBigEndian(QemuSystemTest):
+    """
+    Tests for RISC-V runtime big-endian data support.
+
+    Uses a bare-metal RV64 ELF that detects data endianness at runtime
+    by storing a 32-bit word and reading back byte 0. Prints "ENDIAN: BE"
+    or "ENDIAN: LE" to the NS16550A UART on the virt machine.
+    """
+
+    timeout = 10
+
+    ASSET_BE_TEST = Asset(
+        'https://github.com/MIPS/linux-test-downloads/raw/main/'
+        'riscvbe-baremetal/be-test-bare-metal.elf',
+        '9ad51b675e101de65908fadbac064ed1d0564c17463715d09dd734db86ea0f58')
+
+    def _run_bare_metal(self, big_endian=False):
+        self.set_machine('virt')
+        kernel = self.ASSET_BE_TEST.fetch()
+        self.vm.add_args('-bios', 'none')
+        self.vm.add_args('-kernel', kernel)
+        if big_endian:
+            self.vm.add_args('-cpu', 'rv64,big-endian=on')
+        self.vm.set_console()
+        self.vm.launch()
+        expected = 'ENDIAN: BE' if big_endian else 'ENDIAN: LE'
+        wait_for_console_pattern(self, expected)
+
+    def test_bare_metal_littleendian(self):
+        """
+        Boot bare-metal ELF on virt with default little-endian CPU.
+        Expects "ENDIAN: LE" on UART.
+        """
+        self._run_bare_metal(big_endian=False)
+
+    def test_bare_metal_bigendian(self):
+        """
+        Boot bare-metal ELF on virt with big-endian=on CPU property.
+        Expects "ENDIAN: BE" on UART.
+        """
+        self._run_bare_metal(big_endian=True)
+
+
+if __name__ == '__main__':
+    QemuSystemTest.main()
-- 
2.54.0



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

* [PULL 53/83] target/riscv: Add the implied rule for G extension
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (51 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 52/83] tests/functional: Add RISC-V endianness test alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 54/83] target/riscv: Add standard B extension implied rule alistair23
                   ` (31 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Jim Shu, Frank Chang, Alistair Francis

From: Jim Shu <jim.shu@sifive.com>

Add the missing implied rule from G to imafd_zicsr_zifencei.
We can also remove the auto-enables in riscv_cpu_validate_g() as
IMAFD, Zicsr, Zifencei extensions can be enabled by the implied rule.

Signed-off-by: Jim Shu <jim.shu@sifive.com>
Reviewed-by: Frank Chang <frank.chang@sifive.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260528054213.678458-2-frank.chang@sifive.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c         | 14 +++++++++++++-
 target/riscv/tcg/tcg-cpu.c | 21 ++++-----------------
 2 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5a3560308f..455d5b3d48 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -2095,6 +2095,18 @@ static RISCVCPUImpliedExtsRule RVV_IMPLIED = {
     },
 };
 
+static RISCVCPUImpliedExtsRule RVG_IMPLIED = {
+    .is_misa = true,
+    .ext = RVG,
+    .implied_misa_exts = RVI | RVM | RVA | RVF | RVD,
+    .implied_multi_exts = {
+        CPU_CFG_OFFSET(ext_zicsr),
+        CPU_CFG_OFFSET(ext_zifencei),
+
+        RISCV_IMPLIED_EXTS_RULE_END
+    },
+};
+
 static RISCVCPUImpliedExtsRule ZCB_IMPLIED = {
     .ext = CPU_CFG_OFFSET(ext_zcb),
     .implied_multi_exts = {
@@ -2502,7 +2514,7 @@ static RISCVCPUImpliedExtsRule ZVFBFA_IMPLIED = {
 
 RISCVCPUImpliedExtsRule *riscv_misa_ext_implied_rules[] = {
     &RVA_IMPLIED, &RVD_IMPLIED, &RVF_IMPLIED,
-    &RVM_IMPLIED, &RVV_IMPLIED, NULL
+    &RVM_IMPLIED, &RVV_IMPLIED, &RVG_IMPLIED, NULL
 };
 
 RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[] = {
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 60afb4ccc2..942c2851e8 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -498,30 +498,17 @@ static void riscv_cpu_validate_g(RISCVCPU *cpu)
             continue;
         }
 
-        if (!cpu_misa_ext_is_user_set(bit)) {
-            riscv_cpu_write_misa_bit(cpu, bit, true);
-            continue;
-        }
-
         if (send_warn) {
             warn_report(warn_msg, riscv_get_misa_ext_name(bit));
         }
     }
 
-    if (!cpu->cfg.ext_zicsr) {
-        if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zicsr))) {
-            cpu->cfg.ext_zicsr = true;
-        } else if (send_warn) {
-            warn_report(warn_msg, "zicsr");
-        }
+    if (!cpu->cfg.ext_zicsr && send_warn) {
+        warn_report(warn_msg, "zicsr");
     }
 
-    if (!cpu->cfg.ext_zifencei) {
-        if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zifencei))) {
-            cpu->cfg.ext_zifencei = true;
-        } else if (send_warn) {
-            warn_report(warn_msg, "zifencei");
-        }
+    if (!cpu->cfg.ext_zifencei && send_warn) {
+        warn_report(warn_msg, "zifencei");
     }
 }
 
-- 
2.54.0



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

* [PULL 54/83] target/riscv: Add standard B extension implied rule
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (52 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 53/83] target/riscv: Add the implied rule for G extension alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 55/83] target/riscv: Print privilege level and ELP in riscv_cpu_dump_state alistair23
                   ` (30 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Frank Chang, Jerry Zhang Jian, Jim Shu,
	Alistair Francis, Daniel Henrique Barboza

From: Frank Chang <frank.chang@sifive.com>

Add the missing implied rule for standard B extension.
Standard B extension implies Zba, Zbb, Zbs extensions.
We can also remove the auto-enables in riscv_cpu_validate_b()
as Zba, Zbb, Zbs extensions can be enabled by the implied rule.

RISC-V B spec: https://github.com/riscv/riscv-b

Reviewed-by: Jerry Zhang Jian <jerry.zhangjian@sifive.com>
Reviewed-by: Jim Shu <jim.shu@sifive.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Signed-off-by: Frank Chang <frank.chang@sifive.com>

Signed-off-by: Frank Chang <frank.chang@sifive.com>
Message-ID: <20260528054213.678458-3-frank.chang@sifive.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c         | 14 +++++++++++++-
 target/riscv/tcg/tcg-cpu.c | 18 +++---------------
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 455d5b3d48..df101b1213 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -2107,6 +2107,17 @@ static RISCVCPUImpliedExtsRule RVG_IMPLIED = {
     },
 };
 
+static RISCVCPUImpliedExtsRule RVB_IMPLIED = {
+    .is_misa = true,
+    .ext = RVB,
+    .implied_multi_exts = {
+        CPU_CFG_OFFSET(ext_zba), CPU_CFG_OFFSET(ext_zbb),
+        CPU_CFG_OFFSET(ext_zbs),
+
+        RISCV_IMPLIED_EXTS_RULE_END
+    },
+};
+
 static RISCVCPUImpliedExtsRule ZCB_IMPLIED = {
     .ext = CPU_CFG_OFFSET(ext_zcb),
     .implied_multi_exts = {
@@ -2514,7 +2525,8 @@ static RISCVCPUImpliedExtsRule ZVFBFA_IMPLIED = {
 
 RISCVCPUImpliedExtsRule *riscv_misa_ext_implied_rules[] = {
     &RVA_IMPLIED, &RVD_IMPLIED, &RVF_IMPLIED,
-    &RVM_IMPLIED, &RVV_IMPLIED, &RVG_IMPLIED, NULL
+    &RVM_IMPLIED, &RVV_IMPLIED, &RVG_IMPLIED,
+    &RVB_IMPLIED, NULL
 };
 
 RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[] = {
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 942c2851e8..b73e3e9dd4 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -517,27 +517,15 @@ static void riscv_cpu_validate_b(RISCVCPU *cpu)
     const char *warn_msg = "RVB mandates disabled extension %s";
 
     if (!cpu->cfg.ext_zba) {
-        if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zba))) {
-            cpu->cfg.ext_zba = true;
-        } else {
-            warn_report(warn_msg, "zba");
-        }
+        warn_report(warn_msg, "zba");
     }
 
     if (!cpu->cfg.ext_zbb) {
-        if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zbb))) {
-            cpu->cfg.ext_zbb = true;
-        } else {
-            warn_report(warn_msg, "zbb");
-        }
+        warn_report(warn_msg, "zbb");
     }
 
     if (!cpu->cfg.ext_zbs) {
-        if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zbs))) {
-            cpu->cfg.ext_zbs = true;
-        } else {
-            warn_report(warn_msg, "zbs");
-        }
+        warn_report(warn_msg, "zbs");
     }
 }
 
-- 
2.54.0



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

* [PULL 55/83] target/riscv: Print privilege level and ELP in riscv_cpu_dump_state
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (53 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 54/83] target/riscv: Add standard B extension implied rule alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:04 ` [PULL 56/83] target/riscv: Improve alignment " alistair23
                   ` (29 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Blanchard, Daniel Henrique Barboza,
	Alistair Francis

From: Anton Blanchard <antonb@tenstorrent.com>

The privilege level and ELP are implicit state (like virt), so print them
out.

Signed-off-by: Anton Blanchard <antonb@tenstorrent.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260529053519.1224019-1-antonb@tenstorrent.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index df101b1213..a5b1c2ba62 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -577,6 +577,22 @@ static void riscv_dump_csr(CPURISCVState *env, int csrno, FILE *f)
     }
 }
 
+#if !defined(CONFIG_USER_ONLY)
+static const char *riscv_priv_str(uint32_t priv)
+{
+    switch (priv) {
+    case PRV_M:
+        return "M";
+    case PRV_S:
+        return "S";
+    case PRV_U:
+        return "U";
+    }
+
+    return "?";
+}
+#endif
+
 static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 {
     RISCVCPU *cpu = RISCV_CPU(cs);
@@ -585,9 +601,15 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
     uint8_t *p;
 
 #if !defined(CONFIG_USER_ONLY)
+    qemu_fprintf(f, " %s %s\n", "priv   =  ", riscv_priv_str(env->priv));
+
     if (riscv_has_ext(env, RVH)) {
         qemu_fprintf(f, " %s %d\n", "V      =  ", env->virt_enabled);
     }
+
+    if (cpu->cfg.ext_zicfilp) {
+        qemu_fprintf(f, " %s %d\n", "elp    =  ", env->elp);
+    }
 #endif
     qemu_fprintf(f, " %s %" PRIx64 "\n", "pc      ", env->pc);
 #ifndef CONFIG_USER_ONLY
-- 
2.54.0



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

* [PULL 56/83] target/riscv: Improve alignment in riscv_cpu_dump_state
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (54 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 55/83] target/riscv: Print privilege level and ELP in riscv_cpu_dump_state alistair23
@ 2026-06-16 10:04 ` alistair23
  2026-06-16 10:05 ` [PULL 57/83] target/riscv: mask vxrm csrw write to the low 2 bits alistair23
                   ` (28 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Anton Blanchard, Daniel Henrique Barboza,
	Alistair Francis

From: Anton Blanchard <antonb@tenstorrent.com>

Align all the CSR values. mcountinhibit is the longest CSR name at
13 characters, so use that width for PC, implicit state, and CSR names.
Also remove the redundant '=' from the implicit state lines.t

Signed-off-by: Anton Blanchard <antonb@tenstorrent.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260529053519.1224019-2-antonb@tenstorrent.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index a5b1c2ba62..a74384a091 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -572,7 +572,7 @@ static void riscv_dump_csr(CPURISCVState *env, int csrno, FILE *f)
      * to do the filtering of the registers that are present.
      */
     if (res == RISCV_EXCP_NONE) {
-        qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n",
+        qemu_fprintf(f, " %-13s " TARGET_FMT_lx "\n",
                      csr_ops[csrno].name, val);
     }
 }
@@ -601,17 +601,17 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
     uint8_t *p;
 
 #if !defined(CONFIG_USER_ONLY)
-    qemu_fprintf(f, " %s %s\n", "priv   =  ", riscv_priv_str(env->priv));
+    qemu_fprintf(f, " %-13s %s\n", "priv", riscv_priv_str(env->priv));
 
     if (riscv_has_ext(env, RVH)) {
-        qemu_fprintf(f, " %s %d\n", "V      =  ", env->virt_enabled);
+        qemu_fprintf(f, " %-13s %d\n", "V", env->virt_enabled);
     }
 
     if (cpu->cfg.ext_zicfilp) {
-        qemu_fprintf(f, " %s %d\n", "elp    =  ", env->elp);
+        qemu_fprintf(f, " %-13s %d\n", "elp", env->elp);
     }
 #endif
-    qemu_fprintf(f, " %s %" PRIx64 "\n", "pc      ", env->pc);
+    qemu_fprintf(f, " %-13s %" PRIx64 "\n", "pc", env->pc);
 #ifndef CONFIG_USER_ONLY
     for (i = 0; i < ARRAY_SIZE(csr_ops); i++) {
         int csrno = i;
-- 
2.54.0



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

* [PULL 57/83] target/riscv: mask vxrm csrw write to the low 2 bits
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (55 preceding siblings ...)
  2026-06-16 10:04 ` [PULL 56/83] target/riscv: Improve alignment " alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 58/83] target/riscv: Reorder Smrnmi CPU fields above CPU reset line alistair23
                   ` (27 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Abhigyan Kumar, Alistair Francis,
	Daniel Henrique Barboza

From: Abhigyan Kumar <314abh@gmail.com>

Citing the RISC-V specification:

    "The vector fixed-point rounding-mode register holds a two-bit
    read-write rounding-mode field in the least-significant bits
    (vxrm[1:0]). The upper bits, vxrm[XLEN-1:2], should be written as
    zeros."

QEMU wrote full value into env->vxrm causing read of upper bits too.
Used existing macros for bit-masking. Previous had a hard-coded value.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3470
Signed-off-by: Abhigyan Kumar <314abh@gmail.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260530102100.78150-1-314abh@gmail.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/csr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 19d5a55b54..ec931a8c3d 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -989,7 +989,7 @@ static RISCVException write_vxrm(CPURISCVState *env, int csrno,
 #if !defined(CONFIG_USER_ONLY)
     env->mstatus |= MSTATUS_VS;
 #endif
-    env->vxrm = val;
+    env->vxrm = val & (VCSR_VXRM >> VCSR_VXRM_SHIFT);
     return RISCV_EXCP_NONE;
 }
 
-- 
2.54.0



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

* [PULL 58/83] target/riscv: Reorder Smrnmi CPU fields above CPU reset line
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (56 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 57/83] target/riscv: mask vxrm csrw write to the low 2 bits alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 59/83] hw/riscv/numa.c: Supplement cpu topology arguments alistair23
                   ` (26 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Frank Chang, Alistair Francis

From: Frank Chang <frank.chang@sifive.com>

Smrnmi CPU fields introduced by commit: #5db557f should be reset when
the CPU resets, so move these fields above the CPU reset line.

Fixes: 5db557f82bff ("target/riscv: Add Smrnmi CSRs")
Signed-off-by: Frank Chang <frank.chang@sifive.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260528060007.717307-1-frank.chang@sifive.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index febd905389..eec5acea5f 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -491,6 +491,15 @@ struct CPUArchState {
     uint64_t hstateen[SMSTATEEN_MAX_COUNT];
     uint64_t sstateen[SMSTATEEN_MAX_COUNT];
     uint64_t henvcfg;
+
+    /* RNMI */
+    uint64_t mnscratch;
+    uint64_t mnepc;
+    uint64_t mncause; /* mncause without bit XLEN-1 set to 1 */
+    uint64_t mnstatus;
+    uint64_t rnmip;
+    uint64_t rnmi_irqvec;
+    uint64_t rnmi_excpvec;
 #endif
 
     /* Fields from here on are preserved across CPU reset. */
@@ -509,15 +518,6 @@ struct CPUArchState {
     uint64_t kvm_timer_state;
     uint64_t kvm_timer_frequency;
 #endif /* CONFIG_KVM */
-
-    /* RNMI */
-    uint64_t mnscratch;
-    uint64_t mnepc;
-    uint64_t mncause; /* mncause without bit XLEN-1 set to 1 */
-    uint64_t mnstatus;
-    uint64_t rnmip;
-    uint64_t rnmi_irqvec;
-    uint64_t rnmi_excpvec;
 };
 
 /*
-- 
2.54.0



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

* [PULL 59/83] hw/riscv/numa.c: Supplement cpu topology arguments
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (57 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 58/83] target/riscv: Reorder Smrnmi CPU fields above CPU reset line alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 60/83] hw/riscv: Don't insert DDT cache in Bare mode alistair23
                   ` (25 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Xuemei Liu, Daniel Henrique Barboza, Alistair Francis

From: Xuemei Liu <liu.xuemei1@zte.com.cn>

Supplement RISC-V cpu topology arguments, including support socket
cluster and threads per core.

Signed-off-by: Xuemei Liu <liu.xuemei1@zte.com.cn>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260529181848378wiq8pXCmbwAZR5_-wZFJd@zte.com.cn>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/numa.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/numa.c b/hw/riscv/numa.c
index 24a803f7fa..8a144925c1 100644
--- a/hw/riscv/numa.c
+++ b/hw/riscv/numa.c
@@ -239,8 +239,18 @@ const CPUArchIdList *riscv_numa_possible_cpu_arch_ids(MachineState *ms)
     for (n = 0; n < ms->possible_cpus->len; n++) {
         ms->possible_cpus->cpus[n].type = ms->cpu_type;
         ms->possible_cpus->cpus[n].arch_id = n;
+        ms->possible_cpus->cpus[n].props.has_socket_id = true;
+        ms->possible_cpus->cpus[n].props.socket_id =
+            n / (ms->smp.clusters * ms->smp.cores * ms->smp.threads);
+        ms->possible_cpus->cpus[n].props.has_cluster_id = true;
+        ms->possible_cpus->cpus[n].props.cluster_id =
+            (n / (ms->smp.cores * ms->smp.threads)) % ms->smp.clusters;
         ms->possible_cpus->cpus[n].props.has_core_id = true;
-        ms->possible_cpus->cpus[n].props.core_id = n;
+        ms->possible_cpus->cpus[n].props.core_id =
+            (n / ms->smp.threads) % ms->smp.cores;
+        ms->possible_cpus->cpus[n].props.has_thread_id = true;
+        ms->possible_cpus->cpus[n].props.thread_id =
+            n % ms->smp.threads;
     }
 
     return ms->possible_cpus;
-- 
2.54.0



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

* [PULL 60/83] hw/riscv: Don't insert DDT cache in Bare mode
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (58 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 59/83] hw/riscv/numa.c: Supplement cpu topology arguments alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 61/83] hw/riscv: Refactor riscv_iommu_ctx_put() for Bare mode handling alistair23
                   ` (24 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Jay Chang, Frank Chang, Daniel Henrique Barboza,
	Nutty Liu, Alistair Francis

From: Jay Chang <jay.chang@sifive.com>

In Bare mode the IOMMU does not perform DDT look-ups, therefore
caching DDT entries is unnecessary.

Signed-off-by: Jay Chang <jay.chang@sifive.com>
Reviewed-by: Frank Chang <frank.chang@sifive.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Message-ID: <20260518072239.16293-2-jay.chang@sifive.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/riscv-iommu.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 1b8a8e9ef2..5b28b1ad63 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -1358,16 +1358,23 @@ static RISCVIOMMUContext *riscv_iommu_ctx(RISCVIOMMUState *s,
 
     int fault = riscv_iommu_ctx_fetch(s, ctx);
     if (!fault) {
-        if (g_hash_table_size(ctx_cache) >= LIMIT_CACHE_CTX) {
+        if (mode != RISCV_IOMMU_DDTP_MODE_BARE) {
+            if (g_hash_table_size(ctx_cache) >= LIMIT_CACHE_CTX) {
+                g_hash_table_unref(ctx_cache);
+                ctx_cache = g_hash_table_new_full(riscv_iommu_ctx_hash,
+                                                  riscv_iommu_ctx_equal,
+                                                  g_free, NULL);
+                g_hash_table_ref(ctx_cache);
+                g_hash_table_unref(qatomic_xchg(&s->ctx_cache, ctx_cache));
+            }
+
+            g_hash_table_add(ctx_cache, ctx);
+            *ref = ctx_cache;
+        } else {
             g_hash_table_unref(ctx_cache);
-            ctx_cache = g_hash_table_new_full(riscv_iommu_ctx_hash,
-                                              riscv_iommu_ctx_equal,
-                                              g_free, NULL);
-            g_hash_table_ref(ctx_cache);
-            g_hash_table_unref(qatomic_xchg(&s->ctx_cache, ctx_cache));
+            /* Remember ctx so it can be freed */
+            *ref = ctx;
         }
-        g_hash_table_add(ctx_cache, ctx);
-        *ref = ctx_cache;
         return ctx;
     }
 
-- 
2.54.0



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

* [PULL 61/83] hw/riscv: Refactor riscv_iommu_ctx_put() for Bare mode handling
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (59 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 60/83] hw/riscv: Don't insert DDT cache in Bare mode alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 62/83] hw/riscv/virt.c: fix 'iommu-map' FDT entry alistair23
                   ` (23 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Jay Chang, Frank Chang, Daniel Henrique Barboza,
	Nutty Liu, Alistair Francis

From: Jay Chang <jay.chang@sifive.com>

Align SPEC: Bare mode contexts are not cached, so they require
direct memory deallocation via g_free instead of hash table cleanup.

Signed-off-by: Jay Chang <jay.chang@sifive.com>
Reviewed-by: Frank Chang <frank.chang@sifive.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Message-ID: <20260518072239.16293-3-jay.chang@sifive.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/riscv-iommu.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 5b28b1ad63..a500cb8440 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -1390,7 +1390,16 @@ static RISCVIOMMUContext *riscv_iommu_ctx(RISCVIOMMUState *s,
 
 static void riscv_iommu_ctx_put(RISCVIOMMUState *s, void *ref)
 {
-    if (ref) {
+    unsigned mode = get_field(s->ddtp, RISCV_IOMMU_DDTP_MODE);
+
+    if (!ref) {
+        return;
+    }
+
+    /* ref is pointing to ctx in Bare mode. Bare mode ctx is not cached */
+    if (mode == RISCV_IOMMU_DDTP_MODE_BARE) {
+        g_free(ref);
+    } else {
         g_hash_table_unref((GHashTable *)ref);
     }
 }
-- 
2.54.0



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

* [PULL 62/83] hw/riscv/virt.c: fix 'iommu-map' FDT entry
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (60 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 61/83] hw/riscv: Refactor riscv_iommu_ctx_put() for Bare mode handling alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 63/83] target/riscv: Set mstatus.FS dirty when scalar FP raises exceptions alistair23
                   ` (22 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

Based on the DT documentation of 'iommu-map':

https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/pci-iommu.txt

- iommu-map: Maps a Requester ID to an IOMMU and associated IOMMU specifier
  data.

  The property is an arbitrary number of tuples of
  (rid-base,iommu,iommu-base,length).

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
----------

We're adding a no-op entry (length = 0) in iommu-map:

         qemu_fdt_setprop_cells(ms->fdt, name, "iommu-map",
                                0, iommu_sys_phandle, 0, 0, 0,
                                iommu_sys_phandle, 0, 0xffff);

This is easily seen in the generated DT:

iommu-map = <0x00 0x8000 0x00 0x00 0x00 0x8000 0x00 0xffff>;

The tuple (0 0 0x8000 0) does nothing since it has length = 0.  The
information we want to advertise is in the second tuple only.  Thus
remove the empty tuple.

While we're at it, seems like we've mistaken the API and we're using
0xffff as 'last address', but in fact it is length.  This means that
we're telling the DT we're mapping 0x0 -> 0xfffe, which wasn't our
intention.  Therefore change size to '0x10000' to reflect the address
mapping we want (0x0 -> 0xffff).

Found while reviewing the RISC-V Server Platform DT generation, which
happens to copy a lot of code from the 'virt' board, and this nit is
also present there.

Fixes: 2c12de1460 ("hw/riscv/virt: Add IOMMU as platform device if the option is set")
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260608210642.464131-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/virt.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index ce64eaaef7..0c489bb412 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -900,8 +900,7 @@ static void create_fdt_pcie(RISCVVirtState *s,
 
     if (virt_is_iommu_sys_enabled(s)) {
         qemu_fdt_setprop_cells(ms->fdt, name, "iommu-map",
-                               0, iommu_sys_phandle, 0, 0, 0,
-                               iommu_sys_phandle, 0, 0xffff);
+                               0, iommu_sys_phandle, 0, 0x10000);
     }
 
     create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle);
-- 
2.54.0



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

* [PULL 63/83] target/riscv: Set mstatus.FS dirty when scalar FP raises exceptions
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (61 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 62/83] hw/riscv/virt.c: fix 'iommu-map' FDT entry alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 64/83] target/riscv: rvv: Set mstatus.FS dirty when vector " alistair23
                   ` (21 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Max Chou, Alistair Francis

From: Max Chou <max.chou@sifive.com>

According to the RISC-V privileged spec 3.1.6, any instruction that
modifies FP extension state (FP CSRs including fflags, or f registers)
must set mstatus.FS to Dirty.  Raising fflags bits is modifying fcsr
(an FP CSR).

Scalar FP instructions that write integer registers (FP comparisons and
FP-to-integer conversions) never call mark_fs_dirty at translation time
to set mstatus.FS to dirty.  However, they can raise FP exception flags
via softfloat functions, which modifies fflags without any mechanism to
dirty mstatus.FS.

The affected helpers:
- Comparisons: fle/fleq/flt/fltq/feq
  — raise NV on NaN operands
- FP-to-integer: fcvt.[w|wu|l|lu]/fcvtmod.w.d
  — raise NX on inexact or NV on out-of-range

Fix this issue by
1. Save float_exception_flags before the softfloat operation
2. Perform the operation
3. If any new exception bits are set, set fs to dirty

Signed-off-by: Max Chou <max.chou@sifive.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260611105037.157773-2-max.chou@sifive.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        |   1 +
 target/riscv/fpu_helper.c | 157 +++++++++++++++++++++++++++++++-------
 2 files changed, 130 insertions(+), 28 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index eec5acea5f..7582874c35 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -676,6 +676,7 @@ G_NORETURN void riscv_raise_exception(CPURISCVState *env,
 
 uint8_t riscv_cpu_get_fflags(CPURISCVState *env);
 void riscv_cpu_set_fflags(CPURISCVState *env, uint8_t);
+void riscv_cpu_check_fflags(CPURISCVState *env, FloatExceptionFlags);
 
 #ifndef CONFIG_USER_ONLY
 void cpu_set_exception_base(int vp_index, uint64_t address);
diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c
index e6d1ffb1d6..db1475271b 100644
--- a/target/riscv/fpu_helper.c
+++ b/target/riscv/fpu_helper.c
@@ -50,6 +50,22 @@ void riscv_cpu_set_fflags(CPURISCVState *env, uint8_t hard)
     set_float_exception_flags(soft, &env->fp_status);
 }
 
+#ifndef CONFIG_USER_ONLY
+void riscv_cpu_check_fflags(CPURISCVState *env,
+                            FloatExceptionFlags pre_fflag)
+{
+    if (get_float_exception_flags(&env->fp_status) & ~pre_fflag) {
+        env->mstatus |= MSTATUS_FS;
+        if (env->virt_enabled) {
+            env->mstatus_hs |= MSTATUS_FS;
+        }
+    }
+}
+#else
+void riscv_cpu_check_fflags(CPURISCVState *env,
+                            FloatExceptionFlags pre_fflag) {}
+#endif
+
 void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm)
 {
     FloatRoundMode softrm;
@@ -286,59 +302,86 @@ target_ulong helper_fle_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 {
     float32 frs1 = check_nanbox_s(env, rs1);
     float32 frs2 = check_nanbox_s(env, rs2);
-    return float32_le(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float32_le(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fleq_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 {
     float32 frs1 = check_nanbox_s(env, rs1);
     float32 frs2 = check_nanbox_s(env, rs2);
-    return float32_le_quiet(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float32_le_quiet(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_flt_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 {
     float32 frs1 = check_nanbox_s(env, rs1);
     float32 frs2 = check_nanbox_s(env, rs2);
-    return float32_lt(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float32_lt(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fltq_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 {
     float32 frs1 = check_nanbox_s(env, rs1);
     float32 frs2 = check_nanbox_s(env, rs2);
-    return float32_lt_quiet(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float32_lt_quiet(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_feq_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 {
     float32 frs1 = check_nanbox_s(env, rs1);
     float32 frs2 = check_nanbox_s(env, rs2);
-    return float32_eq_quiet(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float32_eq_quiet(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t rs1)
 {
     float32 frs1 = check_nanbox_s(env, rs1);
-    return float32_to_int32(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float32_to_int32(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t rs1)
 {
     float32 frs1 = check_nanbox_s(env, rs1);
-    return (int32_t)float32_to_uint32(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = (int32_t)float32_to_uint32(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1)
 {
     float32 frs1 = check_nanbox_s(env, rs1);
-    return float32_to_int64(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float32_to_int64(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1)
 {
     float32 frs1 = check_nanbox_s(env, rs1);
-    return float32_to_uint64(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float32_to_uint64(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1)
@@ -453,52 +496,83 @@ uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1)
 
 target_ulong helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 {
-    return float64_le(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float64_le(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fleq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 {
-    return float64_le_quiet(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float64_le_quiet(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 {
-    return float64_lt(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float64_lt(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fltq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 {
-    return float64_lt_quiet(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float64_lt_quiet(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_feq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
 {
-    return float64_eq_quiet(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float64_eq_quiet(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1)
 {
-    return float64_to_int32(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float64_to_int32(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 uint64_t helper_fcvtmod_w_d(CPURISCVState *env, uint64_t value)
 {
-    return float64_to_int32_modulo(value, float_round_to_zero, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    uint64_t ret = float64_to_int32_modulo(value, float_round_to_zero,
+                                           &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1)
 {
-    return (int32_t)float64_to_uint32(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = (int32_t)float64_to_uint32(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1)
 {
-    return float64_to_int64(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float64_to_int64(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1)
 {
-    return float64_to_uint64(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float64_to_uint64(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 uint64_t helper_fcvt_d_w(CPURISCVState *env, target_ulong rs1)
@@ -619,35 +693,50 @@ target_ulong helper_fle_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 {
     float16 frs1 = check_nanbox_h(env, rs1);
     float16 frs2 = check_nanbox_h(env, rs2);
-    return float16_le(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float16_le(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fleq_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 {
     float16 frs1 = check_nanbox_h(env, rs1);
     float16 frs2 = check_nanbox_h(env, rs2);
-    return float16_le_quiet(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float16_le_quiet(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_flt_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 {
     float16 frs1 = check_nanbox_h(env, rs1);
     float16 frs2 = check_nanbox_h(env, rs2);
-    return float16_lt(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float16_lt(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fltq_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 {
     float16 frs1 = check_nanbox_h(env, rs1);
     float16 frs2 = check_nanbox_h(env, rs2);
-    return float16_lt_quiet(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float16_lt_quiet(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_feq_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
 {
     float16 frs1 = check_nanbox_h(env, rs1);
     float16 frs2 = check_nanbox_h(env, rs2);
-    return float16_eq_quiet(frs1, frs2, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float16_eq_quiet(frs1, frs2, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fclass_h(CPURISCVState *env, uint64_t rs1)
@@ -683,25 +772,37 @@ uint64_t helper_froundnx_h(CPURISCVState *env, uint64_t rs1)
 target_ulong helper_fcvt_w_h(CPURISCVState *env, uint64_t rs1)
 {
     float16 frs1 = check_nanbox_h(env, rs1);
-    return float16_to_int32(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float16_to_int32(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_wu_h(CPURISCVState *env, uint64_t rs1)
 {
     float16 frs1 = check_nanbox_h(env, rs1);
-    return (int32_t)float16_to_uint32(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = (int32_t)float16_to_uint32(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_l_h(CPURISCVState *env, uint64_t rs1)
 {
     float16 frs1 = check_nanbox_h(env, rs1);
-    return float16_to_int64(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float16_to_int64(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 target_ulong helper_fcvt_lu_h(CPURISCVState *env, uint64_t rs1)
 {
     float16 frs1 = check_nanbox_h(env, rs1);
-    return float16_to_uint64(frs1, &env->fp_status);
+    FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
+    target_ulong ret = float16_to_uint64(frs1, &env->fp_status);
+    riscv_cpu_check_fflags(env, pre_fflag);
+    return ret;
 }
 
 uint64_t helper_fcvt_h_w(CPURISCVState *env, target_ulong rs1)
-- 
2.54.0



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

* [PULL 64/83] target/riscv: rvv: Set mstatus.FS dirty when vector FP raises exceptions
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (62 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 63/83] target/riscv: Set mstatus.FS dirty when scalar FP raises exceptions alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 65/83] disas/riscv: enable `mnret` disassembly alistair23
                   ` (20 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Max Chou, Alistair Francis

From: Max Chou <max.chou@sifive.com>

According to the RISC-V privileged spec 3.1.6, any instruction that
modifies FP extension state (FP CSRs including fflags, or f registers)
must set mstatus.FS to Dirty.  Raising fflags bits is modifying fcsr
(an FP CSR).

When a vector FP instruction raises a floating-point exception, it
modifies fflags (an FP CSR), but current implementation was not marking
mstatus.FS dirty in this case.

Fix the issue by snapshot fflags before the element loop and OR
MSTATUS_FS into env->mstatus if any new exception bits are set
afterwards.

Signed-off-by: Max Chou <max.chou@sifive.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260611105037.157773-3-max.chou@sifive.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/vector_helper.c | 241 +++++++++++++++++++----------------
 1 file changed, 128 insertions(+), 113 deletions(-)

diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
index 89012fccb3..e321ca2616 100644
--- a/target/riscv/vector_helper.c
+++ b/target/riscv/vector_helper.c
@@ -3172,34 +3172,36 @@ static void do_##NAME(void *vd, void *vs1, void *vs2, int i,   \
     *((TD *)vd + HD(i)) = OP(s2, s1, &env->fp_status);         \
 }
 
-#define GEN_VEXT_VV_ENV(NAME, ESZ)                        \
-void HELPER(NAME)(void *vd, void *v0, void *vs1,          \
-                  void *vs2, CPURISCVState *env,          \
-                  uint32_t desc)                          \
-{                                                         \
-    uint32_t vm = vext_vm(desc);                          \
-    uint32_t vl = env->vl;                                \
-    uint32_t total_elems =                                \
-        vext_get_total_elems(env, desc, ESZ);             \
-    uint32_t vta = vext_vta(desc);                        \
-    uint32_t vma = vext_vma(desc);                        \
-    uint32_t i;                                           \
-                                                          \
-    VSTART_CHECK_EARLY_EXIT(env, vl);                     \
-                                                          \
-    for (i = env->vstart; i < vl; i++) {                  \
-        if (!vm && !vext_elem_mask(v0, i)) {              \
-            /* set masked-off elements to 1s */           \
-            vext_set_elems_1s(vd, vma, i * ESZ,           \
-                              (i + 1) * ESZ);             \
-            continue;                                     \
-        }                                                 \
-        do_##NAME(vd, vs1, vs2, i, env);                  \
-    }                                                     \
-    env->vstart = 0;                                      \
-    /* set tail elements to 1s */                         \
-    vext_set_elems_1s(vd, vta, vl * ESZ,                  \
-                      total_elems * ESZ);                 \
+#define GEN_VEXT_VV_ENV(NAME, ESZ)                           \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2,  \
+                  CPURISCVState *env, uint32_t desc)         \
+{                                                            \
+    uint32_t vm = vext_vm(desc);                             \
+    uint32_t vl = env->vl;                                   \
+    uint32_t total_elems =                                   \
+        vext_get_total_elems(env, desc, ESZ);                \
+    uint32_t vta = vext_vta(desc);                           \
+    uint32_t vma = vext_vma(desc);                           \
+    uint32_t i;                                              \
+    FloatExceptionFlags pre_fflag =                          \
+        get_float_exception_flags(&env->fp_status);          \
+                                                             \
+    VSTART_CHECK_EARLY_EXIT(env, vl);                        \
+                                                             \
+    for (i = env->vstart; i < vl; i++) {                     \
+        if (!vm && !vext_elem_mask(v0, i)) {                 \
+            /* set masked-off elements to 1s */              \
+            vext_set_elems_1s(vd, vma, i * ESZ,              \
+                              (i + 1) * ESZ);                \
+            continue;                                        \
+        }                                                    \
+        do_##NAME(vd, vs1, vs2, i, env);                     \
+    }                                                        \
+    env->vstart = 0;                                         \
+    /* set tail elements to 1s */                            \
+    vext_set_elems_1s(vd, vta, vl * ESZ,                     \
+                      total_elems * ESZ);                    \
+    riscv_cpu_check_fflags(env, pre_fflag);                  \
 }
 
 RVVCALL(OPFVV2, vfadd_vv_h_bf16, OP_UUU_H, H2, H2, H2, bfloat16_add)
@@ -3219,34 +3221,36 @@ static void do_##NAME(void *vd, uint64_t s1, void *vs2, int i, \
     *((TD *)vd + HD(i)) = OP(s2, (TX1)(T1)s1, &env->fp_status);\
 }
 
-#define GEN_VEXT_VF(NAME, ESZ)                            \
-void HELPER(NAME)(void *vd, void *v0, uint64_t s1,        \
-                  void *vs2, CPURISCVState *env,          \
-                  uint32_t desc)                          \
-{                                                         \
-    uint32_t vm = vext_vm(desc);                          \
-    uint32_t vl = env->vl;                                \
-    uint32_t total_elems =                                \
-        vext_get_total_elems(env, desc, ESZ);             \
-    uint32_t vta = vext_vta(desc);                        \
-    uint32_t vma = vext_vma(desc);                        \
-    uint32_t i;                                           \
-                                                          \
-    VSTART_CHECK_EARLY_EXIT(env, vl);                     \
-                                                          \
-    for (i = env->vstart; i < vl; i++) {                  \
-        if (!vm && !vext_elem_mask(v0, i)) {              \
-            /* set masked-off elements to 1s */           \
-            vext_set_elems_1s(vd, vma, i * ESZ,           \
-                              (i + 1) * ESZ);             \
-            continue;                                     \
-        }                                                 \
-        do_##NAME(vd, s1, vs2, i, env);                   \
-    }                                                     \
-    env->vstart = 0;                                      \
-    /* set tail elements to 1s */                         \
-    vext_set_elems_1s(vd, vta, vl * ESZ,                  \
-                      total_elems * ESZ);                 \
+#define GEN_VEXT_VF(NAME, ESZ)                                   \
+void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2,    \
+                  CPURISCVState *env, uint32_t desc)             \
+{                                                                \
+    uint32_t vm = vext_vm(desc);                                 \
+    uint32_t vl = env->vl;                                       \
+    uint32_t total_elems =                                       \
+        vext_get_total_elems(env, desc, ESZ);                    \
+    uint32_t vta = vext_vta(desc);                               \
+    uint32_t vma = vext_vma(desc);                               \
+    uint32_t i;                                                  \
+    FloatExceptionFlags pre_fflag =                              \
+        get_float_exception_flags(&env->fp_status);              \
+                                                                 \
+    VSTART_CHECK_EARLY_EXIT(env, vl);                            \
+                                                                 \
+    for (i = env->vstart; i < vl; i++) {                         \
+        if (!vm && !vext_elem_mask(v0, i)) {                     \
+            /* set masked-off elements to 1s */                  \
+            vext_set_elems_1s(vd, vma, i * ESZ,                  \
+                              (i + 1) * ESZ);                    \
+            continue;                                            \
+        }                                                        \
+        do_##NAME(vd, s1, vs2, i, env);                          \
+    }                                                            \
+    env->vstart = 0;                                             \
+    /* set tail elements to 1s */                                \
+    vext_set_elems_1s(vd, vta, vl * ESZ,                         \
+                      total_elems * ESZ);                        \
+    riscv_cpu_check_fflags(env, pre_fflag);                      \
 }
 
 RVVCALL(OPFVF2, vfadd_vf_h_bf16, OP_UUU_H, H2, H2, bfloat16_add)
@@ -3993,35 +3997,38 @@ static void do_##NAME(void *vd, void *vs2, int i,      \
     *((TD *)vd + HD(i)) = OP(s2, &env->fp_status);     \
 }
 
-#define GEN_VEXT_V_ENV(NAME, ESZ)                      \
-void HELPER(NAME)(void *vd, void *v0, void *vs2,       \
-                  CPURISCVState *env, uint32_t desc)   \
-{                                                      \
-    uint32_t vm = vext_vm(desc);                       \
-    uint32_t vl = env->vl;                             \
-    uint32_t total_elems =                             \
-        vext_get_total_elems(env, desc, ESZ);          \
-    uint32_t vta = vext_vta(desc);                     \
-    uint32_t vma = vext_vma(desc);                     \
-    uint32_t i;                                        \
-                                                       \
-    VSTART_CHECK_EARLY_EXIT(env, vl);                  \
-                                                       \
-    if (vl == 0) {                                     \
-        return;                                        \
-    }                                                  \
-    for (i = env->vstart; i < vl; i++) {               \
-        if (!vm && !vext_elem_mask(v0, i)) {           \
-            /* set masked-off elements to 1s */        \
-            vext_set_elems_1s(vd, vma, i * ESZ,        \
-                              (i + 1) * ESZ);          \
-            continue;                                  \
-        }                                              \
-        do_##NAME(vd, vs2, i, env);                    \
-    }                                                  \
-    env->vstart = 0;                                   \
-    vext_set_elems_1s(vd, vta, vl * ESZ,               \
-                      total_elems * ESZ);              \
+#define GEN_VEXT_V_ENV(NAME, ESZ)                            \
+void HELPER(NAME)(void *vd, void *v0, void *vs2,             \
+                  CPURISCVState *env, uint32_t desc)         \
+{                                                            \
+    uint32_t vm = vext_vm(desc);                             \
+    uint32_t vl = env->vl;                                   \
+    uint32_t total_elems =                                   \
+        vext_get_total_elems(env, desc, ESZ);                \
+    uint32_t vta = vext_vta(desc);                           \
+    uint32_t vma = vext_vma(desc);                           \
+    uint32_t i;                                              \
+    FloatExceptionFlags pre_fflag =                          \
+        get_float_exception_flags(&env->fp_status);          \
+                                                             \
+    VSTART_CHECK_EARLY_EXIT(env, vl);                        \
+                                                             \
+    if (vl == 0) {                                           \
+        return;                                              \
+    }                                                        \
+    for (i = env->vstart; i < vl; i++) {                     \
+        if (!vm && !vext_elem_mask(v0, i)) {                 \
+            /* set masked-off elements to 1s */              \
+            vext_set_elems_1s(vd, vma, i * ESZ,              \
+                              (i + 1) * ESZ);                \
+            continue;                                        \
+        }                                                    \
+        do_##NAME(vd, vs2, i, env);                          \
+    }                                                        \
+    env->vstart = 0;                                         \
+    vext_set_elems_1s(vd, vta, vl * ESZ,                     \
+                      total_elems * ESZ);                    \
+    riscv_cpu_check_fflags(env, pre_fflag);                  \
 }
 
 RVVCALL(OPFVV1, vfsqrt_v_h, OP_UU_H, H2, H2, float16_sqrt)
@@ -4610,6 +4617,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2,   \
     uint32_t vta_all_1s = vext_vta_all_1s(desc);              \
     uint32_t vma = vext_vma(desc);                            \
     uint32_t i;                                               \
+    FloatExceptionFlags pre_fflag =                           \
+        get_float_exception_flags(&env->fp_status);           \
                                                               \
     VSTART_CHECK_EARLY_EXIT(env, vl);                         \
                                                               \
@@ -4636,6 +4645,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2,   \
             vext_set_elem_mask(vd, i, 1);                     \
         }                                                     \
     }                                                         \
+    riscv_cpu_check_fflags(env, pre_fflag);                   \
 }
 
 GEN_VEXT_CMP_VV_ENV(vmfeq_vv_h_bf16, uint16_t, H2, bfloat16_eq_quiet)
@@ -4653,6 +4663,8 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2,       \
     uint32_t vta_all_1s = vext_vta_all_1s(desc);                    \
     uint32_t vma = vext_vma(desc);                                  \
     uint32_t i;                                                     \
+    FloatExceptionFlags pre_fflag =                                 \
+        get_float_exception_flags(&env->fp_status);                 \
                                                                     \
     VSTART_CHECK_EARLY_EXIT(env, vl);                               \
                                                                     \
@@ -4678,6 +4690,7 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2,       \
             vext_set_elem_mask(vd, i, 1);                           \
         }                                                           \
     }                                                               \
+    riscv_cpu_check_fflags(env, pre_fflag);                         \
 }
 
 GEN_VEXT_CMP_VF(vmfeq_vf_h_bf16, uint16_t, H2, bfloat16_eq_quiet)
@@ -5151,34 +5164,36 @@ GEN_VEXT_RED(vwredsumu_vs_h, uint32_t, uint16_t, H4, H2, DO_ADD)
 GEN_VEXT_RED(vwredsumu_vs_w, uint64_t, uint32_t, H8, H4, DO_ADD)
 
 /* Vector Single-Width Floating-Point Reduction Instructions */
-#define GEN_VEXT_FRED(NAME, TD, TS2, HD, HS2, OP)          \
-void HELPER(NAME)(void *vd, void *v0, void *vs1,           \
-                  void *vs2, CPURISCVState *env,           \
-                  uint32_t desc)                           \
-{                                                          \
-    uint32_t vm = vext_vm(desc);                           \
-    uint32_t vl = env->vl;                                 \
-    uint32_t esz = sizeof(TD);                             \
-    uint32_t vlenb = simd_maxsz(desc);                     \
-    uint32_t vta = vext_vta(desc);                         \
-    uint32_t i;                                            \
-    TD s1 =  *((TD *)vs1 + HD(0));                         \
-                                                           \
-    VSTART_CHECK_EARLY_EXIT(env, vl);                      \
-                                                           \
-    for (i = env->vstart; i < vl; i++) {                   \
-        TS2 s2 = *((TS2 *)vs2 + HS2(i));                   \
-        if (!vm && !vext_elem_mask(v0, i)) {               \
-            continue;                                      \
-        }                                                  \
-        s1 = OP(s1, (TD)s2, &env->fp_status);              \
-    }                                                      \
-    if (vl > 0) {                                          \
-        *((TD *)vd + HD(0)) = s1;                          \
-    }                                                      \
-    env->vstart = 0;                                       \
-    /* set tail elements to 1s */                          \
-    vext_set_elems_1s(vd, vta, esz, vlenb);                \
+#define GEN_VEXT_FRED(NAME, TD, TS2, HD, HS2, OP)            \
+void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2,  \
+                  CPURISCVState *env, uint32_t desc)         \
+{                                                            \
+    uint32_t vm = vext_vm(desc);                             \
+    uint32_t vl = env->vl;                                   \
+    uint32_t esz = sizeof(TD);                               \
+    uint32_t vlenb = simd_maxsz(desc);                       \
+    uint32_t vta = vext_vta(desc);                           \
+    uint32_t i;                                              \
+    FloatExceptionFlags pre_fflag =                          \
+        get_float_exception_flags(&env->fp_status);          \
+    TD s1 =  *((TD *)vs1 + HD(0));                           \
+                                                             \
+    VSTART_CHECK_EARLY_EXIT(env, vl);                        \
+                                                             \
+    for (i = env->vstart; i < vl; i++) {                     \
+        TS2 s2 = *((TS2 *)vs2 + HS2(i));                     \
+        if (!vm && !vext_elem_mask(v0, i)) {                 \
+            continue;                                        \
+        }                                                    \
+        s1 = OP(s1, (TD)s2, &env->fp_status);                \
+    }                                                        \
+    if (vl > 0) {                                            \
+        *((TD *)vd + HD(0)) = s1;                            \
+    }                                                        \
+    env->vstart = 0;                                         \
+    /* set tail elements to 1s */                            \
+    vext_set_elems_1s(vd, vta, esz, vlenb);                  \
+    riscv_cpu_check_fflags(env, pre_fflag);                  \
 }
 
 /* Unordered sum */
-- 
2.54.0



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

* [PULL 65/83] disas/riscv: enable `mnret` disassembly
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (63 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 64/83] target/riscv: rvv: Set mstatus.FS dirty when vector " alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 66/83] target/riscv: add thead-c908 cpu support alistair23
                   ` (19 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, imaginos, Alistair Francis

From: imaginos <imaginos32@gmail.com>

The translator has supported mnret since commit 3157a553ec6b9a
("target/riscv: Add Smrnmi mnret instruction"), but the
disassembler still renders it as illegal. Add it unguarded,
since the encoding does not overlap any other extension.

Signed-off-by: imaginos <imaginos32@gmail.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260614141315.17320-1-imaginos32@gmail.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 disas/riscv.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/disas/riscv.c b/disas/riscv.c
index b8ec546883..7f1b262773 100644
--- a/disas/riscv.c
+++ b/disas/riscv.c
@@ -989,6 +989,7 @@ typedef enum {
     rv_op_cbo_clean = 957,
     rv_op_cbo_flush = 958,
     rv_op_cbo_zero = 959,
+    rv_op_mnret = 960,
 } rv_op;
 
 /* register names */
@@ -2263,6 +2264,7 @@ const rv_opcode_data rvi_opcode_data[] = {
    { "cbo.clean", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
    { "cbo.flush", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
    { "cbo.zero", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
+   { "mnret", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
 };
 
 /* CSR names */
@@ -4077,6 +4079,11 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
                     case 64: op = rv_op_mret; break;
                     }
                     break;
+                case 1792:
+                    switch ((inst >> 15) & 0b1111111111) {
+                    case 64: op = rv_op_mnret; break;
+                    }
+                    break;
                 case 1952:
                     switch ((inst >> 15) & 0b1111111111) {
                     case 576: op = rv_op_dret; break;
-- 
2.54.0



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

* [PULL 66/83] target/riscv: add thead-c908 cpu support
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (64 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 65/83] disas/riscv: enable `mnret` disassembly alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 67/83] hw/riscv: add k230 board initial support alistair23
                   ` (18 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Chao Liu, Chao Liu, LIU Zhiwei,
	Daniel Henrique Barboza, Peng Jiang, Alistair Francis, Nutty Liu

From: Chao Liu <chao.liu@zevorn.cn>

The C908 processor is based on the RV64GCB[V] instruction
set, compatible to RVA22 Profile and implements the XIE
(XuanTie Instruction Extension) technology.

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Tested-by: Peng Jiang <3160104094@zju.edu.cn>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Message-ID: <a3e232ace12afd93adb60aed198cac3284daa56c.1781246408.git.chao.liu@processmission.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu-qom.h |   2 +
 target/riscv/cpu.c     |  51 ++++++
 target/riscv/th_csr.c  | 376 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 428 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
index 30dcdcfaae..1a28f1369c 100644
--- a/target/riscv/cpu-qom.h
+++ b/target/riscv/cpu-qom.h
@@ -52,6 +52,8 @@
 #define TYPE_RISCV_CPU_SIFIVE_U34       RISCV_CPU_TYPE_NAME("sifive-u34")
 #define TYPE_RISCV_CPU_SIFIVE_U54       RISCV_CPU_TYPE_NAME("sifive-u54")
 #define TYPE_RISCV_CPU_THEAD_C906       RISCV_CPU_TYPE_NAME("thead-c906")
+#define TYPE_RISCV_CPU_THEAD_C908       RISCV_CPU_TYPE_NAME("thead-c908")
+#define TYPE_RISCV_CPU_THEAD_C908V      RISCV_CPU_TYPE_NAME("thead-c908v")
 #define TYPE_RISCV_CPU_VEYRON_V1        RISCV_CPU_TYPE_NAME("veyron-v1")
 #define TYPE_RISCV_CPU_TT_ASCALON       RISCV_CPU_TYPE_NAME("tt-ascalon")
 #define TYPE_RISCV_CPU_XIANGSHAN_NANHU  RISCV_CPU_TYPE_NAME("xiangshan-nanhu")
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index a74384a091..fa497e5e8a 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -3121,6 +3121,57 @@ static const TypeInfo riscv_cpu_type_infos[] = {
 #endif
     ),
 
+    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908, TYPE_RISCV_VENDOR_CPU,
+        .misa_mxl_max = MXL_RV64,
+        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU,
+        .priv_spec = PRIV_VERSION_1_12_0,
+
+        /* ISA extensions */
+        .cfg.ext_xtheadba = true,
+        .cfg.ext_xtheadbb = true,
+        .cfg.ext_xtheadbs = true,
+        .cfg.ext_xtheadcmo = true,
+        .cfg.ext_xtheadcondmov = true,
+        .cfg.ext_xtheadfmv = true,
+        .cfg.ext_xtheadfmemidx = true,
+        .cfg.ext_xtheadmac = true,
+        .cfg.ext_xtheadmemidx = true,
+        .cfg.ext_xtheadmempair = true,
+        .cfg.ext_xtheadsync = true,
+        .cfg.ext_smepmp = true,
+        .cfg.ext_sscofpmf = true,
+        .cfg.ext_sstc = true,
+        .cfg.ext_svpbmt = true,
+        .cfg.ext_svinval = true,
+        .cfg.ext_svnapot = true,
+        .cfg.ext_zba = true,
+        .cfg.ext_zbb = true,
+        .cfg.ext_zbc = true,
+        .cfg.ext_zbs = true,
+        .cfg.ext_zkt = true,
+        .cfg.ext_zbkc = true,
+        .cfg.ext_zicsr = true,
+        .cfg.ext_zifencei = true,
+        .cfg.ext_zihintpause = true,
+        .cfg.ext_zicbom = true,
+        .cfg.ext_zicboz = true,
+
+        .cfg.pmp = true,
+        .cfg.mmu = true,
+        .cfg.max_satp_mode = VM_1_10_SV48,
+
+        .cfg.marchid = 0x8d143000,
+        .cfg.mvendorid = THEAD_VENDOR_ID,
+#ifndef CONFIG_USER_ONLY
+        .custom_csrs = th_csr_list,
+#endif
+    ),
+
+    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908V, TYPE_RISCV_CPU_THEAD_C908,
+        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU | RVV,
+        .vext_spec = VEXT_VERSION_1_00_0,
+    ),
+
     DEFINE_RISCV_CPU(TYPE_RISCV_CPU_TT_ASCALON, TYPE_RISCV_VENDOR_CPU,
         .misa_mxl_max = MXL_RV64,
         .misa_ext = RVG | RVC | RVS | RVU | RVH | RVV,
diff --git a/target/riscv/th_csr.c b/target/riscv/th_csr.c
index a4ea4ce391..431f4cc286 100644
--- a/target/riscv/th_csr.c
+++ b/target/riscv/th_csr.c
@@ -2,6 +2,9 @@
  * T-Head-specific CSRs.
  *
  * Copyright (c) 2024 VRULL GmbH
+ * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
+ *
+ * For more information, see XuanTie-C908-UserManual_xrvm_20240530.pdf
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -21,13 +24,84 @@
 #include "cpu_vendorid.h"
 #include "target/riscv/csr.h"
 
-#define CSR_TH_SXSTATUS 0x5c0
+/* Extended M-mode control registers of T-Head */
+#define CSR_TH_MXSTATUS        0x7c0
+#define CSR_TH_MHCR            0x7c1
+#define CSR_TH_MCOR            0x7c2
+#define CSR_TH_MCCR2           0x7c3
+#define CSR_TH_MHINT           0x7c5
+#define CSR_TH_MRVBR           0x7c7
+#define CSR_TH_MCOUNTERWEN     0x7c9
+#define CSR_TH_MCOUNTERINTEN   0x7ca
+#define CSR_TH_MCOUNTEROF      0x7cb
+#define CSR_TH_MCINS           0x7d2
+#define CSR_TH_MCINDEX         0x7d3
+#define CSR_TH_MCDATA0         0x7d4
+#define CSR_TH_MCDATA1         0x7d5
+#define CSR_TH_MSMPR           0x7f3
+#define CSR_TH_CPUID           0xfc0
+#define CSR_TH_MAPBADDR        0xfc1
+
+/* TH_MXSTATUS bits */
+#define TH_MXSTATUS_UCME        BIT(16)
+#define TH_MXSTATUS_MAEE        BIT(21)
+#define TH_MXSTATUS_THEADISAEE  BIT(22)
+
+/* Extended S-mode control registers of T-Head */
+#define CSR_TH_SXSTATUS        0x5c0
+#define CSR_TH_SHCR            0x5c1
+#define CSR_TH_SCER2           0x5c2
+#define CSR_TH_SCER            0x5c3
+#define CSR_TH_SCOUNTERINTEN   0x5c4
+#define CSR_TH_SCOUNTEROF      0x5c5
+#define CSR_TH_SCYCLE          0x5e0
+#define CSR_TH_SHPMCOUNTER3    0x5e3
+#define CSR_TH_SHPMCOUNTER4    0x5e4
+#define CSR_TH_SHPMCOUNTER5    0x5e5
+#define CSR_TH_SHPMCOUNTER6    0x5e6
+#define CSR_TH_SHPMCOUNTER7    0x5e7
+#define CSR_TH_SHPMCOUNTER8    0x5e8
+#define CSR_TH_SHPMCOUNTER9    0x5e9
+#define CSR_TH_SHPMCOUNTER10   0x5ea
+#define CSR_TH_SHPMCOUNTER11   0x5eb
+#define CSR_TH_SHPMCOUNTER12   0x5ec
+#define CSR_TH_SHPMCOUNTER13   0x5ed
+#define CSR_TH_SHPMCOUNTER14   0x5ee
+#define CSR_TH_SHPMCOUNTER15   0x5ef
+#define CSR_TH_SHPMCOUNTER16   0x5f0
+#define CSR_TH_SHPMCOUNTER17   0x5f1
+#define CSR_TH_SHPMCOUNTER18   0x5f2
+#define CSR_TH_SHPMCOUNTER19   0x5f3
+#define CSR_TH_SHPMCOUNTER20   0x5f4
+#define CSR_TH_SHPMCOUNTER21   0x5f5
+#define CSR_TH_SHPMCOUNTER22   0x5f6
+#define CSR_TH_SHPMCOUNTER23   0x5f7
+#define CSR_TH_SHPMCOUNTER24   0x5f8
+#define CSR_TH_SHPMCOUNTER25   0x5f9
+#define CSR_TH_SHPMCOUNTER26   0x5fa
+#define CSR_TH_SHPMCOUNTER27   0x5fb
+#define CSR_TH_SHPMCOUNTER28   0x5fc
+#define CSR_TH_SHPMCOUNTER29   0x5fd
+#define CSR_TH_SHPMCOUNTER30   0x5fe
+#define CSR_TH_SHPMCOUNTER31   0x5ff
+#define CSR_TH_SMIR            0x9c0
+#define CSR_TH_SMLO0           0x9c1
+#define CSR_TH_SMEH            0x9c2
+#define CSR_TH_SMCIR           0x9c3
+
+/* Extended U-mode control registers of T-Head */
+#define CSR_TH_FXCR            0x800
 
 /* TH_SXSTATUS bits */
 #define TH_SXSTATUS_UCME        BIT(16)
 #define TH_SXSTATUS_MAEE        BIT(21)
 #define TH_SXSTATUS_THEADISAEE  BIT(22)
 
+static RISCVException mmode(CPURISCVState *env, int csrno)
+{
+    return RISCV_EXCP_NONE;
+}
+
 static RISCVException smode(CPURISCVState *env, int csrno)
 {
     if (riscv_has_ext(env, RVS)) {
@@ -37,11 +111,31 @@ static RISCVException smode(CPURISCVState *env, int csrno)
     return RISCV_EXCP_ILLEGAL_INST;
 }
 
+static RISCVException any(CPURISCVState *env, int csrno)
+{
+    return RISCV_EXCP_NONE;
+}
+
 static bool test_thead_mvendorid(RISCVCPU *cpu)
 {
     return cpu->cfg.mvendorid == THEAD_VENDOR_ID;
 }
 
+static RISCVException read_th_mxstatus(CPURISCVState *env, int csrno,
+                                       target_ulong *val)
+{
+    /* We don't set MAEE here, because QEMU does not implement MAEE. */
+    *val = TH_MXSTATUS_UCME | TH_MXSTATUS_THEADISAEE;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_unimp_th_csr(CPURISCVState *env, int csrno,
+                                        target_ulong *val)
+{
+    *val = 0;
+    return RISCV_EXCP_NONE;
+}
+
 static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
                                        target_ulong *val)
 {
@@ -51,10 +145,290 @@ static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
 }
 
 const RISCVCSR th_csr_list[] = {
+    {
+        .csrno = CSR_TH_MXSTATUS,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mxstatus", mmode, read_th_mxstatus }
+    },
+    {
+        .csrno = CSR_TH_MHCR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mhcr", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcor", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCCR2,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mccr2", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MHINT,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mhint", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MRVBR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mrvbr", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOUNTERWEN,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcounterwen", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOUNTERINTEN,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcounterinten", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOUNTEROF,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcounterof", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCINS,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcins", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCINDEX,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcindex", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCDATA0,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcdata0", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCDATA1,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcdata1", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MSMPR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.msmpr", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_CPUID,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.cpuid", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MAPBADDR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mapbaddr", mmode, read_unimp_th_csr }
+    },
     {
         .csrno = CSR_TH_SXSTATUS,
         .insertion_test = test_thead_mvendorid,
         .csr_ops = { "th.sxstatus", smode, read_th_sxstatus }
     },
+    {
+        .csrno = CSR_TH_SHCR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shcr", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCER2,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scer2", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCER,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scer", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCOUNTERINTEN,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scounterinten", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCOUNTEROF,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scounterof", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCYCLE,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scycle", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER3,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter3", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER4,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter4", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER5,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter5", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER6,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter6", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER7,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter7", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER8,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter8", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER9,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter9", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER10,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter10", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER11,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter11", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER12,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter12", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER13,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter13", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER14,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter14", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER15,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter15", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER16,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter16", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER17,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter17", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER18,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter18", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER19,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter19", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER20,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter20", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER21,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter21", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER22,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter22", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER23,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter23", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER24,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter24", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER25,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter25", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER26,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter26", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER27,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter27", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER28,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter28", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER29,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter29", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER30,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter30", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER31,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter31", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMIR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smir", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMLO0,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smlo0", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMEH,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smeh", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMCIR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smcir", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_FXCR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.fxcr", any, read_unimp_th_csr }
+    },
     { }
 };
-- 
2.54.0



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

* [PULL 67/83] hw/riscv: add k230 board initial support
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (65 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 66/83] target/riscv: add thead-c908 cpu support alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 68/83] hw/watchdog: add k230 watchdog " alistair23
                   ` (17 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Chao Liu, Peng Jiang, Alistair Francis, Nutty Liu

From: Chao Liu <chao.liu.zevorn@gmail.com>

K230 Board compatible with Kendryte K230 SDK.

Preliminarily supports the C908 small core, which can run U-Boot and
Linux kernels compiled by the K230 SDK.

The K230 boot flow provides its device tree from firmware or software.
QEMU does not generate a K230 DTB; users can pass one with -dtb for
direct Linux boot, or rely on firmware/kernel built-in DTB for other
payloads.

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Tested-by: Peng Jiang <3160104094@zju.edu.cn>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Message-ID: <a161697a249b896e44e2748435f6c0caec12c9f4.1781246408.git.chao.liu@processmission.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 MAINTAINERS             |   7 +
 include/hw/riscv/k230.h | 145 ++++++++++++
 hw/riscv/k230.c         | 508 ++++++++++++++++++++++++++++++++++++++++
 hw/riscv/Kconfig        |  10 +
 hw/riscv/meson.build    |   2 +-
 5 files changed, 671 insertions(+), 1 deletion(-)
 create mode 100644 include/hw/riscv/k230.h
 create mode 100644 hw/riscv/k230.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 2b5b581e17..a21796ac6f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1786,6 +1786,13 @@ F: docs/system/riscv/xiangshan-kunminghu.rst
 F: hw/riscv/xiangshan_kmh.c
 F: include/hw/riscv/xiangshan_kmh.h
 
+K230 Machines
+M: Chao Liu <chao.liu.zevorn@gmail.com>
+L: qemu-riscv@nongnu.org
+S: Maintained
+F: hw/riscv/k230.c
+F: include/hw/riscv/k230.h
+
 RX Machines
 -----------
 rx-gdbsim
diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
new file mode 100644
index 0000000000..dcfde39096
--- /dev/null
+++ b/include/hw/riscv/k230.h
@@ -0,0 +1,145 @@
+/*
+ * QEMU RISC-V Virt Board Compatible with kendryte K230 SDK
+ *
+ * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the kendryte K230 SDK
+ *
+ * K230 Technical Reference Manual V0.3.1 (2024-11-18):
+ * https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ */
+#ifndef HW_K230_H
+#define HW_K230_H
+
+#include "hw/core/boards.h"
+#include "hw/riscv/riscv_hart.h"
+
+#define C908_CPU_HARTID   (0)
+
+#define TYPE_RISCV_K230_SOC "riscv.k230.soc"
+#define RISCV_K230_SOC(obj) \
+    OBJECT_CHECK(K230SoCState, (obj), TYPE_RISCV_K230_SOC)
+
+typedef struct K230SoCState {
+    /*< private >*/
+    DeviceState parent_obj;
+
+    /*< public >*/
+    RISCVHartArrayState c908_cpu; /* Small core */
+
+    MemoryRegion sram;
+    MemoryRegion bootrom;
+
+    DeviceState *c908_plic;
+} K230SoCState;
+
+#define TYPE_RISCV_K230_MACHINE MACHINE_TYPE_NAME("k230")
+#define RISCV_K230_MACHINE(obj) \
+    OBJECT_CHECK(K230MachineState, (obj), TYPE_RISCV_K230_MACHINE)
+
+typedef struct K230MachineState {
+    /*< private >*/
+    MachineState parent_obj;
+
+    /*< public >*/
+    K230SoCState soc;
+    Notifier machine_done;
+} K230MachineState;
+
+enum {
+    K230_DEV_DDRC,
+    K230_DEV_KPU_L2_CACHE,
+    K230_DEV_SRAM,
+    K230_DEV_KPU_CFG,
+    K230_DEV_FFT,
+    K230_DEV_AI_2D_ENGINE,
+    K230_DEV_GSDMA,
+    K230_DEV_DMA,
+    K230_DEV_DECOMP_GZIP,
+    K230_DEV_NON_AI_2D,
+    K230_DEV_ISP,
+    K230_DEV_DEWARP,
+    K230_DEV_RX_CSI,
+    K230_DEV_H264,
+    K230_DEV_2P5D,
+    K230_DEV_VO,
+    K230_DEV_VO_CFG,
+    K230_DEV_3D_ENGINE,
+    K230_DEV_PMU,
+    K230_DEV_RTC,
+    K230_DEV_CMU,
+    K230_DEV_RMU,
+    K230_DEV_BOOT,
+    K230_DEV_PWR,
+    K230_DEV_MAILBOX,
+    K230_DEV_IOMUX,
+    K230_DEV_TIMER,
+    K230_DEV_WDT0,
+    K230_DEV_WDT1,
+    K230_DEV_TS,
+    K230_DEV_HDI,
+    K230_DEV_STC,
+    K230_DEV_BOOTROM,
+    K230_DEV_SECURITY,
+    K230_DEV_UART0,
+    K230_DEV_UART1,
+    K230_DEV_UART2,
+    K230_DEV_UART3,
+    K230_DEV_UART4,
+    K230_DEV_I2C0,
+    K230_DEV_I2C1,
+    K230_DEV_I2C2,
+    K230_DEV_I2C3,
+    K230_DEV_I2C4,
+    K230_DEV_PWM,
+    K230_DEV_GPIO0,
+    K230_DEV_GPIO1,
+    K230_DEV_ADC,
+    K230_DEV_CODEC,
+    K230_DEV_I2S,
+    K230_DEV_USB0,
+    K230_DEV_USB1,
+    K230_DEV_SD0,
+    K230_DEV_SD1,
+    K230_DEV_QSPI0,
+    K230_DEV_QSPI1,
+    K230_DEV_SPI,
+    K230_DEV_HI_SYS_CFG,
+    K230_DEV_DDRC_CFG,
+    K230_DEV_FLASH,
+    K230_DEV_PLIC,
+    K230_DEV_CLINT,
+};
+
+enum {
+    /*
+     * K230 TRM v0.3.1 section 2.4 lists peripheral interrupt bits; SDK
+     * DTBs expose the corresponding PLIC IDs as bit + 16.
+     */
+    K230_UART0_IRQ  = 16,
+    K230_UART1_IRQ  = 17,
+    K230_UART2_IRQ  = 18,
+    K230_UART3_IRQ  = 19,
+    K230_UART4_IRQ  = 20,
+};
+
+#define K230_UART_COUNT 5
+
+/*
+ * Integrates with the interrupt controller (PLIC),
+ * which can process 208 interrupt external sources
+ */
+#define K230_PLIC_NUM_SOURCES 208
+#define K230_PLIC_NUM_PRIORITIES 7
+#define K230_PLIC_PRIORITY_BASE 0x00
+#define K230_PLIC_PENDING_BASE 0x1000
+#define K230_PLIC_ENABLE_BASE 0x2000
+#define K230_PLIC_ENABLE_STRIDE 0x80
+#define K230_PLIC_CONTEXT_BASE 0x200000
+#define K230_PLIC_CONTEXT_STRIDE 0x1000
+
+#endif
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
new file mode 100644
index 0000000000..26d1e20c99
--- /dev/null
+++ b/hw/riscv/k230.c
@@ -0,0 +1,508 @@
+/*
+ * QEMU RISC-V Virt Board Compatible with Kendryte K230 SDK
+ *
+ * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the Kendryte K230 SDK
+ *
+ * K230 Technical Reference Manual V0.3.1 (2024-11-18):
+ * https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ */
+
+#include "qemu/osdep.h"
+#include "cpu-qom.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "system/device_tree.h"
+#include "system/system.h"
+#include "system/memory.h"
+#include "target/riscv/cpu.h"
+#include "hw/core/loader.h"
+#include "hw/core/sysbus.h"
+#include "hw/riscv/k230.h"
+#include "hw/riscv/boot.h"
+#include "hw/riscv/machines-qom.h"
+#include "hw/intc/riscv_aclint.h"
+#include "hw/intc/sifive_plic.h"
+#include "hw/char/serial-mm.h"
+#include "hw/misc/unimp.h"
+
+/* Align K230_SDK k230_canmv_defconfig */
+#define K230_DIRECT_OPENSBI_ADDR 0x8000000
+#define K230_DIRECT_KERNEL_ADDR  0x8200000
+#define K230_DIRECT_DTB_ADDR     0xa000000
+
+static const MemMapEntry memmap[] = {
+    [K230_DEV_DDRC] =         { 0x00000000,  0x80000000 },
+    [K230_DEV_KPU_L2_CACHE] = { 0x80000000,  0x00200000 },
+    [K230_DEV_SRAM] =         { 0x80200000,  0x00200000 },
+    [K230_DEV_KPU_CFG] =      { 0x80400000,  0x00000800 },
+    [K230_DEV_FFT] =          { 0x80400800,  0x00000400 },
+    [K230_DEV_AI_2D_ENGINE] = { 0x80400C00,  0x00000800 },
+    [K230_DEV_GSDMA] =        { 0x80800000,  0x00004000 },
+    [K230_DEV_DMA] =          { 0x80804000,  0x00004000 },
+    [K230_DEV_DECOMP_GZIP] =  { 0x80808000,  0x00004000 },
+    [K230_DEV_NON_AI_2D] =    { 0x8080C000,  0x00004000 },
+    [K230_DEV_ISP] =          { 0x90000000,  0x00008000 },
+    [K230_DEV_DEWARP] =       { 0x90008000,  0x00001000 },
+    [K230_DEV_RX_CSI] =       { 0x90009000,  0x00002000 },
+    [K230_DEV_H264] =         { 0x90400000,  0x00010000 },
+    [K230_DEV_2P5D] =         { 0x90800000,  0x00040000 },
+    [K230_DEV_VO] =           { 0x90840000,  0x00010000 },
+    [K230_DEV_VO_CFG] =       { 0x90850000,  0x00001000 },
+    [K230_DEV_3D_ENGINE] =    { 0x90A00000,  0x00000800 },
+    [K230_DEV_PMU] =          { 0x91000000,  0x00000C00 },
+    [K230_DEV_RTC] =          { 0x91000C00,  0x00000400 },
+    [K230_DEV_CMU] =          { 0x91100000,  0x00001000 },
+    [K230_DEV_RMU] =          { 0x91101000,  0x00001000 },
+    [K230_DEV_BOOT] =         { 0x91102000,  0x00001000 },
+    [K230_DEV_PWR] =          { 0x91103000,  0x00001000 },
+    [K230_DEV_MAILBOX] =      { 0x91104000,  0x00001000 },
+    [K230_DEV_IOMUX] =        { 0x91105000,  0x00000800 },
+    [K230_DEV_TIMER] =        { 0x91105800,  0x00000800 },
+    [K230_DEV_WDT0] =         { 0x91106000,  0x00000800 },
+    [K230_DEV_WDT1] =         { 0x91106800,  0x00000800 },
+    [K230_DEV_TS] =           { 0x91107000,  0x00000800 },
+    [K230_DEV_HDI] =          { 0x91107800,  0x00000800 },
+    [K230_DEV_STC] =          { 0x91108000,  0x00000800 },
+    [K230_DEV_BOOTROM] =      { 0x91200000,  0x00010000 },
+    [K230_DEV_SECURITY] =     { 0x91210000,  0x00008000 },
+    [K230_DEV_UART0] =        { 0x91400000,  0x00001000 },
+    [K230_DEV_UART1] =        { 0x91401000,  0x00001000 },
+    [K230_DEV_UART2] =        { 0x91402000,  0x00001000 },
+    [K230_DEV_UART3] =        { 0x91403000,  0x00001000 },
+    [K230_DEV_UART4] =        { 0x91404000,  0x00001000 },
+    [K230_DEV_I2C0] =         { 0x91405000,  0x00001000 },
+    [K230_DEV_I2C1] =         { 0x91406000,  0x00001000 },
+    [K230_DEV_I2C2] =         { 0x91407000,  0x00001000 },
+    [K230_DEV_I2C3] =         { 0x91408000,  0x00001000 },
+    [K230_DEV_I2C4] =         { 0x91409000,  0x00001000 },
+    [K230_DEV_PWM] =          { 0x9140A000,  0x00001000 },
+    [K230_DEV_GPIO0] =        { 0x9140B000,  0x00001000 },
+    [K230_DEV_GPIO1] =        { 0x9140C000,  0x00001000 },
+    [K230_DEV_ADC] =          { 0x9140D000,  0x00001000 },
+    [K230_DEV_CODEC] =        { 0x9140E000,  0x00001000 },
+    [K230_DEV_I2S] =          { 0x9140F000,  0x00001000 },
+    [K230_DEV_USB0] =         { 0x91500000,  0x00010000 },
+    [K230_DEV_USB1] =         { 0x91540000,  0x00010000 },
+    [K230_DEV_SD0] =          { 0x91580000,  0x00001000 },
+    [K230_DEV_SD1] =          { 0x91581000,  0x00001000 },
+    [K230_DEV_QSPI0] =        { 0x91582000,  0x00001000 },
+    [K230_DEV_QSPI1] =        { 0x91583000,  0x00001000 },
+    [K230_DEV_SPI] =          { 0x91584000,  0x00001000 },
+    [K230_DEV_HI_SYS_CFG] =   { 0x91585000,  0x00000400 },
+    [K230_DEV_DDRC_CFG] =     { 0x98000000,  0x02000000 },
+    [K230_DEV_FLASH] =        { 0xC0000000,  0x08000000 },
+    [K230_DEV_PLIC] =         { 0xF00000000, 0x00400000 },
+    [K230_DEV_CLINT] =        { 0xF04000000, 0x00400000 },
+};
+
+static void k230_soc_init(Object *obj)
+{
+    K230SoCState *s = RISCV_K230_SOC(obj);
+    RISCVHartArrayState *cpu0 = &s->c908_cpu;
+
+    object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
+    qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
+    qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
+    qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
+                         memmap[K230_DEV_BOOTROM].base);
+}
+
+static DeviceState *k230_create_plic(int base_hartid, int hartid_count)
+{
+    g_autofree char *plic_hart_config = NULL;
+
+    /* Per-socket PLIC hart topology configuration string */
+    plic_hart_config = riscv_plic_hart_config_string(hartid_count);
+
+    /* Per-socket PLIC */
+    return sifive_plic_create(memmap[K230_DEV_PLIC].base,
+                              plic_hart_config, hartid_count, base_hartid,
+                              K230_PLIC_NUM_SOURCES,
+                              K230_PLIC_NUM_PRIORITIES,
+                              K230_PLIC_PRIORITY_BASE, K230_PLIC_PENDING_BASE,
+                              K230_PLIC_ENABLE_BASE, K230_PLIC_ENABLE_STRIDE,
+                              K230_PLIC_CONTEXT_BASE,
+                              K230_PLIC_CONTEXT_STRIDE,
+                              memmap[K230_DEV_PLIC].size);
+}
+
+static void k230_create_uart(MemoryRegion *sys_mem, DeviceState *plic,
+                             int index)
+{
+    int uart_dev = K230_DEV_UART0 + index;
+    g_autofree char *name = g_strdup_printf("uart%d", index);
+
+    /* Cover the non-16550 part of the SDK's 0x1000 UART window. */
+    create_unimplemented_device(name, memmap[uart_dev].base,
+                                memmap[uart_dev].size);
+
+    serial_mm_init(sys_mem, memmap[uart_dev].base, 2,
+                   qdev_get_gpio_in(plic, K230_UART0_IRQ + index),
+                   399193, serial_hd(index), DEVICE_LITTLE_ENDIAN);
+}
+
+static void k230_soc_realize(DeviceState *dev, Error **errp)
+{
+    K230SoCState *s = RISCV_K230_SOC(dev);
+    MemoryRegion *sys_mem = get_system_memory();
+    int c908_cpus;
+
+    sysbus_realize(SYS_BUS_DEVICE(&s->c908_cpu), &error_fatal);
+
+    c908_cpus = s->c908_cpu.num_harts;
+
+    /* SRAM */
+    memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
+                           memmap[K230_DEV_SRAM].size, &error_fatal);
+    memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
+                                &s->sram);
+
+    /* BootROM */
+    memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
+                           memmap[K230_DEV_BOOTROM].size, &error_fatal);
+    memory_region_add_subregion(sys_mem, memmap[K230_DEV_BOOTROM].base,
+                                &s->bootrom);
+
+    /* PLIC */
+    s->c908_plic = k230_create_plic(C908_CPU_HARTID, c908_cpus);
+
+    /* CLINT */
+    riscv_aclint_swi_create(memmap[K230_DEV_CLINT].base,
+                            C908_CPU_HARTID, c908_cpus, false);
+    riscv_aclint_mtimer_create(memmap[K230_DEV_CLINT].base + 0x4000,
+                               RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
+                               C908_CPU_HARTID, c908_cpus,
+                               RISCV_ACLINT_DEFAULT_MTIMECMP,
+                               RISCV_ACLINT_DEFAULT_MTIME,
+                               RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
+
+    /* UART */
+    for (int i = 0; i < K230_UART_COUNT; i++) {
+        k230_create_uart(sys_mem, DEVICE(s->c908_plic), i);
+    }
+
+    /* unimplemented devices */
+    create_unimplemented_device("kpu.l2-cache",
+                                memmap[K230_DEV_KPU_L2_CACHE].base,
+                                memmap[K230_DEV_KPU_L2_CACHE].size);
+
+    create_unimplemented_device("kpu_cfg", memmap[K230_DEV_KPU_CFG].base,
+                                memmap[K230_DEV_KPU_CFG].size);
+
+    create_unimplemented_device("fft", memmap[K230_DEV_FFT].base,
+                                memmap[K230_DEV_FFT].size);
+
+    create_unimplemented_device("2d-engine.ai",
+                                memmap[K230_DEV_AI_2D_ENGINE].base,
+                                memmap[K230_DEV_AI_2D_ENGINE].size);
+
+    create_unimplemented_device("gsdma", memmap[K230_DEV_GSDMA].base,
+                                memmap[K230_DEV_GSDMA].size);
+
+    create_unimplemented_device("dma", memmap[K230_DEV_DMA].base,
+                                memmap[K230_DEV_DMA].size);
+
+    create_unimplemented_device("decomp-gzip",
+                                memmap[K230_DEV_DECOMP_GZIP].base,
+                                memmap[K230_DEV_DECOMP_GZIP].size);
+
+    create_unimplemented_device("2d-engine.non-ai",
+                                memmap[K230_DEV_NON_AI_2D].base,
+                                memmap[K230_DEV_NON_AI_2D].size);
+
+    create_unimplemented_device("isp", memmap[K230_DEV_ISP].base,
+                                memmap[K230_DEV_ISP].size);
+
+    create_unimplemented_device("dewarp", memmap[K230_DEV_DEWARP].base,
+                                memmap[K230_DEV_DEWARP].size);
+
+    create_unimplemented_device("rx-csi", memmap[K230_DEV_RX_CSI].base,
+                                memmap[K230_DEV_RX_CSI].size);
+
+    create_unimplemented_device("vpu", memmap[K230_DEV_H264].base,
+                                memmap[K230_DEV_H264].size);
+
+    create_unimplemented_device("gpu", memmap[K230_DEV_2P5D].base,
+                                memmap[K230_DEV_2P5D].size);
+
+    create_unimplemented_device("vo", memmap[K230_DEV_VO].base,
+                                memmap[K230_DEV_VO].size);
+
+    create_unimplemented_device("vo_cfg", memmap[K230_DEV_VO_CFG].base,
+                                memmap[K230_DEV_VO_CFG].size);
+
+    create_unimplemented_device("3d-engine", memmap[K230_DEV_3D_ENGINE].base,
+                                memmap[K230_DEV_3D_ENGINE].size);
+
+    create_unimplemented_device("pmu", memmap[K230_DEV_PMU].base,
+                                memmap[K230_DEV_PMU].size);
+
+    create_unimplemented_device("rtc", memmap[K230_DEV_RTC].base,
+                                memmap[K230_DEV_RTC].size);
+
+    create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
+                                memmap[K230_DEV_CMU].size);
+
+    create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
+                                memmap[K230_DEV_RMU].size);
+
+    create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
+                                memmap[K230_DEV_BOOT].size);
+
+    create_unimplemented_device("pwr", memmap[K230_DEV_PWR].base,
+                                memmap[K230_DEV_PWR].size);
+
+    create_unimplemented_device("ipcm", memmap[K230_DEV_MAILBOX].base,
+                                memmap[K230_DEV_MAILBOX].size);
+
+    create_unimplemented_device("iomux", memmap[K230_DEV_IOMUX].base,
+                                memmap[K230_DEV_IOMUX].size);
+
+    create_unimplemented_device("timer", memmap[K230_DEV_TIMER].base,
+                                memmap[K230_DEV_TIMER].size);
+
+    create_unimplemented_device("wdt0", memmap[K230_DEV_WDT0].base,
+                                memmap[K230_DEV_WDT0].size);
+
+    create_unimplemented_device("wdt1", memmap[K230_DEV_WDT1].base,
+                                memmap[K230_DEV_WDT1].size);
+
+    create_unimplemented_device("ts", memmap[K230_DEV_TS].base,
+                                memmap[K230_DEV_TS].size);
+
+    create_unimplemented_device("hdi", memmap[K230_DEV_HDI].base,
+                                memmap[K230_DEV_HDI].size);
+
+    create_unimplemented_device("stc", memmap[K230_DEV_STC].base,
+                                memmap[K230_DEV_STC].size);
+
+    create_unimplemented_device("security", memmap[K230_DEV_SECURITY].base,
+                                memmap[K230_DEV_SECURITY].size);
+
+    create_unimplemented_device("i2c0", memmap[K230_DEV_I2C0].base,
+                                memmap[K230_DEV_I2C0].size);
+
+    create_unimplemented_device("i2c1", memmap[K230_DEV_I2C1].base,
+                                memmap[K230_DEV_I2C1].size);
+
+    create_unimplemented_device("i2c2", memmap[K230_DEV_I2C2].base,
+                                memmap[K230_DEV_I2C2].size);
+
+    create_unimplemented_device("i2c3", memmap[K230_DEV_I2C3].base,
+                                memmap[K230_DEV_I2C3].size);
+
+    create_unimplemented_device("i2c4", memmap[K230_DEV_I2C4].base,
+                                memmap[K230_DEV_I2C4].size);
+
+    create_unimplemented_device("pwm", memmap[K230_DEV_PWM].base,
+                                memmap[K230_DEV_PWM].size);
+
+    create_unimplemented_device("gpio0", memmap[K230_DEV_GPIO0].base,
+                                memmap[K230_DEV_GPIO0].size);
+
+    create_unimplemented_device("gpio1", memmap[K230_DEV_GPIO1].base,
+                                memmap[K230_DEV_GPIO1].size);
+
+    create_unimplemented_device("adc", memmap[K230_DEV_ADC].base,
+                                memmap[K230_DEV_ADC].size);
+
+    create_unimplemented_device("codec", memmap[K230_DEV_CODEC].base,
+                                memmap[K230_DEV_CODEC].size);
+
+    create_unimplemented_device("i2s", memmap[K230_DEV_I2S].base,
+                                memmap[K230_DEV_I2S].size);
+
+    create_unimplemented_device("usb0", memmap[K230_DEV_USB0].base,
+                                memmap[K230_DEV_USB0].size);
+
+    create_unimplemented_device("usb1", memmap[K230_DEV_USB1].base,
+                                memmap[K230_DEV_USB1].size);
+
+    create_unimplemented_device("sd0", memmap[K230_DEV_SD0].base,
+                                memmap[K230_DEV_SD0].size);
+
+    create_unimplemented_device("sd1", memmap[K230_DEV_SD1].base,
+                                memmap[K230_DEV_SD1].size);
+
+    create_unimplemented_device("qspi0", memmap[K230_DEV_QSPI0].base,
+                                memmap[K230_DEV_QSPI0].size);
+
+    create_unimplemented_device("qspi1", memmap[K230_DEV_QSPI1].base,
+                                memmap[K230_DEV_QSPI1].size);
+
+    create_unimplemented_device("spi", memmap[K230_DEV_SPI].base,
+                                memmap[K230_DEV_SPI].size);
+
+    create_unimplemented_device("hi_sys_cfg", memmap[K230_DEV_HI_SYS_CFG].base,
+                                memmap[K230_DEV_HI_SYS_CFG].size);
+
+    create_unimplemented_device("ddrc_cfg", memmap[K230_DEV_DDRC_CFG].base,
+                                memmap[K230_DEV_DDRC_CFG].size);
+
+    create_unimplemented_device("flash", memmap[K230_DEV_FLASH].base,
+                                memmap[K230_DEV_FLASH].size);
+}
+
+static void k230_soc_class_init(ObjectClass *oc, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = k230_soc_realize;
+}
+
+static const TypeInfo k230_soc_type_info = {
+    .name = TYPE_RISCV_K230_SOC,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(K230SoCState),
+    .instance_init = k230_soc_init,
+    .class_init = k230_soc_class_init,
+};
+
+static void k230_soc_register_types(void)
+{
+    type_register_static(&k230_soc_type_info);
+}
+
+type_init(k230_soc_register_types)
+
+static void k230_direct_boot(K230MachineState *s, MachineState *machine)
+{
+    const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
+    RISCVBootInfo boot_info = {0};
+    hwaddr start_addr = K230_DIRECT_OPENSBI_ADDR;
+    hwaddr firmware_end_addr = 0;
+    hwaddr kernel_entry = 0;
+    int fdt_size = 0;
+
+    if (machine->firmware && !strcmp(machine->firmware, "none")) {
+        error_report("K230 direct boot requires OpenSBI firmware; omit "
+                     "-bios none or pass OpenSBI with -bios");
+        exit(EXIT_FAILURE);
+    }
+
+    if (!machine->dtb) {
+        error_report("K230 direct boot requires -dtb");
+        exit(EXIT_FAILURE);
+    }
+
+    machine->fdt = load_device_tree(machine->dtb, &fdt_size);
+    if (!machine->fdt) {
+        error_report("load_device_tree() failed");
+        exit(EXIT_FAILURE);
+    }
+
+    qemu_fdt_add_path(machine->fdt, "/chosen");
+
+    riscv_boot_info_init(&boot_info, &s->soc.c908_cpu);
+    riscv_load_kernel(machine, &boot_info, K230_DIRECT_KERNEL_ADDR, true, NULL);
+    kernel_entry = boot_info.image_low_addr;
+
+    riscv_load_fdt(K230_DIRECT_DTB_ADDR, machine->fdt);
+
+    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
+                                                     &start_addr, NULL);
+    if (firmware_end_addr > K230_DIRECT_KERNEL_ADDR) {
+        error_report("K230 firmware overlaps kernel address 0x%x",
+                     K230_DIRECT_KERNEL_ADDR);
+        exit(EXIT_FAILURE);
+    }
+
+    riscv_setup_rom_reset_vec(machine, &s->soc.c908_cpu, start_addr,
+                              memmap[K230_DEV_BOOTROM].base,
+                              memmap[K230_DEV_BOOTROM].size, kernel_entry,
+                              K230_DIRECT_DTB_ADDR);
+}
+
+static void k230_firmware_boot(K230MachineState *s, MachineState *machine)
+{
+    const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
+    hwaddr start_addr = memmap[K230_DEV_DDRC].base;
+
+    if (machine->dtb || (machine->kernel_cmdline && *machine->kernel_cmdline)) {
+        error_report("K230 firmware boot does not support -dtb or -append");
+        exit(EXIT_FAILURE);
+    }
+
+    riscv_find_and_load_firmware(machine, firmware_name, &start_addr, NULL);
+
+    riscv_setup_rom_reset_vec(machine, &s->soc.c908_cpu, start_addr,
+                              memmap[K230_DEV_BOOTROM].base,
+                              memmap[K230_DEV_BOOTROM].size, 0, 0);
+}
+
+static void k230_machine_done(Notifier *notifier, void *data)
+{
+    K230MachineState *s = container_of(notifier, K230MachineState,
+                                       machine_done);
+    MachineState *machine = MACHINE(s);
+
+    if (machine->kernel_filename) {
+        k230_direct_boot(s, machine);
+    } else {
+        k230_firmware_boot(s, machine);
+    }
+}
+
+static void k230_machine_init(MachineState *machine)
+{
+    MachineClass *mc = MACHINE_GET_CLASS(machine);
+    K230MachineState *s = RISCV_K230_MACHINE(machine);
+    MemoryRegion *sys_mem = get_system_memory();
+
+    if (machine->ram_size < mc->default_ram_size) {
+        char *sz = size_to_str(mc->default_ram_size);
+        error_report("Invalid RAM size, should be %s", sz);
+        g_free(sz);
+        exit(EXIT_FAILURE);
+    }
+
+    /* Initialize SoC */
+    object_initialize_child(OBJECT(machine), "soc", &s->soc,
+                            TYPE_RISCV_K230_SOC);
+    qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
+
+    /* Data Memory */
+    memory_region_add_subregion(sys_mem, memmap[K230_DEV_DDRC].base,
+                                machine->ram);
+
+    s->machine_done.notify = k230_machine_done;
+    qemu_add_machine_init_done_notifier(&s->machine_done);
+}
+
+static void k230_machine_instance_init(Object *obj)
+{
+}
+
+static void k230_machine_class_init(ObjectClass *oc, const void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "RISC-V Board compatible with Kendryte K230 SDK";
+    mc->init = k230_machine_init;
+    mc->default_cpus = 1;
+    mc->default_ram_id = "riscv.K230.ram"; /* DDR */
+    mc->default_ram_size = memmap[K230_DEV_DDRC].size;
+}
+
+static const TypeInfo k230_machine_typeinfo = {
+    .name       = TYPE_RISCV_K230_MACHINE,
+    .parent     = TYPE_MACHINE,
+    .class_init = k230_machine_class_init,
+    .instance_init = k230_machine_instance_init,
+    .instance_size = sizeof(K230MachineState),
+    .interfaces = riscv64_machine_interfaces,
+};
+
+static void k230_machine_init_register_types(void)
+{
+    type_register_static(&k230_machine_typeinfo);
+}
+
+type_init(k230_machine_init_register_types)
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 2518b04175..f512ed65ac 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -138,3 +138,13 @@ config MIPS_BOSTON_AIA
     select RISCV_MIPS_CMGCR
     select RISCV_MIPS_CPC
     select RISCV_MIPS_CPS
+
+config K230
+    bool
+    default y
+    depends on RISCV64
+    select RISCV_ACLINT
+    select RISCV_APLIC
+    select RISCV_IMSIC
+    select SERIAL_MM
+    select UNIMP
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 533472e22a..09cf855984 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -14,8 +14,8 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
 	'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
 riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
 riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c'))
-
 riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c'))
 riscv_ss.add(when: 'CONFIG_MIPS_BOSTON_AIA', if_true: files('boston-aia.c'))
+riscv_ss.add(when: 'CONFIG_K230', if_true: files('k230.c'))
 
 hw_arch += {'riscv': riscv_ss}
-- 
2.54.0



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

* [PULL 68/83] hw/watchdog: add k230 watchdog initial support
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (66 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 67/83] hw/riscv: add k230 board initial support alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 69/83] tests/qtest: add test for K230 watchdog alistair23
                   ` (16 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Chao Liu, Mig Yang, Chao Liu, Daniel Henrique Barboza,
	Nutty Liu, Alistair Francis

From: Chao Liu <chao.liu@zevorn.cn>

Add programmable Watchdog Timer (WDT) peripheral for K230 machine.

Signed-off-by: Mig Yang <temashking@foxmail.com>
Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Message-ID: <805a04d9467556ee6a5f4742c9eb4bbb6fc7898c.1781246408.git.chao.liu@processmission.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 MAINTAINERS                    |   2 +
 include/hw/riscv/k230.h        |   4 +
 include/hw/watchdog/k230_wdt.h | 121 ++++++++++++++
 hw/riscv/k230.c                |  18 ++
 hw/watchdog/k230_wdt.c         | 296 +++++++++++++++++++++++++++++++++
 hw/riscv/Kconfig               |   1 +
 hw/watchdog/Kconfig            |   4 +
 hw/watchdog/meson.build        |   1 +
 hw/watchdog/trace-events       |   9 +
 9 files changed, 456 insertions(+)
 create mode 100644 include/hw/watchdog/k230_wdt.h
 create mode 100644 hw/watchdog/k230_wdt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a21796ac6f..06db33a107 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1791,7 +1791,9 @@ M: Chao Liu <chao.liu.zevorn@gmail.com>
 L: qemu-riscv@nongnu.org
 S: Maintained
 F: hw/riscv/k230.c
+F: hw/watchdog/k230_wdt.c
 F: include/hw/riscv/k230.h
+F: include/hw/watchdog/k230_wdt.h
 
 RX Machines
 -----------
diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
index dcfde39096..592e1c26bf 100644
--- a/include/hw/riscv/k230.h
+++ b/include/hw/riscv/k230.h
@@ -17,6 +17,7 @@
 
 #include "hw/core/boards.h"
 #include "hw/riscv/riscv_hart.h"
+#include "hw/watchdog/k230_wdt.h"
 
 #define C908_CPU_HARTID   (0)
 
@@ -31,6 +32,7 @@ typedef struct K230SoCState {
     /*< public >*/
     RISCVHartArrayState c908_cpu; /* Small core */
 
+    K230WdtState wdt[2];
     MemoryRegion sram;
     MemoryRegion bootrom;
 
@@ -125,6 +127,8 @@ enum {
     K230_UART2_IRQ  = 18,
     K230_UART3_IRQ  = 19,
     K230_UART4_IRQ  = 20,
+    K230_WDT0_IRQ   = 107,
+    K230_WDT1_IRQ   = 108,
 };
 
 #define K230_UART_COUNT 5
diff --git a/include/hw/watchdog/k230_wdt.h b/include/hw/watchdog/k230_wdt.h
new file mode 100644
index 0000000000..ba194abebe
--- /dev/null
+++ b/include/hw/watchdog/k230_wdt.h
@@ -0,0 +1,121 @@
+/*
+ * K230 Watchdog Timer
+ *
+ * K230 Technical Reference Manual V0.3.1 (2024-11-18):
+ * https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
+ * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef K230_WDT_H
+#define K230_WDT_H
+
+#include "qemu/bitops.h"
+#include "hw/core/sysbus.h"
+#include "hw/core/irq.h"
+#include "hw/core/ptimer.h"
+#include "qom/object.h"
+
+#define TYPE_K230_WDT "riscv.k230.wdt"
+OBJECT_DECLARE_SIMPLE_TYPE(K230WdtState, K230_WDT)
+
+#define K230_WDT_DEFAULT_FREQ (32768)
+
+/* K230 Watchdog Register Map */
+enum K230WdtRegisters {
+    K230_WDT_CR      = 0x00,  /* Control Register */
+    K230_WDT_TORR    = 0x04,  /* Timeout Range Register */
+    K230_WDT_CCVR    = 0x08,  /* Current Counter Value Register */
+    K230_WDT_CRR     = 0x0c,  /* Counter Restart Register */
+    K230_WDT_STAT    = 0x10,  /* Interrupt Status Register */
+    K230_WDT_EOI     = 0x14,  /* Interrupt Clear Register */
+    K230_WDT_PROT_LEVEL = 0x1c, /* Protection Level Register */
+    K230_WDT_COMP_PARAM_5 = 0xe4, /* Component Parameters Register 5 */
+    K230_WDT_COMP_PARAM_4 = 0xe8, /* Component Parameters Register 4 */
+    K230_WDT_COMP_PARAM_3 = 0xec, /* Component Parameters Register 3 */
+    K230_WDT_COMP_PARAM_2 = 0xf0, /* Component Parameters Register 2 */
+    K230_WDT_COMP_PARAM_1 = 0xf4, /* Component Parameters Register 1 */
+    K230_WDT_COMP_VERSION = 0xf8, /* Component Version Register */
+    K230_WDT_COMP_TYPE = 0xfc, /* Component Type Register */
+};
+
+#define K230_WDT_MMIO_SIZE 0x100
+
+/* Control Register (WDT_CR) definitions */
+#define K230_WDT_CR_RPL_MASK    0x7        /* Reset Pulse Length */
+#define K230_WDT_CR_RPL_SHIFT   2
+#define K230_WDT_CR_RMOD        BIT(1)     /* Response Mode */
+#define K230_WDT_CR_WDT_EN      BIT(0)     /* Watchdog Enable */
+
+/* Reset Pulse Length values */
+#define K230_WDT_RPL_2_CYCLES   0x0
+#define K230_WDT_RPL_4_CYCLES   0x1
+#define K230_WDT_RPL_8_CYCLES   0x2
+#define K230_WDT_RPL_16_CYCLES  0x3
+#define K230_WDT_RPL_32_CYCLES  0x4
+#define K230_WDT_RPL_64_CYCLES  0x5
+#define K230_WDT_RPL_128_CYCLES 0x6
+#define K230_WDT_RPL_256_CYCLES 0x7
+
+/* Timeout Range Register (WDT_TORR) definitions */
+#define K230_WDT_TORR_TOP_MASK  0xf        /* Timeout Period */
+
+/* Interrupt Status Register (WDT_STAT) definitions */
+#define K230_WDT_STAT_INT       BIT(0)     /* Interrupt Status */
+
+/* Counter Restart Register (WDT_CRR) magic value */
+#define K230_WDT_CRR_RESTART    0x76       /* Restart command */
+
+/* Component Parameters Register 1 (WDT_COMP_PARAM_1) definitions */
+#define K230_WDT_CNT_WIDTH_MASK 0x1f000000 /* Counter Width */
+#define K230_WDT_CNT_WIDTH_SHIFT 24
+#define K230_WDT_DFLT_TOP_INIT_MASK 0xf00000 /* Default Initial Timeout */
+#define K230_WDT_DFLT_TOP_INIT_SHIFT 20
+#define K230_WDT_DFLT_TOP_MASK  0xf0000    /* Default Timeout */
+#define K230_WDT_DFLT_TOP_SHIFT 16
+#define K230_WDT_DFLT_RPL_MASK  0x7        /* Default Reset Pulse Length */
+#define K230_WDT_DFLT_RPL_SHIFT 10
+#define K230_WDT_APB_DATA_WIDTH_MASK 0x3   /* APB Data Width */
+#define K230_WDT_APB_DATA_WIDTH_SHIFT 8
+#define K230_WDT_USE_FIX_TOP    BIT(6)     /* Use Fixed Timeout Values */
+#define K230_WDT_HC_TOP         BIT(5)     /* Hard-coded Timeout */
+#define K230_WDT_HC_RPL         BIT(4)     /* Hard-coded Reset Pulse Length */
+#define K230_WDT_HC_RMOD        BIT(3)     /* Hard-coded Response Mode */
+#define K230_WDT_DUAL_TOP       BIT(2)     /* Dual Timeout Period */
+#define K230_WDT_DFLT_RMOD      BIT(1)     /* Default Response Mode */
+#define K230_WDT_ALWAYS_EN      BIT(0)     /* Always Enabled */
+
+/* Component Type Register value */
+#define K230_WDT_COMP_TYPE_VAL  0x44570120
+
+/* Component Version Register value */
+#define K230_WDT_COMP_VERSION_VAL 0x3131302a  /* "110*" */
+
+struct K230WdtState {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion mmio;
+    qemu_irq irq;
+
+    struct ptimer_state *timer;
+
+    /* Register state */
+    uint32_t cr;           /* Control Register */
+    uint32_t torr;         /* Timeout Range Register */
+    uint32_t ccvr;         /* Current Counter Value Register */
+    uint32_t stat;         /* Interrupt Status Register */
+    uint32_t prot_level;   /* Protection Level Register */
+
+    /* Internal state */
+    bool interrupt_pending;
+    bool enabled;
+    uint32_t timeout_value;
+    uint32_t current_count;
+};
+
+#endif /* K230_WDT_H */
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
index 26d1e20c99..502281c52c 100644
--- a/hw/riscv/k230.c
+++ b/hw/riscv/k230.c
@@ -108,6 +108,9 @@ static void k230_soc_init(Object *obj)
     RISCVHartArrayState *cpu0 = &s->c908_cpu;
 
     object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
+    object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT);
+    object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT);
+
     qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
     qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
     qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
@@ -188,6 +191,21 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
         k230_create_uart(sys_mem, DEVICE(s->c908_plic), i);
     }
 
+    /* Watchdog */
+    for (int i = 0; i < 2; i++) {
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
+            return;
+        }
+    }
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[0]), 0, memmap[K230_DEV_WDT0].base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[0]), 0,
+                       qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT0_IRQ));
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[1]), 0, memmap[K230_DEV_WDT1].base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0,
+                       qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ));
+
     /* unimplemented devices */
     create_unimplemented_device("kpu.l2-cache",
                                 memmap[K230_DEV_KPU_L2_CACHE].base,
diff --git a/hw/watchdog/k230_wdt.c b/hw/watchdog/k230_wdt.c
new file mode 100644
index 0000000000..1f83b499e8
--- /dev/null
+++ b/hw/watchdog/k230_wdt.c
@@ -0,0 +1,296 @@
+/*
+ * K230 Watchdog Compatible with kendryte K230 SDK
+ *
+ * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
+ * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the kendryte K230 SDK
+ *
+ * K230 Technical Reference Manual V0.3.1 (2024-11-18):
+ * https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ */
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/module.h"
+#include "system/watchdog.h"
+#include "migration/vmstate.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/watchdog/k230_wdt.h"
+#include "trace.h"
+
+static void k230_wdt_timeout(void *opaque)
+{
+    K230WdtState *s = K230_WDT(opaque);
+
+    trace_k230_wdt_timeout();
+
+    /* Set interrupt status if in interrupt mode */
+    if (s->cr & K230_WDT_CR_RMOD) {
+        s->stat |= K230_WDT_STAT_INT;
+        s->interrupt_pending = true;
+        qemu_set_irq(s->irq, 1);
+        trace_k230_wdt_interrupt();
+    } else {
+        /* Direct reset mode */
+        trace_k230_wdt_reset();
+        watchdog_perform_action();
+    }
+
+    /* Restart counter */
+    s->current_count = s->timeout_value;
+    ptimer_set_count(s->timer, s->current_count);
+    ptimer_run(s->timer, 1);
+}
+
+static void k230_wdt_reset(DeviceState *dev)
+{
+    K230WdtState *s = K230_WDT(dev);
+
+    trace_k230_wdt_reset_device();
+
+    ptimer_transaction_begin(s->timer);
+    ptimer_stop(s->timer);
+    ptimer_transaction_commit(s->timer);
+
+    /* Reset registers to default values */
+    s->cr = 0;
+    s->torr = 0;
+    s->ccvr = 0xFFFFFFFF;
+    s->stat = 0;
+    s->prot_level = 0x2;
+
+    s->interrupt_pending = false;
+    s->enabled = false;
+    s->timeout_value = 0;
+    s->current_count = 0xFFFFFFFF;
+}
+
+static uint64_t k230_wdt_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    K230WdtState *s = K230_WDT(opaque);
+    uint32_t value = 0;
+
+    switch (addr) {
+    case K230_WDT_CR:
+        value = s->cr;
+        break;
+    case K230_WDT_TORR:
+        value = s->torr;
+        break;
+    case K230_WDT_CCVR:
+        if (s->enabled) {
+            value = ptimer_get_count(s->timer);
+        } else {
+            value = s->current_count;
+        }
+        break;
+    case K230_WDT_STAT:
+        value = s->stat;
+        break;
+    case K230_WDT_PROT_LEVEL:
+        value = s->prot_level;
+        break;
+    case K230_WDT_COMP_PARAM_5:
+        value = 0; /* Upper limit of Timeout Period parameters */
+        break;
+    case K230_WDT_COMP_PARAM_4:
+        value = 0; /* Upper limit of Initial Timeout Period parameters */
+        break;
+    case K230_WDT_COMP_PARAM_3:
+        value = 0; /* Derived from WDT_TOP_RST parameter */
+        break;
+    case K230_WDT_COMP_PARAM_2:
+        value = 0xFFFFFFFF; /* Derived from WDT_RST_CNT parameter */
+        break;
+    case K230_WDT_COMP_PARAM_1:
+        /* Component parameters */
+        value = (32 << K230_WDT_CNT_WIDTH_SHIFT) |  /* 32-bit counter */
+                (0 << K230_WDT_DFLT_TOP_INIT_SHIFT) |
+                (0 << K230_WDT_DFLT_TOP_SHIFT) |
+                (K230_WDT_RPL_16_CYCLES << K230_WDT_DFLT_RPL_SHIFT) |
+                (2 << K230_WDT_APB_DATA_WIDTH_SHIFT) | /* 32-bit APB */
+                K230_WDT_USE_FIX_TOP; /* Use fixed timeout values */
+        break;
+    case K230_WDT_COMP_VERSION:
+        value = K230_WDT_COMP_VERSION_VAL;
+        break;
+    case K230_WDT_COMP_TYPE:
+        value = K230_WDT_COMP_TYPE_VAL;
+        break;
+    default:
+        /* Other registers return 0 */
+        break;
+    }
+
+    trace_k230_wdt_read(addr, value);
+    return value;
+}
+
+static void k230_wdt_update_timer(K230WdtState *s)
+{
+    ptimer_transaction_begin(s->timer);
+
+    if (s->enabled && s->timeout_value > 0) {
+        ptimer_set_count(s->timer, s->current_count);
+        ptimer_run(s->timer, 1);
+    } else {
+        ptimer_stop(s->timer);
+    }
+
+    ptimer_transaction_commit(s->timer);
+}
+
+static uint32_t k230_wdt_calculate_timeout(uint32_t top_value)
+{
+    /* Calculate timeout based on TOP value */
+    /* For fixed timeout mode: 2^(16 + top_value) */
+    if (top_value <= 15) {
+        return 1 << (16 + top_value);
+    }
+    return 1 << 31; /* Maximum value for 32-bit counter */
+}
+
+static void k230_wdt_write(void *opaque, hwaddr addr,
+                           uint64_t value, unsigned int size)
+{
+    K230WdtState *s = K230_WDT(opaque);
+
+    trace_k230_wdt_write(addr, value);
+
+    switch (addr) {
+    case K230_WDT_CR:
+        s->cr = value & (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT |
+                         K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+
+        /* Update enabled state */
+        s->enabled = (s->cr & K230_WDT_CR_WDT_EN) != 0;
+
+        /* Update timer */
+        k230_wdt_update_timer(s);
+        break;
+
+    case K230_WDT_TORR:
+        s->torr = value & K230_WDT_TORR_TOP_MASK;
+
+        /* Calculate new timeout value */
+        s->timeout_value = k230_wdt_calculate_timeout(s->torr);
+        s->current_count = s->timeout_value;
+
+        /* Update timer if enabled */
+        if (s->enabled) {
+            k230_wdt_update_timer(s);
+        }
+        break;
+
+    case K230_WDT_CRR:
+        /* Restart counter with magic value 0x76 */
+        if ((value & 0xFF) == K230_WDT_CRR_RESTART) {
+            trace_k230_wdt_restart();
+            s->current_count = s->timeout_value;
+
+            /* Clear interrupt if pending */
+            if (s->interrupt_pending) {
+                s->stat &= ~K230_WDT_STAT_INT;
+                s->interrupt_pending = false;
+                qemu_set_irq(s->irq, 0);
+            }
+
+            /* Update timer */
+            k230_wdt_update_timer(s);
+        }
+        break;
+
+    case K230_WDT_EOI:
+        /* Clear interrupt */
+        s->stat &= ~K230_WDT_STAT_INT;
+        s->interrupt_pending = false;
+        qemu_set_irq(s->irq, 0);
+        break;
+
+    case K230_WDT_PROT_LEVEL:
+        s->prot_level = value & 0x7;
+        break;
+
+    default:
+        /* Read-only registers, ignore writes */
+        break;
+    }
+}
+
+static const MemoryRegionOps k230_wdt_ops = {
+    .read  = k230_wdt_read,
+    .write = k230_wdt_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false,
+    },
+};
+
+static const VMStateDescription vmstate_k230_wdt = {
+    .name = "k230.wdt",
+    .fields = (const VMStateField[]) {
+        VMSTATE_PTIMER(timer, K230WdtState),
+        VMSTATE_UINT32(cr, K230WdtState),
+        VMSTATE_UINT32(torr, K230WdtState),
+        VMSTATE_UINT32(ccvr, K230WdtState),
+        VMSTATE_UINT32(stat, K230WdtState),
+        VMSTATE_UINT32(prot_level, K230WdtState),
+        VMSTATE_BOOL(interrupt_pending, K230WdtState),
+        VMSTATE_BOOL(enabled, K230WdtState),
+        VMSTATE_UINT32(timeout_value, K230WdtState),
+        VMSTATE_UINT32(current_count, K230WdtState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void k230_wdt_realize(DeviceState *dev, Error **errp)
+{
+    K230WdtState *s = K230_WDT(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->mmio, OBJECT(dev),
+                          &k230_wdt_ops, s,
+                          TYPE_K230_WDT,
+                          K230_WDT_MMIO_SIZE);
+    sysbus_init_mmio(sbd, &s->mmio);
+    sysbus_init_irq(sbd, &s->irq);
+
+    s->timer = ptimer_init(k230_wdt_timeout, s,
+                           PTIMER_POLICY_NO_IMMEDIATE_TRIGGER |
+                           PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
+                           PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
+
+    ptimer_transaction_begin(s->timer);
+    ptimer_set_freq(s->timer, K230_WDT_DEFAULT_FREQ);
+    ptimer_transaction_commit(s->timer);
+}
+
+static void k230_wdt_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = k230_wdt_realize;
+    device_class_set_legacy_reset(dc, k230_wdt_reset);
+    dc->vmsd = &vmstate_k230_wdt;
+    dc->desc = "K230 watchdog timer";
+    set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
+}
+
+static const TypeInfo k230_wdt_info = {
+    .name          = TYPE_K230_WDT,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(K230WdtState),
+    .class_init    = k230_wdt_class_init,
+};
+
+static void k230_wdt_register_type(void)
+{
+    type_register_static(&k230_wdt_info);
+}
+type_init(k230_wdt_register_type)
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index f512ed65ac..54e41a6afc 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -148,3 +148,4 @@ config K230
     select RISCV_IMSIC
     select SERIAL_MM
     select UNIMP
+    select K230_WDT
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
index 861fd00334..55f77c5c84 100644
--- a/hw/watchdog/Kconfig
+++ b/hw/watchdog/Kconfig
@@ -18,6 +18,10 @@ config WDT_DIAG288
 config WDT_IMX2
     bool
 
+config K230_WDT
+    bool
+    select PTIMER
+
 config WDT_SBSA
     bool
 
diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
index 15370565bd..5edae65a36 100644
--- a/hw/watchdog/meson.build
+++ b/hw/watchdog/meson.build
@@ -6,5 +6,6 @@ system_ss.add(when: 'CONFIG_WDT_IB700', if_true: files('wdt_ib700.c'))
 system_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
 system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
 system_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
+system_ss.add(when: 'CONFIG_K230_WDT', if_true: files('k230_wdt.c'))
 system_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
 specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_watchdog.c'))
diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events
index ad3be1e9bd..d85b3ca769 100644
--- a/hw/watchdog/trace-events
+++ b/hw/watchdog/trace-events
@@ -33,3 +33,12 @@ spapr_watchdog_expired(uint64_t num, unsigned action) "num=%" PRIu64 " action=%u
 # watchdog.c
 watchdog_perform_action(unsigned int action) "action=%u"
 watchdog_set_action(unsigned int action) "action=%u"
+
+# k230_wdt.c
+k230_wdt_read(uint64_t addr, uint32_t data) "K230 WDT read: [0x%" PRIx64 "] -> 0x%" PRIx32
+k230_wdt_write(uint64_t addr, uint64_t data) "K230 WDT write: [0x%" PRIx64 "] <- 0x%" PRIx64
+k230_wdt_timeout(void) "K230 WDT timeout"
+k230_wdt_interrupt(void) "K230 WDT interrupt"
+k230_wdt_reset(void) "K230 WDT system reset"
+k230_wdt_restart(void) "K230 WDT restart"
+k230_wdt_reset_device(void) "K230 WDT device reset"
-- 
2.54.0



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

* [PULL 69/83] tests/qtest: add test for K230 watchdog
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (67 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 68/83] hw/watchdog: add k230 watchdog " alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 70/83] docs/system/riscv: add documentation for k230 machine alistair23
                   ` (15 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Chao Liu, Mig Yang, Daniel Henrique Barboza,
	Fabiano Rosas, Chao Liu, Nutty Liu, Alistair Francis

From: Chao Liu <chao.liu@zevorn.cn>

Testing the Basic Functions of K230 WDT:
1. Reset Function
2. Timeout Check
3. Interrupt Function

Signed-off-by: Mig Yang <temashking@foxmail.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Acked-by: Fabiano Rosas <farosas@suse.de>
Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Message-ID: <791beb1d8db07e4d1011cbeb4a8ac3add5b24f09.1781246408.git.chao.liu@processmission.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 MAINTAINERS                 |   1 +
 tests/qtest/k230-wdt-test.c | 189 ++++++++++++++++++++++++++++++++++++
 tests/qtest/meson.build     |   3 +-
 3 files changed, 192 insertions(+), 1 deletion(-)
 create mode 100644 tests/qtest/k230-wdt-test.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 06db33a107..44654b5798 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1794,6 +1794,7 @@ F: hw/riscv/k230.c
 F: hw/watchdog/k230_wdt.c
 F: include/hw/riscv/k230.h
 F: include/hw/watchdog/k230_wdt.h
+F: tests/qtest/k230-wdt-test.c
 
 RX Machines
 -----------
diff --git a/tests/qtest/k230-wdt-test.c b/tests/qtest/k230-wdt-test.c
new file mode 100644
index 0000000000..c8eaeaf1ae
--- /dev/null
+++ b/tests/qtest/k230-wdt-test.c
@@ -0,0 +1,189 @@
+/*
+ * QTest testcase for K230 Watchdog
+ *
+ * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the kendryte K230 SDK
+ *
+ * K230 Technical Reference Manual V0.3.1 (2024-11-18):
+ * https://github.com/revyos/external-docs/blob/master/K230/en-us/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "qemu/bitops.h"
+#include "libqtest.h"
+#include "hw/watchdog/k230_wdt.h"
+
+/* K230 WDT0 base address */
+#define K230_WDT0_BASE 0x91106000
+#define K230_WDT1_BASE 0x91106800
+
+/* Test WDT0 by default */
+#define WDT_BASE K230_WDT0_BASE
+
+static void test_register_read_write(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Test Control Register (CR) read/write */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_CR), ==,
+                    (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT) |
+                    K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+
+    /* Test Timeout Range Register (TORR) read/write */
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_TORR), ==,
+                    K230_WDT_TORR_TOP_MASK);
+
+    /* Test Protection Level Register read/write */
+    qtest_writel(qts, WDT_BASE + K230_WDT_PROT_LEVEL, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_PROT_LEVEL), ==, 0x7);
+
+    qtest_quit(qts);
+}
+
+static void test_counter_restart(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Enable watchdog and set timeout */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x5); /* TOP = 5 */
+
+    /* Read current counter value */
+    uint32_t initial_count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
+    g_assert_cmpuint(initial_count, >, 0);
+
+    /* Restart counter with magic value */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CRR, K230_WDT_CRR_RESTART);
+
+    /* Wait for time */
+    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 2);
+
+    /* Counter should be reset to timeout value */
+    uint32_t new_count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
+    g_assert_cmpuint(new_count, >, 0);
+    g_assert_cmpuint(new_count, !=, initial_count);
+
+    qtest_quit(qts);
+}
+
+static void test_interrupt_mode(void)
+{
+    QTestState *qts = qtest_init("-machine k230 --trace k230_*,file=k230.log");
+
+    /* Set interrupt mode and enable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR,
+                 K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x1); /* Short timeout */
+
+    /* Wait for timeout to trigger interrupt */
+    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 10);
+
+    /* Check interrupt status */
+    uint32_t stat = qtest_readl(qts, WDT_BASE + K230_WDT_STAT);
+    g_assert_cmphex(stat & K230_WDT_STAT_INT, ==, K230_WDT_STAT_INT);
+
+    /* Clear interrupt */
+    qtest_writel(qts, WDT_BASE + K230_WDT_EOI, 0x1);
+    stat = qtest_readl(qts, WDT_BASE + K230_WDT_STAT);
+    g_assert_cmphex(stat & K230_WDT_STAT_INT, ==, 0);
+
+    qtest_quit(qts);
+}
+
+static void test_reset_mode(void)
+{
+    QTestState *qts = qtest_init("-machine k230 -no-reboot");
+
+    /* Set reset mode and enable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x1); /* Short timeout */
+
+    /* Wait for timeout to trigger reset */
+    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 2);
+
+    /* In reset mode, the system should reset */
+    /* This test verifies that reset mode is properly configured */
+
+    qtest_quit(qts);
+}
+
+static void test_timeout_calculation(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Test different timeout values */
+    for (uint32_t top = 0; top <= 15; top++) {
+        qtest_writel(qts, WDT_BASE + K230_WDT_TORR, top);
+        qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+
+        /* Read current counter value */
+        uint32_t count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
+        g_assert_cmpuint(count, >, 0);
+
+        /* Disable watchdog for next iteration */
+        qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0);
+    }
+
+    qtest_quit(qts);
+}
+
+static void test_wdt1_registers(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Test WDT1 registers (second watchdog) */
+    qtest_writel(qts, K230_WDT1_BASE + K230_WDT_CR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, K230_WDT1_BASE + K230_WDT_CR), ==,
+                    (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT) |
+                    K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+
+    qtest_writel(qts, K230_WDT1_BASE + K230_WDT_TORR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, K230_WDT1_BASE + K230_WDT_TORR), ==,
+                    K230_WDT_TORR_TOP_MASK);
+
+    qtest_quit(qts);
+}
+
+static void test_enable_disable(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Initially disabled */
+    uint32_t cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
+    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, 0);
+
+    /* Enable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+    cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
+    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, K230_WDT_CR_WDT_EN);
+
+    /* Disable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0);
+    cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
+    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, 0);
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char *argv[])
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/k230-wdt/register_read_write", test_register_read_write);
+    qtest_add_func("/k230-wdt/counter_restart", test_counter_restart);
+    qtest_add_func("/k230-wdt/interrupt_mode", test_interrupt_mode);
+    qtest_add_func("/k230-wdt/reset_mode", test_reset_mode);
+    qtest_add_func("/k230-wdt/timeout_calculation", test_timeout_calculation);
+    qtest_add_func("/k230-wdt/wdt1_registers", test_wdt1_registers);
+    qtest_add_func("/k230-wdt/enable_disable", test_enable_disable);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 45ea497fa5..37ca38f9e7 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -291,7 +291,8 @@ qtests_riscv64 = ['riscv-csr-test'] + \
   (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
   (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and
    config_all_devices.has_key('CONFIG_RISCV_IOMMU') ?
-   ['iommu-riscv-test'] : [])
+   ['iommu-riscv-test'] : []) + \
+  (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
 
 qos_test_ss = ss.source_set()
 qos_test_ss.add(
-- 
2.54.0



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

* [PULL 70/83] docs/system/riscv: add documentation for k230 machine
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (68 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 69/83] tests/qtest: add test for K230 watchdog alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 71/83] hw/riscv/sifive_u.c: add a FDT phandle to cpu-intc alistair23
                   ` (14 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Chao Liu, Alistair Francis

From: Chao Liu <chao.liu.zevorn@gmail.com>

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <81d2e2fa42ecabf638f841321cf36cee8f10af01.1781246408.git.chao.liu@processmission.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 MAINTAINERS                  |   1 +
 docs/system/riscv/k230.rst   | 113 +++++++++++++++++++++++++++++++++++
 docs/system/target-riscv.rst |   1 +
 3 files changed, 115 insertions(+)
 create mode 100644 docs/system/riscv/k230.rst

diff --git a/MAINTAINERS b/MAINTAINERS
index 44654b5798..4fc073b7ee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1790,6 +1790,7 @@ K230 Machines
 M: Chao Liu <chao.liu.zevorn@gmail.com>
 L: qemu-riscv@nongnu.org
 S: Maintained
+F: docs/system/riscv/k230.rst
 F: hw/riscv/k230.c
 F: hw/watchdog/k230_wdt.c
 F: include/hw/riscv/k230.h
diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
new file mode 100644
index 0000000000..cea8202e55
--- /dev/null
+++ b/docs/system/riscv/k230.rst
@@ -0,0 +1,113 @@
+Kendryte K230 virt reference platform (``k230``)
+==========================================================================
+The ``k230`` machine is compatible with the Kendryte K230 SDK.
+
+The K230 is a chip from the AIoT SoC series made by Kendryte ® — a part of
+Canaan Inc. It uses a brand-new multi-heterogeneous unit accelerated computing
+structure.
+
+This chip has 2 RISC-V computing cores and a new-generation KPU (Knowledge
+Process Unit) smart computing unit.
+
+For more information, see <https://www.kendryte.com/en/proDetail/230>
+
+Supported devices
+-----------------
+The ``k230`` machine supports the following devices:
+
+* 1 c908 cores (little core)
+* Core Local Interruptor (CLINT)
+* Platform-Level Interrupt Controller (PLIC)
+* 2 K230 Watchdog Timer
+* 5 UART
+
+Boot options
+------------
+The ``k230`` machine supports K230 SDK boot through M-mode U-Boot, which then
+starts OpenSBI/Linux with ``bootm``. It also supports direct Linux boot.
+
+K230 SDK Linux kernels use T-HEAD C9xx private MAEE page table attributes. QEMU
+does not implement MAEE in the generic RISC-V MMU, so such kernels need to be
+built with standard RISC-V PTE bits before they can boot under QEMU.
+
+Running
+-------
+
+Direct Linux boot
+~~~~~~~~~~~~~~~~~
+
+This flow lets QEMU load OpenSBI, Linux, initrd, and DTB directly, without
+running SDK U-Boot. The Linux Image must be rebuilt with standard RISC-V PTE
+bits before running under QEMU.
+
+.. code-block:: bash
+
+   $ SDK=k230_sdk/output/k230_canmv_defconfig
+   $ qemu-system-riscv64 -machine k230 \
+      -kernel "$SDK/images/little-core/Image" \
+      -dtb "/tmp/user-k230-qemu.dtb" \
+      -initrd "$SDK/images/little-core/rootfs.cpio.gz" \
+      -append "console=ttyS0,115200 earlycon=sbi cma=0" \
+      -nographic
+
+Direct boot uses the SDK little-core RAM layout for OpenSBI at
+``0x08000000``, Linux at ``0x08200000``, and the DTB at ``0x0a000000``. The
+initrd is placed by QEMU's generic RISC-V boot helper, and QEMU writes the
+initrd range and kernel command line into ``/chosen``. The DTB passed with
+``-dtb`` should be derived from ``$SDK/images/little-core/k230.dtb`` and must
+describe that initrd location as usable memory and disable any devices that are
+not emulated by this machine.
+
+U-Boot boot
+~~~~~~~~~~~
+
+This flow starts SDK U-Boot in M-mode with ``-bios``. Until the SDK storage
+path is modeled, place OpenSBI, Linux, initrd, and DTB in RAM with loader
+devices and run ``bootm`` manually. The Linux Image must be rebuilt with
+standard RISC-V PTE bits before running under QEMU.
+
+.. code-block:: bash
+
+   $ SDK=k230_sdk/output/k230_canmv_defconfig
+   $ IMAGE=$SDK/images/little-core/Image
+   $ INITRD=$SDK/images/little-core/rootfs.cpio.gz
+   $ DTB=$SDK/images/little-core/k230.dtb
+   $ FWJUMP_UIMAGE=/tmp/k230-fw-jump.uImage
+   $ INITRD_END=$(printf "0x%x" $((0x0a100000 + $(stat -c %s "$INITRD"))))
+   $ "$SDK/little/buildroot-ext/host/bin/mkimage" \
+      -A riscv -O linux -T kernel -C none \
+      -a 0x8000000 -e 0x8000000 -n opensbi \
+      -d "$SDK/images/little-core/fw_jump.bin" "$FWJUMP_UIMAGE"
+   $ qemu-system-riscv64 -machine k230 \
+      -bios "$SDK/little/uboot/u-boot" \
+      -device loader,file="$FWJUMP_UIMAGE",addr=0xc100000,force-raw=on \
+      -device loader,file="$IMAGE",addr=0x8200000,force-raw=on \
+      -device loader,file="$INITRD",addr=0xa100000,force-raw=on \
+      -device loader,file="$DTB",addr=0xa000000,force-raw=on \
+      -nographic
+
+The loader addresses mirror the SDK ``k230_canmv_defconfig`` output. Read the
+U-Boot addresses from the generated environment, and read the Linux RAM base
+from the generated ``hw/k230.dts.txt``. This replaces the SDK storage and
+decompression steps.
+
+Press Enter to stop autoboot. At the U-Boot prompt, run these commands:
+
+.. code-block:: bash
+
+   K230# setenv bootargs console=ttyS0,115200 earlycon=sbi cma=0
+   K230# fdt addr 0xa000000
+   K230# fdt resize 8192
+   K230# fdt set /chosen linux,initrd-start <0x0 0xa100000>
+   K230# fdt set /chosen linux,initrd-end <0x0 ${INITRD_END}>
+   K230# fdt set /soc/sdhci0@91580000 status disabled
+   K230# fdt set /soc/sdhci1@91581000 status disabled
+   K230# bootm 0xc100000 - 0xa000000
+
+Use ``setenv`` so ``bootm`` writes the kernel command line into
+``/chosen/bootargs``. The ``fdt`` commands select the loaded DTB, add space for
+edits, describe the initrd range in ``/chosen``, and disable SDHCI nodes because
+this machine does not emulate those controllers yet. Replace ``${INITRD_END}``
+with the host-calculated value above when typing the command. ``cma=0`` avoids
+the SDK kernel reserving too much of the little-core memory window for initramfs
+boot.
diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
index afd86ca2ba..896f14e78b 100644
--- a/docs/system/target-riscv.rst
+++ b/docs/system/target-riscv.rst
@@ -66,6 +66,7 @@ undocumented; you can get a complete list by running
 .. toctree::
    :maxdepth: 1
 
+   riscv/k230
    riscv/microblaze-v-generic
    riscv/microchip-icicle-kit
    riscv/mips
-- 
2.54.0



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

* [PULL 71/83] hw/riscv/sifive_u.c: add a FDT phandle to cpu-intc
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (69 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 70/83] docs/system/riscv: add documentation for k230 machine alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 72/83] hw/riscv: add fdt-common helper alistair23
                   ` (13 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

We're assigning a 'cpu_phandle' phandle to the cpu-intc phandle field.
Make it more in line with the other boards by assigning both a
cpu_phandle and a intc phandle.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-2-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/sifive_u.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 6a637e3b86..3abbd6c823 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -187,8 +187,10 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
         qemu_fdt_setprop_string(fdt, nodename, "status", "okay");
         qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu);
         qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
+        qemu_fdt_setprop_cell(fdt, nodename, "phandle", cpu_phandle);
+
         qemu_fdt_add_subnode(fdt, intc);
-        qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle);
+        qemu_fdt_setprop_cell(fdt, intc, "phandle", phandle++);
         qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
         qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
         qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
-- 
2.54.0



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

* [PULL 72/83] hw/riscv: add fdt-common helper
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (70 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 71/83] hw/riscv/sifive_u.c: add a FDT phandle to cpu-intc alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 73/83] hw/riscv/numa: make numa_enabled() public alistair23
                   ` (12 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

There's too much duplication between RISC-V boards and one of the most
common culprits is the FDT functions.

Add a new file for board FDT helpers.  Start by creating a helper that
initializes the FDT and init it with the common board boilerplate.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-3-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/riscv/fdt-common.h | 14 +++++++++++++
 hw/riscv/fdt-common.c         | 37 +++++++++++++++++++++++++++++++++++
 hw/riscv/sifive_u.c           | 20 +++----------------
 hw/riscv/spike.c              | 19 +++---------------
 hw/riscv/virt.c               | 19 +++---------------
 hw/riscv/meson.build          |  1 +
 6 files changed, 61 insertions(+), 49 deletions(-)
 create mode 100644 include/hw/riscv/fdt-common.h
 create mode 100644 hw/riscv/fdt-common.c

diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
new file mode 100644
index 0000000000..adf9b33dfd
--- /dev/null
+++ b/include/hw/riscv/fdt-common.h
@@ -0,0 +1,14 @@
+/*
+ * RISC-V board helpers for FDT generation.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef RISCV_VIRT_FDT_H
+#define RISCV_VIRT_FDT_H
+
+void *create_board_device_tree(const char *model, const char *compatible,
+                               int *fdt_size);
+#endif
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
new file mode 100644
index 0000000000..b155246998
--- /dev/null
+++ b/hw/riscv/fdt-common.c
@@ -0,0 +1,37 @@
+/*
+ * RISC-V board helpers for FDT generation.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/error-report.h"
+#include "system/device_tree.h"
+#include "hw/riscv/fdt-common.h"
+
+void *create_board_device_tree(const char *model, const char *compatible,
+                               int *fdt_size)
+{
+    void *fdt = create_device_tree(fdt_size);
+
+    if (!fdt) {
+        error_report("create_device_tree() failed");
+        exit(1);
+    }
+
+    qemu_fdt_setprop_string(fdt, "/", "model", model);
+    qemu_fdt_setprop_string(fdt, "/", "compatible", compatible);
+    qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
+    qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
+
+    qemu_fdt_add_subnode(fdt, "/soc");
+    qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
+    qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
+    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
+    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
+
+    return fdt;
+}
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 3abbd6c823..5d3b2751ad 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -52,6 +52,7 @@
 #include "hw/riscv/sifive_u.h"
 #include "hw/riscv/boot.h"
 #include "hw/riscv/machines-qom.h"
+#include "hw/riscv/fdt-common.h"
 #include "hw/char/sifive_uart.h"
 #include "hw/intc/riscv_aclint.h"
 #include "hw/intc/sifive_plic.h"
@@ -112,23 +113,8 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
         "sifive,plic-1.0.0", "riscv,plic0"
     };
 
-    fdt = ms->fdt = create_device_tree(&s->fdt_size);
-    if (!fdt) {
-        error_report("create_device_tree() failed");
-        exit(1);
-    }
-
-    qemu_fdt_setprop_string(fdt, "/", "model", "SiFive HiFive Unleashed A00");
-    qemu_fdt_setprop_string(fdt, "/", "compatible",
-                            "sifive,hifive-unleashed-a00");
-    qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
-
-    qemu_fdt_add_subnode(fdt, "/soc");
-    qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
-    qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
-    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
+    fdt = ms->fdt = create_board_device_tree("SiFive HiFive Unleashed A00",
+        "sifive,hifive-unleashed-a00", &s->fdt_size);
 
     hfclk_phandle = phandle++;
     nodename = g_strdup_printf("/hfclk");
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index f9d00e0d5c..79c9bb041f 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -32,6 +32,7 @@
 #include "hw/riscv/riscv_hart.h"
 #include "hw/riscv/spike.h"
 #include "hw/riscv/boot.h"
+#include "hw/riscv/fdt-common.h"
 #include "hw/riscv/numa.h"
 #include "hw/riscv/machines-qom.h"
 #include "hw/char/riscv_htif.h"
@@ -66,16 +67,8 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
         "sifive,clint0", "riscv,clint0"
     };
 
-    fdt = ms->fdt = create_device_tree(&fdt_size);
-    if (!fdt) {
-        error_report("create_device_tree() failed");
-        exit(1);
-    }
-
-    qemu_fdt_setprop_string(fdt, "/", "model", "ucbbar,spike-bare,qemu");
-    qemu_fdt_setprop_string(fdt, "/", "compatible", "ucbbar,spike-bare-dev");
-    qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
+    fdt = ms->fdt = create_board_device_tree("ucbbar,spike-bare,qemu",
+        "ucbbar,spike-bare-dev", &fdt_size);
 
     qemu_fdt_add_subnode(fdt, "/htif");
     qemu_fdt_setprop_string(fdt, "/htif", "compatible", "ucb,htif0");
@@ -84,12 +77,6 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
             0x0, memmap[SPIKE_HTIF].base, 0x0, memmap[SPIKE_HTIF].size);
     }
 
-    qemu_fdt_add_subnode(fdt, "/soc");
-    qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
-    qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
-    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
-
     qemu_fdt_add_subnode(fdt, "/cpus");
     qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
         RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 0c489bb412..cb1d83fd48 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -36,6 +36,7 @@
 #include "hw/riscv/riscv-iommu-bits.h"
 #include "hw/riscv/virt.h"
 #include "hw/riscv/boot.h"
+#include "hw/riscv/fdt-common.h"
 #include "hw/riscv/machines-qom.h"
 #include "hw/riscv/numa.h"
 #include "kvm/kvm_riscv.h"
@@ -1150,22 +1151,8 @@ static void create_fdt(RISCVVirtState *s)
     uint8_t rng_seed[32];
     g_autofree char *name = NULL;
 
-    ms->fdt = create_device_tree(&s->fdt_size);
-    if (!ms->fdt) {
-        error_report("create_device_tree() failed");
-        exit(1);
-    }
-
-    qemu_fdt_setprop_string(ms->fdt, "/", "model", "riscv-virtio,qemu");
-    qemu_fdt_setprop_string(ms->fdt, "/", "compatible", "riscv-virtio");
-    qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
-
-    qemu_fdt_add_subnode(ms->fdt, "/soc");
-    qemu_fdt_setprop(ms->fdt, "/soc", "ranges", NULL, 0);
-    qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus");
-    qemu_fdt_setprop_cell(ms->fdt, "/soc", "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(ms->fdt, "/soc", "#address-cells", 0x2);
+    ms->fdt = create_board_device_tree("riscv-virtio,qemu", "riscv-virtio",
+                                       &s->fdt_size);
 
     /*
      * The "/soc/pci@..." node is needed for PCIE hotplugs
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 09cf855984..b70a054579 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -1,5 +1,6 @@
 riscv_ss = ss.source_set()
 riscv_ss.add(files('boot.c'))
+riscv_ss.add(files('fdt-common.c'))
 riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c'))
 riscv_ss.add(files('riscv_hart.c'))
 riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c'))
-- 
2.54.0



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

* [PULL 73/83] hw/riscv/numa: make numa_enabled() public
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (71 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 72/83] hw/riscv: add fdt-common helper alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 74/83] hw/riscv: add create_fdt_socket_memory() helper alistair23
                   ` (11 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Daniel Henrique Barboza, Alistair Francis,
	Philippe Mathieu-Daudé

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

There's FDT logic gated around 'numa_enabled()' in virt.c and spike.c.
We want to move the FDT code to a common helper without having to call
hw/riscv/numa.c functions from it, but at the same time being aware of
the FDT changes if numa is enabled.

To do that the boards will inform the FDT helpers if we have
numa_enabled in the env or not.  And for the boards to be able to do
that we need the static 'numa_enabled' function to be public.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Message-ID: <20260615203734.954428-4-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/riscv/numa.h |  8 ++++++++
 hw/riscv/numa.c         | 20 ++++++++++----------
 2 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/include/hw/riscv/numa.h b/include/hw/riscv/numa.h
index e68ce8e8af..ac07786555 100644
--- a/include/hw/riscv/numa.h
+++ b/include/hw/riscv/numa.h
@@ -23,6 +23,14 @@
 #include "hw/core/sysbus.h"
 #include "system/numa.h"
 
+/**
+ * riscv_numa_enabled:
+ * @ms: pointer to machine state
+ *
+ * Returns: true if NUMA is enabled in the machine state.
+ */
+bool riscv_numa_enabled(const MachineState *ms);
+
 /**
  * riscv_socket_count:
  * @ms: pointer to machine state
diff --git a/hw/riscv/numa.c b/hw/riscv/numa.c
index 8a144925c1..8933d9d81f 100644
--- a/hw/riscv/numa.c
+++ b/hw/riscv/numa.c
@@ -25,21 +25,21 @@
 #include "hw/riscv/numa.h"
 #include "system/device_tree.h"
 
-static bool numa_enabled(const MachineState *ms)
+bool riscv_numa_enabled(const MachineState *ms)
 {
     return (ms->numa_state && ms->numa_state->num_nodes) ? true : false;
 }
 
 int riscv_socket_count(const MachineState *ms)
 {
-    return (numa_enabled(ms)) ? ms->numa_state->num_nodes : 1;
+    return (riscv_numa_enabled(ms)) ? ms->numa_state->num_nodes : 1;
 }
 
 int riscv_socket_first_hartid(const MachineState *ms, int socket_id)
 {
     int i, first_hartid = ms->smp.cpus;
 
-    if (!numa_enabled(ms)) {
+    if (!riscv_numa_enabled(ms)) {
         return (!socket_id) ? 0 : -1;
     }
 
@@ -59,7 +59,7 @@ int riscv_socket_last_hartid(const MachineState *ms, int socket_id)
 {
     int i, last_hartid = -1;
 
-    if (!numa_enabled(ms)) {
+    if (!riscv_numa_enabled(ms)) {
         return (!socket_id) ? ms->smp.cpus - 1 : -1;
     }
 
@@ -79,7 +79,7 @@ int riscv_socket_hart_count(const MachineState *ms, int socket_id)
 {
     int first_hartid, last_hartid;
 
-    if (!numa_enabled(ms)) {
+    if (!riscv_numa_enabled(ms)) {
         return (!socket_id) ? ms->smp.cpus : -1;
     }
 
@@ -104,7 +104,7 @@ bool riscv_socket_check_hartids(const MachineState *ms, int socket_id)
 {
     int i, first_hartid, last_hartid;
 
-    if (!numa_enabled(ms)) {
+    if (!riscv_numa_enabled(ms)) {
         return (!socket_id) ? true : false;
     }
 
@@ -132,7 +132,7 @@ uint64_t riscv_socket_mem_offset(const MachineState *ms, int socket_id)
     int i;
     uint64_t mem_offset = 0;
 
-    if (!numa_enabled(ms)) {
+    if (!riscv_numa_enabled(ms)) {
         return 0;
     }
 
@@ -148,7 +148,7 @@ uint64_t riscv_socket_mem_offset(const MachineState *ms, int socket_id)
 
 uint64_t riscv_socket_mem_size(const MachineState *ms, int socket_id)
 {
-    if (!numa_enabled(ms)) {
+    if (!riscv_numa_enabled(ms)) {
         return (!socket_id) ? ms->ram_size : 0;
     }
 
@@ -159,7 +159,7 @@ uint64_t riscv_socket_mem_size(const MachineState *ms, int socket_id)
 void riscv_socket_fdt_write_id(const MachineState *ms, const char *node_name,
                                int socket_id)
 {
-    if (numa_enabled(ms)) {
+    if (riscv_numa_enabled(ms)) {
         qemu_fdt_setprop_cell(ms->fdt, node_name, "numa-node-id", socket_id);
     }
 }
@@ -170,7 +170,7 @@ void riscv_socket_fdt_write_distance_matrix(const MachineState *ms)
     g_autofree uint32_t *dist_matrix = NULL;
     uint32_t dist_matrix_size;
 
-    if (numa_enabled(ms) && ms->numa_state->have_numa_distance) {
+    if (riscv_numa_enabled(ms) && ms->numa_state->have_numa_distance) {
         dist_matrix_size = riscv_socket_count(ms) * riscv_socket_count(ms);
         dist_matrix_size *= (3 * sizeof(uint32_t));
         dist_matrix = g_malloc0(dist_matrix_size);
-- 
2.54.0



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

* [PULL 74/83] hw/riscv: add create_fdt_socket_memory() helper
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (72 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 73/83] hw/riscv/numa: make numa_enabled() public alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 75/83] hw/riscv/sifive_u.c: add intc_phandles array alistair23
                   ` (10 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

This helper encapsulates the creation of /memory@addr FDT subnodes.

Boards are responsible for calculating the adequate addr, size and
inform if we have numa enabled.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-5-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/riscv/fdt-common.h |  2 ++
 hw/riscv/fdt-common.c         | 15 +++++++++++++++
 hw/riscv/sifive_u.c           | 11 ++---------
 hw/riscv/spike.c              | 18 +++++++-----------
 hw/riscv/virt.c               | 23 ++++++-----------------
 5 files changed, 32 insertions(+), 37 deletions(-)

diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index adf9b33dfd..81689f418b 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -11,4 +11,6 @@
 
 void *create_board_device_tree(const char *model, const char *compatible,
                                int *fdt_size);
+void create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
+                              int socket_id, bool numa_enabled);
 #endif
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index b155246998..719c36e001 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -10,6 +10,7 @@
 
 #include "qemu/error-report.h"
 #include "system/device_tree.h"
+#include "hw/core/boards.h"
 #include "hw/riscv/fdt-common.h"
 
 void *create_board_device_tree(const char *model, const char *compatible,
@@ -35,3 +36,17 @@ void *create_board_device_tree(const char *model, const char *compatible,
 
     return fdt;
 }
+
+void create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
+                              int socket_id, bool numa_enabled)
+{
+    g_autofree char *mem_name = g_strdup_printf("/memory@%"HWADDR_PRIx, addr);
+
+    qemu_fdt_add_subnode(fdt, mem_name);
+    qemu_fdt_setprop_sized_cells(fdt, mem_name, "reg", 2, addr, 2, size);
+    qemu_fdt_setprop_string(fdt, mem_name, "device_type", "memory");
+
+    if (numa_enabled) {
+        qemu_fdt_setprop_cell(fdt, mem_name, "numa-node-id", socket_id);
+    }
+}
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 5d3b2751ad..a00cfd08a7 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -98,7 +98,6 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
                        bool is_32_bit)
 {
     MachineState *ms = MACHINE(s);
-    uint64_t mem_size = ms->ram_size;
     void *fdt;
     int cpu;
     uint32_t *cells;
@@ -138,14 +137,8 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
     qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
     g_free(nodename);
 
-    nodename = g_strdup_printf("/memory@%lx",
-        (long)memmap[SIFIVE_U_DEV_DRAM].base);
-    qemu_fdt_add_subnode(fdt, nodename);
-    qemu_fdt_setprop_cells(fdt, nodename, "reg",
-        memmap[SIFIVE_U_DEV_DRAM].base >> 32, memmap[SIFIVE_U_DEV_DRAM].base,
-        mem_size >> 32, mem_size);
-    qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
-    g_free(nodename);
+    create_fdt_socket_memory(fdt, memmap[SIFIVE_U_DEV_DRAM].base,
+                             ms->ram_size, 0, false);
 
     qemu_fdt_add_subnode(fdt, "/cpus");
     qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index 79c9bb041f..92facba29d 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -55,13 +55,12 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
 {
     void *fdt;
     int fdt_size;
-    uint64_t addr, size;
     unsigned long clint_addr;
     int cpu, socket;
     MachineState *ms = MACHINE(s);
     uint32_t *clint_cells;
     uint32_t cpu_phandle, intc_phandle, phandle = 1;
-    char *mem_name, *clint_name, *clust_name;
+    char *clint_name, *clust_name;
     char *core_name, *cpu_name, *intc_name;
     static const char * const clint_compat[2] = {
         "sifive,clint0", "riscv,clint0"
@@ -85,6 +84,10 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
     qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
 
     for (socket = (riscv_socket_count(ms) - 1); socket >= 0; socket--) {
+        hwaddr memaddr = memmap[SPIKE_DRAM].base +
+                         riscv_socket_mem_offset(ms, socket);
+        uint64_t memsize =  riscv_socket_mem_size(ms, socket);
+
         clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
         qemu_fdt_add_subnode(fdt, clust_name);
 
@@ -133,15 +136,8 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
             g_free(cpu_name);
         }
 
-        addr = memmap[SPIKE_DRAM].base + riscv_socket_mem_offset(ms, socket);
-        size = riscv_socket_mem_size(ms, socket);
-        mem_name = g_strdup_printf("/memory@%lx", (long)addr);
-        qemu_fdt_add_subnode(fdt, mem_name);
-        qemu_fdt_setprop_cells(fdt, mem_name, "reg",
-            addr >> 32, addr, size >> 32, size);
-        qemu_fdt_setprop_string(fdt, mem_name, "device_type", "memory");
-        riscv_socket_fdt_write_id(ms, mem_name, socket);
-        g_free(mem_name);
+        create_fdt_socket_memory(fdt, memaddr, memsize, socket,
+                                 riscv_numa_enabled(ms));
 
         clint_addr = memmap[SPIKE_CLINT].base +
             (memmap[SPIKE_CLINT].size * socket);
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index cb1d83fd48..df3eadef78 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -302,22 +302,6 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
     }
 }
 
-static void create_fdt_socket_memory(RISCVVirtState *s, int socket)
-{
-    g_autofree char *mem_name = NULL;
-    hwaddr addr;
-    uint64_t size;
-    MachineState *ms = MACHINE(s);
-
-    addr = s->memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket);
-    size = riscv_socket_mem_size(ms, socket);
-    mem_name = g_strdup_printf("/memory@%"HWADDR_PRIx, addr);
-    qemu_fdt_add_subnode(ms->fdt, mem_name);
-    qemu_fdt_setprop_sized_cells(ms->fdt, mem_name, "reg", 2, addr, 2, size);
-    qemu_fdt_setprop_string(ms->fdt, mem_name, "device_type", "memory");
-    riscv_socket_fdt_write_id(ms, mem_name, socket);
-}
-
 static void create_fdt_socket_clint(RISCVVirtState *s,
                                     int socket,
                                     uint32_t *intc_phandles)
@@ -759,6 +743,10 @@ static void create_fdt_sockets(RISCVVirtState *s,
     phandle_pos = ms->smp.cpus;
     for (socket = (socket_count - 1); socket >= 0; socket--) {
         g_autofree char *clust_name = NULL;
+        hwaddr memaddr = s->memmap[VIRT_DRAM].base +
+                         riscv_socket_mem_offset(ms, socket);
+        uint64_t memsize = riscv_socket_mem_size(ms, socket);
+
         phandle_pos -= s->soc[socket].num_harts;
 
         clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
@@ -767,7 +755,8 @@ static void create_fdt_sockets(RISCVVirtState *s,
         create_fdt_socket_cpus(s, socket, clust_name, phandle,
                                &intc_phandles[phandle_pos]);
 
-        create_fdt_socket_memory(s, socket);
+        create_fdt_socket_memory(ms->fdt, memaddr, memsize,
+                                 socket, riscv_numa_enabled(ms));
 
         if (virt_aclint_allowed() && s->have_aclint) {
             create_fdt_socket_aclint(s, socket,
-- 
2.54.0



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

* [PULL 75/83] hw/riscv/sifive_u.c: add intc_phandles array
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (73 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 74/83] hw/riscv: add create_fdt_socket_memory() helper alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 76/83] hw/riscv/spike.c: " alistair23
                   ` (9 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

Store the intc phandles in an 'intc_phandles' array, like the 'virt'
board does, instead of re-creating the interrupt-controller FDT string
and using qemu_fdt_get_phandle() to fetch it.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-6-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/sifive_u.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index a00cfd08a7..ce86989bc8 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -111,6 +111,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
     static const char * const plic_compat[2] = {
         "sifive,plic-1.0.0", "riscv,plic0"
     };
+    g_autofree uint32_t *intc_phandles = g_new0(uint32_t, ms->smp.cpus);
 
     fdt = ms->fdt = create_board_device_tree("SiFive HiFive Unleashed A00",
         "sifive,hifive-unleashed-a00", &s->fdt_size);
@@ -168,8 +169,10 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
         qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
         qemu_fdt_setprop_cell(fdt, nodename, "phandle", cpu_phandle);
 
+        intc_phandles[cpu] = phandle++;
+
         qemu_fdt_add_subnode(fdt, intc);
-        qemu_fdt_setprop_cell(fdt, intc, "phandle", phandle++);
+        qemu_fdt_setprop_cell(fdt, intc, "phandle", intc_phandles[cpu]);
         qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
         qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
         qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
@@ -179,14 +182,10 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
 
     cells =  g_new0(uint32_t, ms->smp.cpus * 4);
     for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
-        nodename =
-            g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
-        uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename);
-        cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
+        cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
         cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
-        cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
+        cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
         cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
-        g_free(nodename);
     }
     nodename = g_strdup_printf("/soc/clint@%lx",
         (long)memmap[SIFIVE_U_DEV_CLINT].base);
-- 
2.54.0



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

* [PULL 76/83] hw/riscv/spike.c: add intc_phandles array
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (74 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 75/83] hw/riscv/sifive_u.c: add intc_phandles array alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 77/83] hw/riscv: add create_fdt_clint() helper alistair23
                   ` (8 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

The clint FDT generation uses a cells array (clint_cells) that are
populated in the middle of the loop that creates the CPU socket FDT.
This is completely fine but it differs from the other boards that
creates the clint cells array right before creating the clint FDT.
'virt' and 'sifive_u' store the intc phandles in a intc_phandles array
during FDT CPU socket creation, and this array is used to create the
clint FDT cells.

Standardize the clint FDT creation for spike doing the same here,
allowing us to move everything to a common helper later.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-7-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/spike.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index 92facba29d..82005ec163 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -59,7 +59,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
     int cpu, socket;
     MachineState *ms = MACHINE(s);
     uint32_t *clint_cells;
-    uint32_t cpu_phandle, intc_phandle, phandle = 1;
+    uint32_t cpu_phandle, phandle = 1;
     char *clint_name, *clust_name;
     char *core_name, *cpu_name, *intc_name;
     static const char * const clint_compat[2] = {
@@ -84,6 +84,8 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
     qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
 
     for (socket = (riscv_socket_count(ms) - 1); socket >= 0; socket--) {
+        g_autofree uint32_t *intc_phandles = g_new0(uint32_t,
+                                                    s->soc[socket].num_harts);
         hwaddr memaddr = memmap[SPIKE_DRAM].base +
                          riscv_socket_mem_offset(ms, socket);
         uint64_t memsize =  riscv_socket_mem_size(ms, socket);
@@ -91,8 +93,6 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
         clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
         qemu_fdt_add_subnode(fdt, clust_name);
 
-        clint_cells =  g_new0(uint32_t, s->soc[socket].num_harts * 4);
-
         for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
             cpu_phandle = phandle++;
 
@@ -113,20 +113,17 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
             riscv_socket_fdt_write_id(ms, cpu_name, socket);
             qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
 
+            intc_phandles[cpu] = phandle++;
+
             intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
             qemu_fdt_add_subnode(fdt, intc_name);
-            intc_phandle = phandle++;
-            qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
+            qemu_fdt_setprop_cell(fdt, intc_name, "phandle",
+                                  intc_phandles[cpu]);
             qemu_fdt_setprop_string(fdt, intc_name, "compatible",
                 "riscv,cpu-intc");
             qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
             qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
 
-            clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
-            clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
-            clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
-            clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
-
             core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
             qemu_fdt_add_subnode(fdt, core_name);
             qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
@@ -139,6 +136,15 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
         create_fdt_socket_memory(fdt, memaddr, memsize, socket,
                                  riscv_numa_enabled(ms));
 
+        clint_cells =  g_new0(uint32_t, s->soc[socket].num_harts * 4);
+
+        for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
+            clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
+            clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
+            clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
+            clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
+        }
+
         clint_addr = memmap[SPIKE_CLINT].base +
             (memmap[SPIKE_CLINT].size * socket);
         clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
-- 
2.54.0



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

* [PULL 77/83] hw/riscv: add create_fdt_clint() helper
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (75 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 76/83] hw/riscv/spike.c: " alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 78/83] hw/riscv/sifive_u.c: add cpu-map, cluster and core DTs alistair23
                   ` (7 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

Move all clint FDT generation to fdt-common.c reducing code repetition.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-8-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/riscv/fdt-common.h |  5 ++++
 hw/riscv/fdt-common.c         | 33 +++++++++++++++++++++++++
 hw/riscv/sifive_u.c           | 25 +++----------------
 hw/riscv/spike.c              | 31 ++++-------------------
 hw/riscv/virt.c               | 46 ++++++-----------------------------
 5 files changed, 54 insertions(+), 86 deletions(-)

diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index 81689f418b..6e81d6cd6c 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -13,4 +13,9 @@ void *create_board_device_tree(const char *model, const char *compatible,
                                int *fdt_size);
 void create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
                               int socket_id, bool numa_enabled);
+void create_fdt_clint(void *fdt, hwaddr addr, uint64_t size,
+                      uint32_t *intc_phandles, int num_harts);
+void create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
+                             int socket_id, uint32_t *intc_phandles,
+                             int num_harts, bool numa_enabled);
 #endif
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index 719c36e001..d2661ec389 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -12,6 +12,7 @@
 #include "system/device_tree.h"
 #include "hw/core/boards.h"
 #include "hw/riscv/fdt-common.h"
+#include "target/riscv/cpu_bits.h"
 
 void *create_board_device_tree(const char *model, const char *compatible,
                                int *fdt_size)
@@ -50,3 +51,35 @@ void create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
         qemu_fdt_setprop_cell(fdt, mem_name, "numa-node-id", socket_id);
     }
 }
+
+void create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
+                             int socket_id, uint32_t *intc_phandles,
+                             int num_harts, bool numa_enabled)
+{
+    g_autofree uint32_t *clint_cells = g_new0(uint32_t, num_harts * 4);
+    g_autofree char *clint_name = NULL;
+    static const char * const clint_compat[2] = {
+        "sifive,clint0", "riscv,clint0"
+    };
+
+    for (int cpu = 0; cpu < num_harts; cpu++) {
+        clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
+        clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
+        clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
+    }
+
+    clint_name = g_strdup_printf("/soc/clint@%"HWADDR_PRIx, addr);
+    qemu_fdt_add_subnode(fdt, clint_name);
+    qemu_fdt_setprop_string_array(fdt, clint_name, "compatible",
+                                  (char **)&clint_compat,
+                                  ARRAY_SIZE(clint_compat));
+    qemu_fdt_setprop_sized_cells(fdt, clint_name, "reg",
+                                 2, addr, 2, size);
+    qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
+                     clint_cells, num_harts * sizeof(uint32_t) * 4);
+
+    if (numa_enabled) {
+        qemu_fdt_setprop_cell(fdt, clint_name, "numa-node-id", socket_id);
+    }
+}
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index ce86989bc8..9a791b36d6 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -105,9 +105,6 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
     uint32_t plic_phandle, prci_phandle, gpio_phandle, phandle = 1;
     uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle;
     static const char * const ethclk_names[2] = { "pclk", "hclk" };
-    static const char * const clint_compat[2] = {
-        "sifive,clint0", "riscv,clint0"
-    };
     static const char * const plic_compat[2] = {
         "sifive,plic-1.0.0", "riscv,plic0"
     };
@@ -180,25 +177,9 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
         g_free(nodename);
     }
 
-    cells =  g_new0(uint32_t, ms->smp.cpus * 4);
-    for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
-        cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
-        cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
-        cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
-        cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
-    }
-    nodename = g_strdup_printf("/soc/clint@%lx",
-        (long)memmap[SIFIVE_U_DEV_CLINT].base);
-    qemu_fdt_add_subnode(fdt, nodename);
-    qemu_fdt_setprop_string_array(fdt, nodename, "compatible",
-        (char **)&clint_compat, ARRAY_SIZE(clint_compat));
-    qemu_fdt_setprop_cells(fdt, nodename, "reg",
-        0x0, memmap[SIFIVE_U_DEV_CLINT].base,
-        0x0, memmap[SIFIVE_U_DEV_CLINT].size);
-    qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
-        cells, ms->smp.cpus * sizeof(uint32_t) * 4);
-    g_free(cells);
-    g_free(nodename);
+    create_fdt_socket_clint(fdt, memmap[SIFIVE_U_DEV_CLINT].base,
+                            memmap[SIFIVE_U_DEV_CLINT].size, 0,
+                            intc_phandles, ms->smp.cpus, false);
 
     nodename = g_strdup_printf("/soc/otp@%lx",
         (long)memmap[SIFIVE_U_DEV_OTP].base);
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index 82005ec163..b15188fb07 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -58,13 +58,10 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
     unsigned long clint_addr;
     int cpu, socket;
     MachineState *ms = MACHINE(s);
-    uint32_t *clint_cells;
     uint32_t cpu_phandle, phandle = 1;
-    char *clint_name, *clust_name;
+    char *clust_name;
     char *core_name, *cpu_name, *intc_name;
-    static const char * const clint_compat[2] = {
-        "sifive,clint0", "riscv,clint0"
-    };
+    bool numa_enabled = riscv_numa_enabled(ms);
 
     fdt = ms->fdt = create_board_device_tree("ucbbar,spike-bare,qemu",
         "ucbbar,spike-bare-dev", &fdt_size);
@@ -136,29 +133,11 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
         create_fdt_socket_memory(fdt, memaddr, memsize, socket,
                                  riscv_numa_enabled(ms));
 
-        clint_cells =  g_new0(uint32_t, s->soc[socket].num_harts * 4);
-
-        for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
-            clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
-            clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
-            clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
-            clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
-        }
-
         clint_addr = memmap[SPIKE_CLINT].base +
             (memmap[SPIKE_CLINT].size * socket);
-        clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
-        qemu_fdt_add_subnode(fdt, clint_name);
-        qemu_fdt_setprop_string_array(fdt, clint_name, "compatible",
-            (char **)&clint_compat, ARRAY_SIZE(clint_compat));
-        qemu_fdt_setprop_cells(fdt, clint_name, "reg",
-            0x0, clint_addr, 0x0, memmap[SPIKE_CLINT].size);
-        qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
-            clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
-        riscv_socket_fdt_write_id(ms, clint_name, socket);
-
-        g_free(clint_name);
-        g_free(clint_cells);
+        create_fdt_socket_clint(fdt, clint_addr, memmap[SPIKE_CLINT].size,
+                                socket, intc_phandles,
+                                s->soc[socket].num_harts, numa_enabled);
         g_free(clust_name);
     }
 
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index df3eadef78..b134f11266 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -302,42 +302,6 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
     }
 }
 
-static void create_fdt_socket_clint(RISCVVirtState *s,
-                                    int socket,
-                                    uint32_t *intc_phandles)
-{
-    int cpu;
-    g_autofree char *clint_name = NULL;
-    g_autofree uint32_t *clint_cells = NULL;
-    hwaddr clint_addr;
-    MachineState *ms = MACHINE(s);
-    static const char * const clint_compat[2] = {
-        "sifive,clint0", "riscv,clint0"
-    };
-
-    clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
-
-    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
-        clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
-        clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
-        clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
-        clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
-    }
-
-    clint_addr = s->memmap[VIRT_CLINT].base +
-                 s->memmap[VIRT_CLINT].size * socket;
-    clint_name = g_strdup_printf("/soc/clint@%"HWADDR_PRIx, clint_addr);
-    qemu_fdt_add_subnode(ms->fdt, clint_name);
-    qemu_fdt_setprop_string_array(ms->fdt, clint_name, "compatible",
-                                  (char **)&clint_compat,
-                                  ARRAY_SIZE(clint_compat));
-    qemu_fdt_setprop_sized_cells(ms->fdt, clint_name, "reg",
-        2, clint_addr, 2, s->memmap[VIRT_CLINT].size);
-    qemu_fdt_setprop(ms->fdt, clint_name, "interrupts-extended",
-        clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
-    riscv_socket_fdt_write_id(ms, clint_name, socket);
-}
-
 static void create_fdt_socket_aclint(RISCVVirtState *s,
                                      int socket,
                                      uint32_t *intc_phandles)
@@ -728,6 +692,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
     uint32_t xplic_phandles[MAX_NODES];
     g_autofree uint32_t *intc_phandles = NULL;
     int socket_count = riscv_socket_count(ms);
+    bool numa_enabled = riscv_numa_enabled(ms);
 
     qemu_fdt_add_subnode(ms->fdt, "/cpus");
     qemu_fdt_setprop_cell(ms->fdt, "/cpus", "timebase-frequency",
@@ -762,8 +727,13 @@ static void create_fdt_sockets(RISCVVirtState *s,
             create_fdt_socket_aclint(s, socket,
                                      &intc_phandles[phandle_pos]);
         } else if (tcg_enabled()) {
-            create_fdt_socket_clint(s, socket,
-                                    &intc_phandles[phandle_pos]);
+            hwaddr clintaddr = s->memmap[VIRT_CLINT].base +
+                               s->memmap[VIRT_CLINT].size * socket;
+
+            create_fdt_socket_clint(ms->fdt, clintaddr,
+                                    s->memmap[VIRT_CLINT].size,
+                                    socket, &intc_phandles[phandle_pos],
+                                    s->soc[socket].num_harts, numa_enabled);
         }
     }
 
-- 
2.54.0



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

* [PULL 78/83] hw/riscv/sifive_u.c: add cpu-map, cluster and core DTs
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (76 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 77/83] hw/riscv: add create_fdt_clint() helper alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 79/83] hw/riscv: add fdt_create_cpu_socket_subnode() helper alistair23
                   ` (6 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

We want to consolidate the CPU socket FDT creation into a single helper.
'virt' and spike has the same code but sifive_u does not have cpu-map,
cluster and core subnodes.

These subnodes are present in other boards even in single socket configs
without NUMA.  This is a strong indicator that their presence doesn't
hurt a NUMA-less board like sifive_u.

Add these DTs to make the FDT standardization straightforward.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-9-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/sifive_u.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 9a791b36d6..a4265fed0f 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -109,6 +109,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
         "sifive,plic-1.0.0", "riscv,plic0"
     };
     g_autofree uint32_t *intc_phandles = g_new0(uint32_t, ms->smp.cpus);
+    g_autofree char *clust_name = NULL;
 
     fdt = ms->fdt = create_board_device_tree("SiFive HiFive Unleashed A00",
         "sifive,hifive-unleashed-a00", &s->fdt_size);
@@ -143,11 +144,17 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
         CLINT_TIMEBASE_FREQ);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
+    qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
+
+    clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", 0);
+    qemu_fdt_add_subnode(fdt, clust_name);
 
     for (cpu = ms->smp.cpus - 1; cpu >= 0; cpu--) {
         int cpu_phandle = phandle++;
         nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
         char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
+        g_autofree char *core_name = NULL;
+
         qemu_fdt_add_subnode(fdt, nodename);
         /* cpu 0 is the management hart that does not have mmu */
         if (cpu != 0) {
@@ -173,6 +180,11 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
         qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
         qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
         qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
+
+        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
+        qemu_fdt_add_subnode(fdt, core_name);
+        qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
+
         g_free(intc);
         g_free(nodename);
     }
-- 
2.54.0



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

* [PULL 79/83] hw/riscv: add fdt_create_cpu_socket_subnode() helper
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (77 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 78/83] hw/riscv/sifive_u.c: add cpu-map, cluster and core DTs alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 80/83] hw/riscv: add create_fdt_socket_cpus() alistair23
                   ` (5 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

Consolidate the '/cpus' FDT root node creation into a single place.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-10-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/riscv/fdt-common.h |  1 +
 hw/riscv/fdt-common.c         | 10 ++++++++++
 hw/riscv/sifive_u.c           |  7 +------
 hw/riscv/spike.c              |  7 +------
 hw/riscv/virt.c               | 11 +++--------
 5 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index 6e81d6cd6c..27020e69c6 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -18,4 +18,5 @@ void create_fdt_clint(void *fdt, hwaddr addr, uint64_t size,
 void create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
                              int socket_id, uint32_t *intc_phandles,
                              int num_harts, bool numa_enabled);
+void fdt_create_cpu_socket_subnode(void *fdt, uint64_t timebase_frequency);
 #endif
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index d2661ec389..02ac9ddcd8 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -83,3 +83,13 @@ void create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
         qemu_fdt_setprop_cell(fdt, clint_name, "numa-node-id", socket_id);
     }
 }
+
+void fdt_create_cpu_socket_subnode(void *fdt, uint64_t timebase_frequency)
+{
+    qemu_fdt_add_subnode(fdt, "/cpus");
+    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
+                          timebase_frequency);
+    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
+    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
+    qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
+}
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index a4265fed0f..27c1a74d99 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -139,12 +139,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
     create_fdt_socket_memory(fdt, memmap[SIFIVE_U_DEV_DRAM].base,
                              ms->ram_size, 0, false);
 
-    qemu_fdt_add_subnode(fdt, "/cpus");
-    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
-        CLINT_TIMEBASE_FREQ);
-    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
-    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
-    qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
+    fdt_create_cpu_socket_subnode(fdt, CLINT_TIMEBASE_FREQ);
 
     clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", 0);
     qemu_fdt_add_subnode(fdt, clust_name);
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index b15188fb07..ee8232f734 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -73,12 +73,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
             0x0, memmap[SPIKE_HTIF].base, 0x0, memmap[SPIKE_HTIF].size);
     }
 
-    qemu_fdt_add_subnode(fdt, "/cpus");
-    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
-        RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
-    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
-    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
-    qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
+    fdt_create_cpu_socket_subnode(fdt, RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
 
     for (socket = (riscv_socket_count(ms) - 1); socket >= 0; socket--) {
         g_autofree uint32_t *intc_phandles = g_new0(uint32_t,
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index b134f11266..6641b60131 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -694,14 +694,9 @@ static void create_fdt_sockets(RISCVVirtState *s,
     int socket_count = riscv_socket_count(ms);
     bool numa_enabled = riscv_numa_enabled(ms);
 
-    qemu_fdt_add_subnode(ms->fdt, "/cpus");
-    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "timebase-frequency",
-                          kvm_enabled() ?
-                          kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
-                          RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
-    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
-    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
-    qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map");
+    fdt_create_cpu_socket_subnode(ms->fdt,
+        kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
+                        RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
 
     intc_phandles = g_new0(uint32_t, ms->smp.cpus);
 
-- 
2.54.0



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

* [PULL 80/83] hw/riscv: add create_fdt_socket_cpus()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (78 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 79/83] hw/riscv: add fdt_create_cpu_socket_subnode() helper alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 81/83] hw/riscv/spike.c: use create_fdt_socket_cpus() alistair23
                   ` (4 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

Consolidate the creation of CPUs socket FDT in a helper that can be
shared across all boards.

The code was basically moved from the function with the same name from
'virt.c', with additional bits to create the cluster subnode beforehand.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-11-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/riscv/fdt-common.h |  7 +++
 hw/riscv/fdt-common.c         | 74 +++++++++++++++++++++++++++++++
 hw/riscv/virt.c               | 83 +++--------------------------------
 3 files changed, 87 insertions(+), 77 deletions(-)

diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index 27020e69c6..3af9d5c3fd 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -9,6 +9,8 @@
 #ifndef RISCV_VIRT_FDT_H
 #define RISCV_VIRT_FDT_H
 
+#include "target/riscv/cpu.h"
+
 void *create_board_device_tree(const char *model, const char *compatible,
                                int *fdt_size);
 void create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
@@ -19,4 +21,9 @@ void create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
                              int socket_id, uint32_t *intc_phandles,
                              int num_harts, bool numa_enabled);
 void fdt_create_cpu_socket_subnode(void *fdt, uint64_t timebase_frequency);
+void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
+                            int socket_id, int num_harts_socket,
+                            int socket_hartid_base, uint32_t *phandle,
+                            uint32_t *intc_phandles, bool numa_enabled,
+                            bool is_32_bit);
 #endif
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index 02ac9ddcd8..6c795409a4 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -93,3 +93,77 @@ void fdt_create_cpu_socket_subnode(void *fdt, uint64_t timebase_frequency)
     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
     qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
 }
+
+void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
+                            int socket_id, int num_harts_socket,
+                            int socket_hartid_base, uint32_t *phandle,
+                            uint32_t *intc_phandles, bool numa_enabled,
+                            bool is_32_bit)
+{
+    g_autofree char *clust_name = NULL;
+    uint32_t cpu_phandle;
+
+    clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket_id);
+    qemu_fdt_add_subnode(fdt, clust_name);
+
+    for (int cpu = num_harts_socket - 1; cpu >= 0; cpu--) {
+        RISCVCPU *cpu_ptr = &socket_harts[cpu];
+        int8_t satp_mode_max = cpu_ptr->cfg.max_satp_mode;
+        g_autofree char *cpu_name = NULL;
+        g_autofree char *core_name = NULL;
+        g_autofree char *intc_name = NULL;
+
+        cpu_phandle = (*phandle)++;
+
+        cpu_name = g_strdup_printf("/cpus/cpu@%d", socket_hartid_base + cpu);
+        qemu_fdt_add_subnode(fdt, cpu_name);
+
+        if (satp_mode_max != -1) {
+            g_autofree char *sv_name = NULL;
+            sv_name = g_strdup_printf("riscv,%s",
+                                      satp_mode_str(satp_mode_max, is_32_bit));
+            qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", sv_name);
+        }
+        riscv_isa_write_fdt(cpu_ptr, fdt, cpu_name);
+
+        if (cpu_ptr->cfg.ext_zicbom) {
+            qemu_fdt_setprop_cell(fdt, cpu_name, "riscv,cbom-block-size",
+                                  cpu_ptr->cfg.cbom_blocksize);
+        }
+
+        if (cpu_ptr->cfg.ext_zicboz) {
+            qemu_fdt_setprop_cell(fdt, cpu_name, "riscv,cboz-block-size",
+                                  cpu_ptr->cfg.cboz_blocksize);
+        }
+
+        if (cpu_ptr->cfg.ext_zicbop) {
+            qemu_fdt_setprop_cell(fdt, cpu_name, "riscv,cbop-block-size",
+                                  cpu_ptr->cfg.cbop_blocksize);
+        }
+
+        qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
+        qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
+        qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
+                              socket_hartid_base + cpu);
+        qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
+        if (numa_enabled) {
+            qemu_fdt_setprop_cell(fdt, cpu_name, "numa-node-id", socket_id);
+        }
+        qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
+
+        intc_phandles[cpu] = (*phandle)++;
+
+        intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
+        qemu_fdt_add_subnode(fdt, intc_name);
+        qemu_fdt_setprop_cell(fdt, intc_name, "phandle",
+                              intc_phandles[cpu]);
+        qemu_fdt_setprop_string(fdt, intc_name, "compatible",
+                                "riscv,cpu-intc");
+        qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
+        qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
+
+        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
+        qemu_fdt_add_subnode(fdt, core_name);
+        qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
+    }
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 6641b60131..33775a61fd 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -231,77 +231,6 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
                            0x1800, 0, 0, 0x7);
 }
 
-static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
-                                   char *clust_name, uint32_t *phandle,
-                                   uint32_t *intc_phandles)
-{
-    int cpu;
-    uint32_t cpu_phandle;
-    MachineState *ms = MACHINE(s);
-    bool is_32_bit = riscv_is_32bit(&s->soc[0]);
-
-    for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
-        RISCVCPU *cpu_ptr = &s->soc[socket].harts[cpu];
-        int8_t satp_mode_max = cpu_ptr->cfg.max_satp_mode;
-        g_autofree char *cpu_name = NULL;
-        g_autofree char *core_name = NULL;
-        g_autofree char *intc_name = NULL;
-        g_autofree char *sv_name = NULL;
-
-        cpu_phandle = (*phandle)++;
-
-        cpu_name = g_strdup_printf("/cpus/cpu@%d",
-            s->soc[socket].hartid_base + cpu);
-        qemu_fdt_add_subnode(ms->fdt, cpu_name);
-
-        if (satp_mode_max != -1) {
-            sv_name = g_strdup_printf("riscv,%s",
-                                      satp_mode_str(satp_mode_max, is_32_bit));
-            qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", sv_name);
-        }
-
-        riscv_isa_write_fdt(cpu_ptr, ms->fdt, cpu_name);
-
-        if (cpu_ptr->cfg.ext_zicbom) {
-            qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbom-block-size",
-                                  cpu_ptr->cfg.cbom_blocksize);
-        }
-
-        if (cpu_ptr->cfg.ext_zicboz) {
-            qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cboz-block-size",
-                                  cpu_ptr->cfg.cboz_blocksize);
-        }
-
-        if (cpu_ptr->cfg.ext_zicbop) {
-            qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbop-block-size",
-                                  cpu_ptr->cfg.cbop_blocksize);
-        }
-
-        qemu_fdt_setprop_string(ms->fdt, cpu_name, "compatible", "riscv");
-        qemu_fdt_setprop_string(ms->fdt, cpu_name, "status", "okay");
-        qemu_fdt_setprop_cell(ms->fdt, cpu_name, "reg",
-            s->soc[socket].hartid_base + cpu);
-        qemu_fdt_setprop_string(ms->fdt, cpu_name, "device_type", "cpu");
-        riscv_socket_fdt_write_id(ms, cpu_name, socket);
-        qemu_fdt_setprop_cell(ms->fdt, cpu_name, "phandle", cpu_phandle);
-
-        intc_phandles[cpu] = (*phandle)++;
-
-        intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
-        qemu_fdt_add_subnode(ms->fdt, intc_name);
-        qemu_fdt_setprop_cell(ms->fdt, intc_name, "phandle",
-            intc_phandles[cpu]);
-        qemu_fdt_setprop_string(ms->fdt, intc_name, "compatible",
-            "riscv,cpu-intc");
-        qemu_fdt_setprop(ms->fdt, intc_name, "interrupt-controller", NULL, 0);
-        qemu_fdt_setprop_cell(ms->fdt, intc_name, "#interrupt-cells", 1);
-
-        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
-        qemu_fdt_add_subnode(ms->fdt, core_name);
-        qemu_fdt_setprop_cell(ms->fdt, core_name, "cpu", cpu_phandle);
-    }
-}
-
 static void create_fdt_socket_aclint(RISCVVirtState *s,
                                      int socket,
                                      uint32_t *intc_phandles)
@@ -693,6 +622,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
     g_autofree uint32_t *intc_phandles = NULL;
     int socket_count = riscv_socket_count(ms);
     bool numa_enabled = riscv_numa_enabled(ms);
+    bool is_32_bit = riscv_is_32bit(&s->soc[0]);
 
     fdt_create_cpu_socket_subnode(ms->fdt,
         kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
@@ -702,18 +632,17 @@ static void create_fdt_sockets(RISCVVirtState *s,
 
     phandle_pos = ms->smp.cpus;
     for (socket = (socket_count - 1); socket >= 0; socket--) {
-        g_autofree char *clust_name = NULL;
         hwaddr memaddr = s->memmap[VIRT_DRAM].base +
                          riscv_socket_mem_offset(ms, socket);
         uint64_t memsize = riscv_socket_mem_size(ms, socket);
 
         phandle_pos -= s->soc[socket].num_harts;
 
-        clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
-        qemu_fdt_add_subnode(ms->fdt, clust_name);
-
-        create_fdt_socket_cpus(s, socket, clust_name, phandle,
-                               &intc_phandles[phandle_pos]);
+        create_fdt_socket_cpus(ms->fdt, (&s->soc[socket])->harts, socket,
+                               s->soc[socket].num_harts,
+                               s->soc[socket].hartid_base,
+                               phandle, &intc_phandles[phandle_pos],
+                               numa_enabled, is_32_bit);
 
         create_fdt_socket_memory(ms->fdt, memaddr, memsize,
                                  socket, riscv_numa_enabled(ms));
-- 
2.54.0



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

* [PULL 81/83] hw/riscv/spike.c: use create_fdt_socket_cpus()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (79 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 80/83] hw/riscv: add create_fdt_socket_cpus() alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 82/83] hw/riscv/fdt_common.c: create create_fdt_socket_cpu_internal() alistair23
                   ` (3 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

Use the new FDT helper to create FDTs for the CPU sockets.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-12-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/spike.c | 54 +++++++-----------------------------------------
 1 file changed, 7 insertions(+), 47 deletions(-)

diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index ee8232f734..4e60724c14 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -56,11 +56,9 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
     void *fdt;
     int fdt_size;
     unsigned long clint_addr;
-    int cpu, socket;
+    int socket;
     MachineState *ms = MACHINE(s);
-    uint32_t cpu_phandle, phandle = 1;
-    char *clust_name;
-    char *core_name, *cpu_name, *intc_name;
+    uint32_t phandle = 1;
     bool numa_enabled = riscv_numa_enabled(ms);
 
     fdt = ms->fdt = create_board_device_tree("ucbbar,spike-bare,qemu",
@@ -82,48 +80,11 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
                          riscv_socket_mem_offset(ms, socket);
         uint64_t memsize =  riscv_socket_mem_size(ms, socket);
 
-        clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
-        qemu_fdt_add_subnode(fdt, clust_name);
-
-        for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
-            cpu_phandle = phandle++;
-
-            cpu_name = g_strdup_printf("/cpus/cpu@%d",
-                s->soc[socket].hartid_base + cpu);
-            qemu_fdt_add_subnode(fdt, cpu_name);
-            if (is_32_bit) {
-                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv32");
-            } else {
-                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv48");
-            }
-            riscv_isa_write_fdt(&s->soc[socket].harts[cpu], fdt, cpu_name);
-            qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
-            qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
-            qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
-                s->soc[socket].hartid_base + cpu);
-            qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
-            riscv_socket_fdt_write_id(ms, cpu_name, socket);
-            qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
-
-            intc_phandles[cpu] = phandle++;
-
-            intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
-            qemu_fdt_add_subnode(fdt, intc_name);
-            qemu_fdt_setprop_cell(fdt, intc_name, "phandle",
-                                  intc_phandles[cpu]);
-            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
-                "riscv,cpu-intc");
-            qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
-            qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
-
-            core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
-            qemu_fdt_add_subnode(fdt, core_name);
-            qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
-
-            g_free(core_name);
-            g_free(intc_name);
-            g_free(cpu_name);
-        }
+        create_fdt_socket_cpus(fdt, (&s->soc[socket])->harts, socket,
+                               s->soc[socket].num_harts,
+                               s->soc[socket].hartid_base,
+                               &phandle, intc_phandles, numa_enabled,
+                               is_32_bit);
 
         create_fdt_socket_memory(fdt, memaddr, memsize, socket,
                                  riscv_numa_enabled(ms));
@@ -133,7 +94,6 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
         create_fdt_socket_clint(fdt, clint_addr, memmap[SPIKE_CLINT].size,
                                 socket, intc_phandles,
                                 s->soc[socket].num_harts, numa_enabled);
-        g_free(clust_name);
     }
 
     riscv_socket_fdt_write_distance_matrix(ms);
-- 
2.54.0



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

* [PULL 82/83] hw/riscv/fdt_common.c: create create_fdt_socket_cpu_internal()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (80 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 81/83] hw/riscv/spike.c: use create_fdt_socket_cpus() alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 10:05 ` [PULL 83/83] hw/riscv: add create_fdt_socket_cpu_sifive() alistair23
                   ` (2 subsequent siblings)
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

The sifive_u board does not share the same CPU socket FDT bits from the
other boards.  In particular the riscv,isa creation is done using either
CPU0 from soc.e_cpus.harts, and for all other CPUs soc.u_cups.harts is
used.

It would be too cumbersome to add all these details in the common code
so we're going to add a special sifive_u only helper that shares the
common bits with the common helper used by the other boards.

create_fdt_socket_cpu_internal() contains the common bits shared between
the sifive_u board and the rest.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-13-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/fdt-common.c | 108 +++++++++++++++++++++++++-----------------
 1 file changed, 65 insertions(+), 43 deletions(-)

diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index 6c795409a4..70168ad657 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -94,28 +94,29 @@ void fdt_create_cpu_socket_subnode(void *fdt, uint64_t timebase_frequency)
     qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
 }
 
-void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
-                            int socket_id, int num_harts_socket,
-                            int socket_hartid_base, uint32_t *phandle,
-                            uint32_t *intc_phandles, bool numa_enabled,
-                            bool is_32_bit)
+static void
+create_fdt_socket_cpu_internal(void *fdt, char *clust_name, RISCVCPU *cpu_ptr,
+                               int cpu, int socket_id, int socket_hartid_base,
+                               uint32_t *phandle, uint32_t *intc_phandles,
+                               bool numa_enabled, bool is_32_bit)
 {
-    g_autofree char *clust_name = NULL;
-    uint32_t cpu_phandle;
-
-    clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket_id);
-    qemu_fdt_add_subnode(fdt, clust_name);
-
-    for (int cpu = num_harts_socket - 1; cpu >= 0; cpu--) {
-        RISCVCPU *cpu_ptr = &socket_harts[cpu];
+    g_autofree char *cpu_name = NULL;
+    g_autofree char *core_name = NULL;
+    g_autofree char *intc_name = NULL;
+    uint32_t cpu_phandle = (*phandle)++;
+    bool is_sifive_u = cpu_ptr == NULL;
+
+    cpu_name = g_strdup_printf("/cpus/cpu@%d", socket_hartid_base + cpu);
+
+    /*
+     * The sifive_u board has an exclusive satp and riscv,isa
+     * schema that can't be shared with other boards, so part
+     * of the CPU FDT creation (i.e. the /cpus/cpu@N subnode)
+     * is still being done by the board.
+     */
+    if (!is_sifive_u) {
         int8_t satp_mode_max = cpu_ptr->cfg.max_satp_mode;
-        g_autofree char *cpu_name = NULL;
-        g_autofree char *core_name = NULL;
-        g_autofree char *intc_name = NULL;
-
-        cpu_phandle = (*phandle)++;
 
-        cpu_name = g_strdup_printf("/cpus/cpu@%d", socket_hartid_base + cpu);
         qemu_fdt_add_subnode(fdt, cpu_name);
 
         if (satp_mode_max != -1) {
@@ -140,30 +141,51 @@ void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
             qemu_fdt_setprop_cell(fdt, cpu_name, "riscv,cbop-block-size",
                                   cpu_ptr->cfg.cbop_blocksize);
         }
+    }
 
-        qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
-        qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
-        qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
-                              socket_hartid_base + cpu);
-        qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
-        if (numa_enabled) {
-            qemu_fdt_setprop_cell(fdt, cpu_name, "numa-node-id", socket_id);
-        }
-        qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
-
-        intc_phandles[cpu] = (*phandle)++;
-
-        intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
-        qemu_fdt_add_subnode(fdt, intc_name);
-        qemu_fdt_setprop_cell(fdt, intc_name, "phandle",
-                              intc_phandles[cpu]);
-        qemu_fdt_setprop_string(fdt, intc_name, "compatible",
-                                "riscv,cpu-intc");
-        qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
-        qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
-
-        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
-        qemu_fdt_add_subnode(fdt, core_name);
-        qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
+    qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
+    qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
+    qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
+                          socket_hartid_base + cpu);
+    qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
+    if (numa_enabled) {
+        qemu_fdt_setprop_cell(fdt, cpu_name, "numa-node-id", socket_id);
+    }
+    qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
+
+    intc_phandles[cpu] = (*phandle)++;
+
+    intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
+    qemu_fdt_add_subnode(fdt, intc_name);
+    qemu_fdt_setprop_cell(fdt, intc_name, "phandle",
+                          intc_phandles[cpu]);
+    qemu_fdt_setprop_string(fdt, intc_name, "compatible",
+                            "riscv,cpu-intc");
+    qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
+    qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
+
+    core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
+    qemu_fdt_add_subnode(fdt, core_name);
+    qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
+}
+
+void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
+                            int socket_id, int num_harts_socket,
+                            int socket_hartid_base, uint32_t *phandle,
+                            uint32_t *intc_phandles, bool numa_enabled,
+                            bool is_32_bit)
+{
+    g_autofree char *clust_name = NULL;
+
+    clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket_id);
+    qemu_fdt_add_subnode(fdt, clust_name);
+
+    for (int cpu = num_harts_socket - 1; cpu >= 0; cpu--) {
+        RISCVCPU *cpu_ptr = &socket_harts[cpu];
+
+        create_fdt_socket_cpu_internal(fdt, clust_name, cpu_ptr, cpu,
+                                       socket_id, socket_hartid_base,
+                                       phandle, intc_phandles, numa_enabled,
+                                       is_32_bit);
     }
 }
-- 
2.54.0



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

* [PULL 83/83] hw/riscv: add create_fdt_socket_cpu_sifive()
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (81 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 82/83] hw/riscv/fdt_common.c: create create_fdt_socket_cpu_internal() alistair23
@ 2026-06-16 10:05 ` alistair23
  2026-06-16 17:27 ` [PULL 00/83] riscv-to-apply queue Stefan Hajnoczi
  2026-06-16 19:49 ` Michael Tokarev
  84 siblings, 0 replies; 87+ messages in thread
From: alistair23 @ 2026-06-16 10:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>

This sifive_u only helper shares DT code with other boards.  The idea is
to reduce code repetition while keeping sifive_u characteristics in
place.

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615203734.954428-14-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/riscv/fdt-common.h |  4 ++++
 hw/riscv/fdt-common.c         | 11 +++++++++++
 hw/riscv/sifive_u.c           | 24 +++---------------------
 3 files changed, 18 insertions(+), 21 deletions(-)

diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index 3af9d5c3fd..2d6b9a5d03 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -26,4 +26,8 @@ void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
                             int socket_hartid_base, uint32_t *phandle,
                             uint32_t *intc_phandles, bool numa_enabled,
                             bool is_32_bit);
+void create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
+                                  int cpu_id, int socket_id,
+                                  int socket_hartid_base, uint32_t *phandle,
+                                  uint32_t *intc_phandles);
 #endif
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index 70168ad657..b27ff13bca 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -189,3 +189,14 @@ void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
                                        is_32_bit);
     }
 }
+
+void
+create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
+                             int cpu_id, int socket_id,
+                             int socket_hartid_base, uint32_t *phandle,
+                             uint32_t *intc_phandles)
+{
+    create_fdt_socket_cpu_internal(fdt, clust_name, NULL, cpu_id,
+                                   socket_id, socket_hartid_base,
+                                   phandle, intc_phandles, false, false);
+}
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 27c1a74d99..0c6e4204cb 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -145,12 +145,9 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
     qemu_fdt_add_subnode(fdt, clust_name);
 
     for (cpu = ms->smp.cpus - 1; cpu >= 0; cpu--) {
-        int cpu_phandle = phandle++;
         nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
-        char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
-        g_autofree char *core_name = NULL;
-
         qemu_fdt_add_subnode(fdt, nodename);
+
         /* cpu 0 is the management hart that does not have mmu */
         if (cpu != 0) {
             if (is_32_bit) {
@@ -162,25 +159,10 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
         } else {
             riscv_isa_write_fdt(&s->soc.e_cpus.harts[0], fdt, nodename);
         }
-        qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
-        qemu_fdt_setprop_string(fdt, nodename, "status", "okay");
-        qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu);
-        qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
-        qemu_fdt_setprop_cell(fdt, nodename, "phandle", cpu_phandle);
-
-        intc_phandles[cpu] = phandle++;
-
-        qemu_fdt_add_subnode(fdt, intc);
-        qemu_fdt_setprop_cell(fdt, intc, "phandle", intc_phandles[cpu]);
-        qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
-        qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
-        qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
 
-        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
-        qemu_fdt_add_subnode(fdt, core_name);
-        qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
+        create_fdt_socket_cpu_sifive(fdt, clust_name, cpu, 0, 0,
+                                     &phandle, intc_phandles);
 
-        g_free(intc);
         g_free(nodename);
     }
 
-- 
2.54.0



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

* Re: [PULL 00/83] riscv-to-apply queue
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (82 preceding siblings ...)
  2026-06-16 10:05 ` [PULL 83/83] hw/riscv: add create_fdt_socket_cpu_sifive() alistair23
@ 2026-06-16 17:27 ` Stefan Hajnoczi
  2026-06-16 19:49 ` Michael Tokarev
  84 siblings, 0 replies; 87+ messages in thread
From: Stefan Hajnoczi @ 2026-06-16 17:27 UTC (permalink / raw)
  To: alistair23; +Cc: qemu-devel, alistair23, Alistair Francis

[-- 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] 87+ messages in thread

* Re: [PULL 00/83] riscv-to-apply queue
  2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
                   ` (83 preceding siblings ...)
  2026-06-16 17:27 ` [PULL 00/83] riscv-to-apply queue Stefan Hajnoczi
@ 2026-06-16 19:49 ` Michael Tokarev
  2026-06-16 20:12   ` Daniel Henrique Barboza
  84 siblings, 1 reply; 87+ messages in thread
From: Michael Tokarev @ 2026-06-16 19:49 UTC (permalink / raw)
  To: alistair23, qemu-devel
  Cc: Alistair Francis, qemu-stable, Daniel Henrique Barboza,
	Anton Johansson

On 16.06.2026 13:04, alistair23@gmail.com wrote:
> From: Alistair Francis <alistair.francis@wdc.com>
> 
> The following changes since commit 2f28d34ea0aead9830478cd1d3d0dd9d9191d82e:
> 
>    Merge tag 'pull-tcg-20260612' of https://gitlab.com/rth7680/qemu into staging (2026-06-13 14:02:34 -0400)
> 
> are available in the Git repository at:
> 
>    https://github.com/alistair23/qemu.git tags/pull-riscv-to-apply-20260616
> 
> for you to fetch changes up to e968e487acf082279118667f495a3f4275a59d59:
> 
>    hw/riscv: add create_fdt_socket_cpu_sifive() (2026-06-16 20:01:11 +1000)
> 
> ----------------------------------------------------------------
> RISC-V PR for 11.1
> 
> * Disable svpbmt if satp_mode is less then sv39
> * Fix PMP address alignment
> * Mstatus write bug fixes
> * Add 'cbo' insns to disassembler
> * Do not hide Sstc CSRs from gdbstub
> * Reject Svinval instructions in U-mode
> * Save opcode before zicbo helpers
> * Fault with reserved PTE.PBMT val
> * Allow LOAD_ADDR_MIS promotion to AMO fault
> * Make riscv cpu.h target independent
> * Add PMA access fault
> * Disable svnapot if satp_mode is less then sv39
> * Fix disassembler inst_length calculation
> * Add RISC-V big-endian target support
> * Add the implied rules for G and B extensions
> * Print privilege level and ELP in riscv_cpu_dump_state
> * Improve alignment in riscv_cpu_dump_state
> * Mask vxrm csrw write to the low 2 bits
> * Reorder Smrnmi CPU fields above CPU reset line
> * Supplement cpu topology arguments
> * Don't insert DDT cache in Bare mode
> * Fix 'iommu-map' FDT entry
> * Fix mstatus.FS dirty tracking for FP exception-raising instructions
> * Enable `mnret` disassembly
> * Add support for K230 board
> * FDT creation helpers
> 
> ----------------------------------------------------------------
> Abhigyan Kumar (1):
>        target/riscv: mask vxrm csrw write to the low 2 bits
> 
> Anton Blanchard (2):
>        target/riscv: Print privilege level and ELP in riscv_cpu_dump_state
>        target/riscv: Improve alignment in riscv_cpu_dump_state
> 
> Anton Johansson (27):
>        target/riscv: Fix size of gpr and gprh
>        target/riscv: Fix size of vector CSRs
>        target/riscv: Fix size of pc, load_[val|res]
>        target/riscv: Fix size of frm and fflags
>        target/riscv: Fix size of badaddr and bins
>        target/riscv: Fix size of guest_phys_fault_addr
>        target/riscv: Fix size of priv_ver and vext_ver
>        target/riscv: Fix size of retxh
>        target/riscv: Fix size of ssp
>        target/riscv: Fix size of excp_uw2
>        target/riscv: Fix size of sw_check_code
>        target/riscv: Fix size of priv
>        target/riscv: Fix size of gei fields
>        target/riscv: Fix size of [m|s|vs]iselect fields
>        target/riscv: Fix arguments to board IMSIC emulation callbacks
>        target/riscv: Fix size of irq_overflow_left
>        target/riscv: Indent PMUFixedCtrState correctly
>        target/riscv: Replace target_ulong in riscv_cpu_get_trap_name()
>        target/riscv: Replace target_ulong in riscv_ctr_add_entry()
>        target/riscv: Fix size of trigger data
>        target/riscv: Fix size of mseccfg
>        target/riscv: Move debug.h include away from cpu.h
>        target/riscv: Move CSR declarations to separate csr.h header
>        target/riscv: Introduce externally facing CSR access functions
>        target/riscv: Make pmp.h target_ulong agnostic
>        target/riscv: Pass address as uint64_t in cpu_set_exception_base()
>        target/riscv: Fix pmp.h/cpu.h circular inclusion
> 
> Chao Liu (5):
>        target/riscv: add thead-c908 cpu support
>        hw/riscv: add k230 board initial support
>        hw/watchdog: add k230 watchdog initial support
>        tests/qtest: add test for K230 watchdog
>        docs/system/riscv: add documentation for k230 machine
> 
> Daniel Henrique Barboza (24):
>        target/riscv/tcg: disable svpbmt if satp_mode < sv39
>        target/riscv/csr.c: do not allow mstatus MPV/GVA writes
>        target/riscv/csr.c: fix mstatus.UXL reserved value
>        disas/riscv.c: add 'cbo' insns to disassembler
>        target/riscv/insn_trans/trans_rvzicbo.c.inc: save opcode before helpers
>        target/riscv/cpu_helper.c: fault with reserved PTE.PBMT val
>        target/riscv/cpu_helper.c: allow LOAD_ADDR_MIS promotion to AMO fault
>        target/riscv/cpu_helper.c: add PMA access fault
>        target/riscv/tcg: disable svnapot if satp_mode < sv39
>        disas/riscv.c: fix inst_length()
>        hw/riscv/virt.c: fix 'iommu-map' FDT entry
>        hw/riscv/sifive_u.c: add a FDT phandle to cpu-intc
>        hw/riscv: add fdt-common helper
>        hw/riscv/numa: make numa_enabled() public
>        hw/riscv: add create_fdt_socket_memory() helper
>        hw/riscv/sifive_u.c: add intc_phandles array
>        hw/riscv/spike.c: add intc_phandles array
>        hw/riscv: add create_fdt_clint() helper
>        hw/riscv/sifive_u.c: add cpu-map, cluster and core DTs
>        hw/riscv: add fdt_create_cpu_socket_subnode() helper
>        hw/riscv: add create_fdt_socket_cpus()
>        hw/riscv/spike.c: use create_fdt_socket_cpus()
>        hw/riscv/fdt_common.c: create create_fdt_socket_cpu_internal()
>        hw/riscv: add create_fdt_socket_cpu_sifive()
> 
> Djordje Todorovic (6):
>        target/riscv: Implement runtime data endianness via MSTATUS bits
>        target/riscv: Fix page table walk endianness for big-endian harts
>        target/riscv: Add big-endian CPU configuration field and reset logic
>        hw/riscv/boot: Honour data endianness
>        target/riscv: Expose and document the CPU 'big-endian' property
>        tests/functional: Add RISC-V endianness test
> 
> Frank Chang (2):
>        target/riscv: Add standard B extension implied rule
>        target/riscv: Reorder Smrnmi CPU fields above CPU reset line
> 
> Jay Chang (4):
>        target/riscv: Align pmp size to pmp-granularity
>        target/riscv: Improve PMP address alignment readability
>        hw/riscv: Don't insert DDT cache in Bare mode
>        hw/riscv: Refactor riscv_iommu_ctx_put() for Bare mode handling
> 
> Jim Shu (1):
>        target/riscv: Add the implied rule for G extension
> 
> Max Chou (2):
>        target/riscv: Set mstatus.FS dirty when scalar FP raises exceptions
>        target/riscv: rvv: Set mstatus.FS dirty when vector FP raises exceptions
> 
> Philippe Mathieu-Daudé (5):
>        target/riscv: Initialize DisasContext::mo_endian once
>        target/riscv: De-indent some code in get_physical_address()
>        target/riscv: Remove target_ulong use in get_physical_address()
>        hw/riscv/boot: Rewrite setup_rom_reset_vec() using load/store API
>        hw/riscv/boot: Replace cpu_to_le32() -> const_le32()
> 
> Xuemei Liu (1):
>        hw/riscv/numa.c: Supplement cpu topology arguments
> 
> Zephyr Li (2):
>        target/riscv: Do not hide Sstc CSRs from gdbstub
>        target/riscv: Reject Svinval instructions in U-mode
> 
> imaginos (1):
>        disas/riscv: enable `mnret` disassembly

Hi!

Is there anything here worth picking up for the stable series?
The "target/riscv/cpu_helper.c: allow LOAD_ADDR_MIS promotion to
AMO fault" has Cc: stable, so I picked it up.

Thanks,

/mjt


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

* Re: [PULL 00/83] riscv-to-apply queue
  2026-06-16 19:49 ` Michael Tokarev
@ 2026-06-16 20:12   ` Daniel Henrique Barboza
  0 siblings, 0 replies; 87+ messages in thread
From: Daniel Henrique Barboza @ 2026-06-16 20:12 UTC (permalink / raw)
  To: Michael Tokarev, alistair23, qemu-devel
  Cc: Alistair Francis, qemu-stable, Anton Johansson

Hi Michael!


On 6/16/2026 4:49 PM, Michael Tokarev wrote:
> On 16.06.2026 13:04, alistair23@gmail.com wrote:
>> From: Alistair Francis <alistair.francis@wdc.com>
>>
>> The following changes since commit 2f28d34ea0aead9830478cd1d3d0dd9d9191d82e:
>>
>>    Merge tag 'pull-tcg-20260612' of https://gitlab.com/rth7680/qemu into staging (2026-06-13 14:02:34 -0400)
>>
>> are available in the Git repository at:
>>
>>    https://github.com/alistair23/qemu.git tags/pull-riscv-to-apply-20260616
>>
>> for you to fetch changes up to e968e487acf082279118667f495a3f4275a59d59:
>>
>>    hw/riscv: add create_fdt_socket_cpu_sifive() (2026-06-16 20:01:11 +1000)
>>
>> ----------------------------------------------------------------
>> RISC-V PR for 11.1
>>
>> * Disable svpbmt if satp_mode is less then sv39
>> * Fix PMP address alignment
>> * Mstatus write bug fixes
>> * Add 'cbo' insns to disassembler
>> * Do not hide Sstc CSRs from gdbstub
>> * Reject Svinval instructions in U-mode
>> * Save opcode before zicbo helpers
>> * Fault with reserved PTE.PBMT val
>> * Allow LOAD_ADDR_MIS promotion to AMO fault
>> * Make riscv cpu.h target independent
>> * Add PMA access fault
>> * Disable svnapot if satp_mode is less then sv39
>> * Fix disassembler inst_length calculation
>> * Add RISC-V big-endian target support
>> * Add the implied rules for G and B extensions
>> * Print privilege level and ELP in riscv_cpu_dump_state
>> * Improve alignment in riscv_cpu_dump_state
>> * Mask vxrm csrw write to the low 2 bits
>> * Reorder Smrnmi CPU fields above CPU reset line
>> * Supplement cpu topology arguments
>> * Don't insert DDT cache in Bare mode
>> * Fix 'iommu-map' FDT entry
>> * Fix mstatus.FS dirty tracking for FP exception-raising instructions
>> * Enable `mnret` disassembly
>> * Add support for K230 board
>> * FDT creation helpers
>>
>> ----------------------------------------------------------------
>> Abhigyan Kumar (1):
>>        target/riscv: mask vxrm csrw write to the low 2 bits
>>
>> Anton Blanchard (2):
>>        target/riscv: Print privilege level and ELP in riscv_cpu_dump_state
>>        target/riscv: Improve alignment in riscv_cpu_dump_state
>>
>> Anton Johansson (27):
>>        target/riscv: Fix size of gpr and gprh
>>        target/riscv: Fix size of vector CSRs
>>        target/riscv: Fix size of pc, load_[val|res]
>>        target/riscv: Fix size of frm and fflags
>>        target/riscv: Fix size of badaddr and bins
>>        target/riscv: Fix size of guest_phys_fault_addr
>>        target/riscv: Fix size of priv_ver and vext_ver
>>        target/riscv: Fix size of retxh
>>        target/riscv: Fix size of ssp
>>        target/riscv: Fix size of excp_uw2
>>        target/riscv: Fix size of sw_check_code
>>        target/riscv: Fix size of priv
>>        target/riscv: Fix size of gei fields
>>        target/riscv: Fix size of [m|s|vs]iselect fields
>>        target/riscv: Fix arguments to board IMSIC emulation callbacks
>>        target/riscv: Fix size of irq_overflow_left
>>        target/riscv: Indent PMUFixedCtrState correctly
>>        target/riscv: Replace target_ulong in riscv_cpu_get_trap_name()
>>        target/riscv: Replace target_ulong in riscv_ctr_add_entry()
>>        target/riscv: Fix size of trigger data
>>        target/riscv: Fix size of mseccfg
>>        target/riscv: Move debug.h include away from cpu.h
>>        target/riscv: Move CSR declarations to separate csr.h header
>>        target/riscv: Introduce externally facing CSR access functions
>>        target/riscv: Make pmp.h target_ulong agnostic
>>        target/riscv: Pass address as uint64_t in cpu_set_exception_base()
>>        target/riscv: Fix pmp.h/cpu.h circular inclusion
>>
>> Chao Liu (5):
>>        target/riscv: add thead-c908 cpu support
>>        hw/riscv: add k230 board initial support
>>        hw/watchdog: add k230 watchdog initial support
>>        tests/qtest: add test for K230 watchdog
>>        docs/system/riscv: add documentation for k230 machine
>>
>> Daniel Henrique Barboza (24):
>>        target/riscv/tcg: disable svpbmt if satp_mode < sv39
>>        target/riscv/csr.c: do not allow mstatus MPV/GVA writes
>>        target/riscv/csr.c: fix mstatus.UXL reserved value
>>        disas/riscv.c: add 'cbo' insns to disassembler
>>        target/riscv/insn_trans/trans_rvzicbo.c.inc: save opcode before helpers
>>        target/riscv/cpu_helper.c: fault with reserved PTE.PBMT val
>>        target/riscv/cpu_helper.c: allow LOAD_ADDR_MIS promotion to AMO fault
>>        target/riscv/cpu_helper.c: add PMA access fault
>>        target/riscv/tcg: disable svnapot if satp_mode < sv39
>>        disas/riscv.c: fix inst_length()
>>        hw/riscv/virt.c: fix 'iommu-map' FDT entry
>>        hw/riscv/sifive_u.c: add a FDT phandle to cpu-intc
>>        hw/riscv: add fdt-common helper
>>        hw/riscv/numa: make numa_enabled() public
>>        hw/riscv: add create_fdt_socket_memory() helper
>>        hw/riscv/sifive_u.c: add intc_phandles array
>>        hw/riscv/spike.c: add intc_phandles array
>>        hw/riscv: add create_fdt_clint() helper
>>        hw/riscv/sifive_u.c: add cpu-map, cluster and core DTs
>>        hw/riscv: add fdt_create_cpu_socket_subnode() helper
>>        hw/riscv: add create_fdt_socket_cpus()
>>        hw/riscv/spike.c: use create_fdt_socket_cpus()
>>        hw/riscv/fdt_common.c: create create_fdt_socket_cpu_internal()
>>        hw/riscv: add create_fdt_socket_cpu_sifive()
>>
>> Djordje Todorovic (6):
>>        target/riscv: Implement runtime data endianness via MSTATUS bits
>>        target/riscv: Fix page table walk endianness for big-endian harts
>>        target/riscv: Add big-endian CPU configuration field and reset logic
>>        hw/riscv/boot: Honour data endianness
>>        target/riscv: Expose and document the CPU 'big-endian' property
>>        tests/functional: Add RISC-V endianness test
>>
>> Frank Chang (2):
>>        target/riscv: Add standard B extension implied rule
>>        target/riscv: Reorder Smrnmi CPU fields above CPU reset line
>>
>> Jay Chang (4):
>>        target/riscv: Align pmp size to pmp-granularity
>>        target/riscv: Improve PMP address alignment readability
>>        hw/riscv: Don't insert DDT cache in Bare mode
>>        hw/riscv: Refactor riscv_iommu_ctx_put() for Bare mode handling
>>
>> Jim Shu (1):
>>        target/riscv: Add the implied rule for G extension
>>
>> Max Chou (2):
>>        target/riscv: Set mstatus.FS dirty when scalar FP raises exceptions
>>        target/riscv: rvv: Set mstatus.FS dirty when vector FP raises exceptions
>>
>> Philippe Mathieu-Daudé (5):
>>        target/riscv: Initialize DisasContext::mo_endian once
>>        target/riscv: De-indent some code in get_physical_address()
>>        target/riscv: Remove target_ulong use in get_physical_address()
>>        hw/riscv/boot: Rewrite setup_rom_reset_vec() using load/store API
>>        hw/riscv/boot: Replace cpu_to_le32() -> const_le32()
>>
>> Xuemei Liu (1):
>>        hw/riscv/numa.c: Supplement cpu topology arguments
>>
>> Zephyr Li (2):
>>        target/riscv: Do not hide Sstc CSRs from gdbstub
>>        target/riscv: Reject Svinval instructions in U-mode
>>
>> imaginos (1):
>>        disas/riscv: enable `mnret` disassembly
> 
> Hi!
> 
> Is there anything here worth picking up for the stable series?
> The "target/riscv/cpu_helper.c: allow LOAD_ADDR_MIS promotion to
> AMO fault" has Cc: stable, so I picked it up.


 From my patches I believe you can pick all the patches that have a "Resolves"
tag.  All of them are fixing stuff introduced several releases ago that people
on Gitlab found.  Should apply without too much hassle in stable 10.0.x and
above.


Thanks,
Daniel

> 
> Thanks,
> 
> /mjt



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

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

Thread overview: 87+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-16 10:04 [PULL 00/83] riscv-to-apply queue alistair23
2026-06-16 10:04 ` [PULL 01/83] target/riscv/tcg: disable svpbmt if satp_mode < sv39 alistair23
2026-06-16 10:04 ` [PULL 02/83] target/riscv: Align pmp size to pmp-granularity alistair23
2026-06-16 10:04 ` [PULL 03/83] target/riscv: Improve PMP address alignment readability alistair23
2026-06-16 10:04 ` [PULL 04/83] target/riscv/csr.c: do not allow mstatus MPV/GVA writes alistair23
2026-06-16 10:04 ` [PULL 05/83] target/riscv/csr.c: fix mstatus.UXL reserved value alistair23
2026-06-16 10:04 ` [PULL 06/83] disas/riscv.c: add 'cbo' insns to disassembler alistair23
2026-06-16 10:04 ` [PULL 07/83] target/riscv: Do not hide Sstc CSRs from gdbstub alistair23
2026-06-16 10:04 ` [PULL 08/83] target/riscv: Reject Svinval instructions in U-mode alistair23
2026-06-16 10:04 ` [PULL 09/83] target/riscv/insn_trans/trans_rvzicbo.c.inc: save opcode before helpers alistair23
2026-06-16 10:04 ` [PULL 10/83] target/riscv/cpu_helper.c: fault with reserved PTE.PBMT val alistair23
2026-06-16 10:04 ` [PULL 11/83] target/riscv/cpu_helper.c: allow LOAD_ADDR_MIS promotion to AMO fault alistair23
2026-06-16 10:04 ` [PULL 12/83] target/riscv: Fix size of gpr and gprh alistair23
2026-06-16 10:04 ` [PULL 13/83] target/riscv: Fix size of vector CSRs alistair23
2026-06-16 10:04 ` [PULL 14/83] target/riscv: Fix size of pc, load_[val|res] alistair23
2026-06-16 10:04 ` [PULL 15/83] target/riscv: Fix size of frm and fflags alistair23
2026-06-16 10:04 ` [PULL 16/83] target/riscv: Fix size of badaddr and bins alistair23
2026-06-16 10:04 ` [PULL 17/83] target/riscv: Fix size of guest_phys_fault_addr alistair23
2026-06-16 10:04 ` [PULL 18/83] target/riscv: Fix size of priv_ver and vext_ver alistair23
2026-06-16 10:04 ` [PULL 19/83] target/riscv: Fix size of retxh alistair23
2026-06-16 10:04 ` [PULL 20/83] target/riscv: Fix size of ssp alistair23
2026-06-16 10:04 ` [PULL 21/83] target/riscv: Fix size of excp_uw2 alistair23
2026-06-16 10:04 ` [PULL 22/83] target/riscv: Fix size of sw_check_code alistair23
2026-06-16 10:04 ` [PULL 23/83] target/riscv: Fix size of priv alistair23
2026-06-16 10:04 ` [PULL 24/83] target/riscv: Fix size of gei fields alistair23
2026-06-16 10:04 ` [PULL 25/83] target/riscv: Fix size of [m|s|vs]iselect fields alistair23
2026-06-16 10:04 ` [PULL 26/83] target/riscv: Fix arguments to board IMSIC emulation callbacks alistair23
2026-06-16 10:04 ` [PULL 27/83] target/riscv: Fix size of irq_overflow_left alistair23
2026-06-16 10:04 ` [PULL 28/83] target/riscv: Indent PMUFixedCtrState correctly alistair23
2026-06-16 10:04 ` [PULL 29/83] target/riscv: Replace target_ulong in riscv_cpu_get_trap_name() alistair23
2026-06-16 10:04 ` [PULL 30/83] target/riscv: Replace target_ulong in riscv_ctr_add_entry() alistair23
2026-06-16 10:04 ` [PULL 31/83] target/riscv: Fix size of trigger data alistair23
2026-06-16 10:04 ` [PULL 32/83] target/riscv: Fix size of mseccfg alistair23
2026-06-16 10:04 ` [PULL 33/83] target/riscv: Move debug.h include away from cpu.h alistair23
2026-06-16 10:04 ` [PULL 34/83] target/riscv: Move CSR declarations to separate csr.h header alistair23
2026-06-16 10:04 ` [PULL 35/83] target/riscv: Introduce externally facing CSR access functions alistair23
2026-06-16 10:04 ` [PULL 36/83] target/riscv: Make pmp.h target_ulong agnostic alistair23
2026-06-16 10:04 ` [PULL 37/83] target/riscv: Pass address as uint64_t in cpu_set_exception_base() alistair23
2026-06-16 10:04 ` [PULL 38/83] target/riscv: Fix pmp.h/cpu.h circular inclusion alistair23
2026-06-16 10:04 ` [PULL 39/83] target/riscv/cpu_helper.c: add PMA access fault alistair23
2026-06-16 10:04 ` [PULL 40/83] target/riscv/tcg: disable svnapot if satp_mode < sv39 alistair23
2026-06-16 10:04 ` [PULL 41/83] disas/riscv.c: fix inst_length() alistair23
2026-06-16 10:04 ` [PULL 42/83] target/riscv: Initialize DisasContext::mo_endian once alistair23
2026-06-16 10:04 ` [PULL 43/83] target/riscv: Implement runtime data endianness via MSTATUS bits alistair23
2026-06-16 10:04 ` [PULL 44/83] target/riscv: De-indent some code in get_physical_address() alistair23
2026-06-16 10:04 ` [PULL 45/83] target/riscv: Remove target_ulong use " alistair23
2026-06-16 10:04 ` [PULL 46/83] target/riscv: Fix page table walk endianness for big-endian harts alistair23
2026-06-16 10:04 ` [PULL 47/83] hw/riscv/boot: Rewrite setup_rom_reset_vec() using load/store API alistair23
2026-06-16 10:04 ` [PULL 48/83] hw/riscv/boot: Replace cpu_to_le32() -> const_le32() alistair23
2026-06-16 10:04 ` [PULL 49/83] target/riscv: Add big-endian CPU configuration field and reset logic alistair23
2026-06-16 10:04 ` [PULL 50/83] hw/riscv/boot: Honour data endianness alistair23
2026-06-16 10:04 ` [PULL 51/83] target/riscv: Expose and document the CPU 'big-endian' property alistair23
2026-06-16 10:04 ` [PULL 52/83] tests/functional: Add RISC-V endianness test alistair23
2026-06-16 10:04 ` [PULL 53/83] target/riscv: Add the implied rule for G extension alistair23
2026-06-16 10:04 ` [PULL 54/83] target/riscv: Add standard B extension implied rule alistair23
2026-06-16 10:04 ` [PULL 55/83] target/riscv: Print privilege level and ELP in riscv_cpu_dump_state alistair23
2026-06-16 10:04 ` [PULL 56/83] target/riscv: Improve alignment " alistair23
2026-06-16 10:05 ` [PULL 57/83] target/riscv: mask vxrm csrw write to the low 2 bits alistair23
2026-06-16 10:05 ` [PULL 58/83] target/riscv: Reorder Smrnmi CPU fields above CPU reset line alistair23
2026-06-16 10:05 ` [PULL 59/83] hw/riscv/numa.c: Supplement cpu topology arguments alistair23
2026-06-16 10:05 ` [PULL 60/83] hw/riscv: Don't insert DDT cache in Bare mode alistair23
2026-06-16 10:05 ` [PULL 61/83] hw/riscv: Refactor riscv_iommu_ctx_put() for Bare mode handling alistair23
2026-06-16 10:05 ` [PULL 62/83] hw/riscv/virt.c: fix 'iommu-map' FDT entry alistair23
2026-06-16 10:05 ` [PULL 63/83] target/riscv: Set mstatus.FS dirty when scalar FP raises exceptions alistair23
2026-06-16 10:05 ` [PULL 64/83] target/riscv: rvv: Set mstatus.FS dirty when vector " alistair23
2026-06-16 10:05 ` [PULL 65/83] disas/riscv: enable `mnret` disassembly alistair23
2026-06-16 10:05 ` [PULL 66/83] target/riscv: add thead-c908 cpu support alistair23
2026-06-16 10:05 ` [PULL 67/83] hw/riscv: add k230 board initial support alistair23
2026-06-16 10:05 ` [PULL 68/83] hw/watchdog: add k230 watchdog " alistair23
2026-06-16 10:05 ` [PULL 69/83] tests/qtest: add test for K230 watchdog alistair23
2026-06-16 10:05 ` [PULL 70/83] docs/system/riscv: add documentation for k230 machine alistair23
2026-06-16 10:05 ` [PULL 71/83] hw/riscv/sifive_u.c: add a FDT phandle to cpu-intc alistair23
2026-06-16 10:05 ` [PULL 72/83] hw/riscv: add fdt-common helper alistair23
2026-06-16 10:05 ` [PULL 73/83] hw/riscv/numa: make numa_enabled() public alistair23
2026-06-16 10:05 ` [PULL 74/83] hw/riscv: add create_fdt_socket_memory() helper alistair23
2026-06-16 10:05 ` [PULL 75/83] hw/riscv/sifive_u.c: add intc_phandles array alistair23
2026-06-16 10:05 ` [PULL 76/83] hw/riscv/spike.c: " alistair23
2026-06-16 10:05 ` [PULL 77/83] hw/riscv: add create_fdt_clint() helper alistair23
2026-06-16 10:05 ` [PULL 78/83] hw/riscv/sifive_u.c: add cpu-map, cluster and core DTs alistair23
2026-06-16 10:05 ` [PULL 79/83] hw/riscv: add fdt_create_cpu_socket_subnode() helper alistair23
2026-06-16 10:05 ` [PULL 80/83] hw/riscv: add create_fdt_socket_cpus() alistair23
2026-06-16 10:05 ` [PULL 81/83] hw/riscv/spike.c: use create_fdt_socket_cpus() alistair23
2026-06-16 10:05 ` [PULL 82/83] hw/riscv/fdt_common.c: create create_fdt_socket_cpu_internal() alistair23
2026-06-16 10:05 ` [PULL 83/83] hw/riscv: add create_fdt_socket_cpu_sifive() alistair23
2026-06-16 17:27 ` [PULL 00/83] riscv-to-apply queue Stefan Hajnoczi
2026-06-16 19:49 ` Michael Tokarev
2026-06-16 20:12   ` Daniel Henrique Barboza

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.