All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 00/39] riscv-to-apply queue
@ 2024-12-18 22:29 Alistair Francis
  2024-12-19 20:45 ` Stefan Hajnoczi
  0 siblings, 1 reply; 48+ messages in thread
From: Alistair Francis @ 2024-12-18 22:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Alistair Francis

The following changes since commit 8032c78e556cd0baec111740a6c636863f9bd7c8:

  Merge tag 'firmware-20241216-pull-request' of https://gitlab.com/kraxel/qemu into staging (2024-12-16 14:20:33 -0500)

are available in the Git repository at:

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

for you to fetch changes up to 5632d271be16b5e769342d54198c4359658abcb7:

  target/riscv: add support for RV64 Xiangshan Nanhu CPU (2024-12-18 11:07:59 +1000)

----------------------------------------------------------------
RISC-V PR for 10.0

* Correct the validness check of iova
* Fix APLIC in_clrip and clripnum write emulation
* Support riscv-iommu-sys device
* Add Tenstorrent Ascalon CPU
* Add AIA userspace irqchip_split support
* Add Microblaze V generic board
* Upgrade ACPI SPCR table to support SPCR table revision 4 format
* Remove tswap64() calls from HTIF
* Support 64-bit address of initrd
* Introduce svukte ISA extension
* Support ssstateen extension
* Support for RV64 Xiangshan Nanhu CPU

----------------------------------------------------------------
Anton Blanchard (1):
      target/riscv: Add Tenstorrent Ascalon CPU

Daniel Henrique Barboza (15):
      hw/riscv/riscv-iommu.c: add riscv_iommu_instance_init()
      hw/riscv/riscv-iommu: parametrize CAP.IGS
      hw/riscv/virt.c, riscv-iommu-sys.c: add MSIx support
      hw/riscv/riscv-iommu: implement reset protocol
      docs/specs: add riscv-iommu-sys information
      hw/intc/riscv_aplic: rename is_kvm_aia()
      hw/riscv/virt.c: reduce virt_use_kvm_aia() usage
      hw/riscv/virt.c: rename helper to virt_use_kvm_aia_aplic_imsic()
      target/riscv/kvm: consider irqchip_split() in aia_create()
      hw/riscv/virt.c, riscv_aplic.c: add 'emulated_aplic' helpers
      hw/intc/riscv_aplic: add kvm_msicfgaddr for split mode aplic-imsic
      target/riscv/kvm: remove irqchip_split() restriction
      docs: update riscv/virt.rst with kernel-irqchip=split support
      target/riscv/tcg: hide warn for named feats when disabling via priv_ver
      target/riscv: add ssstateen

Fea.Wang (6):
      target/riscv: Add svukte extension capability variable
      target/riscv: Support senvcfg[UKTE] bit when svukte extension is enabled
      target/riscv: Support hstatus[HUKTE] bit when svukte extension is enabled
      target/riscv: Check memory access to meet svukte rule
      target/riscv: Expose svukte ISA extension
      target/riscv: Check svukte is not enabled in RV32

Jason Chien (1):
      hw/riscv/riscv-iommu.c: Correct the validness check of iova

Jim Shu (3):
      hw/riscv: Support to load DTB after 3GB memory on 64-bit system.
      hw/riscv: Add a new struct RISCVBootInfo
      hw/riscv: Add the checking if DTB overlaps to kernel or initrd

MollyChen (1):
      target/riscv: add support for RV64 Xiangshan Nanhu CPU

Philippe Mathieu-Daudé (5):
      MAINTAINERS: Cover RISC-V HTIF interface
      hw/char/riscv_htif: Explicit little-endian implementation
      hw/char/riscv_htif: Clarify MemoryRegionOps expect 32-bit accesses
      target/riscv: Include missing headers in 'vector_internals.h'
      target/riscv: Include missing headers in 'internals.h'

Sai Pavan Boddu (1):
      hw/riscv: Add Microblaze V generic board

Sia Jee Heng (3):
      qtest: allow SPCR acpi table changes
      hw/acpi: Upgrade ACPI SPCR table to support SPCR table revision 4 format
      tests/qtest/bios-tables-test: Update virt SPCR golden reference for RISC-V

Sunil V L (1):
      hw/riscv/virt: Add IOMMU as platform device if the option is set

Tomasz Jeznach (1):
      hw/riscv: add riscv-iommu-sys platform device

Yong-Xuan Wang (1):
      hw/intc/riscv_aplic: Fix APLIC in_clrip and clripnum write emulation

 MAINTAINERS                                |   8 +
 docs/specs/index.rst                       |   1 +
 docs/specs/riscv-aia.rst                   |  83 ++++++++++
 docs/specs/riscv-iommu.rst                 |  30 +++-
 docs/system/riscv/microblaze-v-generic.rst |  42 +++++
 docs/system/riscv/virt.rst                 |  17 ++
 docs/system/target-riscv.rst               |   1 +
 hw/riscv/riscv-iommu-bits.h                |   6 +
 hw/riscv/riscv-iommu.h                     |   5 +
 include/hw/acpi/acpi-defs.h                |   7 +-
 include/hw/acpi/aml-build.h                |   2 +-
 include/hw/intc/riscv_aplic.h              |   8 +
 include/hw/riscv/boot.h                    |  28 +++-
 include/hw/riscv/iommu.h                   |  10 +-
 include/hw/riscv/virt.h                    |   6 +-
 target/riscv/cpu-qom.h                     |   2 +
 target/riscv/cpu_bits.h                    |   2 +
 target/riscv/cpu_cfg.h                     |   2 +
 target/riscv/internals.h                   |   3 +
 target/riscv/vector_internals.h            |   1 +
 hw/acpi/aml-build.c                        |  20 ++-
 hw/arm/virt-acpi-build.c                   |   8 +-
 hw/char/riscv_htif.c                       |  15 +-
 hw/intc/riscv_aplic.c                      |  74 +++++++--
 hw/loongarch/acpi-build.c                  |   6 +-
 hw/riscv/boot.c                            | 100 +++++++----
 hw/riscv/microblaze-v-generic.c            | 184 +++++++++++++++++++++
 hw/riscv/microchip_pfsoc.c                 |  13 +-
 hw/riscv/opentitan.c                       |   4 +-
 hw/riscv/riscv-iommu-pci.c                 |  21 +++
 hw/riscv/riscv-iommu-sys.c                 | 256 +++++++++++++++++++++++++++++
 hw/riscv/riscv-iommu.c                     | 137 ++++++++++-----
 hw/riscv/sifive_e.c                        |   4 +-
 hw/riscv/sifive_u.c                        |  18 +-
 hw/riscv/spike.c                           |  14 +-
 hw/riscv/virt-acpi-build.c                 |  12 +-
 hw/riscv/virt.c                            | 159 +++++++++++++++---
 target/riscv/cpu.c                         | 101 ++++++++++++
 target/riscv/cpu_helper.c                  |  55 +++++++
 target/riscv/csr.c                         |   7 +
 target/riscv/kvm/kvm-cpu.c                 |  43 ++---
 target/riscv/tcg/tcg-cpu.c                 |  27 ++-
 hw/riscv/Kconfig                           |   8 +
 hw/riscv/meson.build                       |   3 +-
 hw/riscv/trace-events                      |   4 +
 tests/data/acpi/riscv64/virt/SPCR          | Bin 80 -> 90 bytes
 46 files changed, 1380 insertions(+), 177 deletions(-)
 create mode 100644 docs/specs/riscv-aia.rst
 create mode 100644 docs/system/riscv/microblaze-v-generic.rst
 create mode 100644 hw/riscv/microblaze-v-generic.c
 create mode 100644 hw/riscv/riscv-iommu-sys.c


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

* Re: [PULL 00/39] riscv-to-apply queue
  2024-12-18 22:29 Alistair Francis
@ 2024-12-19 20:45 ` Stefan Hajnoczi
  2024-12-20  1:55   ` Alistair Francis
  2024-12-20  9:36   ` Daniel Henrique Barboza
  0 siblings, 2 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2024-12-19 20:45 UTC (permalink / raw)
  To: Alistair Francis; +Cc: qemu-devel, alistair23, Alistair Francis

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

Hi Alistair,
Please take a look at the following CI failure:

x86_64-w64-mingw32-gcc -m64 -Ilibqemuutil.a.p -I. -I.. -Iqapi -Itrace -Iui -Iui/shader -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/glib-2.0 -I/usr/x86_64-w64-mingw32/sys-root/mingw/lib/glib-2.0/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/p11-kit-1 -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O2 -g -fstack-protector-strong -Wempty-body -Wendif-labels -Wexpansion-to-defined -Wformat-security -Wformat-y2k -Wignored-qualifiers -Wimplicit-fallthrough=2 -Winit-self -Wmissing-format-attribute -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls -Wshadow=local -Wstrict-prototypes -Wtype-limits -Wundef -Wvla -Wwrite-strings -Wno-missing-include-dirs -Wno-psabi -Wno-shift-negative-value -iquote . -iquote /builds/qemu-project/qemu -iquote /builds/qemu-project/qemu/include -iquote /builds/qemu-project/qemu/host/include/x86_64 -iquote /builds/qemu-project/qemu/host/include/generic -iquote /builds/qemu-project/qemu/tcg/i386 -mms-bitfields -mcx16 -msse2 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -fno-pie -no-pie -ftrivial-auto-var-init=zero -fzero-call-used-regs=used-gpr -mms-bitfields -pthread -mms-bitfields -MD -MQ libqemuutil.a.p/meson-generated_.._trace_trace-hw_riscv.c.obj -MF libqemuutil.a.p/meson-generated_.._trace_trace-hw_riscv.c.obj.d -o libqemuutil.a.p/meson-generated_.._trace_trace-hw_riscv.c.obj -c trace/trace-hw_riscv.c
In file included from trace/trace-hw_riscv.c:5:
../hw/riscv/trace-events: In function '_nocheck__trace_riscv_iommu_sys_msi_sent':
../hw/riscv/trace-events:19:22: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'uint64_t' {aka 'long long unsigned int'} [-Werror=format=]
   19 | riscv_iommu_sys_msi_sent(uint32_t vector, uint64_t msi_addr, uint32_t msi_data, uint32_t result) "MSI sent to vector %u msi_addr 0x%lx msi_data 0x%x result %u"
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......
../hw/riscv/trace-events:19:22: error: format '%lx' expects argument of type 'long unsigned int', but argument 3 has type 'uint64_t' {aka 'long long unsigned int'} [-Werror=format=]
   19 | riscv_iommu_sys_msi_sent(uint32_t vector, uint64_t msi_addr, uint32_t msi_data, uint32_t result) "MSI sent to vector %u msi_addr 0x%lx msi_data 0x%x result %u"
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                              ~~~~~~~~
      |                                                                                                                               |
      |                                                                                                                               uint64_t {aka long long unsigned int}
cc1: all warnings being treated as errors

https://gitlab.com/qemu-project/qemu/-/jobs/8691704969#L2578

Once the issue has been solved, please send a new revision of this pull
request.

Thanks,
Stefan

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

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

* Re: [PULL 00/39] riscv-to-apply queue
  2024-12-19 20:45 ` Stefan Hajnoczi
@ 2024-12-20  1:55   ` Alistair Francis
  2024-12-20  9:36   ` Daniel Henrique Barboza
  1 sibling, 0 replies; 48+ messages in thread
From: Alistair Francis @ 2024-12-20  1:55 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: qemu-devel, Alistair Francis

On Fri, Dec 20, 2024 at 6:45 AM Stefan Hajnoczi <stefanha@redhat.com> wrote:
>
> Hi Alistair,
> Please take a look at the following CI failure:
>
> x86_64-w64-mingw32-gcc -m64 -Ilibqemuutil.a.p -I. -I.. -Iqapi -Itrace -Iui -Iui/shader -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/glib-2.0 -I/usr/x86_64-w64-mingw32/sys-root/mingw/lib/glib-2.0/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/p11-kit-1 -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O2 -g -fstack-protector-strong -Wempty-body -Wendif-labels -Wexpansion-to-defined -Wformat-security -Wformat-y2k -Wignored-qualifiers -Wimplicit-fallthrough=2 -Winit-self -Wmissing-format-attribute -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls -Wshadow=local -Wstrict-prototypes -Wtype-limits -Wundef -Wvla -Wwrite-strings -Wno-missing-include-dirs -Wno-psabi -Wno-shift-negative-value -iquote . -iquote /builds/qemu-project/qemu -iquote /builds/qemu-project/qemu/include -iquote /builds/qemu-project/qemu/host/include/x86_64 -iquote /builds/qemu-project/qemu/host/include/generic -iquote /builds/qemu-project/qemu/tcg/i386 -mms-bitfields -mcx16 -msse2 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -fno-pie -no-pie -ftrivial-auto-var-init=zero -fzero-call-used-regs=used-gpr -mms-bitfields -pthread -mms-bitfields -MD -MQ libqemuutil.a.p/meson-generated_.._trace_trace-hw_riscv.c.obj -MF libqemuutil.a.p/meson-generated_.._trace_trace-hw_riscv.c.obj.d -o libqemuutil.a.p/meson-generated_.._trace_trace-hw_riscv.c.obj -c trace/trace-hw_riscv.c
> In file included from trace/trace-hw_riscv.c:5:
> ../hw/riscv/trace-events: In function '_nocheck__trace_riscv_iommu_sys_msi_sent':
> ../hw/riscv/trace-events:19:22: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'uint64_t' {aka 'long long unsigned int'} [-Werror=format=]
>    19 | riscv_iommu_sys_msi_sent(uint32_t vector, uint64_t msi_addr, uint32_t msi_data, uint32_t result) "MSI sent to vector %u msi_addr 0x%lx msi_data 0x%x result %u"
>       |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ......
> ../hw/riscv/trace-events:19:22: error: format '%lx' expects argument of type 'long unsigned int', but argument 3 has type 'uint64_t' {aka 'long long unsigned int'} [-Werror=format=]
>    19 | riscv_iommu_sys_msi_sent(uint32_t vector, uint64_t msi_addr, uint32_t msi_data, uint32_t result) "MSI sent to vector %u msi_addr 0x%lx msi_data 0x%x result %u"
>       |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                              ~~~~~~~~
>       |                                                                                                                               |
>       |                                                                                                                               uint64_t {aka long long unsigned int}
> cc1: all warnings being treated as errors
>
> https://gitlab.com/qemu-project/qemu/-/jobs/8691704969#L2578
>
> Once the issue has been solved, please send a new revision of this pull

Sorry about that, v2 sent.

Alistair

> request.
>
> Thanks,
> Stefan


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

* Re: [PULL 00/39] riscv-to-apply queue
  2024-12-19 20:45 ` Stefan Hajnoczi
  2024-12-20  1:55   ` Alistair Francis
@ 2024-12-20  9:36   ` Daniel Henrique Barboza
  1 sibling, 0 replies; 48+ messages in thread
From: Daniel Henrique Barboza @ 2024-12-20  9:36 UTC (permalink / raw)
  To: Stefan Hajnoczi, Alistair Francis; +Cc: qemu-devel, Alistair Francis



On 12/19/24 5:45 PM, Stefan Hajnoczi wrote:
> Hi Alistair,
> Please take a look at the following CI failure:
> 
> x86_64-w64-mingw32-gcc -m64 -Ilibqemuutil.a.p -I. -I.. -Iqapi -Itrace -Iui -Iui/shader -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/glib-2.0 -I/usr/x86_64-w64-mingw32/sys-root/mingw/lib/glib-2.0/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/p11-kit-1 -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O2 -g -fstack-protector-strong -Wempty-body -Wendif-labels -Wexpansion-to-defined -Wformat-security -Wformat-y2k -Wignored-qualifiers -Wimplicit-fallthrough=2 -Winit-self -Wmissing-format-attribute -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls -Wshadow=local -Wstrict-prototypes -Wtype-limits -Wundef -Wvla -Wwrite-strings -Wno-missing-include-dirs -Wno-psabi -Wno-shift-negative-value -iquote . -iquote /builds/qemu-project/qemu -iquote /builds/qemu-project/qemu/include -iquote /builds/qemu-project/qemu/host/include/x86_64 -iquote /builds/qemu-project/qemu/host/include/generic -iquote /builds/qemu-project/qemu/tcg/i386 -mms-bitfields -mcx16 -msse2 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -fno-pie -no-pie -ftrivial-auto-var-init=zero -fzero-call-used-regs=used-gpr -mms-bitfields -pthread -mms-bitfields -MD -MQ libqemuutil.a.p/meson-generated_.._trace_trace-hw_riscv.c.obj -MF libqemuutil.a.p/meson-generated_.._trace_trace-hw_riscv.c.obj.d -o libqemuutil.a.p/meson-generated_.._trace_trace-hw_riscv.c.obj -c trace/trace-hw_riscv.c
> In file included from trace/trace-hw_riscv.c:5:
> ../hw/riscv/trace-events: In function '_nocheck__trace_riscv_iommu_sys_msi_sent':
> ../hw/riscv/trace-events:19:22: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'uint64_t' {aka 'long long unsigned int'} [-Werror=format=]
>     19 | riscv_iommu_sys_msi_sent(uint32_t vector, uint64_t msi_addr, uint32_t msi_data, uint32_t result) "MSI sent to vector %u msi_addr 0x%lx msi_data 0x%x result %u"
>        |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ......
> ../hw/riscv/trace-events:19:22: error: format '%lx' expects argument of type 'long unsigned int', but argument 3 has type 'uint64_t' {aka 'long long unsigned int'} [-Werror=format=]
>     19 | riscv_iommu_sys_msi_sent(uint32_t vector, uint64_t msi_addr, uint32_t msi_data, uint32_t result) "MSI sent to vector %u msi_addr 0x%lx msi_data 0x%x result %u"
>        |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                              ~~~~~~~~
>        |                                                                                                                               |
>        |                                                                                                                               uint64_t {aka long long unsigned int}
> cc1: all warnings being treated as errors


It really seems like every time I don't run the gitlab pipeline before posting
patches there's something in there that explodes a windows-like runner :(

Thanks Alistair for cleaning up my mess in v2.


Daniel


> 
> https://gitlab.com/qemu-project/qemu/-/jobs/8691704969#L2578
> 
> Once the issue has been solved, please send a new revision of this pull
> request.
> 
> Thanks,
> Stefan


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

* [PULL 00/39] riscv-to-apply queue
@ 2026-07-01 10:17 alistair23
  2026-07-01 10:17 ` [PULL 01/39] target/riscv: Avoid NULL deref in IMSIC CSR write alistair23
                   ` (40 more replies)
  0 siblings, 41 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Alistair Francis

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

The following changes since commit 30e8a06b64aa58a3990ba39cb5d09531e7d265e0:

  Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging (2026-06-29 17:41:42 +0200)

are available in the Git repository at:

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

for you to fetch changes up to 64ce9ac18757d79f3b5b337f7bcbdd0dabef3ce1:

  hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0 (2026-07-01 20:14:20 +1000)

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

* Fix IMSIC CSR write and add tests
* Parametrise debug trigger number
* Add 'svbare' satp-mode
* Fix RINTC PLIC context ID for KVM
* Avoid abort when reading vtype before env->xl is set
* Skip reset for KVM irqchip
* Skip FP/Vector sync on KVM_PUT_RUNTIME_STATE
* More FDT cleanups (PLIC)
* Make FCTL.BE in IOMMU read only 0
* Check DC.TC reserved bits in IOMMU
* Apply UXL WARL handling to vsstatus
* Set cmd_ill IOFENCE.C if rsvp bits are set in IOMMU
* Set RISCV_IOMMU_FQ_HDR_PV appropriately
* Fix MSI MRIF IOMMU interrupt-pending offset
* Report QEMU CPU archid as 42
* Check PMP before updating PTE
* Add the Tenstorrent Atlantis machine

----------------------------------------------------------------
Alistair Francis (1):
      hw/riscv/atlantis: Ensure OpenSBI has a non-zero next_addr

Charlie Jenkins (1):
      target/riscv: Report QEMU CPU archid as 42

Chris Rauer (1):
      hw/i2c: Add DesignWare I2C Controller

Daniel Henrique Barboza (16):
      target/riscv/cpu: add CPU unrealize callback
      target/riscv: dynamic alloc of debug trigger arrays
      target/riscv: add 'num-triggers' debug property
      target/riscv/cpu.c: add 'svbare' satp-mode
      hw/riscv/sifive_u.c: remove unneeded qemu_fdt_get_phandle() call
      hw/riscv/sifive_u.c: use intc_phandle in plic creation
      hw/riscv/sifive_u: add #address-cells in PLIC FDT
      hw/riscv/virt.c: change 'plic' nodename to 'interrupt-controller'
      hw/riscv: add create_fdt_plic() helper
      hw/riscv/riscv-iommu: rename regs_rw to regs
      hw/riscv/riscv-iommu.c: make FCTL.BE read only 0
      hw/riscv/riscv-iommu: check DC.TC reserved bits
      hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set
      hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately
      hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset
      hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0

Inochi Amaoto (1):
      target/riscv: Check PMP before updating PTE

Joel Stanley (9):
      target/riscv: Avoid NULL deref in IMSIC CSR write
      tests/functional/riscv64: Use newer kernel for tuxrun boot
      tests/functional/riscv64: Add virt machine AIA boot test
      hw/riscv/virt: Move AIA initialisation to helper file
      hw/riscv/aia: Provide number of irq sources
      hw/riscv/aia: Configure stride for the M-mode IMSIC
      hw/riscv: Add Tenstorrent Atlantis machine
      hw/riscv/atlantis: Integrate i2c controllers
      hw/riscv/atlantis: Add some i2c peripherals

Meng Zhuo (1):
      target/riscv/kvm: skip FP/Vector sync on KVM_PUT_RUNTIME_STATE

Nicholas Piggin (4):
      hw/riscv/boot: Describe discontiguous memory in boot_info
      hw/riscv/boot: Account for discontiguous memory when loading firmware
      target/riscv: tt-ascalon: Enable Zkr extension
      tests/functional/riscv64: Add tt-atlantis tests

Qingwei Hu (3):
      hw/riscv/virt-acpi-build: Fix RINTC PLIC context ID for KVM
      hw/intc: riscv_aplic: Skip reset for KVM irqchip
      hw/intc: riscv_imsic: Skip reset for KVM irqchip

SeungJu Cheon (1):
      target/riscv: Apply UXL WARL handling to vsstatus

ZhengXiang Qin (1):
      target/riscv: avoid abort when reading vtype before env->xl is set

 MAINTAINERS                                  |  21 +
 docs/system/riscv/tt_atlantis.rst            |  41 ++
 docs/system/target-riscv.rst                 |   1 +
 hw/riscv/aia.h                               |  26 +
 hw/riscv/riscv-iommu-bits.h                  |   4 +
 hw/riscv/riscv-iommu.h                       |  26 +-
 include/hw/i2c/designware_i2c.h              |  56 ++
 include/hw/riscv/boot.h                      |  12 +-
 include/hw/riscv/fdt-common.h                |   5 +
 include/hw/riscv/sifive_u.h                  |   2 +
 include/hw/riscv/tt_atlantis.h               |  64 +++
 include/hw/riscv/virt.h                      |   2 +-
 target/riscv/cpu.h                           |  39 +-
 target/riscv/debug.h                         |   1 +
 hw/i2c/designware_i2c.c                      | 745 +++++++++++++++++++++++++++
 hw/intc/riscv_aplic.c                        |   4 +
 hw/intc/riscv_imsic.c                        |   4 +
 hw/riscv/aia.c                               |  94 ++++
 hw/riscv/boot.c                              |  34 +-
 hw/riscv/fdt-common.c                        |  30 ++
 hw/riscv/k230.c                              |   8 +-
 hw/riscv/microchip_pfsoc.c                   |   8 +-
 hw/riscv/opentitan.c                         |   6 +-
 hw/riscv/riscv-iommu-hpm.c                   |   4 +-
 hw/riscv/riscv-iommu.c                       |  73 ++-
 hw/riscv/shakti_c.c                          |   6 +-
 hw/riscv/sifive_u.c                          |  48 +-
 hw/riscv/spike.c                             |   6 +-
 hw/riscv/tt_atlantis.c                       | 617 ++++++++++++++++++++++
 hw/riscv/virt-acpi-build.c                   |  29 +-
 hw/riscv/virt.c                              | 148 ++----
 hw/riscv/xiangshan_kmh.c                     |   6 +-
 target/riscv/cpu.c                           |  43 +-
 target/riscv/cpu_helper.c                    |   8 +
 target/riscv/csr.c                           |  48 +-
 target/riscv/debug.c                         |  46 +-
 target/riscv/kvm/kvm-cpu.c                   |  19 +-
 target/riscv/machine.c                       |  16 +-
 hw/i2c/Kconfig                               |   5 +
 hw/i2c/meson.build                           |   1 +
 hw/riscv/Kconfig                             |  13 +
 hw/riscv/meson.build                         |   2 +
 tests/functional/riscv64/meson.build         |   1 +
 tests/functional/riscv64/test_opensbi.py     |   4 +
 tests/functional/riscv64/test_tt_atlantis.py |  57 ++
 tests/functional/riscv64/test_tuxrun.py      |  11 +-
 46 files changed, 2196 insertions(+), 248 deletions(-)
 create mode 100644 docs/system/riscv/tt_atlantis.rst
 create mode 100644 hw/riscv/aia.h
 create mode 100644 include/hw/i2c/designware_i2c.h
 create mode 100644 include/hw/riscv/tt_atlantis.h
 create mode 100644 hw/i2c/designware_i2c.c
 create mode 100644 hw/riscv/aia.c
 create mode 100644 hw/riscv/tt_atlantis.c
 create mode 100755 tests/functional/riscv64/test_tt_atlantis.py


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

* [PULL 01/39] target/riscv: Avoid NULL deref in IMSIC CSR write
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 02/39] tests/functional/riscv64: Use newer kernel for tuxrun boot alistair23
                   ` (39 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Joel Stanley, Alistair Francis, Anton Johansson,
	Daniel Henrique Barboza

From: Joel Stanley <joel@jms.id.au>

rmw_xireg_aia() and rmw_xtopei() were changed to store the IMSIC
callback's value in a local before passing it back to the caller.
For write only CSR accesses that pointer is NULL, causing a crash when
guest programs write to xireg or xtopei, such as when the guest sets up
the IMSIC.

This only happens when setting aia=aplic-imsic so none of the existing
boot tests caught it.

Fix it by guarding the pointer dereference as done for other CSRs.

Fixes: 63469ad75dcc ("target/riscv: Fix arguments to board IMSIC emulation callbacks")
Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Anton Johansson <anjo@rev.ng>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260617054034.1020724-2-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/csr.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index dd9726fcf4..dd790d5bef 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2733,7 +2733,9 @@ static RISCVException rmw_xireg_aia(CPURISCVState *env, int csrno,
                                     AIA_MAKE_IREG(isel, priv, virt, vgein,
                                                   riscv_cpu_mxl_bits(env)),
                                     &wide_val, new_val, wr_mask);
-            *val = wide_val;
+            if (val) {
+                *val = wide_val;
+            }
         }
     } else {
         isel_reserved = true;
@@ -3009,7 +3011,9 @@ static RISCVException rmw_xtopei(CPURISCVState *env, int csrno,
                     AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, priv, virt, vgein,
                                   riscv_cpu_mxl_bits(env)),
                     &wide_val, new_val, wr_mask);
-    *val = wide_val;
+    if (val) {
+        *val = wide_val;
+    }
 
 done:
     if (ret) {
-- 
2.54.0



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

* [PULL 02/39] tests/functional/riscv64: Use newer kernel for tuxrun boot
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
  2026-07-01 10:17 ` [PULL 01/39] target/riscv: Avoid NULL deref in IMSIC CSR write alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 03/39] tests/functional/riscv64: Add virt machine AIA boot test alistair23
                   ` (38 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Joel Stanley, Alistair Francis,
	Daniel Henrique Barboza

From: Joel Stanley <joel@jms.id.au>

The published tuxrun kernel is 6.4 which predates the introduction of
AIA support in Linux. Update it to a 6.11 kernel, the newest build
on the tuxrun site.

Boot times on a laptop are slightly longer but still reasonable:

                       | v6.4.16 | v6.11.9
  ---------------------|---------|--------
   test_riscv64        | 4.82s   | 5.56s
  ---------------------|---------|--------
   test_riscv64_maxcpu | 4.94s   | 5.30s

Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260617054034.1020724-3-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 tests/functional/riscv64/test_tuxrun.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/functional/riscv64/test_tuxrun.py b/tests/functional/riscv64/test_tuxrun.py
index 0d8de36204..43d1242be5 100755
--- a/tests/functional/riscv64/test_tuxrun.py
+++ b/tests/functional/riscv64/test_tuxrun.py
@@ -17,8 +17,8 @@
 class TuxRunRiscV64Test(TuxRunBaselineTest):
 
     ASSET_RISCV64_KERNEL = Asset(
-        'https://storage.tuxboot.com/buildroot/20241119/riscv64/Image',
-        '2bd8132a3bf21570290042324fff48c987f42f2a00c08de979f43f0662ebadba')
+        'https://storage.tuxboot.com/kernels/6.11.9/riscv64/Image',
+        '174f8bb87f08961e54fa3fcd954a8e31f4645f6d6af4dd43983d5e9841490fb0')
     ASSET_RISCV64_ROOTFS = Asset(
         'https://storage.tuxboot.com/buildroot/20241119/riscv64/rootfs.ext4.zst',
         'aa4736a9872651dfc0d95e709465eedf1134fd19d42b8cb305bfd776f9801004')
-- 
2.54.0



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

* [PULL 03/39] tests/functional/riscv64: Add virt machine AIA boot test
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
  2026-07-01 10:17 ` [PULL 01/39] target/riscv: Avoid NULL deref in IMSIC CSR write alistair23
  2026-07-01 10:17 ` [PULL 02/39] tests/functional/riscv64: Use newer kernel for tuxrun boot alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 04/39] target/riscv/cpu: add CPU unrealize callback alistair23
                   ` (37 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Joel Stanley, Alistair Francis,
	Daniel Henrique Barboza

From: Joel Stanley <joel@jms.id.au>

Add coverage of the riscv64 virt machine's Advanced Interrupt
Architecture models. With this the APLIC and IMSIC models are used by
Linux, catching regressions.

This test requires a kernel >= 6.10, as AIA drivers were added to Linux
in 6.10.

Boot time is ~5s on a laptop.

Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260617054034.1020724-4-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 tests/functional/riscv64/test_tuxrun.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tests/functional/riscv64/test_tuxrun.py b/tests/functional/riscv64/test_tuxrun.py
index 43d1242be5..6203a45060 100755
--- a/tests/functional/riscv64/test_tuxrun.py
+++ b/tests/functional/riscv64/test_tuxrun.py
@@ -41,6 +41,13 @@ def test_riscv64_maxcpu(self):
         self.common_tuxrun(kernel_asset=self.ASSET_RISCV64_KERNEL,
                            rootfs_asset=self.ASSET_RISCV64_ROOTFS)
 
+    def test_riscv64_aia(self):
+        self.set_machine('virt')
+        self.vm.set_machine('virt,aia=aplic-imsic')
+        self.cpu='max'
+        self.common_tuxrun(kernel_asset=self.ASSET_RISCV64_KERNEL,
+                           rootfs_asset=self.ASSET_RISCV64_ROOTFS)
+
     def test_riscv64_rv32(self):
         self.set_machine('virt')
         self.cpu='rv32'
-- 
2.54.0



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

* [PULL 04/39] target/riscv/cpu: add CPU unrealize callback
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (2 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 03/39] tests/functional/riscv64: Add virt machine AIA boot test alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 05/39] target/riscv: dynamic alloc of debug trigger arrays alistair23
                   ` (36 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Daniel Henrique Barboza, Philippe Mathieu-Daudé,
	Alistair Francis

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

Next patch is going to dynamically allocate debug trigger arrays during
realize() time.  We need a way of freeing them during unrealize(), which
doesn't exist at this moment.

There's a lot going on in that patch already so we're adding the
callback infrastructure beforehand.

Suggested-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260617131710.1855353-2-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h | 2 ++
 target/riscv/cpu.c | 9 +++++++++
 2 files changed, 11 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 7582874c35..16e9f87b83 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -576,6 +576,7 @@ typedef struct RISCVCPUDef {
 /**
  * RISCVCPUClass:
  * @parent_realize: The parent class' realize handler.
+ * @parent_unrealize: The parent class' unrealize handler.
  * @parent_phases: The parent class' reset phase handlers.
  *
  * A RISCV CPU model.
@@ -584,6 +585,7 @@ struct RISCVCPUClass {
     CPUClass parent_class;
 
     DeviceRealize parent_realize;
+    DeviceUnrealize parent_unrealize;
     ResettablePhases parent_phases;
     RISCVCPUDef *def;
 };
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index fa497e5e8a..b47e2b41c8 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1009,6 +1009,13 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
     mcc->parent_realize(dev, errp);
 }
 
+static void riscv_cpu_unrealize(DeviceState *dev)
+{
+    RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
+
+    mcc->parent_unrealize(dev);
+}
+
 bool riscv_cpu_accelerator_compatible(RISCVCPU *cpu)
 {
     if (tcg_enabled()) {
@@ -2664,6 +2671,8 @@ static void riscv_cpu_common_class_init(ObjectClass *c, const void *data)
 
     device_class_set_parent_realize(dc, riscv_cpu_realize,
                                     &mcc->parent_realize);
+    device_class_set_parent_unrealize(dc, riscv_cpu_unrealize,
+                                      &mcc->parent_unrealize);
 
     resettable_class_set_parent_phases(rc, NULL, riscv_cpu_reset_hold, NULL,
                                        &mcc->parent_phases);
-- 
2.54.0



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

* [PULL 05/39] target/riscv: dynamic alloc of debug trigger arrays
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (3 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 04/39] target/riscv/cpu: add CPU unrealize callback alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 06/39] target/riscv: add 'num-triggers' debug property alistair23
                   ` (35 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Daniel Henrique Barboza, Philippe Mathieu-Daudé,
	Alistair Francis

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

The debug trigger facility consists of a set of arrays: tdata1-3,
cpu_breakpoint, cpu_watchpoint and itrigger_timer.  All of them are
static allocated with RV_MAX_TRIGGERS (2).  This means that all RISC-V
cpus will have 2 triggers per hart.

The RISC-V Server Ref demands at least 11 triggers per hart, and several
CPUs in the wild works with 4+ triggers.  We need more flexibility, ergo
we need to parametrize the amount of triggers and make it configurable.

Before doing that we need to handle a situation faced in a previous
attempt [1].  We were unable to set the tdataN array length in
vmstate_debug, meaning that we would always migrate RV_MAX_TRIGGERS
regardless of the actual amount of triggers in play. To fix that we need
to change the tdata arrays from static to dynamic, allowing us to use
VMSTATE_VARRAY_UINT32().  This also means that, in contrast with [1], we
have the opportunity to turn all trigger arrays into dynamic allocation
and reduce the amount of stuff being carried by CPURISCVState, or in
other words, we can carry just what we're using instead of a static max
value.

All the forementioned trigger facility arrays are now dynamic.  They are
allocated and freed during realize/unrealize, and their size is
expressed by env->num_triggers.  All relevant code is changed to use
env->num_triggers instead of the RV_MAX_TRIGGERS to loop through each
array.

This will make it easier for the next patch to parametrize
env->num_triggers.

[1] https://lore.kernel.org/qemu-devel/94c772b0-5231-40e4-9cab-6ac39b9e4d45@oss.qualcomm.com/

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260617131710.1855353-3-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h     | 18 +++++++++++------
 target/riscv/debug.h   |  1 +
 target/riscv/cpu.c     |  6 ++++++
 target/riscv/csr.c     |  2 +-
 target/riscv/debug.c   | 46 ++++++++++++++++++++++++++++++++++--------
 target/riscv/machine.c | 16 ++++++++++-----
 6 files changed, 69 insertions(+), 20 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 16e9f87b83..af246a56ed 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -467,12 +467,18 @@ struct CPUArchState {
     /* trigger module */
     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];
+    /*
+     * num_triggers is the length of tdata1, tdata2, tdata3,
+     * cpu_breakpoint, cpu_watchpoint and itrigger_timer
+     * arrays.
+     */
+    uint32_t num_triggers;
+    uint64_t *tdata1;
+    uint64_t *tdata2;
+    uint64_t *tdata3;
+    struct CPUBreakpoint **cpu_breakpoint;
+    struct CPUWatchpoint **cpu_watchpoint;
+    QEMUTimer **itrigger_timer;
     int64_t last_icount;
     bool itrigger_enabled;
 
diff --git a/target/riscv/debug.h b/target/riscv/debug.h
index 55a3ac72e6..a25d099b37 100644
--- a/target/riscv/debug.h
+++ b/target/riscv/debug.h
@@ -148,6 +148,7 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs);
 bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp);
 
 void riscv_trigger_realize(CPURISCVState *env);
+void riscv_trigger_unrealize(CPURISCVState *env);
 void riscv_trigger_reset_hold(CPURISCVState *env);
 
 bool riscv_itrigger_enabled(CPURISCVState *env);
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index b47e2b41c8..e7318fe9f9 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1012,7 +1012,13 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
 static void riscv_cpu_unrealize(DeviceState *dev)
 {
     RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
+#ifndef CONFIG_USER_ONLY
+    RISCVCPU *cpu = RISCV_CPU(dev);
 
+    if (cpu->cfg.debug) {
+        riscv_trigger_unrealize(&cpu->env);
+    }
+#endif
     mcc->parent_unrealize(dev);
 }
 
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index dd790d5bef..a60a796725 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -5441,7 +5441,7 @@ static RISCVException read_tdata(CPURISCVState *env, int csrno,
                                  target_ulong *val)
 {
     /* return 0 in tdata1 to end the trigger enumeration */
-    if (env->trigger_cur >= RV_MAX_TRIGGERS && csrno == CSR_TDATA1) {
+    if (env->trigger_cur >= env->num_triggers && csrno == CSR_TDATA1) {
         *val = 0;
         return RISCV_EXCP_NONE;
     }
diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index 30d39ee5cd..9a4910c431 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -172,7 +172,7 @@ target_ulong tselect_csr_read(CPURISCVState *env)
 
 void tselect_csr_write(CPURISCVState *env, target_ulong val)
 {
-    if (val < RV_MAX_TRIGGERS) {
+    if (val < env->num_triggers) {
         env->trigger_cur = val;
     }
 }
@@ -701,7 +701,7 @@ static bool check_itrigger_priv(CPURISCVState *env, int index)
 bool riscv_itrigger_enabled(CPURISCVState *env)
 {
     int count;
-    for (int i = 0; i < RV_MAX_TRIGGERS; i++) {
+    for (int i = 0; i < env->num_triggers; i++) {
         if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) {
             continue;
         }
@@ -721,7 +721,7 @@ bool riscv_itrigger_enabled(CPURISCVState *env)
 void helper_itrigger_match(CPURISCVState *env)
 {
     int count;
-    for (int i = 0; i < RV_MAX_TRIGGERS; i++) {
+    for (int i = 0; i < env->num_triggers; i++) {
         if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) {
             continue;
         }
@@ -750,7 +750,7 @@ static void riscv_itrigger_update_count(CPURISCVState *env)
     int64_t last_icount = env->last_icount, current_icount;
     current_icount = env->last_icount = icount_get_raw();
 
-    for (int i = 0; i < RV_MAX_TRIGGERS; i++) {
+    for (int i = 0; i < env->num_triggers; i++) {
         if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) {
             continue;
         }
@@ -950,7 +950,7 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs)
     int i;
 
     QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
-        for (i = 0; i < RV_MAX_TRIGGERS; i++) {
+        for (i = 0; i < env->num_triggers; i++) {
             trigger_type = get_trigger_type(env, i);
 
             if (!trigger_common_match(env, trigger_type, i)) {
@@ -996,7 +996,7 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
     int flags;
     int i;
 
-    for (i = 0; i < RV_MAX_TRIGGERS; i++) {
+    for (i = 0; i < env->num_triggers; i++) {
         trigger_type = get_trigger_type(env, i);
 
         if (!trigger_common_match(env, trigger_type, i)) {
@@ -1049,19 +1049,49 @@ void riscv_trigger_realize(CPURISCVState *env)
 {
     int i;
 
-    for (i = 0; i < RV_MAX_TRIGGERS; i++) {
+    /*
+     * Alloc env->tdata1/2/3, cpu_breakpoint, cpu_watchpoint and
+     * itrigger_timer dynamically.  This is overkill now
+     * given that they could be static arrays with RV_MAX_TRIGGERS
+     * but we'll parametrize the trigger number later, i.e. the
+     * array length won't be static.
+     */
+    env->num_triggers = RV_MAX_TRIGGERS;
+    env->tdata1 = g_new0(uint64_t, env->num_triggers);
+    env->tdata2 = g_new0(uint64_t, env->num_triggers);
+    env->tdata3 = g_new0(uint64_t, env->num_triggers);
+    env->cpu_breakpoint = g_new0(struct CPUBreakpoint *, env->num_triggers);
+    env->cpu_watchpoint = g_new0(struct CPUWatchpoint *, env->num_triggers);
+    env->itrigger_timer = g_new0(QEMUTimer *, env->num_triggers);
+
+    for (i = 0; i < env->num_triggers; i++) {
         env->itrigger_timer[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                               riscv_itrigger_timer_cb, env);
     }
 }
 
+void riscv_trigger_unrealize(CPURISCVState *env)
+{
+    g_free(env->tdata1);
+    g_free(env->tdata2);
+    g_free(env->tdata3);
+
+    g_free(env->cpu_breakpoint);
+    g_free(env->cpu_watchpoint);
+
+    for (int i = 0; i < env->num_triggers; i++) {
+        timer_del(env->itrigger_timer[i]);
+    }
+    g_free(env->itrigger_timer);
+}
+
 void riscv_trigger_reset_hold(CPURISCVState *env)
 {
     target_ulong tdata1 = build_tdata1(env, TRIGGER_TYPE_AD_MATCH, 0, 0);
     int i;
 
     /* init to type 2 triggers */
-    for (i = 0; i < RV_MAX_TRIGGERS; i++) {
+    for (i = 0; i < env->num_triggers; i++) {
         /*
          * type = TRIGGER_TYPE_AD_MATCH
          * dmode = 0 (both debug and M-mode can write tdata)
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 6e70b145a5..ba96ceceef 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -240,16 +240,22 @@ static int debug_post_load(void *opaque, int version_id)
 
 static const VMStateDescription vmstate_debug = {
     .name = "cpu/debug",
-    .version_id = 3,
-    .minimum_version_id = 3,
+    .version_id = 4,
+    .minimum_version_id = 4,
     .needed = debug_needed,
     .post_load = debug_post_load,
     .fields = (const VMStateField[]) {
         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_VARRAY_UINT32(env.tdata1, RISCVCPU,
+                              env.num_triggers, 0,
+                              vmstate_info_uint64, uint64_t),
+        VMSTATE_VARRAY_UINT32(env.tdata2, RISCVCPU,
+                              env.num_triggers, 0,
+                              vmstate_info_uint64, uint64_t),
+        VMSTATE_VARRAY_UINT32(env.tdata3, RISCVCPU,
+                              env.num_triggers, 0,
+                              vmstate_info_uint64, uint64_t),
         VMSTATE_END_OF_LIST()
     }
 };
-- 
2.54.0



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

* [PULL 06/39] target/riscv: add 'num-triggers' debug property
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (4 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 05/39] target/riscv: dynamic alloc of debug trigger arrays alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 07/39] target/riscv/cpu.c: add 'svbare' satp-mode alistair23
                   ` (34 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Daniel Henrique Barboza, Philippe Mathieu-Daudé,
	Alistair Francis

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

All CPUs have the same amount of triggers: 2 triggers per hart, set via
RV_MAX_TRIGGERS.  This is not enough anymore: we'll have at least one
future CPU that will demand more triggers per hart when implementing the
RISC-V Server Ref Platform, requiring at least 11 triggers per hart.

Parametrize the trigger amount using a new 'num_triggers' property.  The
default amount is kept at 2 for backwards compatibility.  The new
maximum is bumped to a generous 1024 triggers per hart, which hopefully
will be enough for the foreseeable future.

The property can be set in two ways:

- a '.num_triggers' CPU definition flag, allowing CPUs to set a custom
  amount inside the CPU def in DEFINE_RISCV_CPU();
- a new 'num-triggers' user property.  The user property has a higher
  priority than an existing '.num_triggers' CPU def setting.

Assuming a hypothetical case where a CPU 'X' is defined with
'.num_triggers = 8':

- -cpu X,num-triggers=30 => num_triggers set to 30
- -cpu X (...)           => num_triggers set to 8

For a CPU that doesn't set '.num_triggers':

- -cpu rv64,num-triggers=30 => num_triggers set to 30
- -cpu rv64 (...)           => num_triggers set to 2

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260617131710.1855353-4-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h   | 19 ++++++++++++++++++-
 target/riscv/cpu.c   | 11 +++++++++++
 target/riscv/debug.c | 16 ++++++++--------
 3 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index af246a56ed..bdd28d329b 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -189,7 +189,22 @@ extern RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[];
 #define RV_VLEN_MAX 1024
 #define RV_MAX_MHPMEVENTS 32
 #define RV_MAX_MHPMCOUNTERS 32
-#define RV_MAX_TRIGGERS 2
+
+/*
+ * The Debug 1.0 spec allows a humongous amount of triggers.  Section
+ * "Enumeration" says: "The above algorithm reads back tselect so that
+ * implementations which have 2^n triggers only need to implement n
+ * bits of tselect.".  tselect can have up to XLEN bits, so the max
+ * theoretical RV_MAX_TRIGGERS value is 2^XLEN.
+ *
+ * Allowing 2^XLEN triggers per hart is silly so we'll set a max to a
+ * modest 1024 triggers, which is way more than what we see current
+ * hardware use (most chips uses 2-4 triggers per hart, RISC-V Server
+ * Ref requires at least 11).  With a 1024 max per hart we'll be set
+ * for a long time ... hopefully.
+ */
+#define RV_MAX_TRIGGERS 1024
+#define RV_DEFAULT_NUM_TRIGGERS 2
 
 FIELD(VTYPE, VLMUL, 0, 3)
 FIELD(VTYPE, VSEW, 3, 3)
@@ -577,6 +592,8 @@ typedef struct RISCVCPUDef {
     RISCVCPUConfig cfg;
     bool bare;
     const RISCVCSR *custom_csrs;
+    /* This is just a setter for env->num_triggers.  */
+    uint32_t num_triggers;
 } RISCVCPUDef;
 
 /**
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e7318fe9f9..e16608bbbe 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1164,6 +1164,11 @@ static void riscv_cpu_init(Object *obj)
                       IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX);
     qdev_init_gpio_in_named(DEVICE(cpu), riscv_cpu_set_nmi,
                             "riscv.cpu.rnmi", RNMI_MAX);
+
+    if (mcc->def->num_triggers) {
+        env->num_triggers = mcc->def->num_triggers;
+    }
+
 #endif /* CONFIG_USER_ONLY */
 
     cpu->user_options = g_hash_table_new(g_str_hash, g_str_equal);
@@ -2616,6 +2621,8 @@ static const Property riscv_cpu_properties[] = {
                        DEFAULT_RNMI_IRQVEC),
     DEFINE_PROP_UINT64("rnmi-exception-vector", RISCVCPU, env.rnmi_excpvec,
                        DEFAULT_RNMI_EXCPVEC),
+    DEFINE_PROP_UINT32("num-triggers", RISCVCPU, env.num_triggers,
+                       RV_DEFAULT_NUM_TRIGGERS),
 #endif
 
     DEFINE_PROP_BOOL("short-isa-string", RISCVCPU, cfg.short_isa_string, false),
@@ -2761,6 +2768,10 @@ static void riscv_cpu_class_base_init(ObjectClass *c, const void *data)
                 !valid_vm_1_10_32[mcc->def->cfg.max_satp_mode]) {
                 mcc->def->cfg.max_satp_mode = VM_1_10_SV32;
             }
+
+            if (def->num_triggers) {
+                mcc->def->num_triggers = def->num_triggers;
+            }
 #endif
         }
         if (def->priv_spec != RISCV_PROFILE_ATTR_UNUSED) {
diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index 9a4910c431..ba5bc6ae13 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -26,6 +26,7 @@
 #include "qemu/osdep.h"
 #include "qemu/log.h"
 #include "qapi/error.h"
+#include "qemu/error-report.h"
 #include "cpu.h"
 #include "target/riscv/debug.h"
 #include "trace.h"
@@ -1049,14 +1050,13 @@ void riscv_trigger_realize(CPURISCVState *env)
 {
     int i;
 
-    /*
-     * Alloc env->tdata1/2/3, cpu_breakpoint, cpu_watchpoint and
-     * itrigger_timer dynamically.  This is overkill now
-     * given that they could be static arrays with RV_MAX_TRIGGERS
-     * but we'll parametrize the trigger number later, i.e. the
-     * array length won't be static.
-     */
-    env->num_triggers = RV_MAX_TRIGGERS;
+    if (env->num_triggers > RV_MAX_TRIGGERS) {
+        error_report(
+                "Invalid configuration: 'num-triggers' must be less than %u",
+                RV_MAX_TRIGGERS);
+        exit(1);
+    }
+
     env->tdata1 = g_new0(uint64_t, env->num_triggers);
     env->tdata2 = g_new0(uint64_t, env->num_triggers);
     env->tdata3 = g_new0(uint64_t, env->num_triggers);
-- 
2.54.0



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

* [PULL 07/39] target/riscv/cpu.c: add 'svbare' satp-mode
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (5 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 06/39] target/riscv: add 'num-triggers' debug property alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 08/39] hw/riscv/virt-acpi-build: Fix RINTC PLIC context ID for KVM alistair23
                   ` (33 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

Seems like we forgot to add a flag to set satp-mode=bare.  What we're
doing instead is to set the CPU default satp-mode to 'off' to set it to
bare ... assuming we know the default satp-mode.  Otherwise one needs to
do -cpu X,sv39=off,sv48=off,sv57=off,sv64=off to get a bare-mode CPU.

Add a flag to make this process easier.  The name choice is based on the
fact that I didn't find many references to 'mbare' in RISC-V docs, but
'svbare' is a flag name that toolchain uses to set satp-mode=bare.
Might as well use the same name to help with cross project compat.

After this patch:

$ ./build/qemu-system-riscv64 -M virt,dumpdtb=fdt.dtb -cpu rv64
$ dtc -I dtb -O dts fdt.dtb  | grep mmu-type
                        mmu-type = "riscv,sv57";
$ ./build/qemu-system-riscv64 -M virt,dumpdtb=fdt.dtb -cpu rv64,svbare=on
$ dtc -I dtb -O dts fdt.dtb  | grep mmu-type
                        mmu-type = "riscv,none";

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

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e16608bbbe..bff3ed5de1 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -418,7 +418,7 @@ int riscv_cpu_max_xlen(RISCVCPUClass *mcc)
 #ifndef CONFIG_USER_ONLY
 static uint8_t satp_mode_from_str(const char *satp_mode_str)
 {
-    if (!strncmp(satp_mode_str, "mbare", 5)) {
+    if (!strncmp(satp_mode_str, "svbare", 6)) {
         return VM_1_10_MBARE;
     }
 
@@ -1063,6 +1063,9 @@ void riscv_add_satp_mode_properties(Object *obj)
 {
     RISCVCPU *cpu = RISCV_CPU(obj);
 
+    object_property_add(obj, "svbare", "bool", cpu_riscv_get_satp,
+                        cpu_riscv_set_satp, NULL, &cpu->satp_modes);
+
     if (cpu->env.misa_mxl == MXL_RV32) {
         object_property_add(obj, "sv32", "bool", cpu_riscv_get_satp,
                             cpu_riscv_set_satp, NULL, &cpu->satp_modes);
-- 
2.54.0



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

* [PULL 08/39] hw/riscv/virt-acpi-build: Fix RINTC PLIC context ID for KVM
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (6 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 07/39] target/riscv/cpu.c: add 'svbare' satp-mode alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 09/39] target/riscv: avoid abort when reading vtype before env->xl is set alistair23
                   ` (32 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Qingwei Hu, Nutty Liu, Sunil V L, Alistair Francis

From: Qingwei Hu <qingwei.hu@bytedance.com>

Each RISC-V MADT RINTC entry contains an External Interrupt Controller
ID field. On the virt machine without AIA, this field identifies the
S-mode PLIC context associated with the hart.

TCG virt has both M-mode and S-mode PLIC contexts, so the S-mode context
ID is odd and 2 * local_cpu_id + 1 is correct. KVM virt exposes only
S-mode PLIC contexts, and those contexts are numbered contiguously from
0. Reporting the TCG context ID for KVM makes the guest enable a
different PLIC context from the one used by QEMU.

With ACPI enabled, this can leave PCI INTx interrupts pending in QEMU
while the guest-programmed PLIC context remains disabled. A virtio-blk
root disk can then stall during boot because its first interrupt is never
delivered.

Use local_cpu_id for KVM and keep the existing odd S-mode context ID for
TCG.

Fixes: d641da6ed43 ("hw/riscv/virt-acpi-build.c: Add PLIC in MADT")
Signed-off-by: Qingwei Hu <qingwei.hu@bytedance.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Reviewed-by: Sunil V L <sunilvl@oss.qualcomm.com>
Message-ID: <20260604120017.398890-1-qingwei.hu@bytedance.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/virt-acpi-build.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c
index 413d47d70e..6b06d9aa87 100644
--- a/hw/riscv/virt-acpi-build.c
+++ b/hw/riscv/virt-acpi-build.c
@@ -100,6 +100,8 @@ static void riscv_acpi_madt_add_rintc(uint32_t uid,
         build_append_int_noprefix(entry,
                                   ACPI_BUILD_INTC_ID(
                                       arch_ids->cpus[uid].props.node_id,
+                                      kvm_enabled() ?
+                                      local_cpu_id :
                                       2 * local_cpu_id + 1),
                                   4);
     } else {
-- 
2.54.0



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

* [PULL 09/39] target/riscv: avoid abort when reading vtype before env->xl is set
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (7 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 08/39] hw/riscv/virt-acpi-build: Fix RINTC PLIC context ID for KVM alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 10/39] hw/intc: riscv_aplic: Skip reset for KVM irqchip alistair23
                   ` (31 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, ZhengXiang Qin, Daniel Henrique Barboza,
	Alistair Francis

From: ZhengXiang Qin <qinzhengxiang@foxmail.com>

TCG plugins may read registers from the vcpu_init_cb() callback.  For
vtype, this reaches read_vtype() before env->xl has been initialized.

In that case read_vtype() currently hits g_assert_not_reached() because
env->xl is zero.  Fall back to the CPU's maximum XLEN only for this
early-init case.

Fixes: 638181a180bd ("core/cpu-common: initialise plugin state before thread creation")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3545
Signed-off-by: ZhengXiang Qin <qinzhengxiang@foxmail.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <tencent_FB929239B227F05F30D62745E38BA01D4307@qq.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/csr.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index a60a796725..7fb0ad5bc1 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -949,7 +949,16 @@ static RISCVException read_vtype(CPURISCVState *env, int csrno,
                                  target_ulong *val)
 {
     uint64_t vill;
-    switch (env->xl) {
+    int xl = env->xl;
+    /*
+     * TCG plugins can read registers before env->xl is initialized.
+     * Fall back to the CPU's maximum XLEN in that early-init case.
+     */
+    if (xl == 0) {
+        xl = riscv_cpu_mxl(env);
+    }
+
+    switch (xl) {
     case MXL_RV32:
         vill = (uint32_t)env->vill << 31;
         break;
-- 
2.54.0



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

* [PULL 10/39] hw/intc: riscv_aplic: Skip reset for KVM irqchip
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (8 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 09/39] target/riscv: avoid abort when reading vtype before env->xl is set alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 11/39] hw/intc: riscv_imsic: " alistair23
                   ` (30 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Qingwei Hu, Nutty Liu, Alistair Francis

From: Qingwei Hu <qingwei.hu@bytedance.com>

The emulated APLIC state arrays are only allocated when QEMU handles
the interrupt controller state itself. With KVM AIA/APLIC-IMSIC, the
interrupt controller state is owned by the KVM in-kernel irqchip, so
these emulated state arrays are not allocated.

The APLIC reset handler still clears those arrays unconditionally. This
makes qemu_system_reset(), which runs during machine creation,
dereference NULL pointers with -machine virt,aia=aplic-imsic and KVM.

Skip the emulated APLIC reset path when the interrupt controller is
handled by KVM. The emulated path is unchanged for TCG and for
configurations that use QEMU emulation.

Fixes: 99bfcd329a ("hw/intc: riscv_aplic: Add reset API to APLIC")
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Signed-off-by: Qingwei Hu <qingwei.hu@bytedance.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615131925.3019370-2-qingwei.hu@bytedance.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/intc/riscv_aplic.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c
index c2c67c29e6..84606e9f3d 100644
--- a/hw/intc/riscv_aplic.c
+++ b/hw/intc/riscv_aplic.c
@@ -910,6 +910,10 @@ static void riscv_aplic_reset_enter(Object *obj, ResetType type)
     RISCVAPLICState *aplic = RISCV_APLIC(obj);
     int i;
 
+    if (!riscv_use_emulated_aplic(aplic->msimode)) {
+        return;
+    }
+
     aplic->domaincfg = 0;
     memset(aplic->sourcecfg, 0, sizeof(uint32_t) * aplic->num_irqs);
     memset(aplic->target, 0, sizeof(uint32_t) * aplic->num_irqs);
-- 
2.54.0



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

* [PULL 11/39] hw/intc: riscv_imsic: Skip reset for KVM irqchip
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (9 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 10/39] hw/intc: riscv_aplic: Skip reset for KVM irqchip alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 12/39] target/riscv/kvm: skip FP/Vector sync on KVM_PUT_RUNTIME_STATE alistair23
                   ` (29 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Qingwei Hu, Nutty Liu, Alistair Francis

From: Qingwei Hu <qingwei.hu@bytedance.com>

The emulated IMSIC state arrays are only allocated when QEMU handles
the interrupt controller state itself. With KVM AIA/APLIC-IMSIC, the
interrupt controller state is owned by the KVM in-kernel irqchip, so
these emulated state arrays are not allocated.

The IMSIC reset handler still clears those arrays unconditionally. This
makes qemu_system_reset(), which runs during machine creation,
dereference NULL pointers with -machine virt,aia=aplic-imsic and KVM.

Skip the emulated IMSIC reset path when the interrupt controller is
handled by KVM. The emulated path is unchanged for TCG and for
configurations that use QEMU emulation.

Fixes: 766391483b ("hw/intc: riscv_imsic: Add reset API to IMSIC")
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Signed-off-by: Qingwei Hu <qingwei.hu@bytedance.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615131925.3019370-3-qingwei.hu@bytedance.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/intc/riscv_imsic.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c
index 1c86ecdb2c..7e5b5349ba 100644
--- a/hw/intc/riscv_imsic.c
+++ b/hw/intc/riscv_imsic.c
@@ -347,6 +347,10 @@ static void riscv_imsic_reset_enter(Object *obj, ResetType type)
     RISCVIMSICState *imsic = RISCV_IMSIC(obj);
     int i;
 
+    if (kvm_irqchip_in_kernel()) {
+        return;
+    }
+
     memset(imsic->eidelivery, 0, sizeof(uint32_t) * imsic->num_pages);
     memset(imsic->eithreshold, 0, sizeof(uint32_t) * imsic->num_pages);
 
-- 
2.54.0



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

* [PULL 12/39] target/riscv/kvm: skip FP/Vector sync on KVM_PUT_RUNTIME_STATE
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (10 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 11/39] hw/intc: riscv_imsic: " alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 13/39] hw/riscv/sifive_u.c: remove unneeded qemu_fdt_get_phandle() call alistair23
                   ` (28 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Meng Zhuo, Alistair Francis, Chao Liu

From: Meng Zhuo <mengzhuo@iscas.ac.cn>

During KVM exit processing (KVM_PUT_RUNTIME_STATE), QEMU never modifies
FP or Vector registers — only core GPRs/PC and CSRs are potentially
changed.  Re-syncing 32 FP and 32 Vector registers on every KVM exit
wastes 36-68 individual KVM_SET_ONE_REG ioctls per vCPU exit.

Follow the s390x pattern: early return on RUNTIME after syncing core
registers and CSRs.  KVM_PUT_FULL_STATE and KVM_PUT_RESET_STATE continue
to sync everything for correctness during migration and initialization.

Signed-off-by: Meng Zhuo <mengzhuo@iscas.ac.cn>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Message-ID: <20260518102118.2768383-1-mengzhuo@iscas.ac.cn>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/kvm/kvm-cpu.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index f0de5c3071..39d48a9db4 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1395,6 +1395,17 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
         return ret;
     }
 
+    /*
+     * For RUNTIME_STATE, KVM already has the correct FP and Vector state
+     * from the preceding KVM_RUN exit. QEMU never modifies these registers
+     * during exit handling, so re-syncing is unnecessary.  This saves ~68
+     * KVM_SET_ONE_REG ioctls per vCPU exit.  See also s390x which uses
+     * the same pattern.
+     */
+    if (KVM_PUT_RUNTIME_STATE == level) {
+        return ret;
+    }
+
     ret = kvm_riscv_put_regs_fp(cs);
     if (ret) {
         return ret;
@@ -1407,11 +1418,9 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
 
     if (KVM_PUT_RESET_STATE == level) {
         RISCVCPU *cpu = RISCV_CPU(cs);
-        if (cs->cpu_index == 0) {
-            ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_RUNNABLE);
-        } else {
-            ret = kvm_riscv_sync_mpstate_to_kvm(cpu, KVM_MP_STATE_STOPPED);
-        }
+        int state = cs->cpu_index == 0 ? KVM_MP_STATE_RUNNABLE
+                                       : KVM_MP_STATE_STOPPED;
+        ret = kvm_riscv_sync_mpstate_to_kvm(cpu, state);
         if (ret) {
             return ret;
         }
-- 
2.54.0



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

* [PULL 13/39] hw/riscv/sifive_u.c: remove unneeded qemu_fdt_get_phandle() call
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (11 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 12/39] target/riscv/kvm: skip FP/Vector sync on KVM_PUT_RUNTIME_STATE alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 14/39] hw/riscv/sifive_u.c: use intc_phandle in plic creation alistair23
                   ` (27 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

create_fdt() has the following code sequence:

    plic_phandle = phandle++;
    (...)
    qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
    plic_phandle = qemu_fdt_get_phandle(fdt, nodename);

What this is doing is assigning a value to plic_phandle, then use that
as phandle of "nodename", and then fetching the phandle of "nodename"
again in the same variable that already had the right phandle val.

Here's how it looks like in gdb:

Thread 1 "qemu-system-ris" hit Breakpoint 1, create_fdt
     (s=0xaaaaac162a30, memmap=0xaaaaab8f70c8 <sifive_u_memmap>,
      is_32_bit=false) at ../hw/riscv/sifive_u.c:199
199         plic_phandle = phandle++;
(gdb) n
200         cells =  g_new0(uint32_t, ms->smp.cpus * 4 - 2);
(gdb) p plic_phandle
$3 = 12
(gdb) c
Continuing.

Thread 1 "qemu-system-ris" hit Breakpoint 2, create_fdt
    (s=0xaaaaac162a30, memmap=0xaaaaab8f70c8 <sifive_u_memmap>,
     is_32_bit=false) at ../hw/riscv/sifive_u.c:232
232         plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
(gdb) n
233         g_free(cells);
(gdb) p plic_phandle
$4 = 12
(gdb)

Remove the extra qemu_fdt_get_phandle() call.

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

diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 0c6e4204cb..fda9a09f06 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -229,7 +229,6 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
     qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev",
                           SIFIVE_U_PLIC_NUM_SOURCES - 1);
     qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
-    plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
     g_free(cells);
     g_free(nodename);
 
-- 
2.54.0



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

* [PULL 14/39] hw/riscv/sifive_u.c: use intc_phandle in plic creation
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (12 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 13/39] hw/riscv/sifive_u.c: remove unneeded qemu_fdt_get_phandle() call alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 15/39] hw/riscv/sifive_u: add #address-cells in PLIC FDT alistair23
                   ` (26 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

The info about intc_phandles for each CPU is already stored in the
intc_phandles array.  We don't need to fetch them again using
qemu_fdt_get_phandle().

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

diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index fda9a09f06..b3468254f5 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -199,20 +199,16 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
     plic_phandle = phandle++;
     cells =  g_new0(uint32_t, ms->smp.cpus * 4 - 2);
     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);
         /* cpu 0 is the management hart that does not have S-mode */
         if (cpu == 0) {
-            cells[0] = cpu_to_be32(intc_phandle);
+            cells[0] = cpu_to_be32(intc_phandles[cpu]);
             cells[1] = cpu_to_be32(IRQ_M_EXT);
         } else {
-            cells[cpu * 4 - 2] = cpu_to_be32(intc_phandle);
+            cells[cpu * 4 - 2] = cpu_to_be32(intc_phandles[cpu]);
             cells[cpu * 4 - 1] = cpu_to_be32(IRQ_M_EXT);
-            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_S_EXT);
         }
-        g_free(nodename);
     }
     nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
         (long)memmap[SIFIVE_U_DEV_PLIC].base);
-- 
2.54.0



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

* [PULL 15/39] hw/riscv/sifive_u: add #address-cells in PLIC FDT
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (13 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 14/39] hw/riscv/sifive_u.c: use intc_phandle in plic creation alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 16/39] hw/riscv/virt.c: change 'plic' nodename to 'interrupt-controller' alistair23
                   ` (25 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

By Linux FDT docs in [1] the "address-cells" property is mandatory.  Set
it to zero.

While we're at it let's also put this new value and the interrupt-cells
value in macros, like the 'virt' board is doing.

[1] https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/sifive%2Cplic-1.0.0.txt

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

diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h
index e4c9860d50..aed966a62d 100644
--- a/include/hw/riscv/sifive_u.h
+++ b/include/hw/riscv/sifive_u.h
@@ -156,6 +156,8 @@ enum {
 #define SIFIVE_U_MANAGEMENT_CPU_COUNT   1
 #define SIFIVE_U_COMPUTE_CPU_COUNT      4
 
+#define SIFIVE_U_PLIC_ADDR_CELLS   0
+#define SIFIVE_U_PLIC_INT_CELLS    1
 #define SIFIVE_U_PLIC_NUM_SOURCES 54
 #define SIFIVE_U_PLIC_NUM_PRIORITIES 7
 #define SIFIVE_U_PLIC_PRIORITY_BASE 0x00
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index b3468254f5..7dfc18d3ec 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -213,7 +213,10 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
     nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
         (long)memmap[SIFIVE_U_DEV_PLIC].base);
     qemu_fdt_add_subnode(fdt, nodename);
-    qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1);
+    qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells",
+                          SIFIVE_U_PLIC_INT_CELLS);
+    qemu_fdt_setprop_cell(fdt, nodename, "#address-cells",
+                          SIFIVE_U_PLIC_ADDR_CELLS);
     qemu_fdt_setprop_string_array(fdt, nodename, "compatible",
         (char **)&plic_compat, ARRAY_SIZE(plic_compat));
     qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
-- 
2.54.0



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

* [PULL 16/39] hw/riscv/virt.c: change 'plic' nodename to 'interrupt-controller'
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (14 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 15/39] hw/riscv/sifive_u: add #address-cells in PLIC FDT alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 17/39] hw/riscv: add create_fdt_plic() helper alistair23
                   ` (24 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

We're still using "/soc/plic@..." as FDT nodename in virt.c.  This is
not the right nodename per the DT docs:

https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/sifive%2Cplic-1.0.0.txt

The nodename must be 'interrupt-controller@...' since the node inherits
the 'interrupt-controller' type.  In fact, ever since at least the 2020
Linux kernel commit c825a081c169cc7f ("dt-bindings: riscv: convert plic
bindings to json-schema") the correct nodename has been
'interrupt-controller' for the sifive PLIC controller.

There's no deprecation needed for bug fixes so we're just fixing the
name.  This was the policy we dud when fixing the aplic [1] and the
imsic [2] nodenames to 'interrupt-controller@...' as well.

The sifive_u PLIC FDT already uses the correct nodename for PLIC, so it
is safe to assume that available SW is already aware of the correct
nodename and this change won't affect well-behaved SW.

[1] commit 29390fd ("hw/riscv/virt.c: rename aplic nodename to 'interrupt-controller'")
[2] commit e8ad581 ("hw/riscv/virt.c: change imsic nodename to 'interrupt-controller'")

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

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 33775a61fd..fa464e644f 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -335,7 +335,7 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
     plic_phandles[socket] = (*phandle)++;
     plic_addr = s->memmap[VIRT_PLIC].base +
                 (s->memmap[VIRT_PLIC].size * socket);
-    plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
+    plic_name = g_strdup_printf("/soc/interrupt-controller@%lx", plic_addr);
     qemu_fdt_add_subnode(ms->fdt, plic_name);
     qemu_fdt_setprop_cell(ms->fdt, plic_name,
         "#interrupt-cells", FDT_PLIC_INT_CELLS);
-- 
2.54.0



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

* [PULL 17/39] hw/riscv: add create_fdt_plic() helper
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (15 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 16/39] hw/riscv/virt.c: change 'plic' nodename to 'interrupt-controller' alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 18/39] hw/riscv/riscv-iommu: rename regs_rw to regs alistair23
                   ` (23 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

Consolidate the common plic FDT code between 'virt' and sifive_u boards
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: <20260616235939.1358663-6-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         | 30 +++++++++++++++++++++
 hw/riscv/sifive_u.c           | 34 +++++++-----------------
 hw/riscv/virt.c               | 49 ++++++++++++-----------------------
 4 files changed, 61 insertions(+), 57 deletions(-)

diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index 2d6b9a5d03..017278b611 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -30,4 +30,9 @@ 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);
+void create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
+                     uint32_t plic_phandle, uint32_t int_cells,
+                     uint32_t addr_cells, uint32_t *plic_cells,
+                     uint32_t cells_size, uint32_t ndev_sources,
+                     bool numa_enabled, int socket);
 #endif
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index b27ff13bca..e0e31af09b 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -200,3 +200,33 @@ create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
                                    socket_id, socket_hartid_base,
                                    phandle, intc_phandles, false, false);
 }
+
+void create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
+                     uint32_t plic_phandle, uint32_t int_cells,
+                     uint32_t addr_cells, uint32_t *plic_cells,
+                     uint32_t cells_size, uint32_t ndev_sources,
+                     bool numa_enabled, int socket_id)
+{
+    g_autofree char *nodename = NULL;
+    static const char * const plic_compat[2] = {
+        "sifive,plic-1.0.0", "riscv,plic0"
+    };
+
+    nodename = g_strdup_printf("/soc/interrupt-controller@%"HWADDR_PRIx, addr);
+
+    qemu_fdt_add_subnode(fdt, nodename);
+    qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", int_cells);
+    qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", addr_cells);
+    qemu_fdt_setprop_string_array(fdt, nodename, "compatible",
+        (char **)&plic_compat, ARRAY_SIZE(plic_compat));
+    qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
+    qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
+                     plic_cells, cells_size);
+    qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
+                                 2, addr, 2, size);
+    qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", ndev_sources);
+    if (numa_enabled) {
+        qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id", socket_id);
+    }
+    qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
+}
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 7dfc18d3ec..d923f041e0 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -100,14 +100,11 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
     MachineState *ms = MACHINE(s);
     void *fdt;
     int cpu;
-    uint32_t *cells;
+    uint32_t *cells, cells_length;
     char *nodename;
     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 plic_compat[2] = {
-        "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;
 
@@ -197,7 +194,8 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
     g_free(nodename);
 
     plic_phandle = phandle++;
-    cells =  g_new0(uint32_t, ms->smp.cpus * 4 - 2);
+    cells_length = ms->smp.cpus * 4 - 2;
+    cells =  g_new0(uint32_t, cells_length);
     for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
         /* cpu 0 is the management hart that does not have S-mode */
         if (cpu == 0) {
@@ -210,26 +208,14 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
             cells[cpu * 4 + 1] = cpu_to_be32(IRQ_S_EXT);
         }
     }
-    nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
-        (long)memmap[SIFIVE_U_DEV_PLIC].base);
-    qemu_fdt_add_subnode(fdt, nodename);
-    qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells",
-                          SIFIVE_U_PLIC_INT_CELLS);
-    qemu_fdt_setprop_cell(fdt, nodename, "#address-cells",
-                          SIFIVE_U_PLIC_ADDR_CELLS);
-    qemu_fdt_setprop_string_array(fdt, nodename, "compatible",
-        (char **)&plic_compat, ARRAY_SIZE(plic_compat));
-    qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
-    qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
-        cells, (ms->smp.cpus * 4 - 2) * sizeof(uint32_t));
-    qemu_fdt_setprop_cells(fdt, nodename, "reg",
-        0x0, memmap[SIFIVE_U_DEV_PLIC].base,
-        0x0, memmap[SIFIVE_U_DEV_PLIC].size);
-    qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev",
-                          SIFIVE_U_PLIC_NUM_SOURCES - 1);
-    qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
+
+    create_fdt_plic(fdt, memmap[SIFIVE_U_DEV_PLIC].base,
+                    memmap[SIFIVE_U_DEV_PLIC].size,
+                    plic_phandle, SIFIVE_U_PLIC_INT_CELLS,
+                    SIFIVE_U_PLIC_ADDR_CELLS, cells,
+                    cells_length * sizeof(uint32_t),
+                    SIFIVE_U_PLIC_NUM_SOURCES - 1, false, 0);
     g_free(cells);
-    g_free(nodename);
 
     gpio_phandle = phandle++;
     nodename = g_strdup_printf("/soc/gpio@%lx",
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index fa464e644f..92c30a6f4c 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -326,39 +326,25 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
     int cpu;
     g_autofree char *plic_name = NULL;
     g_autofree uint32_t *plic_cells;
-    unsigned long plic_addr;
     MachineState *ms = MACHINE(s);
-    static const char * const plic_compat[2] = {
-        "sifive,plic-1.0.0", "riscv,plic0"
-    };
+    unsigned long plic_addr = s->memmap[VIRT_PLIC].base +
+                              (s->memmap[VIRT_PLIC].size * socket);
+    bool numa_enabled = riscv_numa_enabled(MACHINE(s));
+    uint32_t cells_length;
 
-    plic_phandles[socket] = (*phandle)++;
-    plic_addr = s->memmap[VIRT_PLIC].base +
-                (s->memmap[VIRT_PLIC].size * socket);
     plic_name = g_strdup_printf("/soc/interrupt-controller@%lx", plic_addr);
-    qemu_fdt_add_subnode(ms->fdt, plic_name);
-    qemu_fdt_setprop_cell(ms->fdt, plic_name,
-        "#interrupt-cells", FDT_PLIC_INT_CELLS);
-    qemu_fdt_setprop_cell(ms->fdt, plic_name,
-        "#address-cells", FDT_PLIC_ADDR_CELLS);
-    qemu_fdt_setprop_string_array(ms->fdt, plic_name, "compatible",
-                                  (char **)&plic_compat,
-                                  ARRAY_SIZE(plic_compat));
-    qemu_fdt_setprop(ms->fdt, plic_name, "interrupt-controller", NULL, 0);
 
     if (kvm_enabled()) {
-        plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
+        cells_length = s->soc[socket].num_harts * 2;
+        plic_cells = g_new0(uint32_t, cells_length);
 
         for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
             plic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
             plic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT);
         }
-
-        qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended",
-                         plic_cells,
-                         s->soc[socket].num_harts * sizeof(uint32_t) * 2);
    } else {
-        plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
+        cells_length = s->soc[socket].num_harts * 4;
+        plic_cells = g_new0(uint32_t, cells_length);
 
         for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
             plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
@@ -366,19 +352,16 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
             plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
             plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
         }
-
-        qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended",
-                         plic_cells,
-                         s->soc[socket].num_harts * sizeof(uint32_t) * 4);
     }
 
-    qemu_fdt_setprop_sized_cells(ms->fdt, plic_name, "reg",
-                                 2, plic_addr, 2, s->memmap[VIRT_PLIC].size);
-    qemu_fdt_setprop_cell(ms->fdt, plic_name, "riscv,ndev",
-                          VIRT_IRQCHIP_NUM_SOURCES - 1);
-    riscv_socket_fdt_write_id(ms, plic_name, socket);
-    qemu_fdt_setprop_cell(ms->fdt, plic_name, "phandle",
-        plic_phandles[socket]);
+    plic_phandles[socket] = (*phandle)++;
+
+    create_fdt_plic(ms->fdt, plic_addr, s->memmap[VIRT_PLIC].size,
+                    plic_phandles[socket], FDT_PLIC_INT_CELLS,
+                    FDT_PLIC_ADDR_CELLS, plic_cells,
+                    cells_length * sizeof(uint32_t),
+                    VIRT_IRQCHIP_NUM_SOURCES - 1,
+                    numa_enabled, socket);
 
     if (!socket) {
         platform_bus_add_all_fdt_nodes(ms->fdt, plic_name,
-- 
2.54.0



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

* [PULL 18/39] hw/riscv/riscv-iommu: rename regs_rw to regs
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (16 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 17/39] hw/riscv: add create_fdt_plic() helper alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 19/39] hw/riscv/riscv-iommu.c: make FCTL.BE read only 0 alistair23
                   ` (22 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

The existing nomenclature can be misleading: regs_rw can cosplay as
'read and write' mask, in particular because we have regs_ro which is a
read only mask.

regs_rw is the current reg value, and all bits that aren't on the
regs_ro mask is considered r/w bits.

Rename regs_rw to 'regs' to be on par with the nomenclature other
devices uses (e.g. cadence_gem).

Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260625210833.3294437-2-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/riscv-iommu.h     | 26 +++++++++++++++-----------
 hw/riscv/riscv-iommu-hpm.c |  4 ++--
 hw/riscv/riscv-iommu.c     | 36 ++++++++++++++++++------------------
 3 files changed, 35 insertions(+), 31 deletions(-)

diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
index 2a9f6fccd5..a778e86fb7 100644
--- a/hw/riscv/riscv-iommu.h
+++ b/hw/riscv/riscv-iommu.h
@@ -76,9 +76,13 @@ struct RISCVIOMMUState {
 
     /* MMIO Hardware Interface */
     MemoryRegion regs_mr;
-    uint8_t *regs_rw;  /* register state (user write) */
+    uint8_t *regs;  /* current register state */
     uint8_t *regs_wc;  /* write-1-to-clear mask */
-    uint8_t *regs_ro;  /* read-only mask */
+    /*
+     * read-only mask. NOTE: bits not present in this RO
+     * mask are assumed to be read and write.
+     */
+    uint8_t *regs_ro;
 
     QLIST_ENTRY(RISCVIOMMUState) iommus;
     QLIST_HEAD(, RISCVIOMMUSpace) spaces;
@@ -120,39 +124,39 @@ struct RISCVIOMMUContext {
 static inline uint32_t riscv_iommu_reg_mod32(RISCVIOMMUState *s,
     unsigned idx, uint32_t set, uint32_t clr)
 {
-    uint32_t val = ldl_le_p(s->regs_rw + idx);
-    stl_le_p(s->regs_rw + idx, (val & ~clr) | set);
+    uint32_t val = ldl_le_p(s->regs + idx);
+    stl_le_p(s->regs + idx, (val & ~clr) | set);
     return val;
 }
 
 static inline void riscv_iommu_reg_set32(RISCVIOMMUState *s, unsigned idx,
                                          uint32_t set)
 {
-    stl_le_p(s->regs_rw + idx, set);
+    stl_le_p(s->regs + idx, set);
 }
 
 static inline uint32_t riscv_iommu_reg_get32(RISCVIOMMUState *s, unsigned idx)
 {
-    return ldl_le_p(s->regs_rw + idx);
+    return ldl_le_p(s->regs + idx);
 }
 
 static inline uint64_t riscv_iommu_reg_mod64(RISCVIOMMUState *s, unsigned idx,
                                              uint64_t set, uint64_t clr)
 {
-    uint64_t val = ldq_le_p(s->regs_rw + idx);
-    stq_le_p(s->regs_rw + idx, (val & ~clr) | set);
+    uint64_t val = ldq_le_p(s->regs + idx);
+    stq_le_p(s->regs + idx, (val & ~clr) | set);
     return val;
 }
 
 static inline void riscv_iommu_reg_set64(RISCVIOMMUState *s, unsigned idx,
                                          uint64_t set)
 {
-    stq_le_p(s->regs_rw + idx, set);
+    stq_le_p(s->regs + idx, set);
 }
 
 static inline uint64_t riscv_iommu_reg_get64(RISCVIOMMUState *s,
-    unsigned idx)
+                                             unsigned idx)
 {
-    return ldq_le_p(s->regs_rw + idx);
+    return ldq_le_p(s->regs + idx);
 }
 #endif
diff --git a/hw/riscv/riscv-iommu-hpm.c b/hw/riscv/riscv-iommu-hpm.c
index 5bf80a8db9..9bfef6db45 100644
--- a/hw/riscv/riscv-iommu-hpm.c
+++ b/hw/riscv/riscv-iommu-hpm.c
@@ -60,8 +60,8 @@ static void hpm_incr_ctr(RISCVIOMMUState *s, uint32_t ctr_idx)
     const uint32_t off = ctr_idx << 3;
     uint64_t cntr_val;
 
-    cntr_val = ldq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off]);
-    stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_IOHPMCTR_BASE + off], cntr_val + 1);
+    cntr_val = ldq_le_p(&s->regs[RISCV_IOMMU_REG_IOHPMCTR_BASE + off]);
+    stq_le_p(&s->regs[RISCV_IOMMU_REG_IOHPMCTR_BASE + off], cntr_val + 1);
 
     trace_riscv_iommu_hpm_incr_ctr(cntr_val);
 
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index a500cb8440..30f16b999c 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -2034,8 +2034,8 @@ static void riscv_iommu_process_cq_control(RISCVIOMMUState *s)
         s->cq_mask = (2ULL << get_field(base, RISCV_IOMMU_CQB_LOG2SZ)) - 1;
         s->cq_addr = PPN_PHYS(get_field(base, RISCV_IOMMU_CQB_PPN));
         stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_CQT], ~s->cq_mask);
-        stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_CQH], 0);
-        stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_CQT], 0);
+        stl_le_p(&s->regs[RISCV_IOMMU_REG_CQH], 0);
+        stl_le_p(&s->regs[RISCV_IOMMU_REG_CQT], 0);
         ctrl_set = RISCV_IOMMU_CQCSR_CQON;
         ctrl_clr = RISCV_IOMMU_CQCSR_BUSY | RISCV_IOMMU_CQCSR_CQMF |
                    RISCV_IOMMU_CQCSR_CMD_ILL | RISCV_IOMMU_CQCSR_CMD_TO |
@@ -2075,8 +2075,8 @@ static void riscv_iommu_process_fq_control(RISCVIOMMUState *s)
         s->fq_mask = (2ULL << get_field(base, RISCV_IOMMU_FQB_LOG2SZ)) - 1;
         s->fq_addr = PPN_PHYS(get_field(base, RISCV_IOMMU_FQB_PPN));
         stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_FQH], ~s->fq_mask);
-        stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_FQH], 0);
-        stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_FQT], 0);
+        stl_le_p(&s->regs[RISCV_IOMMU_REG_FQH], 0);
+        stl_le_p(&s->regs[RISCV_IOMMU_REG_FQT], 0);
         ctrl_set = RISCV_IOMMU_FQCSR_FQON;
         ctrl_clr = RISCV_IOMMU_FQCSR_BUSY | RISCV_IOMMU_FQCSR_FQMF |
             RISCV_IOMMU_FQCSR_FQOF;
@@ -2105,8 +2105,8 @@ static void riscv_iommu_process_pq_control(RISCVIOMMUState *s)
         s->pq_mask = (2ULL << get_field(base, RISCV_IOMMU_PQB_LOG2SZ)) - 1;
         s->pq_addr = PPN_PHYS(get_field(base, RISCV_IOMMU_PQB_PPN));
         stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_PQH], ~s->pq_mask);
-        stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_PQH], 0);
-        stl_le_p(&s->regs_rw[RISCV_IOMMU_REG_PQT], 0);
+        stl_le_p(&s->regs[RISCV_IOMMU_REG_PQH], 0);
+        stl_le_p(&s->regs[RISCV_IOMMU_REG_PQT], 0);
         ctrl_set = RISCV_IOMMU_PQCSR_PQON;
         ctrl_clr = RISCV_IOMMU_PQCSR_BUSY | RISCV_IOMMU_PQCSR_PQMF |
             RISCV_IOMMU_PQCSR_PQOF;
@@ -2276,9 +2276,9 @@ static void riscv_iommu_write_reg_val(RISCVIOMMUState *s,
 {
     uint64_t ro = ldn_le_p(&s->regs_ro[reg_addr], size);
     uint64_t wc = ldn_le_p(&s->regs_wc[reg_addr], size);
-    uint64_t rw = ldn_le_p(&s->regs_rw[reg_addr], size);
+    uint64_t curr_val = ldn_le_p(&s->regs[reg_addr], size);
 
-    stn_le_p(dest, size, ((rw & ro) | (data & ~ro)) & ~(data & wc));
+    stn_le_p(dest, size, ((curr_val & ro) | (data & ~ro)) & ~(data & wc));
 }
 
 static MemTxResult riscv_iommu_mmio_write(void *opaque, hwaddr addr,
@@ -2378,12 +2378,12 @@ static MemTxResult riscv_iommu_mmio_write(void *opaque, hwaddr addr,
      * is set IOMMU behavior of additional writes to the register
      * is UNSPECIFIED.
      */
-    riscv_iommu_write_reg_val(s, &s->regs_rw[addr], addr, size, data);
+    riscv_iommu_write_reg_val(s, &s->regs[addr], addr, size, data);
 
     /* Busy flag update, MSB 4-byte register. */
     if (busy) {
-        uint32_t rw = ldl_le_p(&s->regs_rw[regb]);
-        stl_le_p(&s->regs_rw[regb], rw | busy);
+        uint32_t rw = ldl_le_p(&s->regs[regb]);
+        stl_le_p(&s->regs[regb], rw | busy);
     }
 
     /* Process HPM writes and update any internal state if needed. */
@@ -2428,13 +2428,13 @@ static MemTxResult riscv_iommu_mmio_read(void *opaque, hwaddr addr,
          * it's not dependent over the timer callback and is computed
          * from cycle overflow.
          */
-        val = ldq_le_p(&s->regs_rw[addr]);
+        val = ldq_le_p(&s->regs[addr]);
         val |= (riscv_iommu_hpmcycle_read(s) & RISCV_IOMMU_IOHPMCYCLES_OVF)
                    ? RISCV_IOMMU_IOCOUNTOVF_CY
                    : 0;
         ptr = (uint8_t *)&val + (addr & 3);
     } else {
-        ptr = &s->regs_rw[addr];
+        ptr = &s->regs[addr];
     }
 
     val = ldn_le_p(ptr, size);
@@ -2529,7 +2529,7 @@ static void riscv_iommu_instance_init(Object *obj)
     s->cap |= RISCV_IOMMU_CAP_PD8;
 
     /* register storage */
-    s->regs_rw = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
+    s->regs = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
     s->regs_ro = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
     s->regs_wc = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
 
@@ -2554,7 +2554,7 @@ static void riscv_iommu_instance_finalize(Object *obj)
 {
     RISCVIOMMUState *s = RISCV_IOMMU(obj);
 
-    g_free(s->regs_rw);
+    g_free(s->regs);
     g_free(s->regs_ro);
     g_free(s->regs_wc);
 
@@ -2608,8 +2608,8 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
         "riscv-iommu-regs", RISCV_IOMMU_REG_SIZE);
 
     /* Set power-on register state */
-    stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_CAP], s->cap);
-    stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_FCTL], 0);
+    stq_le_p(&s->regs[RISCV_IOMMU_REG_CAP], s->cap);
+    stq_le_p(&s->regs[RISCV_IOMMU_REG_FCTL], 0);
     stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_FCTL],
              ~(RISCV_IOMMU_FCTL_BE | RISCV_IOMMU_FCTL_WSI));
     stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_DDTP],
@@ -2634,7 +2634,7 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
         RISCV_IOMMU_PQCSR_BUSY);
     stl_le_p(&s->regs_wc[RISCV_IOMMU_REG_IPSR], ~0);
     stl_le_p(&s->regs_ro[RISCV_IOMMU_REG_ICVEC], 0);
-    stq_le_p(&s->regs_rw[RISCV_IOMMU_REG_DDTP], s->ddtp);
+    stq_le_p(&s->regs[RISCV_IOMMU_REG_DDTP], s->ddtp);
     /* If debug registers enabled. */
     if (s->cap & RISCV_IOMMU_CAP_DBG) {
         stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_TR_REQ_IOVA], 0);
-- 
2.54.0



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

* [PULL 19/39] hw/riscv/riscv-iommu.c: make FCTL.BE read only 0
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (17 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 18/39] hw/riscv/riscv-iommu: rename regs_rw to regs alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 20/39] hw/riscv/riscv-iommu: check DC.TC reserved bits alistair23
                   ` (21 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

We do not support FCTL.BE equal to 1 hence do not allow this bit to be
set by software.

While we're at it: the riscv-iommu spec allows FCTL.GXL to be set freely
and we do not have hardcoded restrictions on it, so make it writable.

Fixes: 0c54acb824 ("hw/riscv: add RISC-V IOMMU base emulation")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3576
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260625210833.3294437-3-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/riscv-iommu.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 30f16b999c..c9687e01a8 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -2609,9 +2609,11 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
 
     /* Set power-on register state */
     stq_le_p(&s->regs[RISCV_IOMMU_REG_CAP], s->cap);
+
     stq_le_p(&s->regs[RISCV_IOMMU_REG_FCTL], 0);
     stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_FCTL],
-             ~(RISCV_IOMMU_FCTL_BE | RISCV_IOMMU_FCTL_WSI));
+             ~(RISCV_IOMMU_FCTL_GXL | RISCV_IOMMU_FCTL_WSI));
+
     stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_DDTP],
         ~(RISCV_IOMMU_DDTP_PPN | RISCV_IOMMU_DDTP_MODE));
     stq_le_p(&s->regs_ro[RISCV_IOMMU_REG_CQB],
-- 
2.54.0



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

* [PULL 20/39] hw/riscv/riscv-iommu: check DC.TC reserved bits
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (18 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 19/39] hw/riscv/riscv-iommu.c: make FCTL.BE read only 0 alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 21/39] target/riscv: Apply UXL WARL handling to vsstatus alistair23
                   ` (20 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

We are not checking for reserved TC bits being set during device context
validation.

Fixes: 0c54acb8243d ("hw/riscv: add RISC-V IOMMU base emulation")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3548
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260627194640.4130073-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/riscv-iommu-bits.h | 3 +++
 hw/riscv/riscv-iommu.c      | 4 ++++
 2 files changed, 7 insertions(+)

diff --git a/hw/riscv/riscv-iommu-bits.h b/hw/riscv/riscv-iommu-bits.h
index a938fd3eb4..f9b6f35170 100644
--- a/hw/riscv/riscv-iommu-bits.h
+++ b/hw/riscv/riscv-iommu-bits.h
@@ -308,6 +308,9 @@ struct riscv_iommu_dc {
 #define RISCV_IOMMU_DC_IOHGATP_GSCID    GENMASK_ULL(59, 44)
 #define RISCV_IOMMU_DC_IOHGATP_MODE     RISCV_IOMMU_ATP_MODE_FIELD
 
+#define RISCV_IOMMU_DC_TC_RESERVED      (GENMASK_ULL(23, 12) \
+                                         | GENMASK_ULL(63, 32))
+
 enum riscv_iommu_dc_iohgatp_modes {
     RISCV_IOMMU_DC_IOHGATP_MODE_BARE = 0,
     RISCV_IOMMU_DC_IOHGATP_MODE_SV32X4 = 8,
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index c9687e01a8..c2c470b5df 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -752,6 +752,10 @@ static bool riscv_iommu_validate_device_ctx(RISCVIOMMUState *s,
     uint32_t fsc_mode, msi_mode;
     uint64_t gatp;
 
+    if (ctx->tc & RISCV_IOMMU_DC_TC_RESERVED) {
+        return false;
+    }
+
     if (!(s->cap & RISCV_IOMMU_CAP_ATS) &&
         (ctx->tc & RISCV_IOMMU_DC_TC_EN_ATS ||
          ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI ||
-- 
2.54.0



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

* [PULL 21/39] target/riscv: Apply UXL WARL handling to vsstatus
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (19 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 20/39] hw/riscv/riscv-iommu: check DC.TC reserved bits alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 22/39] hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set alistair23
                   ` (19 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, SeungJu Cheon, Daniel Henrique Barboza,
	Alistair Francis

From: SeungJu Cheon <suunj1331@gmail.com>

write_mstatus() already handles the reserved UXL value by writing a
legal value instead.

Apply the same handling when writing vsstatus so that reserved UXL
values follow the same WARL behavior.

Factor the common logic into a local helper riscv_write_uxl() and use
it for both mstatus and vsstatus.

Suggested-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Fixes: f310df58bd2 ("target/riscv: Enable uxl field write")
Signed-off-by: SeungJu Cheon <suunj1331@gmail.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260625081521.595683-1-suunj1331@gmail.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/csr.c | 27 +++++++++++++++++----------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 7fb0ad5bc1..7168a4dc12 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2021,6 +2021,20 @@ static target_ulong legalize_mpp(CPURISCVState *env, target_ulong old_mpp,
     return val;
 }
 
+static uint64_t riscv_write_uxl(CPURISCVState *env, uint64_t val,
+                                uint64_t field)
+{
+    RISCVMXL xl = riscv_cpu_mxl(env);
+    uint64_t uxl = get_field(val, field);
+
+    if (uxl == MXL_RV128) {
+        uxl = xl == MXL_RV128 ? MXL_RV64 : xl;
+        val = set_field(val, field, uxl);
+    }
+
+    return val;
+}
+
 static RISCVException write_mstatus(CPURISCVState *env, int csrno,
                                     target_ulong val, uintptr_t ra)
 {
@@ -2067,17 +2081,8 @@ 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);
-            }
+            val = riscv_write_uxl(env, val, MSTATUS64_UXL);
         }
     }
 
@@ -5239,6 +5244,8 @@ static RISCVException write_vsstatus(CPURISCVState *env, int csrno,
     uint64_t mask = (target_ulong)-1;
     if ((val & VSSTATUS64_UXL) == 0) {
         mask &= ~VSSTATUS64_UXL;
+    } else {
+        val = riscv_write_uxl(env, val, VSSTATUS64_UXL);
     }
     if ((env->henvcfg & HENVCFG_DTE)) {
         if ((val & SSTATUS_SDT) != 0) {
-- 
2.54.0



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

* [PULL 22/39] hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (20 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 21/39] target/riscv: Apply UXL WARL handling to vsstatus alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 23/39] hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately alistair23
                   ` (18 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

We're not setting RISCV_IOMMU_CQCSR_CMD_ILL if a reserved bit happens to
be set in an IOFENCE.C command.

Fixes: 0c54acb8243d ("hw/riscv: add RISC-V IOMMU base emulation")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3575
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260626170533.3562484-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/riscv-iommu-bits.h | 1 +
 hw/riscv/riscv-iommu.c      | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/hw/riscv/riscv-iommu-bits.h b/hw/riscv/riscv-iommu-bits.h
index f9b6f35170..cc0b1c3ccd 100644
--- a/hw/riscv/riscv-iommu-bits.h
+++ b/hw/riscv/riscv-iommu-bits.h
@@ -347,6 +347,7 @@ struct riscv_iommu_command {
 #define RISCV_IOMMU_CMD_IOFENCE_OPCODE          2
 #define RISCV_IOMMU_CMD_IOFENCE_FUNC_C          0
 #define RISCV_IOMMU_CMD_IOFENCE_AV      BIT_ULL(10)
+#define RISCV_IOMMU_CMD_IOFENCE_RESERVED GENMASK_ULL(31, 14)
 #define RISCV_IOMMU_CMD_IOFENCE_DATA    GENMASK_ULL(63, 32)
 
 #define RISCV_IOMMU_CMD_IODIR_OPCODE            3
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index c2c470b5df..9bf02084cc 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -1880,6 +1880,10 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
         switch (cmd_opcode) {
         case RISCV_IOMMU_CMD(RISCV_IOMMU_CMD_IOFENCE_FUNC_C,
                              RISCV_IOMMU_CMD_IOFENCE_OPCODE):
+            if (cmd.dword0 & RISCV_IOMMU_CMD_IOFENCE_RESERVED) {
+                goto cmd_ill;
+            }
+
             res = riscv_iommu_iofence(s,
                 cmd.dword0 & RISCV_IOMMU_CMD_IOFENCE_AV, cmd.dword1 << 2,
                 get_field(cmd.dword0, RISCV_IOMMU_CMD_IOFENCE_DATA));
-- 
2.54.0



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

* [PULL 23/39] hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (21 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 22/39] hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 24/39] hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset alistair23
                   ` (17 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

We're hardcoding 'true' to FQ_HDR_PV in riscv_iommu_report_fault().  Use
the 'pv' bool the caller provides that indicates if the process_id is
valid.

Fixes: 0c54acb8243d ("hw/riscv: add RISC-V IOMMU base emulation")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3556
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260626173341.3661446-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/riscv-iommu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 9bf02084cc..c65e273dbb 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -580,7 +580,7 @@ static void riscv_iommu_report_fault(RISCVIOMMUState *s,
     ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_CAUSE, cause);
     ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_TTYPE, fault_type);
     ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_DID, ctx->devid);
-    ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_PV, true);
+    ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_PV, pv);
 
     if (pv) {
         ev.hdr = set_field(ev.hdr, RISCV_IOMMU_FQ_HDR_PID, ctx->process_id);
-- 
2.54.0



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

* [PULL 24/39] hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (22 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 23/39] hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 25/39] target/riscv: Report QEMU CPU archid as 42 alistair23
                   ` (16 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Daniel Henrique Barboza, Alistair Francis

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

We're doing a wrong shift when calculating the offset for the
interrupt-pending bits, off by one right shift order.

This went undercover for awhile because the calculation works for
interrupt entities 1 to 63.  The math goes wrong when using interrupt
entities 64 or greater.

Instead of fixing the issue and running we're also adding some notes
on where this calc comes from.

Fixes: 0c54acb8243d ("hw/riscv: add RISC-V IOMMU base emulation")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3561
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260626220529.3800372-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/riscv-iommu.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index c65e273dbb..01f5634f04 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -686,7 +686,26 @@ static MemTxResult riscv_iommu_msi_write(RISCVIOMMUState *s,
 
     /* MRIF pending bit address */
     addr = get_field(pte[0], RISCV_IOMMU_MSI_PTE_MRIF_ADDR) << 9;
-    addr = addr | ((data & 0x7c0) >> 3);
+    /*
+     * AIA spec section "Format of a memory-resident interrupt file":
+     * address offset 0x000 contains interrupt-pending bits for
+     * identities 1-63, offfset 0x010 for identities 64-127, and
+     * so it goes up to 0x1F0 for identities 1984-2047.
+     *
+     * Hence each batch of identities advances offset by 16 (0x010)
+     * for every interrupt-pending bits.  This means that doing
+     * (data & 0x7c0) will filter out the first 6 bits, then
+     * a >> 2 will turn the result in the 0x10 steps we need.
+     *
+     * E.g:
+     *
+     * - (1-63 & 0x7c0) = 0, 0 >> 2 = 0, offset 0x000
+     * - (64-127 & 0x7c0) = 64, 64 >> 2 = 16, offset 0x010
+     * - (128-191 & 0x7c0) = 128, 128 >> 2 = 32, offset 0x020
+     *
+     * and so on.
+     */
+    addr = addr | ((data & 0x7c0) >> 2);
 
     trace_riscv_iommu_msi(s->parent_obj.id, PCI_BUS_NUM(ctx->devid),
                           PCI_SLOT(ctx->devid), PCI_FUNC(ctx->devid),
-- 
2.54.0



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

* [PULL 25/39] target/riscv: Report QEMU CPU archid as 42
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (23 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 24/39] hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 26/39] target/riscv: Check PMP before updating PTE alistair23
                   ` (15 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Charlie Jenkins, Alistair Francis,
	Philippe Mathieu-Daudé

From: Charlie Jenkins <thecharlesjenkins@gmail.com>

When a non-vendor CPU is used, report the archid as 42 which has been
allocated for QEMU in the riscv isa manual [1]. This can help software
check if it is running in QEMU.

[1] https://github.com/riscv/riscv-isa-manual/blob/main/marchid.md

Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Message-ID: <20260625-marchid-v2-1-3821c351028b@gmail.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index bff3ed5de1..de94f5d57e 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -47,6 +47,13 @@
 static const char riscv_single_letter_exts[] = "IEMAFDQCBPVH";
 const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV,
                               RVC, RVS, RVU, RVH, RVG, RVB, 0};
+#define RISCV_CPU_MVENDORID 0
+#define RISCV_CPU_MIMPID 0
+/*
+ * marchid allocated for qemu:
+ * https://github.com/riscv/riscv-isa-manual/blob/main/marchid.md
+ */
+#define RISCV_CPU_MARCHID 42
 
 /*
  * From vector_helper.c
@@ -1204,6 +1211,10 @@ static void riscv_cpu_init(Object *obj)
         mcc->def->profile->enabled = true;
     }
 
+    cpu->cfg.mvendorid = RISCV_CPU_MVENDORID;
+    cpu->cfg.marchid = RISCV_CPU_MARCHID;
+    cpu->cfg.mimpid = RISCV_CPU_MIMPID;
+
     env->misa_ext_mask = env->misa_ext = mcc->def->misa_ext;
     riscv_cpu_cfg_merge(&cpu->cfg, &mcc->def->cfg);
 
-- 
2.54.0



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

* [PULL 26/39] target/riscv: Check PMP before updating PTE
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (24 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 25/39] target/riscv: Report QEMU CPU archid as 42 alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 27/39] hw/riscv/boot: Describe discontiguous memory in boot_info alistair23
                   ` (14 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Inochi Amaoto, qemu-stable, Alistair Francis

From: Inochi Amaoto <inochiama@gmail.com>

According to the RISC-V spec, the PTE update is a supervisor write
operations, and it should also follow the CPU PMP configuration like
the PTE read.

Cc: qemu-stable@nongnu.org
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260622113402.563196-1-inochiama@gmail.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 59edcdd370..2db07f5dfb 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1655,10 +1655,18 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
 
     /* Page table updates need to be atomic with MTTCG enabled */
     if (updated_pte != pte && !is_debug) {
+        int pmp_prot, pmp_ret;
+
         if (!adue) {
             return TRANSLATE_FAIL;
         }
 
+        pmp_ret = get_physical_address_pmp(env, &pmp_prot, pte_addr,
+                                           sxlen_bytes, MMU_DATA_STORE, PRV_S);
+        if (pmp_ret != TRANSLATE_SUCCESS) {
+            return TRANSLATE_PMP_FAIL;
+        }
+
         /*
          * - if accessed or dirty bits need updating, and the PTE is
          *   in RAM, then we do so atomically with a compare and swap.
-- 
2.54.0



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

* [PULL 27/39] hw/riscv/boot: Describe discontiguous memory in boot_info
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (25 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 26/39] target/riscv: Check PMP before updating PTE alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 28/39] hw/riscv/boot: Account for discontiguous memory when loading firmware alistair23
                   ` (13 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Nicholas Piggin, Daniel Henrique Barboza,
	Alistair Francis, Joel Stanley

From: Nicholas Piggin <npiggin@gmail.com>

Machines that have discontiguous memory may need to adjust where
firmware and images are loaded at boot. Provide an interface for
machines to describe a discontiguous low/high RAM scheme for this
purpose.

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-2-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/riscv/boot.h |  7 +++++++
 hw/riscv/boot.c         | 16 ++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h
index f00b3ca122..69c99a1496 100644
--- a/include/hw/riscv/boot.h
+++ b/include/hw/riscv/boot.h
@@ -28,6 +28,10 @@
 #define RISCV64_BIOS_BIN    "opensbi-riscv64-generic-fw_dynamic.bin"
 
 typedef struct RISCVBootInfo {
+    /* First contiguous RAM region. If size is zero then assume entire RAM */
+    hwaddr ram_low_start;
+    hwaddr ram_low_size;
+
     ssize_t kernel_size;
     hwaddr image_low_addr;
     hwaddr image_high_addr;
@@ -43,6 +47,9 @@ bool riscv_is_32bit(RISCVHartArrayState *harts);
 char *riscv_plic_hart_config_string(int hart_count);
 
 void riscv_boot_info_init(RISCVBootInfo *info, RISCVHartArrayState *harts);
+void riscv_boot_info_init_discontig_mem(RISCVBootInfo *info,
+                                        RISCVHartArrayState *harts,
+                                        hwaddr low_start, hwaddr low_size);
 vaddr riscv_calc_kernel_start_addr(RISCVBootInfo *info,
                                    hwaddr firmware_end_addr);
 hwaddr riscv_find_and_load_firmware(MachineState *machine,
diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index 7c9cd61468..c8418f83f4 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -70,11 +70,27 @@ char *riscv_plic_hart_config_string(int hart_count)
 
 void riscv_boot_info_init(RISCVBootInfo *info, RISCVHartArrayState *harts)
 {
+    info->ram_low_start = 0;
+    info->ram_low_size = 0;
     info->kernel_size = 0;
     info->initrd_size = 0;
     info->is_32bit = riscv_is_32bit(harts);
 }
 
+/*
+ * This can be used instead of riscv_boot_info_init() if the machine has
+ * discontiguous physical memory. The low memory range specified will be
+ * used to place firmware images.
+ */
+void riscv_boot_info_init_discontig_mem(RISCVBootInfo *info,
+                                        RISCVHartArrayState *harts,
+                                        hwaddr low_start, hwaddr low_size)
+{
+    riscv_boot_info_init(info, harts);
+    info->ram_low_start = low_start;
+    info->ram_low_size = low_size;
+}
+
 vaddr riscv_calc_kernel_start_addr(RISCVBootInfo *info,
                                    hwaddr firmware_end_addr) {
     if (info->is_32bit) {
-- 
2.54.0



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

* [PULL 28/39] hw/riscv/boot: Account for discontiguous memory when loading firmware
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (26 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 27/39] hw/riscv/boot: Describe discontiguous memory in boot_info alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 29/39] hw/riscv/virt: Move AIA initialisation to helper file alistair23
                   ` (12 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Nicholas Piggin, Daniel Henrique Barboza,
	Alistair Francis, Joel Stanley

From: Nicholas Piggin <npiggin@gmail.com>

This loads firmware into the first (low) memory range,
accounting for machines having discontiguous memory regions.

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-3-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/riscv/boot.h    |  5 ++++-
 hw/riscv/boot.c            | 18 ++++++++++++------
 hw/riscv/k230.c            |  8 ++++++--
 hw/riscv/microchip_pfsoc.c |  8 ++++++--
 hw/riscv/opentitan.c       |  6 ++++--
 hw/riscv/shakti_c.c        |  6 +++++-
 hw/riscv/sifive_u.c        |  6 ++++--
 hw/riscv/spike.c           |  6 ++++--
 hw/riscv/virt.c            |  7 ++++---
 hw/riscv/xiangshan_kmh.c   |  6 +++++-
 10 files changed, 54 insertions(+), 22 deletions(-)

diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h
index 69c99a1496..4e7bd9a225 100644
--- a/include/hw/riscv/boot.h
+++ b/include/hw/riscv/boot.h
@@ -53,13 +53,16 @@ void riscv_boot_info_init_discontig_mem(RISCVBootInfo *info,
 vaddr riscv_calc_kernel_start_addr(RISCVBootInfo *info,
                                    hwaddr firmware_end_addr);
 hwaddr riscv_find_and_load_firmware(MachineState *machine,
+                                    RISCVBootInfo *info,
                                     const char *default_machine_firmware,
                                     hwaddr *firmware_load_addr,
                                     symbol_fn_t sym_cb);
 const char *riscv_default_firmware_name(RISCVHartArrayState *harts);
 char *riscv_find_firmware(const char *firmware_filename,
                           const char *default_machine_firmware);
-hwaddr riscv_load_firmware(const char *firmware_filename,
+hwaddr riscv_load_firmware(MachineState *machine,
+                           const RISCVBootInfo *info,
+                           const char *firmware_filename,
                            hwaddr *firmware_load_addr,
                            symbol_fn_t sym_cb);
 void riscv_load_kernel(MachineState *machine,
diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index c8418f83f4..5e2dfa091a 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -151,6 +151,7 @@ char *riscv_find_firmware(const char *firmware_filename,
 }
 
 hwaddr riscv_find_and_load_firmware(MachineState *machine,
+                                    RISCVBootInfo *info,
                                     const char *default_machine_firmware,
                                     hwaddr *firmware_load_addr,
                                     symbol_fn_t sym_cb)
@@ -163,7 +164,8 @@ hwaddr riscv_find_and_load_firmware(MachineState *machine,
 
     if (firmware_filename) {
         /* If not "none" load the firmware */
-        firmware_end_addr = riscv_load_firmware(firmware_filename,
+        firmware_end_addr = riscv_load_firmware(machine, info,
+                                                firmware_filename,
                                                 firmware_load_addr, sym_cb);
         g_free(firmware_filename);
     }
@@ -171,10 +173,13 @@ hwaddr riscv_find_and_load_firmware(MachineState *machine,
     return firmware_end_addr;
 }
 
-hwaddr riscv_load_firmware(const char *firmware_filename,
+hwaddr riscv_load_firmware(MachineState *machine,
+                           const RISCVBootInfo *info,
+                           const char *firmware_filename,
                            hwaddr *firmware_load_addr,
                            symbol_fn_t sym_cb)
 {
+    uint64_t mem_size = info->ram_low_size ?: machine->ram_size;
     uint64_t firmware_entry, firmware_end;
     ssize_t firmware_size;
 
@@ -203,7 +208,7 @@ hwaddr riscv_load_firmware(const char *firmware_filename,
 
     firmware_size = load_image_targphys_as(firmware_filename,
                                            *firmware_load_addr,
-                                           current_machine->ram_size, NULL,
+                                           mem_size, NULL,
                                            NULL);
 
     if (firmware_size > 0) {
@@ -218,7 +223,7 @@ hwaddr riscv_load_firmware(const char *firmware_filename,
 static void riscv_load_initrd(MachineState *machine, RISCVBootInfo *info)
 {
     const char *filename = machine->initrd_filename;
-    uint64_t mem_size = machine->ram_size;
+    uint64_t mem_size = info->ram_low_size ?: machine->ram_size;
     void *fdt = machine->fdt;
     hwaddr start, end;
     ssize_t size;
@@ -264,6 +269,7 @@ void riscv_load_kernel(MachineState *machine,
                        bool load_initrd,
                        symbol_fn_t sym_cb)
 {
+    uint64_t mem_size = info->ram_low_size ?: machine->ram_size;
     const char *kernel_filename = machine->kernel_filename;
     ssize_t kernel_size;
     void *fdt = machine->fdt;
@@ -295,7 +301,7 @@ void riscv_load_kernel(MachineState *machine,
     }
 
     kernel_size = load_image_targphys_as(kernel_filename, kernel_start_addr,
-                                         current_machine->ram_size, NULL, NULL);
+                                         mem_size, NULL, NULL);
     if (kernel_size > 0) {
         info->kernel_size = kernel_size;
         info->image_low_addr = kernel_start_addr;
@@ -391,7 +397,7 @@ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size,
     dtb_start = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB);
 
     if (dtb_start_limit && (dtb_start < dtb_start_limit)) {
-        error_report("No enough memory to place DTB after kernel/initrd");
+        error_report("Not enough memory to place DTB after kernel/initrd");
         exit(1);
     }
 
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
index 502281c52c..656f28190c 100644
--- a/hw/riscv/k230.c
+++ b/hw/riscv/k230.c
@@ -424,7 +424,8 @@ static void k230_direct_boot(K230MachineState *s, MachineState *machine)
 
     riscv_load_fdt(K230_DIRECT_DTB_ADDR, machine->fdt);
 
-    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
+    firmware_end_addr = riscv_find_and_load_firmware(machine, &boot_info,
+                                                     firmware_name,
                                                      &start_addr, NULL);
     if (firmware_end_addr > K230_DIRECT_KERNEL_ADDR) {
         error_report("K230 firmware overlaps kernel address 0x%x",
@@ -442,13 +443,16 @@ 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;
+    RISCVBootInfo boot_info = {0};
 
     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_boot_info_init(&boot_info, &s->soc.c908_cpu);
+    riscv_find_and_load_firmware(machine, &boot_info, firmware_name,
+                                 &start_addr, NULL);
 
     riscv_setup_rom_reset_vec(machine, &s->soc.c908_cpu, start_addr,
                               memmap[K230_DEV_BOOTROM].base,
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index 5e48a29708..4017129c83 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -619,18 +619,22 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
         firmware_load_addr = RESET_VECTOR;
     }
 
+    riscv_boot_info_init_discontig_mem(&boot_info, &s->soc.u_cpus,
+                                       memmap[MICROCHIP_PFSOC_DRAM_LO].base,
+                                       mem_low_size);
+
     /* Load the firmware if necessary */
     firmware_end_addr = firmware_load_addr;
     if (firmware_name) {
         char *filename = riscv_find_firmware(firmware_name, NULL);
         if (filename) {
-            firmware_end_addr = riscv_load_firmware(filename,
+            firmware_end_addr = riscv_load_firmware(machine, &boot_info,
+                                                    filename,
                                                     &firmware_load_addr, NULL);
             g_free(filename);
         }
     }
 
-    riscv_boot_info_init(&boot_info, &s->soc.u_cpus);
     if (machine->kernel_filename) {
         kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
                                                          firmware_end_addr);
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index c8b2f028f2..5b2f33d5ac 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -100,12 +100,14 @@ static void opentitan_machine_init(MachineState *machine)
     memory_region_add_subregion(sys_mem,
         memmap[IBEX_DEV_RAM].base, machine->ram);
 
+    riscv_boot_info_init(&boot_info, &s->soc.cpus);
+
     if (machine->firmware) {
         hwaddr firmware_load_addr = memmap[IBEX_DEV_RAM].base;
-        riscv_load_firmware(machine->firmware, &firmware_load_addr, NULL);
+        riscv_load_firmware(machine, &boot_info, machine->firmware,
+                            &firmware_load_addr, NULL);
     }
 
-    riscv_boot_info_init(&boot_info, &s->soc.cpus);
     if (machine->kernel_filename) {
         riscv_load_kernel(machine, &boot_info,
                           memmap[IBEX_DEV_RAM].base,
diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c
index b1823a3125..835b1f879b 100644
--- a/hw/riscv/shakti_c.c
+++ b/hw/riscv/shakti_c.c
@@ -46,6 +46,7 @@ static void shakti_c_machine_state_init(MachineState *mstate)
 {
     ShaktiCMachineState *sms = RISCV_SHAKTI_MACHINE(mstate);
     MemoryRegion *system_memory = get_system_memory();
+    RISCVBootInfo boot_info;
     hwaddr firmware_load_addr = shakti_c_memmap[SHAKTI_C_RAM].base;
 
     /* Initialize SoC */
@@ -58,8 +59,11 @@ static void shakti_c_machine_state_init(MachineState *mstate)
                                 shakti_c_memmap[SHAKTI_C_RAM].base,
                                 mstate->ram);
 
+    riscv_boot_info_init(&boot_info, &sms->soc.cpus);
+
     if (mstate->firmware) {
-        riscv_load_firmware(mstate->firmware, &firmware_load_addr, NULL);
+        riscv_load_firmware(mstate, &boot_info, mstate->firmware,
+                            &firmware_load_addr, NULL);
     }
 
     /* ROM reset vector */
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index d923f041e0..99423ef472 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -524,11 +524,13 @@ static void sifive_u_machine_init(MachineState *machine)
         break;
     }
 
+    riscv_boot_info_init(&boot_info, &s->soc.u_cpus);
+
     firmware_name = riscv_default_firmware_name(&s->soc.u_cpus);
-    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
+    firmware_end_addr = riscv_find_and_load_firmware(machine, &boot_info,
+                                                     firmware_name,
                                                      &start_addr, NULL);
 
-    riscv_boot_info_init(&boot_info, &s->soc.u_cpus);
     if (machine->kernel_filename) {
         kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
                                                          firmware_end_addr);
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index 4e60724c14..9fde0faf39 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -205,9 +205,12 @@ static void spike_board_init(MachineState *machine)
         }
     }
 
+    riscv_boot_info_init(&boot_info, &s->soc[0]);
+
     /* Load firmware */
     if (firmware_name) {
-        firmware_end_addr = riscv_load_firmware(firmware_name,
+        firmware_end_addr = riscv_load_firmware(machine, &boot_info,
+                                                firmware_name,
                                                 &firmware_load_addr,
                                                 htif_symbol_callback);
         g_free(firmware_name);
@@ -217,7 +220,6 @@ static void spike_board_init(MachineState *machine)
     create_fdt(s, memmap, riscv_is_32bit(&s->soc[0]), htif_custom_base);
 
     /* Load kernel */
-    riscv_boot_info_init(&boot_info, &s->soc[0]);
     if (machine->kernel_filename) {
         kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
                                                          firmware_end_addr);
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 92c30a6f4c..efdb992cb8 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -1310,7 +1310,10 @@ static void virt_machine_done(Notifier *notifier, void *data)
         }
     }
 
-    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
+    riscv_boot_info_init(&boot_info, &s->soc[0]);
+
+    firmware_end_addr = riscv_find_and_load_firmware(machine, &boot_info,
+                                                     firmware_name,
                                                      &start_addr, NULL);
 
     pflash_blk0 = pflash_cfi01_get_blk(s->flash[0]);
@@ -1333,8 +1336,6 @@ static void virt_machine_done(Notifier *notifier, void *data)
         }
     }
 
-    riscv_boot_info_init(&boot_info, &s->soc[0]);
-
     if (machine->kernel_filename && !kernel_entry) {
         kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
                                                          firmware_end_addr);
diff --git a/hw/riscv/xiangshan_kmh.c b/hw/riscv/xiangshan_kmh.c
index 76417ba7ab..384624d69a 100644
--- a/hw/riscv/xiangshan_kmh.c
+++ b/hw/riscv/xiangshan_kmh.c
@@ -167,6 +167,7 @@ static void xiangshan_kmh_machine_init(MachineState *machine)
     const MemMapEntry *memmap = xiangshan_kmh_memmap;
     MemoryRegion *system_memory = get_system_memory();
     hwaddr start_addr = memmap[XIANGSHAN_KMH_DRAM].base;
+    RISCVBootInfo boot_info;
 
     /* Initialize SoC */
     object_initialize_child(OBJECT(machine), "soc", &s->soc,
@@ -178,13 +179,16 @@ static void xiangshan_kmh_machine_init(MachineState *machine)
                                 memmap[XIANGSHAN_KMH_DRAM].base,
                                 machine->ram);
 
+    riscv_boot_info_init(&boot_info, &s->soc.cpus);
+
     /* ROM reset vector */
     riscv_setup_rom_reset_vec(machine, &s->soc.cpus,
                               start_addr,
                               memmap[XIANGSHAN_KMH_ROM].base,
                               memmap[XIANGSHAN_KMH_ROM].size, 0, 0);
     if (machine->firmware) {
-        riscv_load_firmware(machine->firmware, &start_addr, NULL);
+        riscv_load_firmware(machine, &boot_info, machine->firmware,
+                            &start_addr, NULL);
     }
 
     /* Note: dtb has been integrated into firmware(OpenSBI) when compiling */
-- 
2.54.0



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

* [PULL 29/39] hw/riscv/virt: Move AIA initialisation to helper file
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (27 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 28/39] hw/riscv/boot: Account for discontiguous memory when loading firmware alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 30/39] hw/riscv/aia: Provide number of irq sources alistair23
                   ` (11 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Joel Stanley, Daniel Henrique Barboza, Nutty Liu,
	Philippe Mathieu-Daudé, Alistair Francis, Nicholas Piggin

From: Joel Stanley <joel@jms.id.au>

The AIA init will be used by any server class riscv machine. Separate it
out in order to share code with such systems.

The virt machine keeps machine specific #defines such as
VIRT_IRQCHIP_NUM_MSIS, VIRT_IRQCHIP_NUM_PRIO_BITS.

Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-4-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/aia.h             | 26 +++++++++++
 include/hw/riscv/virt.h    |  1 -
 hw/riscv/aia.c             | 89 ++++++++++++++++++++++++++++++++++++++
 hw/riscv/virt-acpi-build.c |  2 +
 hw/riscv/virt.c            | 87 +++++--------------------------------
 hw/riscv/meson.build       |  1 +
 6 files changed, 129 insertions(+), 77 deletions(-)
 create mode 100644 hw/riscv/aia.h
 create mode 100644 hw/riscv/aia.c

diff --git a/hw/riscv/aia.h b/hw/riscv/aia.h
new file mode 100644
index 0000000000..dbb8333402
--- /dev/null
+++ b/hw/riscv/aia.h
@@ -0,0 +1,26 @@
+/*
+ * QEMU RISC-V Advanced Interrupt Architecture (AIA)
+ *
+ * Copyright (C) 2019 Western Digital Corporation or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_RISCV_AIA_H
+#define HW_RISCV_AIA_H
+
+#include "exec/hwaddr.h"
+
+#define VIRT_IRQCHIP_NUM_SOURCES 96
+
+uint32_t imsic_num_bits(uint32_t count);
+
+DeviceState *riscv_create_aia(bool msimode, int aia_guests,
+                             const MemMapEntry *aplic_m,
+                             const MemMapEntry *aplic_s,
+                             const MemMapEntry *imsic_m,
+                             const MemMapEntry *imsic_s,
+                             int socket, int base_hartid, int hart_count,
+                             uint32_t num_msis, uint32_t num_prio_bits);
+
+#endif
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 18a2a323a3..ad858deb76 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -135,7 +135,6 @@ enum {
 bool virt_is_acpi_enabled(RISCVVirtState *s);
 bool virt_is_iommu_sys_enabled(RISCVVirtState *s);
 void virt_acpi_setup(RISCVVirtState *vms);
-uint32_t imsic_num_bits(uint32_t count);
 
 /*
  * The virt machine physical address space used by some of the devices
diff --git a/hw/riscv/aia.c b/hw/riscv/aia.c
new file mode 100644
index 0000000000..c724612a50
--- /dev/null
+++ b/hw/riscv/aia.c
@@ -0,0 +1,89 @@
+/*
+ * QEMU RISC-V Advanced Interrupt Architecture (AIA)
+ *
+ * Copyright (C) 2019 Western Digital Corporation or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "system/kvm.h"
+#include "hw/intc/riscv_aplic.h"
+#include "hw/intc/riscv_imsic.h"
+
+#include "aia.h"
+
+uint32_t imsic_num_bits(uint32_t count)
+{
+    uint32_t ret = 0;
+
+    while (BIT(ret) < count) {
+        ret++;
+    }
+
+    return ret;
+}
+
+DeviceState *riscv_create_aia(bool msimode, int aia_guests,
+                             const MemMapEntry *aplic_m,
+                             const MemMapEntry *aplic_s,
+                             const MemMapEntry *imsic_m,
+                             const MemMapEntry *imsic_s,
+                             int socket, int base_hartid, int hart_count,
+                             uint32_t num_msis, uint32_t num_prio_bits)
+{
+    int i;
+    hwaddr addr = 0;
+    uint32_t guest_bits;
+    DeviceState *aplic_s_dev = NULL;
+    DeviceState *aplic_m_dev = NULL;
+
+    if (msimode) {
+        if (!kvm_enabled()) {
+            /* Per-socket M-level IMSICs */
+            addr = imsic_m->base + socket * (1U << IMSIC_MMIO_GROUP_MIN_SHIFT);
+            for (i = 0; i < hart_count; i++) {
+                riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0),
+                                   base_hartid + i, true, 1,
+                                   num_msis);
+            }
+        }
+
+        /* Per-socket S-level IMSICs */
+        guest_bits = imsic_num_bits(aia_guests + 1);
+        addr = imsic_s->base + socket * (1U << IMSIC_MMIO_GROUP_MIN_SHIFT);
+        for (i = 0; i < hart_count; i++) {
+            riscv_imsic_create(addr + i * IMSIC_HART_SIZE(guest_bits),
+                               base_hartid + i, false, 1 + aia_guests,
+                               num_msis);
+        }
+    }
+
+    if (!kvm_enabled()) {
+        /* Per-socket M-level APLIC */
+        aplic_m_dev = riscv_aplic_create(aplic_m->base +
+                                     socket * aplic_m->size,
+                                     aplic_m->size,
+                                     (msimode) ? 0 : base_hartid,
+                                     (msimode) ? 0 : hart_count,
+                                     VIRT_IRQCHIP_NUM_SOURCES,
+                                     num_prio_bits,
+                                     msimode, true, NULL);
+    }
+
+    /* Per-socket S-level APLIC */
+    aplic_s_dev = riscv_aplic_create(aplic_s->base +
+                                 socket * aplic_s->size,
+                                 aplic_s->size,
+                                 (msimode) ? 0 : base_hartid,
+                                 (msimode) ? 0 : hart_count,
+                                 VIRT_IRQCHIP_NUM_SOURCES,
+                                 num_prio_bits,
+                                 msimode, false, aplic_m_dev);
+
+    if (kvm_enabled() && msimode) {
+        riscv_aplic_set_kvm_msicfgaddr(RISCV_APLIC(aplic_s_dev), addr);
+    }
+
+    return kvm_enabled() ? aplic_s_dev : aplic_m_dev;
+}
diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c
index 6b06d9aa87..02ab460e58 100644
--- a/hw/riscv/virt-acpi-build.c
+++ b/hw/riscv/virt-acpi-build.c
@@ -42,6 +42,8 @@
 #include "system/kvm.h"
 #include "system/reset.h"
 
+#include "aia.h"
+
 #define ACPI_BUILD_TABLE_SIZE             0x20000
 #define ACPI_BUILD_INTC_ID(socket, index) ((socket << 24) | (index))
 
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index efdb992cb8..b76bbb62f8 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -61,6 +61,8 @@
 #include "hw/virtio/virtio-iommu.h"
 #include "hw/uefi/var-service-api.h"
 
+#include "aia.h"
+
 /* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */
 static bool virt_use_kvm_aia_aplic_imsic(RISCVVirtAIAType aia_type)
 {
@@ -371,17 +373,6 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
     }
 }
 
-uint32_t imsic_num_bits(uint32_t count)
-{
-    uint32_t ret = 0;
-
-    while (BIT(ret) < count) {
-        ret++;
-    }
-
-    return ret;
-}
-
 static void create_fdt_one_imsic(RISCVVirtState *s, hwaddr base_addr,
                                  uint32_t *intc_phandles, uint32_t msi_phandle,
                                  bool m_mode, uint32_t imsic_guest_bits)
@@ -1146,68 +1137,6 @@ static DeviceState *virt_create_plic(const MemMapEntry *memmap, int socket,
              memmap[VIRT_PLIC].size);
 }
 
-static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests,
-                                    const MemMapEntry *memmap, int socket,
-                                    int base_hartid, int hart_count)
-{
-    int i;
-    hwaddr addr = 0;
-    uint32_t guest_bits;
-    DeviceState *aplic_s = NULL;
-    DeviceState *aplic_m = NULL;
-    bool msimode = aia_type == VIRT_AIA_TYPE_APLIC_IMSIC;
-
-    if (msimode) {
-        if (!kvm_enabled()) {
-            /* Per-socket M-level IMSICs */
-            addr = memmap[VIRT_IMSIC_M].base +
-                   socket * VIRT_IMSIC_GROUP_MAX_SIZE;
-            for (i = 0; i < hart_count; i++) {
-                riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0),
-                                   base_hartid + i, true, 1,
-                                   VIRT_IRQCHIP_NUM_MSIS);
-            }
-        }
-
-        /* Per-socket S-level IMSICs */
-        guest_bits = imsic_num_bits(aia_guests + 1);
-        addr = memmap[VIRT_IMSIC_S].base + socket * VIRT_IMSIC_GROUP_MAX_SIZE;
-        for (i = 0; i < hart_count; i++) {
-            riscv_imsic_create(addr + i * IMSIC_HART_SIZE(guest_bits),
-                               base_hartid + i, false, 1 + aia_guests,
-                               VIRT_IRQCHIP_NUM_MSIS);
-        }
-    }
-
-    if (!kvm_enabled()) {
-        /* Per-socket M-level APLIC */
-        aplic_m = riscv_aplic_create(memmap[VIRT_APLIC_M].base +
-                                     socket * memmap[VIRT_APLIC_M].size,
-                                     memmap[VIRT_APLIC_M].size,
-                                     (msimode) ? 0 : base_hartid,
-                                     (msimode) ? 0 : hart_count,
-                                     VIRT_IRQCHIP_NUM_SOURCES,
-                                     VIRT_IRQCHIP_NUM_PRIO_BITS,
-                                     msimode, true, NULL);
-    }
-
-    /* Per-socket S-level APLIC */
-    aplic_s = riscv_aplic_create(memmap[VIRT_APLIC_S].base +
-                                 socket * memmap[VIRT_APLIC_S].size,
-                                 memmap[VIRT_APLIC_S].size,
-                                 (msimode) ? 0 : base_hartid,
-                                 (msimode) ? 0 : hart_count,
-                                 VIRT_IRQCHIP_NUM_SOURCES,
-                                 VIRT_IRQCHIP_NUM_PRIO_BITS,
-                                 msimode, false, aplic_m);
-
-    if (kvm_enabled() && msimode) {
-        riscv_aplic_set_kvm_msicfgaddr(RISCV_APLIC(aplic_s), addr);
-    }
-
-    return kvm_enabled() ? aplic_s : aplic_m;
-}
-
 static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip)
 {
     DeviceState *dev;
@@ -1470,9 +1399,15 @@ static void virt_machine_init(MachineState *machine)
             s->irqchip[i] = virt_create_plic(s->memmap, i,
                                              base_hartid, hart_count);
         } else {
-            s->irqchip[i] = virt_create_aia(s->aia_type, s->aia_guests,
-                                            s->memmap, i, base_hartid,
-                                            hart_count);
+            s->irqchip[i] = riscv_create_aia(s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC,
+                                             s->aia_guests,
+                                             &s->memmap[VIRT_APLIC_M],
+                                             &s->memmap[VIRT_APLIC_S],
+                                             &s->memmap[VIRT_IMSIC_M],
+                                             &s->memmap[VIRT_IMSIC_S],
+                                             i, base_hartid, hart_count,
+                                             VIRT_IRQCHIP_NUM_MSIS,
+                                             VIRT_IRQCHIP_NUM_PRIO_BITS);
         }
 
         /* Try to use different IRQCHIP instance based device type */
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index b70a054579..798477b788 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -1,4 +1,5 @@
 riscv_ss = ss.source_set()
+riscv_ss.add(files('aia.c'))
 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'))
-- 
2.54.0



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

* [PULL 30/39] hw/riscv/aia: Provide number of irq sources
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (28 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 29/39] hw/riscv/virt: Move AIA initialisation to helper file alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 31/39] hw/riscv/aia: Configure stride for the M-mode IMSIC alistair23
                   ` (10 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Joel Stanley, Nutty Liu, Daniel Henrique Barboza,
	Philippe Mathieu-Daudé, Alistair Francis, Nicholas Piggin

From: Joel Stanley <joel@jms.id.au>

Instead of hard coding the number of IRQ sources used by the APLIC pass
it in as a parameter. This allows other machines to configure this as
required.

The maximum number of sources is 1023.

Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-5-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/aia.h             |  3 +--
 include/hw/riscv/virt.h    |  1 +
 hw/riscv/aia.c             |  8 ++++++--
 hw/riscv/virt-acpi-build.c | 25 ++++++++++++++++---------
 hw/riscv/virt.c            |  2 ++
 5 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/hw/riscv/aia.h b/hw/riscv/aia.h
index dbb8333402..5ad0a902be 100644
--- a/hw/riscv/aia.h
+++ b/hw/riscv/aia.h
@@ -11,11 +11,10 @@
 
 #include "exec/hwaddr.h"
 
-#define VIRT_IRQCHIP_NUM_SOURCES 96
-
 uint32_t imsic_num_bits(uint32_t count);
 
 DeviceState *riscv_create_aia(bool msimode, int aia_guests,
+                             uint16_t num_sources,
                              const MemMapEntry *aplic_m,
                              const MemMapEntry *aplic_s,
                              const MemMapEntry *imsic_m,
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index ad858deb76..36a2def410 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -64,6 +64,7 @@ struct RISCVVirtState {
     struct GPEXHost *gpex_host;
     OnOffAuto iommu_sys;
     uint16_t pci_iommu_bdf;
+    uint16_t num_sources;
 };
 
 enum {
diff --git a/hw/riscv/aia.c b/hw/riscv/aia.c
index c724612a50..82ea9d48ea 100644
--- a/hw/riscv/aia.c
+++ b/hw/riscv/aia.c
@@ -25,6 +25,7 @@ uint32_t imsic_num_bits(uint32_t count)
 }
 
 DeviceState *riscv_create_aia(bool msimode, int aia_guests,
+                             uint16_t num_sources,
                              const MemMapEntry *aplic_m,
                              const MemMapEntry *aplic_s,
                              const MemMapEntry *imsic_m,
@@ -38,6 +39,9 @@ DeviceState *riscv_create_aia(bool msimode, int aia_guests,
     DeviceState *aplic_s_dev = NULL;
     DeviceState *aplic_m_dev = NULL;
 
+    /* The RISC-V Advanced Interrupt Architecture, Chapter 1.2. Limits */
+    g_assert(num_sources <= 1023);
+
     if (msimode) {
         if (!kvm_enabled()) {
             /* Per-socket M-level IMSICs */
@@ -66,7 +70,7 @@ DeviceState *riscv_create_aia(bool msimode, int aia_guests,
                                      aplic_m->size,
                                      (msimode) ? 0 : base_hartid,
                                      (msimode) ? 0 : hart_count,
-                                     VIRT_IRQCHIP_NUM_SOURCES,
+                                     num_sources,
                                      num_prio_bits,
                                      msimode, true, NULL);
     }
@@ -77,7 +81,7 @@ DeviceState *riscv_create_aia(bool msimode, int aia_guests,
                                  aplic_s->size,
                                  (msimode) ? 0 : base_hartid,
                                  (msimode) ? 0 : hart_count,
-                                 VIRT_IRQCHIP_NUM_SOURCES,
+                                 num_sources,
                                  num_prio_bits,
                                  msimode, false, aplic_m_dev);
 
diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c
index 02ab460e58..59c454f4f9 100644
--- a/hw/riscv/virt-acpi-build.c
+++ b/hw/riscv/virt-acpi-build.c
@@ -148,6 +148,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s)
 }
 
 static void acpi_dsdt_add_plic_aplic(Aml *scope, uint8_t socket_count,
+                                     uint16_t num_sources,
                                      uint64_t mmio_base, uint64_t mmio_size,
                                      const char *hid)
 {
@@ -155,9 +156,12 @@ static void acpi_dsdt_add_plic_aplic(Aml *scope, uint8_t socket_count,
     uint32_t gsi_base;
     uint8_t  socket;
 
+    /* The RISC-V Advanced Interrupt Architecture, Chapter 1.2. Limits */
+    g_assert(num_sources <= 1023);
+
     for (socket = 0; socket < socket_count; socket++) {
         plic_aplic_addr = mmio_base + mmio_size * socket;
-        gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
+        gsi_base = num_sources * socket;
         Aml *dev = aml_device("IC%.02X", socket);
         aml_append(dev, aml_name_decl("_HID", aml_string("%s", hid)));
         aml_append(dev, aml_name_decl("_UID", aml_int(socket)));
@@ -476,10 +480,13 @@ static void build_dsdt(GArray *table_data,
     socket_count = riscv_socket_count(ms);
 
     if (s->aia_type == VIRT_AIA_TYPE_NONE) {
-        acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_PLIC].base,
-                                 memmap[VIRT_PLIC].size, "RSCV0001");
+        acpi_dsdt_add_plic_aplic(scope, socket_count, s->num_sources,
+                                 memmap[VIRT_PLIC].base,
+                                 memmap[VIRT_PLIC].size,
+                                 "RSCV0001");
     } else {
-        acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_APLIC_S].base,
+        acpi_dsdt_add_plic_aplic(scope, socket_count, s->num_sources,
+                                 memmap[VIRT_APLIC_S].base,
                                  memmap[VIRT_APLIC_S].size, "RSCV0002");
     }
 
@@ -496,15 +503,15 @@ static void build_dsdt(GArray *table_data,
     } else if (socket_count == 2) {
         virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
                              memmap[VIRT_VIRTIO].size,
-                             VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0,
+                             VIRTIO_IRQ + s->num_sources, 0,
                              VIRTIO_COUNT);
-        acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES);
+        acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + s->num_sources);
     } else {
         virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
                              memmap[VIRT_VIRTIO].size,
-                             VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0,
+                             VIRTIO_IRQ + s->num_sources, 0,
                              VIRTIO_COUNT);
-        acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES * 2);
+        acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + s->num_sources * 2);
     }
 
     aml_append(dsdt, scope);
@@ -583,7 +590,7 @@ static void build_madt(GArray *table_data,
         for (socket = 0; socket < riscv_socket_count(ms); socket++) {
             aplic_addr = s->memmap[VIRT_APLIC_S].base +
                              s->memmap[VIRT_APLIC_S].size * socket;
-            gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
+            gsi_base = s->num_sources * socket;
             build_append_int_noprefix(table_data, 0x1A, 1);    /* Type */
             build_append_int_noprefix(table_data, 36, 1);      /* Length */
             build_append_int_noprefix(table_data, 1, 1);       /* Version */
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index b76bbb62f8..8f80c0607b 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -1401,6 +1401,7 @@ static void virt_machine_init(MachineState *machine)
         } else {
             s->irqchip[i] = riscv_create_aia(s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC,
                                              s->aia_guests,
+                                             s->num_sources,
                                              &s->memmap[VIRT_APLIC_M],
                                              &s->memmap[VIRT_APLIC_S],
                                              &s->memmap[VIRT_IMSIC_M],
@@ -1557,6 +1558,7 @@ static void virt_machine_instance_init(Object *obj)
     s->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
     s->acpi = ON_OFF_AUTO_AUTO;
     s->iommu_sys = ON_OFF_AUTO_AUTO;
+    s->num_sources = VIRT_IRQCHIP_NUM_SOURCES;
 }
 
 static char *virt_get_aia_guests(Object *obj, Error **errp)
-- 
2.54.0



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

* [PULL 31/39] hw/riscv/aia: Configure stride for the M-mode IMSIC
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (29 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 30/39] hw/riscv/aia: Provide number of irq sources alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 32/39] target/riscv: tt-ascalon: Enable Zkr extension alistair23
                   ` (9 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Joel Stanley, Philippe Mathieu-Daudé,
	Alistair Francis

From: Joel Stanley <joel@jms.id.au>

riscv_create_aia() currently hard-codes the M-IMSIC at one 4 KiB page
per hart and gives callers no way to widen it.

Add an m_imsic_stride parameter that supplies the per hart byte
stride directly. The virt machine passes IMSIC_HART_SIZE(0)
(= 4 KiB), preserving its existing compact layout.

The parameter only changes how the slots are spaced, with the rest of
each slot reserved. This allows future platforms that have different
layouts to control the stride.

Reviewed-by: Philippe Mathieu-Daudé <philmd@mailo.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-6-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/aia.h  | 1 +
 hw/riscv/aia.c  | 3 ++-
 hw/riscv/virt.c | 1 +
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/aia.h b/hw/riscv/aia.h
index 5ad0a902be..565f91accc 100644
--- a/hw/riscv/aia.h
+++ b/hw/riscv/aia.h
@@ -14,6 +14,7 @@
 uint32_t imsic_num_bits(uint32_t count);
 
 DeviceState *riscv_create_aia(bool msimode, int aia_guests,
+                             uint32_t m_imsic_stride,
                              uint16_t num_sources,
                              const MemMapEntry *aplic_m,
                              const MemMapEntry *aplic_s,
diff --git a/hw/riscv/aia.c b/hw/riscv/aia.c
index 82ea9d48ea..ed89160029 100644
--- a/hw/riscv/aia.c
+++ b/hw/riscv/aia.c
@@ -25,6 +25,7 @@ uint32_t imsic_num_bits(uint32_t count)
 }
 
 DeviceState *riscv_create_aia(bool msimode, int aia_guests,
+                             uint32_t m_imsic_stride,
                              uint16_t num_sources,
                              const MemMapEntry *aplic_m,
                              const MemMapEntry *aplic_s,
@@ -47,7 +48,7 @@ DeviceState *riscv_create_aia(bool msimode, int aia_guests,
             /* Per-socket M-level IMSICs */
             addr = imsic_m->base + socket * (1U << IMSIC_MMIO_GROUP_MIN_SHIFT);
             for (i = 0; i < hart_count; i++) {
-                riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0),
+                riscv_imsic_create(addr + i * m_imsic_stride,
                                    base_hartid + i, true, 1,
                                    num_msis);
             }
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 8f80c0607b..b68067cfdd 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -1401,6 +1401,7 @@ static void virt_machine_init(MachineState *machine)
         } else {
             s->irqchip[i] = riscv_create_aia(s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC,
                                              s->aia_guests,
+                                             IMSIC_HART_SIZE(0),
                                              s->num_sources,
                                              &s->memmap[VIRT_APLIC_M],
                                              &s->memmap[VIRT_APLIC_S],
-- 
2.54.0



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

* [PULL 32/39] target/riscv: tt-ascalon: Enable Zkr extension
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (30 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 31/39] hw/riscv/aia: Configure stride for the M-mode IMSIC alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 33/39] hw/riscv: Add Tenstorrent Atlantis machine alistair23
                   ` (8 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Nicholas Piggin, Chao Liu, Alistair Francis,
	Joel Stanley

From: Nicholas Piggin <npiggin@gmail.com>

Ascalon supports Zkr and the SEED CSR.

Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-7-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index de94f5d57e..4d2eb281bf 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -3251,6 +3251,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
         .cfg.ext_zba = true,
         .cfg.ext_zbb = true,
         .cfg.ext_zbs = true,
+        .cfg.ext_zkr = true,
         .cfg.ext_zkt = true,
         .cfg.ext_zvbb = true,
         .cfg.ext_zvbc = true,
-- 
2.54.0



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

* [PULL 33/39] hw/riscv: Add Tenstorrent Atlantis machine
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (31 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 32/39] target/riscv: tt-ascalon: Enable Zkr extension alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 34/39] hw/riscv/atlantis: Ensure OpenSBI has a non-zero next_addr alistair23
                   ` (7 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Joel Stanley, Nicholas Piggin,
	Philippe Mathieu-Daudé, Chao Liu, Alistair Francis

From: Joel Stanley <joel@jms.id.au>

The Tenstorrent Atlantis platform is a collaboration between Tenstorrent
and CoreLab Technology. It is based on the Atlantis SoC, which includes
the Ascalon-X CPU and other IP from Tenstorrent and CoreLab Technology.
The Tenstorrent Ascalon-X is a high performance 64-bit RVA23 compliant
RISC-V CPU.

Add the tt-atlantis machine containing serial console, interrupt
controllers, and device tree support.

The Atlantis boot images loaded from include OpenSBI and an initial DTB
that is passed to OpenSBI. This is approximated in the model by having
QEMU build the device tree rather than load a DTB image directly.
Subsequent stages may use the modified DTB provided by OpenSBI or opt to
supply their own.

  qemu-system-riscv64 -M tt-atlantis -m 512M \
   -kernel Image -initrd rootfs.cpio -nographic

Co-Developed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260630024952.1520546-8-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 MAINTAINERS                       |  12 +
 docs/system/riscv/tt_atlantis.rst |  41 +++
 docs/system/target-riscv.rst      |   1 +
 include/hw/riscv/tt_atlantis.h    |  50 +++
 hw/riscv/tt_atlantis.c            | 523 ++++++++++++++++++++++++++++++
 hw/riscv/Kconfig                  |  10 +
 hw/riscv/meson.build              |   1 +
 7 files changed, 638 insertions(+)
 create mode 100644 docs/system/riscv/tt_atlantis.rst
 create mode 100644 include/hw/riscv/tt_atlantis.h
 create mode 100644 hw/riscv/tt_atlantis.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 2ecfd7159d..a6d1e1f676 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1790,6 +1790,18 @@ F: hw/*/*sifive*.c
 F: include/hw/*/*sifive*.h
 F: tests/functional/riscv64/test_sifive_u.py
 
+Tenstorrent Machines
+M: Joel Stanley <joel@jms.id.au>
+M: Nicholas Piggin <npiggin@gmail.com>
+R: Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com>
+R: Michael Ellerman <mpe@kernel.org>
+R: Portia Stephens <portias@oss.tenstorrent.com>
+L: qemu-riscv@nongnu.org
+S: Supported
+F: docs/system/riscv/tt_*.rst
+F: hw/riscv/tt_*.c
+F: include/hw/riscv/tt_*.h
+
 AMD Microblaze-V Generic Board
 M: Sai Pavan Boddu <sai.pavan.boddu@amd.com>
 S: Maintained
diff --git a/docs/system/riscv/tt_atlantis.rst b/docs/system/riscv/tt_atlantis.rst
new file mode 100644
index 0000000000..1f2880d617
--- /dev/null
+++ b/docs/system/riscv/tt_atlantis.rst
@@ -0,0 +1,41 @@
+Tenstorrent Atlantis (``tt-atlantis``)
+======================================
+
+The Tenstorrent Atlantis platform is a collaboration between Tenstorrent
+and CoreLab Technology. It is based on the Atlantis SoC, which includes
+the Ascalon-X CPU and other IP from Tenstorrent and CoreLab Technology.
+
+The Tenstorrent Ascalon-X is a high performance 64-bit RVA23 compliant
+RISC-V CPU.
+
+tt-atlantis QEMU model features
+-------------------------------
+
+* 8-core Ascalon-X CPU Cluster
+* RISC-V compliant Advanced Interrupt Architecture
+* 16550A compatible UART
+
+Known limitations
+-----------------
+
+The QEMU tt-atlantis machine does not yet model every device on the
+real platform. Notably:
+
+* There is no PCI host bridge, so virtio-pci devices cannot be
+  attached. Boots that need block storage must use ``-initrd`` with
+  an initramfs.
+* The DesignWare UART is modelled with QEMU's ns16550-compatible
+  ``serial_mm`` device; DesignWare-specific registers beyond that
+  set return 0.
+
+Supported software
+------------------
+
+The Tenstorrent Ascalon CPUs avoid proprietary or non-standard
+extensions, so compatibility with existing software is generally
+good. The QEMU tt-atlantis machine works with upstream OpenSBI
+and Linux with default configurations.
+
+The development board hardware will require some implementation
+specific setup in firmware which is being developed and may
+become a requirement or option for the tt-atlantis machine.
diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
index 896f14e78b..2639866a3e 100644
--- a/docs/system/target-riscv.rst
+++ b/docs/system/target-riscv.rst
@@ -72,6 +72,7 @@ undocumented; you can get a complete list by running
    riscv/mips
    riscv/shakti-c
    riscv/sifive_u
+   riscv/tt_atlantis
    riscv/virt
    riscv/xiangshan-kunminghu
 
diff --git a/include/hw/riscv/tt_atlantis.h b/include/hw/riscv/tt_atlantis.h
new file mode 100644
index 0000000000..a17732ce81
--- /dev/null
+++ b/include/hw/riscv/tt_atlantis.h
@@ -0,0 +1,50 @@
+/*
+ * Tenstorrent Atlantis RISC-V System on Chip
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright 2025 Tenstorrent, Joel Stanley <joel@jms.id.au>
+ */
+
+#ifndef HW_RISCV_TT_ATLANTIS_H
+#define HW_RISCV_TT_ATLANTIS_H
+
+#include "hw/core/boards.h"
+#include "hw/core/sysbus.h"
+#include "hw/intc/riscv_imsic.h"
+#include "hw/riscv/riscv_hart.h"
+
+#define TYPE_TT_ATLANTIS_MACHINE MACHINE_TYPE_NAME("tt-atlantis")
+OBJECT_DECLARE_SIMPLE_TYPE(TTAtlantisState, TT_ATLANTIS_MACHINE)
+
+struct TTAtlantisState {
+    /*< private >*/
+    MachineState parent;
+
+    /*< public >*/
+    Notifier machine_done;
+    const MemMapEntry *memmap;
+
+    RISCVHartArrayState soc;
+    DeviceState *irqchip;
+
+    int fdt_size;
+};
+
+enum {
+    TT_ATL_UART1_IRQ = 39,
+};
+
+enum {
+    TT_ATL_ACLINT,
+    TT_ATL_BOOTROM,
+    TT_ATL_DDR_LO,
+    TT_ATL_DDR_HI,
+    TT_ATL_MAPLIC,
+    TT_ATL_MIMSIC,
+    TT_ATL_SAPLIC,
+    TT_ATL_SIMSIC,
+    TT_ATL_UART1,
+};
+
+#endif
diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c
new file mode 100644
index 0000000000..1f0cd08ac9
--- /dev/null
+++ b/hw/riscv/tt_atlantis.c
@@ -0,0 +1,523 @@
+/*
+ * Tenstorrent Atlantis RISC-V System on Chip
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright 2025 Tenstorrent, Joel Stanley <joel@jms.id.au>
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "qemu/guest-random.h"
+#include "qemu/units.h"
+
+#include "hw/core/boards.h"
+#include "hw/core/loader.h"
+#include "hw/core/sysbus.h"
+
+#include "target/riscv/cpu.h"
+#include "target/riscv/pmu.h"
+
+#include "hw/riscv/boot.h"
+#include "hw/riscv/fdt-common.h"
+#include "hw/riscv/machines-qom.h"
+#include "hw/riscv/riscv_hart.h"
+
+#include "hw/char/serial-mm.h"
+#include "hw/intc/riscv_aclint.h"
+#include "hw/misc/unimp.h"
+
+#include "system/system.h"
+#include "system/device_tree.h"
+
+#include "hw/riscv/tt_atlantis.h"
+
+#include "aia.h"
+
+#define TT_IRQCHIP_NUM_MSIS       255
+#define TT_IRQCHIP_NUM_SOURCES    128
+#define TT_IRQCHIP_NUM_PRIO_BITS  3
+#define TT_IRQCHIP_GUESTS         63 /* aia_guests, gives guest_index_bits=6 */
+#define TT_IRQCHIP_MIMSIC_STRIDE  0x40000
+
+#define TT_ACLINT_MTIME_SIZE    0x8050
+#define TT_ACLINT_MTIME         0x0
+#define TT_ACLINT_MTIMECMP      0x8000
+#define TT_ACLINT_TIMEBASE_FREQ 1000000000
+
+static const MemMapEntry tt_atlantis_memmap[] = {
+    /* Keep sorted with :'<,'>!sort -g -k 4 */
+    [TT_ATL_DDR_LO] =           { 0x00000000,    0x80000000 },
+    [TT_ATL_BOOTROM] =          { 0x80000000,        0x2000 },
+    [TT_ATL_MIMSIC] =           { 0xa0000000,      0x200000 },
+    [TT_ATL_ACLINT] =           { 0xa2180000,       0x10000 },
+    [TT_ATL_SIMSIC] =           { 0xa4000000,      0x200000 },
+    [TT_ATL_MAPLIC] =           { 0xcc000000,     0x4000000 },
+    [TT_ATL_UART1] =            { 0xd4110000,       0x10000 },
+    [TT_ATL_SAPLIC] =           { 0xe8000000,     0x4000000 },
+    [TT_ATL_DDR_HI] =          { 0x100000000,  0x1000000000 },
+};
+
+static uint32_t fdt_phandle = 1;
+static uint32_t next_phandle(void)
+{
+    return fdt_phandle++;
+}
+
+static void create_fdt_memory(TTAtlantisState *s)
+{
+    void *fdt = MACHINE(s)->fdt;
+    hwaddr size_lo = MACHINE(s)->ram_size;
+    hwaddr size_hi = 0;
+
+    if (size_lo > s->memmap[TT_ATL_DDR_LO].size) {
+        size_lo = s->memmap[TT_ATL_DDR_LO].size;
+        size_hi = MACHINE(s)->ram_size - size_lo;
+    }
+
+    create_fdt_socket_memory(fdt, s->memmap[TT_ATL_DDR_LO].base, size_lo,
+                             0, false);
+    if (size_hi) {
+        /*
+         * The first part of the HI address is aliased at the LO address
+         * so do not include that as usable memory. Is there any way
+         * (or good reason) to describe that aliasing 2GB with DT?
+         */
+        create_fdt_socket_memory(fdt, s->memmap[TT_ATL_DDR_HI].base + size_lo,
+                                 size_hi, 0, false);
+    }
+}
+
+static void create_fdt_aclint(TTAtlantisState *s, uint32_t *intc_phandles)
+{
+    void *fdt = MACHINE(s)->fdt;
+    g_autofree char *name = NULL;
+    g_autofree uint32_t *aclint_mtimer_cells = NULL;
+    uint32_t aclint_cells_size;
+    hwaddr addr;
+
+    aclint_mtimer_cells = g_new0(uint32_t, s->soc.num_harts * 2);
+
+    for (int cpu = 0; cpu < s->soc.num_harts; cpu++) {
+        aclint_mtimer_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER);
+    }
+    aclint_cells_size = s->soc.num_harts * sizeof(uint32_t) * 2;
+
+    addr = s->memmap[TT_ATL_ACLINT].base;
+
+    name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIX, addr);
+    qemu_fdt_add_subnode(fdt, name);
+    qemu_fdt_setprop_string(fdt, name, "compatible", "riscv,aclint-mtimer");
+    qemu_fdt_setprop_sized_cells(fdt, name, "reg",
+                                 2, addr + TT_ACLINT_MTIME,
+                                 2, 0x1000,
+                                 2, addr + TT_ACLINT_MTIMECMP,
+                                 2, 0x1000);
+    qemu_fdt_setprop(fdt, name, "interrupts-extended",
+                     aclint_mtimer_cells, aclint_cells_size);
+}
+
+static void create_fdt_one_imsic(void *fdt, const MemMapEntry *mem, int cpus,
+                                 uint32_t *intc_phandles, uint32_t msi_phandle,
+                                 int irq_line, uint32_t imsic_guest_bits)
+{
+    g_autofree char *name = NULL;
+    g_autofree uint32_t *imsic_cells = g_new0(uint32_t, cpus * 2);
+
+    for (int cpu = 0; cpu < cpus; cpu++) {
+        imsic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        imsic_cells[cpu * 2 + 1] = cpu_to_be32(irq_line);
+    }
+
+    name = g_strdup_printf("/soc/interrupt-controller@%"HWADDR_PRIX, mem->base);
+    qemu_fdt_add_subnode(fdt, name);
+    qemu_fdt_setprop_string(fdt, name, "compatible", "riscv,imsics");
+
+    qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 0);
+    qemu_fdt_setprop(fdt, name, "interrupt-controller", NULL, 0);
+    qemu_fdt_setprop(fdt, name, "msi-controller", NULL, 0);
+    qemu_fdt_setprop(fdt, name, "interrupts-extended",
+                     imsic_cells, sizeof(uint32_t) * cpus * 2);
+    qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem->base, 2, mem->size);
+    qemu_fdt_setprop_cell(fdt, name, "riscv,num-ids", TT_IRQCHIP_NUM_MSIS);
+
+    if (imsic_guest_bits) {
+        qemu_fdt_setprop_cell(fdt, name, "riscv,guest-index-bits",
+                              imsic_guest_bits);
+    }
+    qemu_fdt_setprop_cell(fdt, name, "phandle", msi_phandle);
+}
+
+static void create_fdt_one_aplic(void *fdt,
+                                 const MemMapEntry *mem,
+                                 uint32_t msi_phandle,
+                                 uint32_t *intc_phandles,
+                                 uint32_t aplic_phandle,
+                                 uint32_t aplic_child_phandle,
+                                 int irq_line, int num_harts)
+{
+    g_autofree char *name =
+        g_strdup_printf("/soc/interrupt-controller@%"HWADDR_PRIX, mem->base);
+    g_autofree uint32_t *aplic_cells = g_new0(uint32_t, num_harts * 2);
+
+    for (int cpu = 0; cpu < num_harts; cpu++) {
+        aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        aplic_cells[cpu * 2 + 1] = cpu_to_be32(irq_line);
+    }
+
+    qemu_fdt_add_subnode(fdt, name);
+    qemu_fdt_setprop_string(fdt, name, "compatible", "riscv,aplic");
+    qemu_fdt_setprop_cell(fdt, name, "#address-cells", 0);
+    qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 2);
+    qemu_fdt_setprop(fdt, name, "interrupt-controller", NULL, 0);
+
+    qemu_fdt_setprop(fdt, name, "interrupts-extended",
+                     aplic_cells, num_harts * sizeof(uint32_t) * 2);
+    qemu_fdt_setprop_cell(fdt, name, "msi-parent", msi_phandle);
+
+    qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem->base, 2, mem->size);
+    qemu_fdt_setprop_cell(fdt, name, "riscv,num-sources",
+                          TT_IRQCHIP_NUM_SOURCES);
+
+    if (aplic_child_phandle) {
+        qemu_fdt_setprop_cell(fdt, name, "riscv,children",
+                              aplic_child_phandle);
+        qemu_fdt_setprop_cells(fdt, name, "riscv,delegation",
+                               aplic_child_phandle, 1, TT_IRQCHIP_NUM_SOURCES);
+    }
+
+    qemu_fdt_setprop_cell(fdt, name, "phandle", aplic_phandle);
+}
+
+static void create_fdt_pmu(TTAtlantisState *s)
+{
+    char pmu_name[] = "/pmu";
+    void *fdt = MACHINE(s)->fdt;
+    RISCVCPU *hart = &s->soc.harts[0];
+
+    qemu_fdt_add_subnode(fdt, pmu_name);
+    qemu_fdt_setprop_string(fdt, pmu_name, "compatible", "riscv,pmu");
+    riscv_pmu_generate_fdt_node(fdt, hart->pmu_avail_ctrs, pmu_name);
+}
+
+static void create_fdt_cpu(TTAtlantisState *s, const MemMapEntry *memmap,
+                           uint32_t aplic_s_phandle,
+                           uint32_t imsic_s_phandle)
+{
+    MachineState *ms = MACHINE(s);
+    void *fdt = MACHINE(s)->fdt;
+    g_autofree uint32_t *intc_phandles = g_new0(uint32_t, ms->smp.cpus);
+
+    fdt_create_cpu_socket_subnode(fdt, TT_ACLINT_TIMEBASE_FREQ);
+
+    create_fdt_socket_cpus(fdt, s->soc.harts, 0, s->soc.num_harts,
+                           s->soc.hartid_base, &fdt_phandle, intc_phandles,
+                           false, false);
+
+    create_fdt_memory(s);
+
+    create_fdt_aclint(s, intc_phandles);
+
+    uint32_t imsic_guest_bits = imsic_num_bits(TT_IRQCHIP_GUESTS + 1);
+
+    /* M-level IMSIC node */
+    uint32_t msi_m_phandle = next_phandle();
+    create_fdt_one_imsic(fdt, &s->memmap[TT_ATL_MIMSIC], ms->smp.cpus,
+                         intc_phandles, msi_m_phandle,
+                         IRQ_M_EXT, imsic_guest_bits);
+
+    /* S-level IMSIC node */
+    create_fdt_one_imsic(fdt, &s->memmap[TT_ATL_SIMSIC], ms->smp.cpus,
+                         intc_phandles, imsic_s_phandle,
+                         IRQ_S_EXT, imsic_guest_bits);
+
+    uint32_t aplic_m_phandle = next_phandle();
+
+    /* M-level APLIC node */
+    create_fdt_one_aplic(fdt, &s->memmap[TT_ATL_MAPLIC],
+                         msi_m_phandle, intc_phandles,
+                         aplic_m_phandle, aplic_s_phandle,
+                         IRQ_M_EXT, s->soc.num_harts);
+
+    /* S-level APLIC node */
+    create_fdt_one_aplic(fdt, &s->memmap[TT_ATL_SAPLIC],
+                         imsic_s_phandle, intc_phandles,
+                         aplic_s_phandle, 0,
+                         IRQ_S_EXT, s->soc.num_harts);
+}
+
+static void create_fdt_uart(void *fdt, const MemMapEntry *mem, int irq,
+                            int irqchip_phandle)
+{
+    g_autofree char *name = g_strdup_printf("/soc/serial@%"HWADDR_PRIX,
+                                            mem->base);
+
+    qemu_fdt_add_subnode(fdt, name);
+    qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
+    qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem->base, 2, mem->size);
+    qemu_fdt_setprop_cell(fdt, name, "reg-shift", 2);
+    qemu_fdt_setprop_cell(fdt, name, "reg-io-width", 4);
+    qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 3686400);
+    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irqchip_phandle);
+    qemu_fdt_setprop_cells(fdt, name, "interrupts", irq, 0x4);
+
+    qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", name);
+    qemu_fdt_setprop_string(fdt, "/aliases", "serial0", name);
+}
+
+static void create_fdt_rng(void *fdt)
+{
+    uint8_t rng_seed[32];
+
+    qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
+    qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
+}
+
+static void finalize_fdt(TTAtlantisState *s)
+{
+    uint32_t aplic_s_phandle = next_phandle();
+    uint32_t imsic_s_phandle = next_phandle();
+    void *fdt = MACHINE(s)->fdt;
+
+    create_fdt_cpu(s, s->memmap, aplic_s_phandle, imsic_s_phandle);
+
+    /*
+     * We want to do this, but the Linux aplic driver was broken before v6.16
+     *
+     * qemu_fdt_setprop_cell(MACHINE(s)->fdt, "/soc", "interrupt-parent",
+     *                       aplic_s_phandle);
+     */
+
+    create_fdt_uart(fdt, &s->memmap[TT_ATL_UART1], TT_ATL_UART1_IRQ,
+                    aplic_s_phandle);
+}
+
+static void create_fdt(TTAtlantisState *s)
+{
+    MachineState *ms = MACHINE(s);
+
+    ms->fdt = create_board_device_tree("Tenstorrent Atlantis RISC-V Machine",
+                                       "tenstorrent,atlantis", &s->fdt_size);
+
+    qemu_fdt_add_subnode(ms->fdt, "/chosen");
+
+    create_fdt_rng(ms->fdt);
+
+    qemu_fdt_add_subnode(ms->fdt, "/aliases");
+
+    create_fdt_pmu(s);
+}
+
+static void load_fdt(TTAtlantisState *s)
+{
+    MachineState *ms = MACHINE(s);
+    char **node_path;
+    Error *err = NULL;
+
+    ms->fdt = load_device_tree(ms->dtb, &s->fdt_size);
+    if (!ms->fdt) {
+        error_report("load_device_tree() failed");
+        exit(1);
+    }
+
+    qemu_fdt_add_path(ms->fdt, "/chosen");
+
+    /* Clear memory nodes and update with the specified RAM size */
+    node_path = qemu_fdt_node_unit_path(ms->fdt, "memory", &err);
+    if (err) {
+        warn_report_err(err);
+    } else {
+        for (int i = 0; node_path[i]; i++) {
+            warn_report("Replacing device tree %s with the requested RAM size",
+                        node_path[i]);
+            qemu_fdt_nop_node(ms->fdt, node_path[i]);
+        }
+        g_strfreev(node_path);
+    }
+
+    create_fdt_memory(s);
+}
+
+static void tt_atlantis_machine_done(Notifier *notifier, void *data)
+{
+    TTAtlantisState *s = container_of(notifier, TTAtlantisState, machine_done);
+    MachineState *machine = MACHINE(s);
+    hwaddr start_addr = s->memmap[TT_ATL_DDR_LO].base;
+    hwaddr mem_size;
+    target_ulong firmware_end_addr, kernel_start_addr;
+    const char *firmware_name = riscv_default_firmware_name(&s->soc);
+    uint64_t fdt_load_addr;
+    uint64_t kernel_entry;
+    RISCVBootInfo boot_info;
+
+    /*
+     * A user provided dtb must include everything, including
+     * dynamic sysbus devices. Our FDT needs to be finalized.
+     */
+    if (machine->dtb == NULL) {
+        finalize_fdt(s);
+    }
+
+    mem_size = machine->ram_size;
+    if (mem_size > s->memmap[TT_ATL_DDR_LO].size) {
+        mem_size = s->memmap[TT_ATL_DDR_LO].size;
+    }
+    riscv_boot_info_init_discontig_mem(&boot_info, &s->soc,
+                                       s->memmap[TT_ATL_DDR_LO].base,
+                                       mem_size);
+
+    firmware_end_addr = riscv_find_and_load_firmware(machine, &boot_info,
+                                                     firmware_name,
+                                                     &start_addr, NULL);
+
+    kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
+                                                     firmware_end_addr);
+    if (machine->kernel_filename) {
+        riscv_load_kernel(machine, &boot_info, kernel_start_addr,
+                          true, NULL);
+    }
+    kernel_entry = boot_info.image_low_addr;
+
+    fdt_load_addr = riscv_compute_fdt_addr(s->memmap[TT_ATL_DDR_LO].base,
+                                           s->memmap[TT_ATL_DDR_LO].size,
+                                           machine, &boot_info);
+    riscv_load_fdt(fdt_load_addr, machine->fdt);
+
+    /* load the reset vector */
+    riscv_setup_rom_reset_vec(machine, &s->soc, start_addr,
+                              s->memmap[TT_ATL_BOOTROM].base,
+                              s->memmap[TT_ATL_BOOTROM].size,
+                              kernel_entry,
+                              fdt_load_addr);
+}
+
+static void tt_atlantis_machine_init(MachineState *machine)
+{
+    TTAtlantisState *s = TT_ATLANTIS_MACHINE(machine);
+
+    MemoryRegion *system_memory = get_system_memory();
+    MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_lo = g_new(MemoryRegion, 1);
+    MemoryRegion *bootrom = g_new(MemoryRegion, 1);
+    ram_addr_t lo_ram_size;
+    int hart_count = machine->smp.cpus;
+
+    s->memmap = tt_atlantis_memmap;
+
+    object_initialize_child(OBJECT(machine), "soc", &s->soc,
+                            TYPE_RISCV_HART_ARRAY);
+    object_property_set_str(OBJECT(&s->soc), "cpu-type", machine->cpu_type,
+                            &error_abort);
+    object_property_set_int(OBJECT(&s->soc), "hartid-base", 0,
+                            &error_abort);
+    object_property_set_int(OBJECT(&s->soc), "num-harts", hart_count,
+                            &error_abort);
+    object_property_set_int(OBJECT(&s->soc), "resetvec",
+                            s->memmap[TT_ATL_BOOTROM].base,
+                            &error_abort);
+    sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal);
+
+    s->irqchip = riscv_create_aia(true, TT_IRQCHIP_GUESTS,
+                                  TT_IRQCHIP_MIMSIC_STRIDE,
+                                  TT_IRQCHIP_NUM_SOURCES,
+                                  &s->memmap[TT_ATL_MAPLIC],
+                                  &s->memmap[TT_ATL_SAPLIC],
+                                  &s->memmap[TT_ATL_MIMSIC],
+                                  &s->memmap[TT_ATL_SIMSIC],
+                                  0, 0, hart_count,
+                                  TT_IRQCHIP_NUM_MSIS,
+                                  TT_IRQCHIP_NUM_PRIO_BITS);
+
+    riscv_aclint_mtimer_create(s->memmap[TT_ATL_ACLINT].base,
+            TT_ACLINT_MTIME_SIZE,
+            0, hart_count,
+            TT_ACLINT_MTIMECMP,
+            TT_ACLINT_MTIME,
+            TT_ACLINT_TIMEBASE_FREQ, true);
+
+    /*
+     * DDR
+     *
+     * The high address is where RAM lives. It is always present and may be
+     * up to 64GB. The low address is an alias of the first 2GB of that RAM.
+     */
+    if (machine->ram_size > s->memmap[TT_ATL_DDR_HI].size) {
+        char *sz = size_to_str(s->memmap[TT_ATL_DDR_HI].size);
+        error_report("RAM size is too large, maximum is %s", sz);
+        g_free(sz);
+        exit(EXIT_FAILURE);
+    }
+
+    memory_region_init_alias(ram_hi, OBJECT(machine), "ram.high", machine->ram,
+                             0, machine->ram_size);
+    memory_region_add_subregion(system_memory,
+                                s->memmap[TT_ATL_DDR_HI].base, ram_hi);
+
+    lo_ram_size = MIN(machine->ram_size, s->memmap[TT_ATL_DDR_LO].size);
+    memory_region_init_alias(ram_lo, OBJECT(machine), "ram.low", machine->ram,
+                             0, lo_ram_size);
+    memory_region_add_subregion(system_memory,
+                                s->memmap[TT_ATL_DDR_LO].base, ram_lo);
+
+    /* Boot ROM */
+    memory_region_init_rom(bootrom, NULL, "tt-atlantis.bootrom",
+                           s->memmap[TT_ATL_BOOTROM].size, &error_fatal);
+    memory_region_add_subregion(system_memory, s->memmap[TT_ATL_BOOTROM].base,
+                                bootrom);
+
+    /* UART1, the soc console (UART0 is for the boot microcontroller) */
+    serial_mm_init(system_memory, s->memmap[TT_ATL_UART1].base, 2,
+                   qdev_get_gpio_in(s->irqchip, TT_ATL_UART1_IRQ),
+                   115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
+    /*
+     * Atlantis contains a DesignWare uart while the QEMU machine
+     * uses the serial_mm model with the base ns16550 register set.
+     * Linux's dw driver writes outside of serial_mm's 0x20 sized
+     * mapping and faults.
+     *
+     * Create an unimplemented device region so writes don't fault
+     * and reads return zero, which keeps Linux happy.
+     */
+    create_unimplemented_device("tt-atlantis.uart0",
+                                s->memmap[TT_ATL_UART1].base,
+                                s->memmap[TT_ATL_UART1].size);
+
+    /* Load or create device tree */
+    if (machine->dtb) {
+        load_fdt(s);
+    } else {
+        create_fdt(s);
+    }
+
+    s->machine_done.notify = tt_atlantis_machine_done;
+    qemu_add_machine_init_done_notifier(&s->machine_done);
+}
+
+static void tt_atlantis_machine_class_init(ObjectClass *oc, const void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "Tenstorrent Atlantis RISC-V SoC (Experimental)";
+    mc->init = tt_atlantis_machine_init;
+    mc->max_cpus = 8;
+    mc->default_cpus = 8;
+    mc->default_ram_size = 4 * GiB;
+    mc->default_cpu_type = TYPE_RISCV_CPU_TT_ASCALON;
+    mc->block_default_type = IF_VIRTIO;
+    mc->no_cdrom = 1;
+    mc->default_ram_id = "tt_atlantis.ram";
+}
+
+static const TypeInfo tt_atlantis_types[] = {
+    {
+        .name       = MACHINE_TYPE_NAME("tt-atlantis"),
+        .parent     = TYPE_MACHINE,
+        .class_init = tt_atlantis_machine_class_init,
+        .instance_size = sizeof(TTAtlantisState),
+        .interfaces = riscv64_machine_interfaces,
+    },
+};
+
+DEFINE_TYPES(tt_atlantis_types)
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 54e41a6afc..5033415440 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -120,6 +120,16 @@ config SPIKE
     select RISCV_ACLINT
     select SIFIVE_PLIC
 
+config TENSTORRENT
+    bool
+    default y
+    depends on RISCV64
+    select RISCV_ACLINT
+    select RISCV_APLIC
+    select RISCV_IMSIC
+    select SERIAL_MM
+    select DEVICE_TREE
+
 config XIANGSHAN_KUNMINGHU
     bool
     default y
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 798477b788..0d82ceacc4 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -11,6 +11,7 @@ riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c'))
 riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c'))
 riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c'))
 riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c'))
+riscv_ss.add(when: 'CONFIG_TENSTORRENT', if_true: files('tt_atlantis.c'))
 riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
 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'))
-- 
2.54.0



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

* [PULL 34/39] hw/riscv/atlantis: Ensure OpenSBI has a non-zero next_addr
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (32 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 33/39] hw/riscv: Add Tenstorrent Atlantis machine alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 35/39] tests/functional/riscv64: Add tt-atlantis tests alistair23
                   ` (6 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: alistair23, Alistair Francis, Joel Stanley

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

When using OpenSBI fw_dynamic on the Atlantis board OpenSBI fails
to print any output, as it hits an error early on
in the boot process and gets stuck in `sbi_hart_hang()`.

The error occurs in the `sanitize_domain()` function inside OpenSBI.
`sanitize_domain()` is called after a M-Mode OpenSBI Firmware and a generic
coverall S-Mode RWX memory region are created. `sanitize_domain()` is
checking that the next address is executable.

If no next address is provided (which occurs on QEMU with an empty payload),
then `dom->next_addr` will be 0. On most RISC-V boards address 0 will fall
inside the coverall S-Mode RWX memory region and pass this check. On
Atlantis the OpenSBI firmware is running at address 0, so this address
falls inside the M-Mode only OpenSBI firmware region and fails the check.

Once the check has failed OpenSBI aborts and the user doesn't see any
messages. This can be fixed by either supplying a payload, or just
manually forcing a non-zero address (actually just any address that
isn't the OpenSBI firmware) for next_addr.

This patch ensures that if no kernel is loaded we still specify a
default kernel_entry so that OpenSBI happily boots and jumps to
the first address in memory.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260630024952.1520546-9-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/tt_atlantis.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c
index 1f0cd08ac9..d4fa9c251d 100644
--- a/hw/riscv/tt_atlantis.c
+++ b/hw/riscv/tt_atlantis.c
@@ -377,8 +377,16 @@ static void tt_atlantis_machine_done(Notifier *notifier, void *data)
     if (machine->kernel_filename) {
         riscv_load_kernel(machine, &boot_info, kernel_start_addr,
                           true, NULL);
+        kernel_entry = boot_info.image_low_addr;
+    } else {
+        /* If we aren't loading a payload, OpenSBI thinks we are trying to boot
+         * address 0, which fails `sbi_domain_check_addr()` as that is where
+         * OpenSBI is running. Instead point OpenSBI to the end of the region
+         * where it was loaded, which avoids the early hang, allowing the
+         * system to proceed with the OpenSBI boot output.
+         */
+        kernel_entry = kernel_start_addr;
     }
-    kernel_entry = boot_info.image_low_addr;
 
     fdt_load_addr = riscv_compute_fdt_addr(s->memmap[TT_ATL_DDR_LO].base,
                                            s->memmap[TT_ATL_DDR_LO].size,
-- 
2.54.0



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

* [PULL 35/39] tests/functional/riscv64: Add tt-atlantis tests
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (33 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 34/39] hw/riscv/atlantis: Ensure OpenSBI has a non-zero next_addr alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 36/39] hw/i2c: Add DesignWare I2C Controller alistair23
                   ` (5 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Nicholas Piggin, Philippe Mathieu-Daudé,
	Alistair Francis, Joel Stanley

From: Nicholas Piggin <npiggin@gmail.com>

Add OpenSBI and Linux boot tests for the tt-atlantis machine. Based on
tests/functional/riscv64/test_sifive_u.py.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-10-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 MAINTAINERS                                  |  1 +
 tests/functional/riscv64/meson.build         |  1 +
 tests/functional/riscv64/test_opensbi.py     |  4 ++
 tests/functional/riscv64/test_tt_atlantis.py | 57 ++++++++++++++++++++
 4 files changed, 63 insertions(+)
 create mode 100755 tests/functional/riscv64/test_tt_atlantis.py

diff --git a/MAINTAINERS b/MAINTAINERS
index a6d1e1f676..78e48ae8df 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1801,6 +1801,7 @@ S: Supported
 F: docs/system/riscv/tt_*.rst
 F: hw/riscv/tt_*.c
 F: include/hw/riscv/tt_*.h
+F: tests/functional/riscv64/test_tt_*.py
 
 AMD Microblaze-V Generic Board
 M: Sai Pavan Boddu <sai.pavan.boddu@amd.com>
diff --git a/tests/functional/riscv64/meson.build b/tests/functional/riscv64/meson.build
index 5871211e89..c9d4c090fb 100644
--- a/tests/functional/riscv64/meson.build
+++ b/tests/functional/riscv64/meson.build
@@ -14,5 +14,6 @@ tests_riscv64_system_thorough = [
   'endianness',
   'boston',
   'sifive_u',
+  'tt_atlantis',
   'tuxrun',
 ]
diff --git a/tests/functional/riscv64/test_opensbi.py b/tests/functional/riscv64/test_opensbi.py
index d077e40f42..0f8beb7e7a 100755
--- a/tests/functional/riscv64/test_opensbi.py
+++ b/tests/functional/riscv64/test_opensbi.py
@@ -28,6 +28,10 @@ def test_riscv_sifive_u(self):
         self.set_machine('sifive_u')
         self.boot_opensbi()
 
+    def test_riscv_tt_atlantis(self):
+        self.set_machine('tt-atlantis')
+        self.boot_opensbi()
+
     def test_riscv_virt(self):
         self.set_machine('virt')
         self.boot_opensbi()
diff --git a/tests/functional/riscv64/test_tt_atlantis.py b/tests/functional/riscv64/test_tt_atlantis.py
new file mode 100755
index 0000000000..48abd5cd27
--- /dev/null
+++ b/tests/functional/riscv64/test_tt_atlantis.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a Tenstorrent Atlantis machine
+# and checks the console
+#
+# Copyright (c) Linaro Ltd.
+# Copyright 2026 Tenstorrent
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset, LinuxKernelTest
+
+
+class TTAtlantis(LinuxKernelTest):
+
+    ASSET_KERNEL = Asset(
+        'https://storage.tuxboot.com/kernels/6.11.9/riscv64/Image',
+        '174f8bb87f08961e54fa3fcd954a8e31f4645f6d6af4dd43983d5e9841490fb0')
+    ASSET_ROOTFS = Asset(
+        ('https://github.com/groeck/linux-build-test/raw/'
+         '9819da19e6eef291686fdd7b029ea00e764dc62f/rootfs/riscv64/'
+         'rootfs.ext2.gz'),
+        'b6ed95610310b7956f9bf20c4c9c0c05fea647900df441da9dfe767d24e8b28b')
+
+    def do_test_riscv64_tt_atlantis(self, connect_disk):
+        self.set_machine('tt-atlantis')
+        kernel_path = self.ASSET_KERNEL.fetch()
+        rootfs_path = self.uncompress(self.ASSET_ROOTFS)
+
+        self.vm.set_console()
+        kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'earlycon=sbi '
+
+        if connect_disk:
+            kernel_command_line += 'root=/dev/vda panic=-1 noreboot rootwait '
+            self.vm.add_args('-device',
+                             'virtio-blk,drive=drive0,serial=0x1234,bus=pcie.0')
+            self.vm.add_args('-drive',
+                             f'file={rootfs_path},if=none,id=drive0,format=raw')
+            pattern = 'Boot successful.'
+        else:
+            kernel_command_line += 'panic=0 noreboot '
+            pattern = 'Cannot open root device'
+
+        self.vm.add_args('-kernel', kernel_path,
+                         '-append', kernel_command_line,
+                         '-no-reboot')
+
+        self.vm.launch()
+        self.wait_for_console_pattern(pattern)
+
+    def test_riscv64_tt_atlantis(self):
+        # tt-atlantis machine has no PCI host yet, so no disk
+        self.do_test_riscv64_tt_atlantis(False)
+
+
+if __name__ == '__main__':
+    LinuxKernelTest.main()
-- 
2.54.0



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

* [PULL 36/39] hw/i2c: Add DesignWare I2C Controller
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (34 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 35/39] tests/functional/riscv64: Add tt-atlantis tests alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 37/39] hw/riscv/atlantis: Integrate i2c controllers alistair23
                   ` (4 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Chris Rauer, Hao Wu, Nicholas Piggin,
	Alistair Francis, Philippe Mathieu-Daudé, Corey Minyard,
	Alano Song, Joel Stanley

From: Chris Rauer <crauer@google.com>

Add a model for the Synopsys DesignWare Advanced I2C/SMBus Controller
with sufficient functionality to be used by the Linux Designware I2C
platform driver.

This IP is used in the Tenstorrent Atlantis RISC-V SoC and will be
added to the QEMU tt-atlantis machine.

[npiggin: changelog, code cleanups and fixes as-per below link]

Reviewed-by: Hao Wu <wuhaotsh@google.com>
Signed-off-by: Chris Rauer <crauer@google.com>
Link: https://lore.kernel.org/qemu-devel/20220110214755.810343-2-venture@google.com
[jms: rebase and minor build fixes for class_init and reset callback]
Link: https://lore.kernel.org/qemu-devel/20260507120524.111056-1-npiggin@gmail.com
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Corey Minyard <cminyard@mvista.com>
Tested-by: Alano Song <AlanoSong@163.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-11-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 MAINTAINERS                     |   8 +
 include/hw/i2c/designware_i2c.h |  56 +++
 hw/i2c/designware_i2c.c         | 745 ++++++++++++++++++++++++++++++++
 hw/i2c/Kconfig                  |   5 +
 hw/i2c/meson.build              |   1 +
 5 files changed, 815 insertions(+)
 create mode 100644 include/hw/i2c/designware_i2c.h
 create mode 100644 hw/i2c/designware_i2c.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 78e48ae8df..7268c431b7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2766,6 +2766,14 @@ S: Orphan
 F: hw/gpio/pcf8574.c
 F: include/hw/gpio/pcf8574.h
 
+DesignWare I2C
+M: Chris Rauer <crauer@google.com>
+R: Alano Song <alanosong@163.com>
+R: Joel Stanley <joel@jms.id.au>
+S: Maintained
+F: hw/i2c/designware_i2c.c
+F: include/hw/i2c/designware_i2c.h
+
 Generic Loader
 M: Alistair Francis <alistair@alistair23.me>
 S: Maintained
diff --git a/include/hw/i2c/designware_i2c.h b/include/hw/i2c/designware_i2c.h
new file mode 100644
index 0000000000..4d5ff5d973
--- /dev/null
+++ b/include/hw/i2c/designware_i2c.h
@@ -0,0 +1,56 @@
+/*
+ * DesignWare I2C Module.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef DESIGNWARE_I2C_H
+#define DESIGNWARE_I2C_H
+
+#include "qemu/fifo8.h"
+#include "hw/i2c/i2c.h"
+#include "hw/core/irq.h"
+#include "hw/core/register.h"
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+
+#define DESIGNWARE_I2C_R_MAX (0x100 / 4)
+
+#define DESIGNWARE_I2C_RX_FIFO_SIZE 16
+#define DESIGNWARE_I2C_TX_FIFO_SIZE 16
+
+typedef enum DesignWareI2CStatus {
+    DW_I2C_STATUS_IDLE,
+    DW_I2C_STATUS_SENDING_ADDRESS,
+    DW_I2C_STATUS_SENDING,
+    DW_I2C_STATUS_RECEIVING,
+} DesignWareI2CStatus;
+
+#define TYPE_DESIGNWARE_I2C "designware-i2c"
+OBJECT_DECLARE_SIMPLE_TYPE(DesignWareI2CState, DESIGNWARE_I2C)
+
+/*
+ * struct DesignWareI2CState - DesignWare I2C device state.
+ * @bus: The underlying I2C Bus
+ * @irq: Interrupt line fired on transaction events.
+ * @rx_fifo: The FIFO buffer for receiving in FIFO mode.
+ */
+struct DesignWareI2CState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion iomem;
+
+    I2CBus      *bus;
+    qemu_irq     irq;
+
+    uint32_t regs[DESIGNWARE_I2C_R_MAX];
+    RegisterInfo regs_info[DESIGNWARE_I2C_R_MAX];
+
+    /* fifo8_num_used(rx_fifo) should always equal DW_IC_RXFLR */
+    Fifo8    rx_fifo;
+
+    DesignWareI2CStatus status;
+};
+
+#endif /* DESIGNWARE_I2C_H */
diff --git a/hw/i2c/designware_i2c.c b/hw/i2c/designware_i2c.c
new file mode 100644
index 0000000000..daa9714cb7
--- /dev/null
+++ b/hw/i2c/designware_i2c.c
@@ -0,0 +1,745 @@
+/*
+ * DesignWare I2C Module.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/i2c/designware_i2c.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+
+#ifndef DESIGNWARE_I2C_ERR_DEBUG
+#define DESIGNWARE_I2C_ERR_DEBUG 0
+#endif
+
+REG32(DW_IC_CON,                0x00) /* I2C control */
+    FIELD(DW_IC_CON, STOP_DET_IF_MASTER_ACTIV, 10, 1)
+    FIELD(DW_IC_CON, RX_FIFO_FULL_HLD_CTRL,     9, 1)
+    FIELD(DW_IC_CON, TX_EMPTY_CTRL,             8, 1)
+    FIELD(DW_IC_CON, STOP_IF_ADDRESSED,         7, 1)
+    FIELD(DW_IC_CON, SLAVE_DISABLE,             6, 1)
+    FIELD(DW_IC_CON, IC_RESTART_EN,             5, 1)
+    FIELD(DW_IC_CON, 10BITADDR_MASTER,          4, 1)
+    FIELD(DW_IC_CON, 10BITADDR_SLAVE,           3, 1)
+    FIELD(DW_IC_CON, SPEED,                     1, 2)
+    FIELD(DW_IC_CON, MASTER_MODE,               0, 1)
+REG32(DW_IC_TAR,                0x04) /* I2C target address */
+    FIELD(DW_IC_TAR, IC_10BITADDR_MASTER, 12,  1)
+    FIELD(DW_IC_TAR, SPECIAL,             11,  1)
+    FIELD(DW_IC_TAR, GC_OR_START,         10,  1)
+    FIELD(DW_IC_TAR, ADDRESS,              0, 10)
+REG32(DW_IC_SAR,                0x08) /* I2C slave address */
+REG32(DW_IC_DATA_CMD,           0x10)
+    FIELD(DW_IC_DATA_CMD, RESTART, 10, 1)
+    FIELD(DW_IC_DATA_CMD, STOP,     9, 1)
+    FIELD(DW_IC_DATA_CMD, CMD,      8, 1)
+    FIELD(DW_IC_DATA_CMD, DAT,      0, 8)
+REG32(DW_IC_SS_SCL_HCNT,        0x14) /* Standard speed i2c clock scl high count */
+REG32(DW_IC_SS_SCL_LCNT,        0x18) /* Standard speed i2c clock scl low count */
+REG32(DW_IC_FS_SCL_HCNT,        0x1c) /* Fast or fast plus i2c clock scl high count */
+REG32(DW_IC_FS_SCL_LCNT,        0x20) /* Fast or fast plus i2c clock scl low count */
+REG32(DW_IC_INTR_STAT,          0x2c)
+REG32(DW_IC_INTR_MASK,          0x30) /* I2C Interrupt Mask */
+REG32(DW_IC_RAW_INTR_STAT,      0x34) /* I2C raw interrupt status */
+    /* DW_IC_INTR_STAT/INTR_MASK/RAW_INTR_STAT fields */
+    SHARED_FIELD(DW_IC_INTR_RESTART_DET, 12, 1)
+    SHARED_FIELD(DW_IC_INTR_GEN_CALL,    11, 1)
+    SHARED_FIELD(DW_IC_INTR_START_DET,   10, 1)
+    SHARED_FIELD(DW_IC_INTR_STOP_DET,    9, 1)
+    SHARED_FIELD(DW_IC_INTR_ACTIVITY,    8, 1)
+    SHARED_FIELD(DW_IC_INTR_RX_DONE,     7, 1)
+    SHARED_FIELD(DW_IC_INTR_TX_ABRT,     6, 1)
+    SHARED_FIELD(DW_IC_INTR_RD_REQ,      5, 1)
+    SHARED_FIELD(DW_IC_INTR_TX_EMPTY,    4, 1) /* Hardware clear only. */
+    SHARED_FIELD(DW_IC_INTR_TX_OVER,     3, 1)
+    SHARED_FIELD(DW_IC_INTR_RX_FULL,     2, 1) /* Hardware clear only. */
+    SHARED_FIELD(DW_IC_INTR_RX_OVER,     1, 1)
+    SHARED_FIELD(DW_IC_INTR_RX_UNDER,    0, 1)
+
+#define DW_IC_INTR_ANY_MASK                \
+            (DW_IC_INTR_RESTART_DET_MASK | \
+             DW_IC_INTR_GEN_CALL_MASK    | \
+             DW_IC_INTR_START_DET_MASK   | \
+             DW_IC_INTR_STOP_DET_MASK    | \
+             DW_IC_INTR_ACTIVITY_MASK    | \
+             DW_IC_INTR_RX_DONE_MASK     | \
+             DW_IC_INTR_TX_ABRT_MASK     | \
+             DW_IC_INTR_RD_REQ_MASK      | \
+             DW_IC_INTR_TX_EMPTY_MASK    | \
+             DW_IC_INTR_TX_OVER_MASK     | \
+             DW_IC_INTR_RX_FULL_MASK     | \
+             DW_IC_INTR_RX_OVER_MASK     | \
+             DW_IC_INTR_RX_UNDER_MASK)
+
+#define DW_IC_INTR_ANY_SW_CLEAR_MASK       \
+            (DW_IC_INTR_ANY_MASK         & \
+            ~(DW_IC_INTR_TX_EMPTY_MASK   | \
+              DW_IC_INTR_RX_FULL_MASK))
+
+REG32(DW_IC_RX_TL,              0x38) /* I2C receive FIFO threshold */
+REG32(DW_IC_TX_TL,              0x3c) /* I2C transmit FIFO threshold */
+REG32(DW_IC_CLR_INTR,           0x40)
+REG32(DW_IC_CLR_RX_UNDER,       0x44)
+REG32(DW_IC_CLR_RX_OVER,        0x48)
+REG32(DW_IC_CLR_TX_OVER,        0x4c)
+REG32(DW_IC_CLR_RD_REQ,         0x50)
+REG32(DW_IC_CLR_TX_ABRT,        0x54)
+REG32(DW_IC_CLR_RX_DONE,        0x58)
+REG32(DW_IC_CLR_ACTIVITY,       0x5c)
+REG32(DW_IC_CLR_STOP_DET,       0x60)
+REG32(DW_IC_CLR_START_DET,      0x64)
+REG32(DW_IC_CLR_GEN_CALL,       0x68)
+REG32(DW_IC_ENABLE,             0x6c) /* I2C enable */
+    FIELD(DW_IC_ENABLE, TX_CMD_BLOCK, 2, 1)
+    FIELD(DW_IC_ENABLE, ABORT,        1, 1)
+    FIELD(DW_IC_ENABLE, ENABLE,       0, 1)
+REG32(DW_IC_STATUS,             0x70) /* I2C status */
+    FIELD(DW_IC_STATUS, SLV_ACTIVITY, 6, 1)
+    FIELD(DW_IC_STATUS, MST_ACTIVITY, 5, 1)
+    FIELD(DW_IC_STATUS, RFF,          4, 1)
+    FIELD(DW_IC_STATUS, RFNE,         3, 1)
+    FIELD(DW_IC_STATUS, TFE,          2, 1)
+    FIELD(DW_IC_STATUS, TFNF,         1, 1)
+    FIELD(DW_IC_STATUS, ACTIVITY,     0, 1)
+REG32(DW_IC_TXFLR,              0x74) /* I2C transmit fifo level */
+REG32(DW_IC_RXFLR,              0x78) /* I2C receive fifo level */
+REG32(DW_IC_SDA_HOLD,           0x7c) /* I2C SDA hold time length */
+REG32(DW_IC_TX_ABRT_SOURCE,     0x80) /* The I2C transmit abort source */
+    FIELD(DW_IC_TX_ABRT_SOURCE, USER_ABRT,       16, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, SLVRD_INTX,      15, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, SLV_ARBLOST,     14, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, SLVFLUSH_TXFIFO, 13, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, ARB_LOST,        12, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, MASTER_DIS,      11, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, 10B_RD_NORSTRT,  10, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, SBYTE_NORSTRT,   9, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, HS_NORSTRT,      8, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, SBYTE_ACKDET,    7, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, HS_ACKDET,       6, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, GCALL_READ,      5, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, GCALL_NOACK,     4, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, TXDATA_NOACK,    3, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, 10ADDR2_NOACK,   2, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, 10ADDR1_NOACK,   1, 1)
+    FIELD(DW_IC_TX_ABRT_SOURCE, 7B_ADDR_NOACK,   0, 1)
+REG32(DW_IC_SLV_DATA_NACK_ONLY, 0x84)
+REG32(DW_IC_DMA_CR,             0x88)
+REG32(DW_IC_DMA_TDLR,           0x8c)
+REG32(DW_IC_DMA_RDLR,           0x90)
+REG32(DW_IC_SDA_SETUP,          0x94) /* I2C SDA setup */
+REG32(DW_IC_ACK_GENERAL_CALL,   0x98)
+REG32(DW_IC_ENABLE_STATUS,      0x9c) /* I2C enable status */
+    FIELD(DW_IC_ENABLE_STATUS, SLV_RX_DATA_LOST,        2, 1)
+    FIELD(DW_IC_ENABLE_STATUS, SLV_DISABLED_WHILE_BUSY, 1, 1)
+    FIELD(DW_IC_ENABLE_STATUS, IC_EN,                   0, 1)
+REG32(DW_IC_FS_SPKLEN,          0xa0) /* I2C SS, FS or FM+ spike suppression limit */
+REG32(DW_IC_CLR_RESTART_DET,    0xa8)
+REG32(DW_IC_SMBUS_INTR_MASK,    0xcc) /* SMBus Interrupt Mask */
+REG32(DW_IC_COMP_PARAM_1,       0xf4) /* Component parameter */
+    FIELD(DW_IC_COMP_PARAM_1, TX_FIFO_SIZE,       16, 8)
+    FIELD(DW_IC_COMP_PARAM_1, RX_FIFO_SIZE,        8, 8)
+    FIELD(DW_IC_COMP_PARAM_1, HAS_ENCODED_PARAMS,  7, 1)
+    FIELD(DW_IC_COMP_PARAM_1, HAS_DMA,             6, 1)
+    FIELD(DW_IC_COMP_PARAM_1, INTR_IO,             5, 1)
+    FIELD(DW_IC_COMP_PARAM_1, HC_COUNT_VAL,        4, 1)
+    FIELD(DW_IC_COMP_PARAM_1, HIGH_SPEED_MODE,     2, 2)
+    FIELD(DW_IC_COMP_PARAM_1, APB_DATA_WIDTH_32,   0, 2)
+REG32(DW_IC_COMP_VERSION,       0xf8) /* I2C component version */
+REG32(DW_IC_COMP_TYPE,          0xfc) /* I2C component type */
+
+static void dw_i2c_update_irq(DesignWareI2CState *s)
+{
+    uint32_t intr = s->regs[R_DW_IC_RAW_INTR_STAT] & s->regs[R_DW_IC_INTR_MASK];
+
+    qemu_set_irq(s->irq, !!(intr & DW_IC_INTR_ANY_MASK));
+}
+
+static uint64_t dw_ic_data_cmd_reg_post_read(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    g_assert(value == 0);
+
+    if (s->status != DW_I2C_STATUS_RECEIVING) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Attempted to read from RX fifo when not in receive "
+                      "state.\n", DEVICE(s)->canonical_path);
+        if (s->status != DW_I2C_STATUS_IDLE) {
+            SHARED_ARRAY_FIELD_DP32(s->regs, R_DW_IC_RAW_INTR_STAT,
+                                    DW_IC_INTR_RX_UNDER, 1);
+            dw_i2c_update_irq(s);
+        }
+        return 0;
+    }
+
+    g_assert(s->regs[R_DW_IC_RXFLR] == fifo8_num_used(&s->rx_fifo));
+
+    if (fifo8_is_empty(&s->rx_fifo)) {
+        SHARED_ARRAY_FIELD_DP32(s->regs, R_DW_IC_RAW_INTR_STAT, DW_IC_INTR_RX_UNDER, 1);
+        dw_i2c_update_irq(s);
+        return 0;
+    }
+
+    s->regs[R_DW_IC_RXFLR]--;
+    if (s->regs[R_DW_IC_RXFLR] <= s->regs[R_DW_IC_RX_TL]) {
+        SHARED_ARRAY_FIELD_DP32(s->regs, R_DW_IC_RAW_INTR_STAT, DW_IC_INTR_RX_FULL, 0);
+        dw_i2c_update_irq(s);
+    }
+
+    return fifo8_pop(&s->rx_fifo);
+}
+
+static uint64_t dw_ic_clr_intr_reg_post_read(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    g_assert(value == 0);
+
+    switch (reg->access->addr) {
+    case A_DW_IC_CLR_INTR:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_ANY_SW_CLEAR_MASK;
+        break;
+    case A_DW_IC_CLR_RX_UNDER:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_UNDER_MASK;
+        break;
+    case A_DW_IC_CLR_RX_OVER:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_OVER_MASK;
+        break;
+    case A_DW_IC_CLR_TX_OVER:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_TX_OVER_MASK;
+        break;
+    case A_DW_IC_CLR_RD_REQ:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RD_REQ_MASK;
+        break;
+    case A_DW_IC_CLR_TX_ABRT:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_TX_ABRT_MASK;
+        break;
+    case A_DW_IC_CLR_RX_DONE:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_DONE_MASK;
+        break;
+    case A_DW_IC_CLR_ACTIVITY:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_ACTIVITY_MASK;
+        break;
+    case A_DW_IC_CLR_STOP_DET:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_STOP_DET_MASK;
+        break;
+    case A_DW_IC_CLR_START_DET:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_START_DET_MASK;
+        break;
+    case A_DW_IC_CLR_GEN_CALL:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_GEN_CALL_MASK;
+        break;
+    case A_DW_IC_CLR_RESTART_DET:
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RESTART_DET_MASK;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    dw_i2c_update_irq(s);
+
+    return 0;
+}
+
+static uint64_t dw_ic_intr_stat_reg_post_read(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    g_assert(value == 0);
+
+    return s->regs[R_DW_IC_RAW_INTR_STAT] & s->regs[R_DW_IC_INTR_MASK];
+}
+
+static uint64_t dw_ic_unsupported_reg_post_read(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    qemu_log_mask(LOG_UNIMP, "%s: unsupported read - %s\n",
+                  DEVICE(s)->canonical_path, reg->access->name);
+
+    return 0;
+}
+
+static uint64_t dw_ic_unsupported_reg_pre_write(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    qemu_log_mask(LOG_UNIMP, "%s: unsupported write - %s\n",
+                  DEVICE(s)->canonical_path, reg->access->name);
+
+    return 0;
+}
+
+static uint64_t dw_ic_con_reg_pre_write(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    if (s->regs[R_DW_IC_ENABLE] & R_DW_IC_ENABLE_ENABLE_MASK) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid setting to ic_con %d when ic_enable[0]==1\n",
+                      DEVICE(s)->canonical_path, (int)value);
+        return s->regs[R_DW_IC_CON]; /* keep old value */
+    }
+
+    return value;
+}
+
+static void dw_i2c_reset_to_idle(DesignWareI2CState *s)
+{
+    s->regs[R_DW_IC_ENABLE_STATUS] &= ~R_DW_IC_ENABLE_STATUS_IC_EN_MASK;
+    s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_TX_EMPTY_MASK;
+    s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_FULL_MASK;
+    s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_UNDER_MASK;
+    s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_OVER_MASK;
+    s->regs[R_DW_IC_RXFLR] = 0;
+    fifo8_reset(&s->rx_fifo);
+    s->regs[R_DW_IC_STATUS] &= ~R_DW_IC_STATUS_ACTIVITY_MASK;
+    s->status = DW_I2C_STATUS_IDLE;
+    dw_i2c_update_irq(s);
+}
+
+static void dw_ic_tx_abort(DesignWareI2CState *s, uint32_t src)
+{
+    s->regs[R_DW_IC_TX_ABRT_SOURCE] |= src;
+    s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_TX_ABRT_MASK;
+    dw_i2c_reset_to_idle(s);
+    dw_i2c_update_irq(s);
+}
+
+static void dw_ic_data_cmd_reg_post_write(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+    int recv = !!(value & R_DW_IC_DATA_CMD_CMD_MASK);
+
+    s->regs[R_DW_IC_DATA_CMD] = 0; /* Register has no storage */
+
+    if (!(s->regs[R_DW_IC_ENABLE] & R_DW_IC_ENABLE_ENABLE_MASK)) {
+        /*
+         * Controller is not enabled. The register_reset() path also lands
+         * here with value == 0, so silently ignore rather than reporting
+         * a spurious guest error.
+         */
+        return;
+    }
+
+    if (s->status == DW_I2C_STATUS_IDLE ||
+        s->regs[R_DW_IC_RAW_INTR_STAT] & DW_IC_INTR_TX_ABRT_MASK) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Attempted to write to TX fifo when it is held in "
+                      "reset\n", DEVICE(s)->canonical_path);
+        return;
+    }
+
+    /* Send the address if it hasn't been sent yet. */
+    if (s->status == DW_I2C_STATUS_SENDING_ADDRESS) {
+        int rv = i2c_start_transfer(s->bus,
+                     ARRAY_FIELD_EX32(s->regs, DW_IC_TAR, ADDRESS), recv);
+        if (rv) {
+            dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_7B_ADDR_NOACK_MASK);
+            return;
+        }
+        s->status = recv ? DW_I2C_STATUS_RECEIVING : DW_I2C_STATUS_SENDING;
+    }
+
+    /* Send data */
+    if (!recv) {
+        int rv = i2c_send(s->bus, FIELD_EX32(value, DW_IC_DATA_CMD, DAT));
+        if (rv) {
+            i2c_end_transfer(s->bus);
+            dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_TXDATA_NOACK_MASK);
+            return;
+        }
+        dw_i2c_update_irq(s);
+    }
+
+    /* Restart command */
+    if (value & R_DW_IC_DATA_CMD_RESTART_MASK &&
+            s->regs[R_DW_IC_CON] & R_DW_IC_CON_IC_RESTART_EN_MASK) {
+        s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_RESTART_DET_MASK |
+                                          DW_IC_INTR_START_DET_MASK |
+                                          DW_IC_INTR_ACTIVITY_MASK;
+        s->regs[R_DW_IC_STATUS] |= R_DW_IC_STATUS_ACTIVITY_MASK;
+        dw_i2c_update_irq(s);
+
+        if (i2c_start_transfer(s->bus,
+                    ARRAY_FIELD_EX32(s->regs, DW_IC_TAR, ADDRESS), recv)) {
+            dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_7B_ADDR_NOACK_MASK);
+            return;
+        }
+
+        s->status = recv ? DW_I2C_STATUS_RECEIVING : DW_I2C_STATUS_SENDING;
+    }
+
+    /* Receive data */
+    if (recv) {
+        g_assert(s->regs[R_DW_IC_RXFLR] == fifo8_num_used(&s->rx_fifo));
+
+        if (!fifo8_is_full(&s->rx_fifo)) {
+            fifo8_push(&s->rx_fifo, i2c_recv(s->bus));
+            s->regs[R_DW_IC_RXFLR]++;
+        } else {
+            s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_RX_OVER_MASK;
+            dw_i2c_update_irq(s);
+        }
+
+        if (s->regs[R_DW_IC_RXFLR] > s->regs[R_DW_IC_RX_TL]) {
+            s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_RX_FULL_MASK;
+            dw_i2c_update_irq(s);
+        }
+        if (value & R_DW_IC_DATA_CMD_STOP_MASK) {
+            i2c_nack(s->bus);
+        }
+    }
+
+    /* Stop command */
+    if (value & R_DW_IC_DATA_CMD_STOP_MASK) {
+        s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_STOP_DET_MASK;
+        s->regs[R_DW_IC_STATUS] &= ~R_DW_IC_STATUS_ACTIVITY_MASK;
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_TX_EMPTY_MASK;
+        i2c_end_transfer(s->bus);
+        dw_i2c_update_irq(s);
+    }
+}
+
+static void dw_ic_intr_mask_reg_post_write(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    dw_i2c_update_irq(s);
+}
+
+static uint64_t dw_ic_enable_reg_pre_write(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    if (value & R_DW_IC_ENABLE_ENABLE_MASK &&
+            !(s->regs[R_DW_IC_CON] & R_DW_IC_CON_SLAVE_DISABLE_MASK)) {
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Designware I2C slave mode is not supported.\n",
+                      DEVICE(s)->canonical_path);
+        return s->regs[R_DW_IC_ENABLE]; /* keep old value */
+    }
+
+    return value;
+}
+
+static void dw_ic_enable_reg_post_write(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    s->regs[R_DW_IC_ENABLE] = value & R_DW_IC_ENABLE_ENABLE_MASK;
+
+    if (value & R_DW_IC_ENABLE_ABORT_MASK || value & R_DW_IC_ENABLE_TX_CMD_BLOCK_MASK) {
+        dw_ic_tx_abort(s, R_DW_IC_TX_ABRT_SOURCE_USER_ABRT_MASK);
+        return;
+    }
+
+    if (value & R_DW_IC_ENABLE_ENABLE_MASK) {
+        s->regs[R_DW_IC_ENABLE_STATUS] |= R_DW_IC_ENABLE_STATUS_IC_EN_MASK;
+        s->regs[R_DW_IC_STATUS] |= R_DW_IC_STATUS_ACTIVITY_MASK;
+        s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_ACTIVITY_MASK |
+                                          DW_IC_INTR_START_DET_MASK |
+                                          DW_IC_INTR_TX_EMPTY_MASK;
+        s->status = DW_I2C_STATUS_SENDING_ADDRESS;
+        dw_i2c_update_irq(s);
+    } else if ((value & R_DW_IC_ENABLE_ENABLE_MASK) == 0) {
+        dw_i2c_reset_to_idle(s);
+    }
+}
+
+static uint64_t dw_ic_rx_tl_reg_pre_write(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    /* Note that a value of 0 for ic_rx_tl indicates a threshold of 1. */
+    if (value > DESIGNWARE_I2C_RX_FIFO_SIZE - 1) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid setting to ic_rx_tl %d\n",
+                      DEVICE(s)->canonical_path, (int)value);
+        return DESIGNWARE_I2C_RX_FIFO_SIZE - 1;
+    }
+
+    return value;
+}
+
+static void dw_ic_rx_tl_reg_post_write(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    if (s->regs[R_DW_IC_RXFLR] > s->regs[R_DW_IC_RX_TL] &&
+            s->regs[R_DW_IC_ENABLE] & R_DW_IC_ENABLE_ENABLE_MASK) {
+        s->regs[R_DW_IC_RAW_INTR_STAT] |= DW_IC_INTR_RX_FULL_MASK;
+    } else {
+        s->regs[R_DW_IC_RAW_INTR_STAT] &= ~DW_IC_INTR_RX_FULL_MASK;
+    }
+    dw_i2c_update_irq(s);
+}
+
+static uint64_t dw_ic_tx_tl_reg_pre_write(RegisterInfo *reg, uint64_t value)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(reg->opaque);
+
+    /*
+     * Note that a value of 0 for ic_tx_tl indicates a threshold of 1.
+     * However, the tx threshold is not used in the model because commands are
+     * always sent out as soon as they are written.
+     */
+    if (value > DESIGNWARE_I2C_TX_FIFO_SIZE - 1) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid setting to ic_tx_tl %d\n",
+                      DEVICE(s)->canonical_path, (int)value);
+        return DESIGNWARE_I2C_TX_FIFO_SIZE - 1;
+    }
+
+    return value;
+}
+
+static const RegisterAccessInfo designware_i2c_regs_info[] = {
+    {   .name  = "DW_IC_CON", .addr = A_DW_IC_CON,
+        .reset =       0x7d,
+        .unimp = 0xfffffc00,
+        .pre_write = dw_ic_con_reg_pre_write,
+    },{ .name  = "DW_IC_TAR", .addr = A_DW_IC_TAR,
+        .reset =     0x1055,
+        .unimp = 0xfffff000,
+    },{ .name  = "DW_IC_SAR", .addr = A_DW_IC_SAR,
+        .reset =       0x55,
+        .unimp = 0xfffffc00,
+        .post_read = dw_ic_unsupported_reg_post_read,
+        .pre_write = dw_ic_unsupported_reg_pre_write,
+    },{ .name  = "DW_IC_DATA_CMD", .addr = A_DW_IC_DATA_CMD,
+        .post_read = dw_ic_data_cmd_reg_post_read,
+        .post_write = dw_ic_data_cmd_reg_post_write,
+    },{ .name  = "DW_IC_SS_SCL_HCNT", .addr = A_DW_IC_SS_SCL_HCNT,
+        .reset =      0x190,
+        .unimp = 0xffff0000,
+    },{ .name  = "DW_IC_SS_SCL_LCNT", .addr = A_DW_IC_SS_SCL_LCNT,
+        .reset =      0x1d6,
+        .unimp = 0xffff0000,
+    },{ .name  = "DW_IC_FS_SCL_HCNT", .addr = A_DW_IC_FS_SCL_HCNT,
+        .reset =       0x3c,
+        .unimp = 0xffff0000,
+    },{ .name  = "DW_IC_FS_SCL_LCNT", .addr = A_DW_IC_FS_SCL_LCNT,
+        .reset =       0x82,
+        .unimp = 0xffff0000,
+    },{ .name  = "DW_IC_INTR_STAT", .addr = A_DW_IC_INTR_STAT,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_intr_stat_reg_post_read,
+    },{ .name  = "DW_IC_INTR_MASK", .addr = A_DW_IC_INTR_MASK,
+        .reset =      0x8ff,
+        .unimp = 0xffff8000,
+        .post_write = dw_ic_intr_mask_reg_post_write,
+    },{ .name  = "DW_IC_RAW_INTR_STAT", .addr = A_DW_IC_RAW_INTR_STAT,
+        .ro    = 0xffffffff,
+    },{ .name  = "DW_IC_RX_TL", .addr = A_DW_IC_RX_TL,
+        .pre_write = dw_ic_rx_tl_reg_pre_write,
+        .post_write = dw_ic_rx_tl_reg_post_write,
+    },{ .name  = "DW_IC_TX_TL", .addr = A_DW_IC_TX_TL,
+        .pre_write = dw_ic_tx_tl_reg_pre_write,
+    },{ .name  = "DW_IC_CLR_INTR", .addr = A_DW_IC_CLR_INTR,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_CLR_RX_UNDER", .addr = A_DW_IC_CLR_RX_UNDER,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_CLR_RX_OVER", .addr = A_DW_IC_CLR_RX_OVER,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_CLR_TX_OVER", .addr = A_DW_IC_CLR_TX_OVER,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_CLR_RD_REQ", .addr = A_DW_IC_CLR_RD_REQ,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_CLR_TX_ABRT", .addr = A_DW_IC_CLR_TX_ABRT,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_CLR_RX_DONE", .addr = A_DW_IC_CLR_RX_DONE,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_CLR_ACTIVITY", .addr = A_DW_IC_CLR_ACTIVITY,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_CLR_STOP_DET", .addr = A_DW_IC_CLR_STOP_DET,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_CLR_START_DET", .addr = A_DW_IC_CLR_START_DET,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_CLR_GEN_CALL", .addr = A_DW_IC_CLR_GEN_CALL,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_ENABLE", .addr = A_DW_IC_ENABLE,
+        .unimp = 0xfffffff8,
+        .pre_write = dw_ic_enable_reg_pre_write,
+        .post_write = dw_ic_enable_reg_post_write,
+    },{ .name  = "DW_IC_STATUS", .addr = A_DW_IC_STATUS,
+        .reset =        0x6,
+        .ro    = 0xffffffff,
+    },{ .name  = "DW_IC_TXFLR", .addr = A_DW_IC_TXFLR,
+        .ro    = 0xffffffff,
+    },{ .name  = "DW_IC_RXFLR", .addr = A_DW_IC_RXFLR,
+        .ro    = 0xffffffff,
+    },{ .name  = "DW_IC_SDA_HOLD", .addr = A_DW_IC_SDA_HOLD,
+        .reset =        0x1,
+        .unimp = 0xff000000,
+    },{ .name  = "DW_IC_TX_ABRT_SOURCE", .addr = A_DW_IC_TX_ABRT_SOURCE,
+        .ro    = 0xffffffff,
+    },{ .name  = "DW_IC_SLV_DATA_NACK_ONLY", .addr = A_DW_IC_SLV_DATA_NACK_ONLY,
+        .post_read = dw_ic_unsupported_reg_post_read,
+        .pre_write = dw_ic_unsupported_reg_pre_write,
+    },{ .name  = "DW_IC_DMA_CR", .addr = A_DW_IC_DMA_CR,
+        .post_read = dw_ic_unsupported_reg_post_read,
+        .pre_write = dw_ic_unsupported_reg_pre_write,
+    },{ .name  = "DW_IC_DMA_TDLR", .addr = A_DW_IC_DMA_TDLR,
+        .post_read = dw_ic_unsupported_reg_post_read,
+        .pre_write = dw_ic_unsupported_reg_pre_write,
+    },{ .name  = "DW_IC_DMA_RDLR", .addr = A_DW_IC_DMA_RDLR,
+        .post_read = dw_ic_unsupported_reg_post_read,
+        .pre_write = dw_ic_unsupported_reg_pre_write,
+    },{ .name  = "DW_IC_SDA_SETUP", .addr = A_DW_IC_SDA_SETUP,
+        .reset =       0x64,
+        .unimp = 0xffffff00,
+    },{ .name  = "DW_IC_ACK_GENERAL_CALL", .addr = A_DW_IC_ACK_GENERAL_CALL,
+        .post_read = dw_ic_unsupported_reg_post_read,
+        .pre_write = dw_ic_unsupported_reg_pre_write,
+    },{ .name  = "DW_IC_ENABLE_STATUS", .addr = A_DW_IC_ENABLE_STATUS,
+        .ro    = 0xffffffff,
+    },{ .name  = "DW_IC_FS_SPKLEN", .addr = A_DW_IC_FS_SPKLEN,
+        .reset =        0x2,
+        .ro    = 0xffffff00,
+    },{ .name  = "DW_IC_CLR_RESTART_DET", .addr = A_DW_IC_CLR_RESTART_DET,
+        .ro    = 0xffffffff,
+        .post_read = dw_ic_clr_intr_reg_post_read,
+    },{ .name  = "DW_IC_SMBUS_INTR_MASK", .addr = A_DW_IC_SMBUS_INTR_MASK,
+        /* No SMBus interrupts are implemented, Linux updates the mask */
+        .reset =      0x7ff,
+        .unimp = 0xfffff800,
+    },{ .name  = "DW_IC_COMP_PARAM_1", .addr = A_DW_IC_COMP_PARAM_1,
+        .reset = /* HAS_DMA and HC_COUNT_VAL are disabled */
+            ((2 << R_DW_IC_COMP_PARAM_1_APB_DATA_WIDTH_32_SHIFT) |
+             R_DW_IC_COMP_PARAM_1_HIGH_SPEED_MODE_MASK           |
+             R_DW_IC_COMP_PARAM_1_INTR_IO_MASK                   |
+             R_DW_IC_COMP_PARAM_1_HAS_ENCODED_PARAMS_MASK        |
+             ((DESIGNWARE_I2C_RX_FIFO_SIZE - 1)
+                  << R_DW_IC_COMP_PARAM_1_RX_FIFO_SIZE_SHIFT)    |
+             ((DESIGNWARE_I2C_TX_FIFO_SIZE - 1)
+                  << R_DW_IC_COMP_PARAM_1_TX_FIFO_SIZE_SHIFT)),
+        .ro    = 0xffffffff,
+    },{ .name  = "DW_IC_COMP_VERSION", .addr = A_DW_IC_COMP_VERSION,
+        .reset = 0x3132302a,
+        .ro    = 0xffffffff,
+    },{ .name  = "DW_IC_COMP_TYPE", .addr = A_DW_IC_COMP_TYPE,
+        .reset = 0x44570140,
+        .ro    = 0xffffffff,
+    }
+};
+
+static const MemoryRegionOps designware_i2c_ops = {
+    .read = register_read_memory,
+    .write = register_write_memory,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false,
+    },
+};
+
+static void designware_i2c_enter_reset(Object *obj, ResetType type)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(obj);
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->regs); ++i) {
+        register_reset(&s->regs_info[i]);
+    }
+
+    fifo8_reset(&s->rx_fifo);
+
+    s->status = DW_I2C_STATUS_IDLE;
+}
+
+static void designware_i2c_hold_reset(Object *obj, ResetType type)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(obj);
+
+    qemu_irq_lower(s->irq);
+}
+
+static const VMStateDescription vmstate_designware_i2c = {
+    .name = TYPE_DESIGNWARE_I2C,
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, DesignWareI2CState, DESIGNWARE_I2C_R_MAX),
+        VMSTATE_FIFO8(rx_fifo, DesignWareI2CState),
+        VMSTATE_UINT32(status, DesignWareI2CState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static void designware_i2c_instance_init(Object *obj)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    RegisterInfoArray *reg_array;
+
+    fifo8_create(&s->rx_fifo, DESIGNWARE_I2C_RX_FIFO_SIZE);
+
+    s->bus = i2c_init_bus(DEVICE(s), "i2c-bus");
+
+    memory_region_init(&s->iomem, obj, TYPE_DESIGNWARE_I2C, 4 * KiB);
+    reg_array = register_init_block32(DEVICE(obj), designware_i2c_regs_info,
+                                      ARRAY_SIZE(designware_i2c_regs_info),
+                                      s->regs_info, s->regs,
+                                      &designware_i2c_ops,
+                                      DESIGNWARE_I2C_ERR_DEBUG,
+                                      DESIGNWARE_I2C_R_MAX * 4);
+    memory_region_add_subregion(&s->iomem, 0, &reg_array->mem);
+
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq);
+}
+
+static void designware_i2c_finalize(Object *obj)
+{
+    DesignWareI2CState *s = DESIGNWARE_I2C(obj);
+
+    fifo8_destroy(&s->rx_fifo);
+}
+
+static void designware_i2c_class_init(ObjectClass *klass, const void *data)
+{
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc = "Designware I2C";
+    dc->vmsd = &vmstate_designware_i2c;
+    rc->phases.enter = designware_i2c_enter_reset;
+    rc->phases.hold = designware_i2c_hold_reset;
+
+    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+}
+
+static const TypeInfo designware_i2c_types[] = {
+    {
+        .name = TYPE_DESIGNWARE_I2C,
+        .parent = TYPE_SYS_BUS_DEVICE,
+        .instance_size = sizeof(DesignWareI2CState),
+        .class_init = designware_i2c_class_init,
+        .instance_init = designware_i2c_instance_init,
+        .instance_finalize = designware_i2c_finalize,
+    },
+};
+DEFINE_TYPES(designware_i2c_types);
diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig
index 596a7a3165..0766130b59 100644
--- a/hw/i2c/Kconfig
+++ b/hw/i2c/Kconfig
@@ -18,6 +18,11 @@ config ARM_SBCON_I2C
     bool
     select BITBANG_I2C
 
+config DESIGNWARE_I2C
+    bool
+    select REGISTER
+    select I2C
+
 config ACPI_SMBUS
     bool
     select SMBUS
diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build
index c459adcb59..88aea35662 100644
--- a/hw/i2c/meson.build
+++ b/hw/i2c/meson.build
@@ -11,6 +11,7 @@ i2c_ss.add(when: 'CONFIG_MPC_I2C', if_true: files('mpc_i2c.c'))
 i2c_ss.add(when: 'CONFIG_ALLWINNER_I2C', if_true: files('allwinner-i2c.c'))
 i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c'))
 i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c'))
+i2c_ss.add(when: 'CONFIG_DESIGNWARE_I2C', if_true: files('designware_i2c.c'))
 i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c'))
 i2c_ss.add(when: 'CONFIG_ARM_SBCON_I2C', if_true: files('arm_sbcon_i2c.c'))
 i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c'))
-- 
2.54.0



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

* [PULL 37/39] hw/riscv/atlantis: Integrate i2c controllers
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (35 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 36/39] hw/i2c: Add DesignWare I2C Controller alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 38/39] hw/riscv/atlantis: Add some i2c peripherals alistair23
                   ` (3 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Joel Stanley, Philippe Mathieu-Daudé,
	Alistair Francis, Nicholas Piggin

From: Joel Stanley <joel@jms.id.au>

Add DesignWare I2C controllers to the tt-atlantis machine.

Provide a fixed clock in the device tree so that the Linux driver probes
without WARNing.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-12-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 include/hw/riscv/tt_atlantis.h | 14 ++++++++
 hw/riscv/tt_atlantis.c         | 59 ++++++++++++++++++++++++++++++++++
 hw/riscv/Kconfig               |  1 +
 3 files changed, 74 insertions(+)

diff --git a/include/hw/riscv/tt_atlantis.h b/include/hw/riscv/tt_atlantis.h
index a17732ce81..7f7d4a5a59 100644
--- a/include/hw/riscv/tt_atlantis.h
+++ b/include/hw/riscv/tt_atlantis.h
@@ -11,12 +11,15 @@
 
 #include "hw/core/boards.h"
 #include "hw/core/sysbus.h"
+#include "hw/i2c/designware_i2c.h"
 #include "hw/intc/riscv_imsic.h"
 #include "hw/riscv/riscv_hart.h"
 
 #define TYPE_TT_ATLANTIS_MACHINE MACHINE_TYPE_NAME("tt-atlantis")
 OBJECT_DECLARE_SIMPLE_TYPE(TTAtlantisState, TT_ATLANTIS_MACHINE)
 
+#define TT_ATL_NUM_I2C 5
+
 struct TTAtlantisState {
     /*< private >*/
     MachineState parent;
@@ -27,11 +30,17 @@ struct TTAtlantisState {
 
     RISCVHartArrayState soc;
     DeviceState *irqchip;
+    DesignWareI2CState i2c[TT_ATL_NUM_I2C];
 
     int fdt_size;
 };
 
 enum {
+    TT_ATL_I2C0_IRQ = 33,
+    TT_ATL_I2C1_IRQ = 34,
+    TT_ATL_I2C2_IRQ = 35,
+    TT_ATL_I2C3_IRQ = 36,
+    TT_ATL_I2C4_IRQ = 37,
     TT_ATL_UART1_IRQ = 39,
 };
 
@@ -40,6 +49,11 @@ enum {
     TT_ATL_BOOTROM,
     TT_ATL_DDR_LO,
     TT_ATL_DDR_HI,
+    TT_ATL_I2C0,
+    TT_ATL_I2C1,
+    TT_ATL_I2C2,
+    TT_ATL_I2C3,
+    TT_ATL_I2C4,
     TT_ATL_MAPLIC,
     TT_ATL_MIMSIC,
     TT_ATL_SAPLIC,
diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c
index d4fa9c251d..5ce150fff7 100644
--- a/hw/riscv/tt_atlantis.c
+++ b/hw/riscv/tt_atlantis.c
@@ -54,6 +54,11 @@ static const MemMapEntry tt_atlantis_memmap[] = {
     [TT_ATL_ACLINT] =           { 0xa2180000,       0x10000 },
     [TT_ATL_SIMSIC] =           { 0xa4000000,      0x200000 },
     [TT_ATL_MAPLIC] =           { 0xcc000000,     0x4000000 },
+    [TT_ATL_I2C0] =             { 0xd4040000,       0x10000 },
+    [TT_ATL_I2C1] =             { 0xd4050000,       0x10000 },
+    [TT_ATL_I2C2] =             { 0xd4060000,       0x10000 },
+    [TT_ATL_I2C3] =             { 0xd4070000,       0x10000 },
+    [TT_ATL_I2C4] =             { 0xd4080000,       0x10000 },
     [TT_ATL_UART1] =            { 0xd4110000,       0x10000 },
     [TT_ATL_SAPLIC] =           { 0xe8000000,     0x4000000 },
     [TT_ATL_DDR_HI] =          { 0x100000000,  0x1000000000 },
@@ -275,10 +280,40 @@ static void create_fdt_rng(void *fdt)
     qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
 }
 
+static void create_fdt_clk(void *fdt, const char *clock_name,
+                           uint32_t freq, uint32_t phandle)
+{
+    g_autofree char *name = g_strdup_printf("/clocks/%s", clock_name);
+
+    qemu_fdt_add_path(fdt, name);
+    qemu_fdt_setprop_string(fdt, name, "compatible", "fixed-clock");
+    qemu_fdt_setprop_string(fdt, name, "clock-output-names", clock_name);
+    qemu_fdt_setprop_cell(fdt, name, "#clock-cells", 0);
+    qemu_fdt_setprop_cell(fdt, name, "clock-frequency", freq);
+    qemu_fdt_setprop_cell(fdt, name, "phandle", phandle);
+}
+
+static void create_fdt_i2c(void *fdt, const MemMapEntry *mem, uint32_t irq,
+                           uint32_t irqchip_phandle, uint32_t clk_phandle)
+{
+    g_autofree char *name = g_strdup_printf("/soc/i2c@%"HWADDR_PRIX, mem->base);
+
+    qemu_fdt_add_subnode(fdt, name);
+    qemu_fdt_setprop_string(fdt, name, "compatible", "snps,designware-i2c");
+    qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem->base, 2, mem->size);
+    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irqchip_phandle);
+    qemu_fdt_setprop_cells(fdt, name, "interrupts", irq, 0x4);
+    qemu_fdt_setprop_cell(fdt, name, "clocks", clk_phandle);
+    qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 100000);
+    qemu_fdt_setprop_cell(fdt, name, "#address-cells", 1);
+    qemu_fdt_setprop_cell(fdt, name, "#size-cells", 0);
+}
+
 static void finalize_fdt(TTAtlantisState *s)
 {
     uint32_t aplic_s_phandle = next_phandle();
     uint32_t imsic_s_phandle = next_phandle();
+    uint32_t periph_clk_phandle = next_phandle();
     void *fdt = MACHINE(s)->fdt;
 
     create_fdt_cpu(s, s->memmap, aplic_s_phandle, imsic_s_phandle);
@@ -292,6 +327,15 @@ static void finalize_fdt(TTAtlantisState *s)
 
     create_fdt_uart(fdt, &s->memmap[TT_ATL_UART1], TT_ATL_UART1_IRQ,
                     aplic_s_phandle);
+
+    create_fdt_clk(fdt, "periph-clk", 100000000, periph_clk_phandle);
+
+    for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
+        create_fdt_i2c(fdt,
+                       &s->memmap[TT_ATL_I2C0 + i],
+                       TT_ATL_I2C0_IRQ + i,
+                       aplic_s_phandle, periph_clk_phandle);
+    }
 }
 
 static void create_fdt(TTAtlantisState *s)
@@ -492,6 +536,21 @@ static void tt_atlantis_machine_init(MachineState *machine)
                                 s->memmap[TT_ATL_UART1].base,
                                 s->memmap[TT_ATL_UART1].size);
 
+    /* I2C */
+    for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
+        SysBusDevice *sbd;
+
+        object_initialize_child(OBJECT(s), "i2c[*]", &s->i2c[i],
+                                TYPE_DESIGNWARE_I2C);
+        sbd = SYS_BUS_DEVICE(&s->i2c[i]);
+        sysbus_realize(sbd, &error_fatal);
+        memory_region_add_subregion(system_memory,
+                                    s->memmap[TT_ATL_I2C0 + i].base,
+                                    sysbus_mmio_get_region(sbd, 0));
+        sysbus_connect_irq(sbd, 0,
+                           qdev_get_gpio_in(s->irqchip, TT_ATL_I2C0_IRQ + i));
+    }
+
     /* Load or create device tree */
     if (machine->dtb) {
         load_fdt(s);
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 5033415440..dcce819bf6 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -129,6 +129,7 @@ config TENSTORRENT
     select RISCV_IMSIC
     select SERIAL_MM
     select DEVICE_TREE
+    select DESIGNWARE_I2C
 
 config XIANGSHAN_KUNMINGHU
     bool
-- 
2.54.0



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

* [PULL 38/39] hw/riscv/atlantis: Add some i2c peripherals
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (36 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 37/39] hw/riscv/atlantis: Integrate i2c controllers alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-01 10:17 ` [PULL 39/39] hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0 alistair23
                   ` (2 subsequent siblings)
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Joel Stanley, Philippe Mathieu-Daudé,
	Alistair Francis, Nicholas Piggin

From: Joel Stanley <joel@jms.id.au>

Add an I2C RTC device and a temperature sensor. These are not present
on the board but help for testing.

The tmp105 is a lm75 compatible temperature sensor used by the
SENSORS_LM75 Linux kernel driver.

The ds1338 is a RTC device that is used by the RTC_DRV_DS1307 Linux
kernel driver.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Message-ID: <20260630024952.1520546-13-joel@jms.id.au>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/tt_atlantis.c | 27 +++++++++++++++++++++++++++
 hw/riscv/Kconfig       |  2 ++
 2 files changed, 29 insertions(+)

diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c
index 5ce150fff7..beaf64e0c1 100644
--- a/hw/riscv/tt_atlantis.c
+++ b/hw/riscv/tt_atlantis.c
@@ -64,6 +64,13 @@ static const MemMapEntry tt_atlantis_memmap[] = {
     [TT_ATL_DDR_HI] =          { 0x100000000,  0x1000000000 },
 };
 
+static I2CBus *i2c_get_bus(TTAtlantisState *s, unsigned busnr)
+{
+    assert(busnr < TT_ATL_NUM_I2C);
+
+    return s->i2c[busnr].bus;
+}
+
 static uint32_t fdt_phandle = 1;
 static uint32_t next_phandle(void)
 {
@@ -309,6 +316,19 @@ static void create_fdt_i2c(void *fdt, const MemMapEntry *mem, uint32_t irq,
     qemu_fdt_setprop_cell(fdt, name, "#size-cells", 0);
 }
 
+static void create_fdt_i2c_device(TTAtlantisState *s, int bus,
+                                  const char *compat, int addr)
+{
+    void *fdt = MACHINE(s)->fdt;
+    hwaddr base = s->memmap[TT_ATL_I2C0 + bus].base;
+    g_autofree char *name = g_strdup_printf("/soc/i2c@%"HWADDR_PRIX"/sensor@%x",
+                                            base, addr);
+
+    qemu_fdt_add_subnode(fdt, name);
+    qemu_fdt_setprop_string(fdt, name, "compatible", compat);
+    qemu_fdt_setprop_cell(fdt, name, "reg", addr);
+}
+
 static void finalize_fdt(TTAtlantisState *s)
 {
     uint32_t aplic_s_phandle = next_phandle();
@@ -336,6 +356,9 @@ static void finalize_fdt(TTAtlantisState *s)
                        TT_ATL_I2C0_IRQ + i,
                        aplic_s_phandle, periph_clk_phandle);
     }
+
+    create_fdt_i2c_device(s, 0, "dallas,ds1338", 0x6f);
+    create_fdt_i2c_device(s, 4, "ti,tmp105", 0x48);
 }
 
 static void create_fdt(TTAtlantisState *s)
@@ -551,6 +574,10 @@ static void tt_atlantis_machine_init(MachineState *machine)
                            qdev_get_gpio_in(s->irqchip, TT_ATL_I2C0_IRQ + i));
     }
 
+    /* I2C peripherals: qemu specific */
+    i2c_slave_create_simple(i2c_get_bus(s, 0), "ds1338", 0x6f);
+    i2c_slave_create_simple(i2c_get_bus(s, 4), "tmp105", 0x48);
+
     /* Load or create device tree */
     if (machine->dtb) {
         load_fdt(s);
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index dcce819bf6..de37c08cae 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -130,6 +130,8 @@ config TENSTORRENT
     select SERIAL_MM
     select DEVICE_TREE
     select DESIGNWARE_I2C
+    select DS1338
+    select TMP105
 
 config XIANGSHAN_KUNMINGHU
     bool
-- 
2.54.0



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

* [PULL 39/39] hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (37 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 38/39] hw/riscv/atlantis: Add some i2c peripherals alistair23
@ 2026-07-01 10:17 ` alistair23
  2026-07-02 10:32 ` [PULL 00/39] riscv-to-apply queue Stefan Hajnoczi
  2026-07-02 10:54 ` Michael Tokarev
  40 siblings, 0 replies; 48+ messages in thread
From: alistair23 @ 2026-07-01 10:17 UTC (permalink / raw)
  To: qemu-devel
  Cc: alistair23, Daniel Henrique Barboza, Alistair Francis, Nutty Liu

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

riscv-iommu spec: "If SADE is 1, the IOMMU updates A and D bits in
first-stage PTEs atomically. If SADE is 0, the IOMMU causes a
page-fault corresponding to the original access type if the
A bit is 0 or if the memory access is a store and the D bit is 0.".

Note that SADE=0 and A=0 will always cause a fault regardless of the
original access type.  Right now we're faulting in this case just for
reads.

Fixes: 0c54acb8243d ("hw/riscv: add RISC-V IOMMU base emulation")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3551
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Nutty Liu <nutty.liu@hotmail.com>
Message-ID: <20260630211044.82894-1-daniel.barboza@oss.qualcomm.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/riscv-iommu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 01f5634f04..974042d017 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -480,7 +480,7 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
             break;                /* Read access check failed */
         } else if ((iotlb->perm & IOMMU_WO) && !(pte & PTE_W)) {
             break;                /* Write access check failed */
-        } else if ((iotlb->perm & IOMMU_RO) && !ade && !(pte & PTE_A)) {
+        } else if (!ade && !(pte & PTE_A)) {
             break;                /* Access bit not set */
         } else if ((iotlb->perm & IOMMU_WO) && !ade && !(pte & PTE_D)) {
             break;                /* Dirty bit not set */
-- 
2.54.0



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

* Re: [PULL 00/39] riscv-to-apply queue
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (38 preceding siblings ...)
  2026-07-01 10:17 ` [PULL 39/39] hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0 alistair23
@ 2026-07-02 10:32 ` Stefan Hajnoczi
  2026-07-02 10:54 ` Michael Tokarev
  40 siblings, 0 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2026-07-02 10:32 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] 48+ messages in thread

* Re: [PULL 00/39] riscv-to-apply queue
  2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
                   ` (39 preceding siblings ...)
  2026-07-02 10:32 ` [PULL 00/39] riscv-to-apply queue Stefan Hajnoczi
@ 2026-07-02 10:54 ` Michael Tokarev
  2026-07-02 11:44   ` Daniel Henrique Barboza
  2026-07-03  0:02   ` Alistair Francis
  40 siblings, 2 replies; 48+ messages in thread
From: Michael Tokarev @ 2026-07-02 10:54 UTC (permalink / raw)
  To: alistair23, qemu-devel
  Cc: Alistair Francis, qemu-stable, Daniel Henrique Barboza

On 01.07.2026 13:17, alistair23@gmail.com wrote:
...
> RISC-V PR for 11.1
> 
> * Fix IMSIC CSR write and add tests
> * Parametrise debug trigger number
> * Add 'svbare' satp-mode
> * Fix RINTC PLIC context ID for KVM
> * Avoid abort when reading vtype before env->xl is set
> * Skip reset for KVM irqchip
> * Skip FP/Vector sync on KVM_PUT_RUNTIME_STATE
> * More FDT cleanups (PLIC)
> * Make FCTL.BE in IOMMU read only 0
> * Check DC.TC reserved bits in IOMMU
> * Apply UXL WARL handling to vsstatus
> * Set cmd_ill IOFENCE.C if rsvp bits are set in IOMMU
> * Set RISCV_IOMMU_FQ_HDR_PV appropriately
> * Fix MSI MRIF IOMMU interrupt-pending offset
> * Report QEMU CPU archid as 42
> * Check PMP before updating PTE
> * Add the Tenstorrent Atlantis machine
> 
> ----------------------------------------------------------------
> Alistair Francis (1):
>        hw/riscv/atlantis: Ensure OpenSBI has a non-zero next_addr
> 
> Charlie Jenkins (1):
>        target/riscv: Report QEMU CPU archid as 42
> 
> Chris Rauer (1):
>        hw/i2c: Add DesignWare I2C Controller
> 
> Daniel Henrique Barboza (16):
>        target/riscv/cpu: add CPU unrealize callback
>        target/riscv: dynamic alloc of debug trigger arrays
>        target/riscv: add 'num-triggers' debug property
>        target/riscv/cpu.c: add 'svbare' satp-mode
>        hw/riscv/sifive_u.c: remove unneeded qemu_fdt_get_phandle() call
>        hw/riscv/sifive_u.c: use intc_phandle in plic creation
>        hw/riscv/sifive_u: add #address-cells in PLIC FDT
>        hw/riscv/virt.c: change 'plic' nodename to 'interrupt-controller'
>        hw/riscv: add create_fdt_plic() helper
>        hw/riscv/riscv-iommu: rename regs_rw to regs
>        hw/riscv/riscv-iommu.c: make FCTL.BE read only 0
>        hw/riscv/riscv-iommu: check DC.TC reserved bits
>        hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set
>        hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately
>        hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset
>        hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0
> 
> Inochi Amaoto (1):
>        target/riscv: Check PMP before updating PTE
> 
> Joel Stanley (9):
>        target/riscv: Avoid NULL deref in IMSIC CSR write
>        tests/functional/riscv64: Use newer kernel for tuxrun boot
>        tests/functional/riscv64: Add virt machine AIA boot test
>        hw/riscv/virt: Move AIA initialisation to helper file
>        hw/riscv/aia: Provide number of irq sources
>        hw/riscv/aia: Configure stride for the M-mode IMSIC
>        hw/riscv: Add Tenstorrent Atlantis machine
>        hw/riscv/atlantis: Integrate i2c controllers
>        hw/riscv/atlantis: Add some i2c peripherals
> 
> Meng Zhuo (1):
>        target/riscv/kvm: skip FP/Vector sync on KVM_PUT_RUNTIME_STATE
> 
> Nicholas Piggin (4):
>        hw/riscv/boot: Describe discontiguous memory in boot_info
>        hw/riscv/boot: Account for discontiguous memory when loading firmware
>        target/riscv: tt-ascalon: Enable Zkr extension
>        tests/functional/riscv64: Add tt-atlantis tests
> 
> Qingwei Hu (3):
>        hw/riscv/virt-acpi-build: Fix RINTC PLIC context ID for KVM
>        hw/intc: riscv_aplic: Skip reset for KVM irqchip
>        hw/intc: riscv_imsic: Skip reset for KVM irqchip
> 
> SeungJu Cheon (1):
>        target/riscv: Apply UXL WARL handling to vsstatus
> 
> ZhengXiang Qin (1):
>        target/riscv: avoid abort when reading vtype before env->xl is set


Hi!

Is there anything here worth picking up for the stable series
(besides "target/riscv: Check PMP before updating PTE")?

For example,

  46d96da130 target/riscv: avoid abort when reading vtype before env->xl 
is set
  5a3fd18f4f hw/riscv/riscv-iommu.c: make FCTL.BE read only 0
  13c2fc34f1 hw/riscv/riscv-iommu: check DC.TC reserved bits
  6ed77682d5 hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set
  887d2d75b1 hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately
  3cee183ff9 hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset
  64ce9ac187 hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0

resolves various bugs from the qemu issue/work-items tracker.

Thanks,

/mjt


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

* Re: [PULL 00/39] riscv-to-apply queue
  2026-07-02 10:54 ` Michael Tokarev
@ 2026-07-02 11:44   ` Daniel Henrique Barboza
  2026-07-03  0:02   ` Alistair Francis
  1 sibling, 0 replies; 48+ messages in thread
From: Daniel Henrique Barboza @ 2026-07-02 11:44 UTC (permalink / raw)
  To: Michael Tokarev, alistair23, qemu-devel; +Cc: Alistair Francis, qemu-stable

Hi Michael,

On 7/2/2026 7:54 AM, Michael Tokarev wrote:
> On 01.07.2026 13:17, alistair23@gmail.com wrote:
> ...
>> RISC-V PR for 11.1
>>
>> * Fix IMSIC CSR write and add tests
>> * Parametrise debug trigger number
>> * Add 'svbare' satp-mode
>> * Fix RINTC PLIC context ID for KVM
>> * Avoid abort when reading vtype before env->xl is set
>> * Skip reset for KVM irqchip
>> * Skip FP/Vector sync on KVM_PUT_RUNTIME_STATE
>> * More FDT cleanups (PLIC)
>> * Make FCTL.BE in IOMMU read only 0
>> * Check DC.TC reserved bits in IOMMU
>> * Apply UXL WARL handling to vsstatus
>> * Set cmd_ill IOFENCE.C if rsvp bits are set in IOMMU
>> * Set RISCV_IOMMU_FQ_HDR_PV appropriately
>> * Fix MSI MRIF IOMMU interrupt-pending offset
>> * Report QEMU CPU archid as 42
>> * Check PMP before updating PTE
>> * Add the Tenstorrent Atlantis machine
>>
>> ----------------------------------------------------------------
>> Alistair Francis (1):
>>        hw/riscv/atlantis: Ensure OpenSBI has a non-zero next_addr
>>
>> Charlie Jenkins (1):
>>        target/riscv: Report QEMU CPU archid as 42
>>
>> Chris Rauer (1):
>>        hw/i2c: Add DesignWare I2C Controller
>>
>> Daniel Henrique Barboza (16):
>>        target/riscv/cpu: add CPU unrealize callback
>>        target/riscv: dynamic alloc of debug trigger arrays
>>        target/riscv: add 'num-triggers' debug property
>>        target/riscv/cpu.c: add 'svbare' satp-mode
>>        hw/riscv/sifive_u.c: remove unneeded qemu_fdt_get_phandle() call
>>        hw/riscv/sifive_u.c: use intc_phandle in plic creation
>>        hw/riscv/sifive_u: add #address-cells in PLIC FDT
>>        hw/riscv/virt.c: change 'plic' nodename to 'interrupt-controller'
>>        hw/riscv: add create_fdt_plic() helper
>>        hw/riscv/riscv-iommu: rename regs_rw to regs
>>        hw/riscv/riscv-iommu.c: make FCTL.BE read only 0
>>        hw/riscv/riscv-iommu: check DC.TC reserved bits
>>        hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set
>>        hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately
>>        hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset
>>        hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0
>>
>> Inochi Amaoto (1):
>>        target/riscv: Check PMP before updating PTE
>>
>> Joel Stanley (9):
>>        target/riscv: Avoid NULL deref in IMSIC CSR write
>>        tests/functional/riscv64: Use newer kernel for tuxrun boot
>>        tests/functional/riscv64: Add virt machine AIA boot test
>>        hw/riscv/virt: Move AIA initialisation to helper file
>>        hw/riscv/aia: Provide number of irq sources
>>        hw/riscv/aia: Configure stride for the M-mode IMSIC
>>        hw/riscv: Add Tenstorrent Atlantis machine
>>        hw/riscv/atlantis: Integrate i2c controllers
>>        hw/riscv/atlantis: Add some i2c peripherals
>>
>> Meng Zhuo (1):
>>        target/riscv/kvm: skip FP/Vector sync on KVM_PUT_RUNTIME_STATE
>>
>> Nicholas Piggin (4):
>>        hw/riscv/boot: Describe discontiguous memory in boot_info
>>        hw/riscv/boot: Account for discontiguous memory when loading firmware
>>        target/riscv: tt-ascalon: Enable Zkr extension
>>        tests/functional/riscv64: Add tt-atlantis tests
>>
>> Qingwei Hu (3):
>>        hw/riscv/virt-acpi-build: Fix RINTC PLIC context ID for KVM
>>        hw/intc: riscv_aplic: Skip reset for KVM irqchip
>>        hw/intc: riscv_imsic: Skip reset for KVM irqchip
>>
>> SeungJu Cheon (1):
>>        target/riscv: Apply UXL WARL handling to vsstatus
>>
>> ZhengXiang Qin (1):
>>        target/riscv: avoid abort when reading vtype before env->xl is set
> 
> 
> Hi!
> 
> Is there anything here worth picking up for the stable series
> (besides "target/riscv: Check PMP before updating PTE")?
> 
> For example,
> 
>   46d96da130 target/riscv: avoid abort when reading vtype before env->xl is set
>   5a3fd18f4f hw/riscv/riscv-iommu.c: make FCTL.BE read only 0
>   13c2fc34f1 hw/riscv/riscv-iommu: check DC.TC reserved bits
>   6ed77682d5 hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set
>   887d2d75b1 hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately
>   3cee183ff9 hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset
>   64ce9ac187 hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0
> 
> resolves various bugs from the qemu issue/work-items tracker.

All riscv-iommu stuff is worth getting. They are all fixes for code that is
around since QEMU 9.x or something.

In fact there's more to come in future PRs (I'm actively hunting riscv-iommu
stuff in gitlab) so same thing applies for those future cases too.


Cheers,
Daniel

> 
> Thanks,
> 
> /mjt



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

* Re: [PULL 00/39] riscv-to-apply queue
  2026-07-02 10:54 ` Michael Tokarev
  2026-07-02 11:44   ` Daniel Henrique Barboza
@ 2026-07-03  0:02   ` Alistair Francis
  1 sibling, 0 replies; 48+ messages in thread
From: Alistair Francis @ 2026-07-03  0:02 UTC (permalink / raw)
  To: Michael Tokarev
  Cc: qemu-devel, Alistair Francis, qemu-stable,
	Daniel Henrique Barboza

On Thu, Jul 2, 2026 at 8:54 PM Michael Tokarev <mjt@tls.msk.ru> wrote:
>
> On 01.07.2026 13:17, alistair23@gmail.com wrote:
> ...
> > RISC-V PR for 11.1
> >
> > * Fix IMSIC CSR write and add tests
> > * Parametrise debug trigger number
> > * Add 'svbare' satp-mode
> > * Fix RINTC PLIC context ID for KVM
> > * Avoid abort when reading vtype before env->xl is set
> > * Skip reset for KVM irqchip
> > * Skip FP/Vector sync on KVM_PUT_RUNTIME_STATE
> > * More FDT cleanups (PLIC)
> > * Make FCTL.BE in IOMMU read only 0
> > * Check DC.TC reserved bits in IOMMU
> > * Apply UXL WARL handling to vsstatus
> > * Set cmd_ill IOFENCE.C if rsvp bits are set in IOMMU
> > * Set RISCV_IOMMU_FQ_HDR_PV appropriately
> > * Fix MSI MRIF IOMMU interrupt-pending offset
> > * Report QEMU CPU archid as 42
> > * Check PMP before updating PTE
> > * Add the Tenstorrent Atlantis machine
> >
> > ----------------------------------------------------------------
> > Alistair Francis (1):
> >        hw/riscv/atlantis: Ensure OpenSBI has a non-zero next_addr
> >
> > Charlie Jenkins (1):
> >        target/riscv: Report QEMU CPU archid as 42
> >
> > Chris Rauer (1):
> >        hw/i2c: Add DesignWare I2C Controller
> >
> > Daniel Henrique Barboza (16):
> >        target/riscv/cpu: add CPU unrealize callback
> >        target/riscv: dynamic alloc of debug trigger arrays
> >        target/riscv: add 'num-triggers' debug property
> >        target/riscv/cpu.c: add 'svbare' satp-mode
> >        hw/riscv/sifive_u.c: remove unneeded qemu_fdt_get_phandle() call
> >        hw/riscv/sifive_u.c: use intc_phandle in plic creation
> >        hw/riscv/sifive_u: add #address-cells in PLIC FDT
> >        hw/riscv/virt.c: change 'plic' nodename to 'interrupt-controller'
> >        hw/riscv: add create_fdt_plic() helper
> >        hw/riscv/riscv-iommu: rename regs_rw to regs
> >        hw/riscv/riscv-iommu.c: make FCTL.BE read only 0
> >        hw/riscv/riscv-iommu: check DC.TC reserved bits
> >        hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set
> >        hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately
> >        hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset
> >        hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0
> >
> > Inochi Amaoto (1):
> >        target/riscv: Check PMP before updating PTE
> >
> > Joel Stanley (9):
> >        target/riscv: Avoid NULL deref in IMSIC CSR write
> >        tests/functional/riscv64: Use newer kernel for tuxrun boot
> >        tests/functional/riscv64: Add virt machine AIA boot test
> >        hw/riscv/virt: Move AIA initialisation to helper file
> >        hw/riscv/aia: Provide number of irq sources
> >        hw/riscv/aia: Configure stride for the M-mode IMSIC
> >        hw/riscv: Add Tenstorrent Atlantis machine
> >        hw/riscv/atlantis: Integrate i2c controllers
> >        hw/riscv/atlantis: Add some i2c peripherals
> >
> > Meng Zhuo (1):
> >        target/riscv/kvm: skip FP/Vector sync on KVM_PUT_RUNTIME_STATE
> >
> > Nicholas Piggin (4):
> >        hw/riscv/boot: Describe discontiguous memory in boot_info
> >        hw/riscv/boot: Account for discontiguous memory when loading firmware
> >        target/riscv: tt-ascalon: Enable Zkr extension
> >        tests/functional/riscv64: Add tt-atlantis tests
> >
> > Qingwei Hu (3):
> >        hw/riscv/virt-acpi-build: Fix RINTC PLIC context ID for KVM
> >        hw/intc: riscv_aplic: Skip reset for KVM irqchip
> >        hw/intc: riscv_imsic: Skip reset for KVM irqchip
> >
> > SeungJu Cheon (1):
> >        target/riscv: Apply UXL WARL handling to vsstatus
> >
> > ZhengXiang Qin (1):
> >        target/riscv: avoid abort when reading vtype before env->xl is set
>
>
> Hi!
>
> Is there anything here worth picking up for the stable series
> (besides "target/riscv: Check PMP before updating PTE")?
>
> For example,
>
>   46d96da130 target/riscv: avoid abort when reading vtype before env->xl
> is set
>   5a3fd18f4f hw/riscv/riscv-iommu.c: make FCTL.BE read only 0
>   13c2fc34f1 hw/riscv/riscv-iommu: check DC.TC reserved bits
>   6ed77682d5 hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set
>   887d2d75b1 hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately
>   3cee183ff9 hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset
>   64ce9ac187 hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0
>
> resolves various bugs from the qemu issue/work-items tracker.

Everything with a Fixes tag should be backported to releases that have
the relevant commits

Alistair

>
> Thanks,
>
> /mjt


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

end of thread, other threads:[~2026-07-03  0:03 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-01 10:17 [PULL 00/39] riscv-to-apply queue alistair23
2026-07-01 10:17 ` [PULL 01/39] target/riscv: Avoid NULL deref in IMSIC CSR write alistair23
2026-07-01 10:17 ` [PULL 02/39] tests/functional/riscv64: Use newer kernel for tuxrun boot alistair23
2026-07-01 10:17 ` [PULL 03/39] tests/functional/riscv64: Add virt machine AIA boot test alistair23
2026-07-01 10:17 ` [PULL 04/39] target/riscv/cpu: add CPU unrealize callback alistair23
2026-07-01 10:17 ` [PULL 05/39] target/riscv: dynamic alloc of debug trigger arrays alistair23
2026-07-01 10:17 ` [PULL 06/39] target/riscv: add 'num-triggers' debug property alistair23
2026-07-01 10:17 ` [PULL 07/39] target/riscv/cpu.c: add 'svbare' satp-mode alistair23
2026-07-01 10:17 ` [PULL 08/39] hw/riscv/virt-acpi-build: Fix RINTC PLIC context ID for KVM alistair23
2026-07-01 10:17 ` [PULL 09/39] target/riscv: avoid abort when reading vtype before env->xl is set alistair23
2026-07-01 10:17 ` [PULL 10/39] hw/intc: riscv_aplic: Skip reset for KVM irqchip alistair23
2026-07-01 10:17 ` [PULL 11/39] hw/intc: riscv_imsic: " alistair23
2026-07-01 10:17 ` [PULL 12/39] target/riscv/kvm: skip FP/Vector sync on KVM_PUT_RUNTIME_STATE alistair23
2026-07-01 10:17 ` [PULL 13/39] hw/riscv/sifive_u.c: remove unneeded qemu_fdt_get_phandle() call alistair23
2026-07-01 10:17 ` [PULL 14/39] hw/riscv/sifive_u.c: use intc_phandle in plic creation alistair23
2026-07-01 10:17 ` [PULL 15/39] hw/riscv/sifive_u: add #address-cells in PLIC FDT alistair23
2026-07-01 10:17 ` [PULL 16/39] hw/riscv/virt.c: change 'plic' nodename to 'interrupt-controller' alistair23
2026-07-01 10:17 ` [PULL 17/39] hw/riscv: add create_fdt_plic() helper alistair23
2026-07-01 10:17 ` [PULL 18/39] hw/riscv/riscv-iommu: rename regs_rw to regs alistair23
2026-07-01 10:17 ` [PULL 19/39] hw/riscv/riscv-iommu.c: make FCTL.BE read only 0 alistair23
2026-07-01 10:17 ` [PULL 20/39] hw/riscv/riscv-iommu: check DC.TC reserved bits alistair23
2026-07-01 10:17 ` [PULL 21/39] target/riscv: Apply UXL WARL handling to vsstatus alistair23
2026-07-01 10:17 ` [PULL 22/39] hw/riscv/riscv-iommu: set cmd_ill IOFENCE.C rsvp bits are set alistair23
2026-07-01 10:17 ` [PULL 23/39] hw/riscv/riscv-iommu.c: set RISCV_IOMMU_FQ_HDR_PV appropriately alistair23
2026-07-01 10:17 ` [PULL 24/39] hw/riscv/riscv-iommu.c: fix MSI MRIF interrupt-pending offset alistair23
2026-07-01 10:17 ` [PULL 25/39] target/riscv: Report QEMU CPU archid as 42 alistair23
2026-07-01 10:17 ` [PULL 26/39] target/riscv: Check PMP before updating PTE alistair23
2026-07-01 10:17 ` [PULL 27/39] hw/riscv/boot: Describe discontiguous memory in boot_info alistair23
2026-07-01 10:17 ` [PULL 28/39] hw/riscv/boot: Account for discontiguous memory when loading firmware alistair23
2026-07-01 10:17 ` [PULL 29/39] hw/riscv/virt: Move AIA initialisation to helper file alistair23
2026-07-01 10:17 ` [PULL 30/39] hw/riscv/aia: Provide number of irq sources alistair23
2026-07-01 10:17 ` [PULL 31/39] hw/riscv/aia: Configure stride for the M-mode IMSIC alistair23
2026-07-01 10:17 ` [PULL 32/39] target/riscv: tt-ascalon: Enable Zkr extension alistair23
2026-07-01 10:17 ` [PULL 33/39] hw/riscv: Add Tenstorrent Atlantis machine alistair23
2026-07-01 10:17 ` [PULL 34/39] hw/riscv/atlantis: Ensure OpenSBI has a non-zero next_addr alistair23
2026-07-01 10:17 ` [PULL 35/39] tests/functional/riscv64: Add tt-atlantis tests alistair23
2026-07-01 10:17 ` [PULL 36/39] hw/i2c: Add DesignWare I2C Controller alistair23
2026-07-01 10:17 ` [PULL 37/39] hw/riscv/atlantis: Integrate i2c controllers alistair23
2026-07-01 10:17 ` [PULL 38/39] hw/riscv/atlantis: Add some i2c peripherals alistair23
2026-07-01 10:17 ` [PULL 39/39] hw/riscv/riscv-iommu.c: always fault with SADE=0 and A=0 alistair23
2026-07-02 10:32 ` [PULL 00/39] riscv-to-apply queue Stefan Hajnoczi
2026-07-02 10:54 ` Michael Tokarev
2026-07-02 11:44   ` Daniel Henrique Barboza
2026-07-03  0:02   ` Alistair Francis
  -- strict thread matches above, loose matches on Subject: below --
2024-12-18 22:29 Alistair Francis
2024-12-19 20:45 ` Stefan Hajnoczi
2024-12-20  1:55   ` Alistair Francis
2024-12-20  9:36   ` 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.