Merge tag 'pull-10.2-maintainer-071025-1' of https://gitlab.com/stsquad/qemu into staging
testing updates
- tweak .gitpublish base to origin/master
- restore .gitmodules to qemu-project hosts
- drop 64 bits guests from i686
- update aarch64/s390x custom runners to 24.04
- tweak gitlab-runner registration method
- make check-venv dependency for functional tests
- replace avocado's gdb support with pygdbmi
- remove avocado dependencies from reverse_debug tests
- ensure replay.bin doesn't loose events after SHUTDOWN_HOST_QMP
# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmjk1K8ACgkQ+9DbCVqe
# KkSMAQf/X/vltf2njNMiBtlEh3H5j7RHFYs83V+UYa1m2DRSrx9B8dBDwTv+kqeh
# KRSnHMufdVuqKhaPAavvI4v4E1kqjjTy1U4YjjMA7zKPrTafJHGhI6QGiQ3i7vhA
# 3/XTiqYhTJZfVFGDWlTkE8GbmTsT+mQVwt2BCoKjazibGVNWvRwUcWk81cNw/YI5
# e28dRbDCB+K03y+QVhyEOVBm59r0Qft0v3nLMq8+kGxW/Nh0oGKpuagWT2D24Tp0
# bEMlkcMJv20fVV9wd5f8NmAyMucczkt2vuLhghA/wUQveO0jBJwMxoMfgiGtlI1s
# iy1Q1iFx7bMEOeHO2fDQSvAfSXzvSw==
# =m/Gd
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 07 Oct 2025 01:51:59 AM PDT
# gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44
# gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44
* tag 'pull-10.2-maintainer-071025-1' of https://gitlab.com/stsquad/qemu:
record/replay: fix race condition on test_aarch64_reverse_debug
tests/functional: Adapt arches to reverse_debugging w/o Avocado
tests/functional: Adapt reverse_debugging to run w/o Avocado
tests/functional: Add decorator to skip test on missing env vars
tests/functional: drop datadrainer class in reverse debugging
tests/functional: replace avocado process with subprocess
tests/functional: Add GDB class
tests/functional: Provide GDB to the functional tests
python: Install pygdbmi in meson's venv
tests/functional: Re-activate the check-venv target
scripts/ci: use recommended registration command
gitlab: move custom runners to Ubuntu 24.04
tests/lcitool: bump custom runner packages to Ubuntu 24.04
tests/lcitool: drop 64 bit guests from i686 cross build
.gitmodules: restore qemu-project mirror of u-boot-sam460ex
.gitmodules: restore qemu-project mirror of u-boot
.gitpublish: use origin/master as default base
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/MAINTAINERS b/MAINTAINERS
index 75e1fa5..128f90b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1006,7 +1006,6 @@
F: hw/arm/collie.c
F: hw/arm/strongarm*
F: hw/gpio/zaurus.c
-F: include/hw/arm/sharpsl.h
F: docs/system/arm/collie.rst
F: tests/functional/arm/test_collie.py
@@ -3223,6 +3222,7 @@
F: include/system/ioport.h
F: include/exec/memop.h
F: include/system/memory.h
+F: include/system/physmem.h
F: include/system/ram_addr.h
F: include/system/ramblock.h
F: include/system/memory_mapping.h
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 9060599..58802f7 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -32,11 +32,13 @@
#include "system/runstate.h"
#include "system/cpus.h"
#include "system/accel-blocker.h"
+#include "system/physmem.h"
+#include "system/ramblock.h"
#include "accel/accel-ops.h"
#include "qemu/bswap.h"
#include "exec/tswap.h"
+#include "exec/target_page.h"
#include "system/memory.h"
-#include "system/ram_addr.h"
#include "qemu/event_notifier.h"
#include "qemu/main-loop.h"
#include "trace.h"
@@ -756,7 +758,7 @@
ram_addr_t start = slot->ram_start_offset;
ram_addr_t pages = slot->memory_size / qemu_real_host_page_size();
- cpu_physical_memory_set_dirty_lebitmap(slot->dirty_bmap, start, pages);
+ physical_memory_set_dirty_lebitmap(slot->dirty_bmap, start, pages);
}
static void kvm_slot_reset_dirty_pages(KVMSlot *slot)
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 2a6aa01..7214d41 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -25,6 +25,7 @@
#include "accel/tcg/probe.h"
#include "exec/page-protection.h"
#include "system/memory.h"
+#include "system/physmem.h"
#include "accel/tcg/cpu-ldst-common.h"
#include "accel/tcg/cpu-mmu-index.h"
#include "exec/cputlb.h"
@@ -858,7 +859,7 @@
can be detected */
void tlb_protect_code(ram_addr_t ram_addr)
{
- cpu_physical_memory_test_and_clear_dirty(ram_addr & TARGET_PAGE_MASK,
+ physical_memory_test_and_clear_dirty(ram_addr & TARGET_PAGE_MASK,
TARGET_PAGE_SIZE,
DIRTY_MEMORY_CODE);
}
@@ -867,7 +868,7 @@
tested for self modifying code */
void tlb_unprotect_code(ram_addr_t ram_addr)
{
- cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE);
+ physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE);
}
@@ -1085,7 +1086,7 @@
if (prot & PAGE_WRITE) {
if (section->readonly) {
write_flags |= TLB_DISCARD_WRITE;
- } else if (cpu_physical_memory_is_clean(iotlb)) {
+ } else if (physical_memory_is_clean(iotlb)) {
write_flags |= TLB_NOTDIRTY;
}
}
@@ -1341,7 +1342,7 @@
trace_memory_notdirty_write_access(mem_vaddr, ram_addr, size);
- if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
+ if (!physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
tb_invalidate_phys_range_fast(cpu, ram_addr, size, retaddr);
}
@@ -1349,10 +1350,10 @@
* Set both VGA and migration bits for simplicity and to remove
* the notdirty callback faster.
*/
- cpu_physical_memory_set_dirty_range(ram_addr, size, DIRTY_CLIENTS_NOCODE);
+ physical_memory_set_dirty_range(ram_addr, size, DIRTY_CLIENTS_NOCODE);
/* We remove the notdirty callback only if the code has been flushed. */
- if (!cpu_physical_memory_is_clean(ram_addr)) {
+ if (!physical_memory_is_clean(ram_addr)) {
trace_memory_notdirty_set_dirty(mem_vaddr);
tlb_set_dirty(cpu, mem_vaddr);
}
diff --git a/docs/devel/loads-stores.rst b/docs/devel/loads-stores.rst
index 9471bac..c906c65 100644
--- a/docs/devel/loads-stores.rst
+++ b/docs/devel/loads-stores.rst
@@ -460,10 +460,8 @@
``cpu_physical_memory_write``
-``cpu_physical_memory_rw``
-
Regexes for git grep:
- - ``\<cpu_physical_memory_\(read\|write\|rw\)\>``
+ - ``\<cpu_physical_memory_\(read\|write\)\>``
``cpu_memory_rw_debug``
~~~~~~~~~~~~~~~~~~~~~~~
@@ -474,7 +472,7 @@
It takes a virtual address, converts it to a physical address via
an MMU lookup using the current settings of the specified CPU,
and then performs the access (using ``address_space_rw`` for
-reads or ``cpu_physical_memory_write_rom`` for writes).
+reads or ``address_space_write_rom`` for writes).
This means that if the access is a write to a ROM then this
function will modify the contents (whereas a normal guest CPU access
would ignore the write attempt).
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index 6b04c96..1aa0a6e 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -120,6 +120,7 @@
- FEAT_RASv1p1 (RAS Extension v1.1)
- FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions)
- FEAT_RME (Realm Management Extension) (NB: support status in QEMU is experimental)
+- FEAT_RME_GPC2 (RME Granule Protection Check 2 Extension)
- FEAT_RNG (Random number generator)
- FEAT_RPRES (Increased precision of FRECPE and FRSQRTE)
- FEAT_S2FWB (Stage 2 forced Write-Back)
diff --git a/docs/system/arm/xlnx-versal-virt.rst b/docs/system/arm/xlnx-versal-virt.rst
index c5f35f2..640cc07 100644
--- a/docs/system/arm/xlnx-versal-virt.rst
+++ b/docs/system/arm/xlnx-versal-virt.rst
@@ -1,29 +1,37 @@
-Xilinx Versal Virt (``xlnx-versal-virt``)
-=========================================
+AMD Versal Virt (``amd-versal-virt``, ``amd-versal2-virt``)
+===========================================================
-Xilinx Versal is a family of heterogeneous multi-core SoCs
+AMD Versal is a family of heterogeneous multi-core SoCs
(System on Chip) that combine traditional hardened CPUs and I/O
peripherals in a Processing System (PS) with runtime programmable
FPGA logic (PL) and an Artificial Intelligence Engine (AIE).
+QEMU implements the following Versal SoCs variants:
+
+- Versal (the ``amd-versal-virt`` machine, the alias ``xlnx-versal-virt`` is
+ kept for backward compatibility)
+- Versal Gen 2 (the ``amd-versal2-virt`` machine)
+
More details here:
-https://www.xilinx.com/products/silicon-devices/acap/versal.html
+https://www.amd.com/en/products/adaptive-socs-and-fpgas/versal.html
The family of Versal SoCs share a single architecture but come in
different parts with different speed grades, amounts of PL and
other differences.
-The Xilinx Versal Virt board in QEMU is a model of a virtual board
+The AMD Versal Virt board in QEMU is a model of a virtual board
(does not exist in reality) with a virtual Versal SoC without I/O
limitations. Currently, we support the following cores and devices:
+Versal
+""""""
Implemented CPU cores:
-- 2 ACPUs (ARM Cortex-A72)
+- 2 ACPUs (ARM Cortex-A72) with their GICv3 and ITS
+- 2 RCPUs (ARM Cortex-R5F) with their GICv2
Implemented devices:
-- Interrupt controller (ARM GICv3)
- 2 UARTs (ARM PL011)
- An RTC (Versal built-in)
- 2 GEMs (Cadence MACB Ethernet MACs)
@@ -35,6 +43,31 @@
- BBRAM (36 bytes of Battery-backed RAM)
- eFUSE (3072 bytes of one-time field-programmable bit array)
- 2 CANFDs
+- USB controller
+- OSPI controller
+- TRNG controller
+
+Versal Gen 2
+""""""""""""
+Implemented CPU cores:
+
+- 8 ACPUs (ARM Cortex-A78AE) with their GICv3 and ITS
+- 10 RCPUs (ARM Cortex-R52) with their GICv3 (one per cluster)
+
+Implemented devices:
+
+- 2 UARTs (ARM PL011)
+- An RTC (Versal built-in)
+- 3 GEMs (Cadence MACB Ethernet MACs)
+- 8 ADMA (Xilinx zDMA) channels
+- 2 SD Controllers
+- OCM (256KB of On Chip Memory)
+- DDR memory
+- BBRAM (36 bytes of Battery-backed RAM)
+- 2 CANFDs
+- 2 USB controllers
+- OSPI controller
+- TRNG controller
QEMU does not yet model any other devices, including the PL and the AI Engine.
@@ -44,8 +77,8 @@
``-m`` argument. If a DTB is provided on the command line then QEMU will
edit it to include suitable entries describing the Versal DDR memory ranges.
-- QEMU provides 8 virtio-mmio virtio transports; these start at
- address ``0xa0000000`` and have IRQs from 111 and upwards.
+- QEMU provides 8 virtio-mmio virtio transports. They use reserved memory
+ regions and IRQ pins to avoid conflicts with real SoC peripherals.
Running
"""""""
@@ -58,7 +91,13 @@
where it gets loaded. This DTB will be passed to the kernel in register x0.
If there's no ``-kernel`` option, we generate a DTB and place it at 0x1000
-for boot-loaders or firmware to pick it up.
+for boot-loaders or firmware to pick it up. To dump and observe the generated
+DTB, one can use the ``dumpdtb`` machine option:
+
+.. code-block:: bash
+
+ $ qemu-system-aarch64 -M amd-versal-virt,dumpdtb=example.dtb -m 2G
+
If users want to provide their own DTB, they can use the ``-dtb`` option.
These DTBs will have their memory nodes modified to match QEMU's
@@ -74,7 +113,7 @@
.. code-block:: bash
- $ qemu-system-aarch64 -M xlnx-versal-virt -m 2G \
+ $ qemu-system-aarch64 -M amd-versal-virt -m 2G \
-serial mon:stdio -display none \
-kernel arch/arm64/boot/Image \
-nic user -nic user \
@@ -87,7 +126,7 @@
.. code-block:: bash
- $ qemu-system-aarch64 -M xlnx-versal-virt -m 2G \
+ $ qemu-system-aarch64 -M amd-versal-virt -m 2G \
-serial mon:stdio -display none \
-kernel petalinux-v2019.2/Image \
-append "rdinit=/sbin/init console=ttyAMA0,115200n8 earlycon=pl011,mmio,0xFF000000,115200n8" \
@@ -100,7 +139,7 @@
.. code-block:: bash
- $ qemu-system-aarch64 -M xlnx-versal-virt -m 2G \
+ $ qemu-system-aarch64 -M amd-versal-virt -m 2G \
-serial stdio -display none \
-device loader,file=petalinux-v2018.3/bl31.elf,cpu-num=0 \
-device loader,file=petalinux-v2019.2/u-boot.elf \
@@ -125,7 +164,7 @@
.. code-block:: bash
- $ qemu-system-aarch64 -M xlnx-versal-virt -m 4G \
+ $ qemu-system-aarch64 -M amd-versal-virt -m 4G \
-serial stdio -display none \
-device loader,file=petalinux-v2019.2/u-boot.elf,cpu-num=0 \
-device loader,addr=0x30000000,file=linux/2018-04-24/xen \
@@ -153,7 +192,7 @@
.. code-block:: bash
- $ qemu-system-aarch64 -M xlnx-versal-virt -m 4G \
+ $ qemu-system-aarch64 -M amd-versal-virt -m 4G \
-serial stdio -display none \
-device loader,file=petalinux-v2018.3/bl31.elf,cpu-num=0 \
-device loader,file=petalinux-v2019.2/u-boot.elf \
@@ -201,6 +240,11 @@
eFUSE File Backend
""""""""""""""""""
+
+.. note::
+ The eFUSE device is not implemented in the Versal Gen 2 QEMU model
+ yet.
+
eFUSE can have an optional file backend, which must be a seekable
binary file with a size of 3072 bytes or larger. A file with all
binary 0s is a 'blank'.
@@ -227,7 +271,7 @@
is highly recommended (albeit with usage complexity).
Better yet, do not use actual product data when running guest image
- on this Xilinx Versal Virt board.
+ on this AMD Versal Virt board.
Using CANFDs for Versal Virt
""""""""""""""""""""""""""""
@@ -258,3 +302,7 @@
-object can-bus,id=canbus -machine canbus0=canbus -machine canbus1=canbus
-object can-host-socketcan,id=canhost0,if=can0,canbus=canbus
+
+.. note::
+ Versal Gen 2 has 4 CAN controllers. ``canbus0`` to ``canbus3`` can
+ be specified on the command line.
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
index adadbb7..149b448 100644
--- a/hw/arm/xlnx-versal-virt.c
+++ b/hw/arm/xlnx-versal-virt.c
@@ -1,7 +1,8 @@
/*
- * Xilinx Versal Virtual board.
+ * AMD/Xilinx Versal family Virtual board.
*
* Copyright (c) 2018 Xilinx Inc.
+ * Copyright (c) 2025 Advanced Micro Devices, Inc.
* Written by Edgar E. Iglesias
*
* This program is free software; you can redistribute it and/or modify
@@ -13,18 +14,22 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "system/device_tree.h"
+#include "system/address-spaces.h"
#include "hw/block/flash.h"
#include "hw/boards.h"
#include "hw/sysbus.h"
#include "hw/arm/fdt.h"
-#include "hw/qdev-properties.h"
#include "hw/arm/xlnx-versal.h"
#include "hw/arm/boot.h"
-#include "target/arm/multiprocessing.h"
#include "qom/object.h"
+#include "target/arm/cpu.h"
-#define TYPE_XLNX_VERSAL_VIRT_MACHINE MACHINE_TYPE_NAME("xlnx-versal-virt")
-OBJECT_DECLARE_SIMPLE_TYPE(VersalVirt, XLNX_VERSAL_VIRT_MACHINE)
+#define TYPE_XLNX_VERSAL_VIRT_BASE_MACHINE \
+ MACHINE_TYPE_NAME("amd-versal-virt-base")
+OBJECT_DECLARE_TYPE(VersalVirt, VersalVirtClass, XLNX_VERSAL_VIRT_BASE_MACHINE)
+
+#define TYPE_XLNX_VERSAL_VIRT_MACHINE MACHINE_TYPE_NAME("amd-versal-virt")
+#define TYPE_XLNX_VERSAL2_VIRT_MACHINE MACHINE_TYPE_NAME("amd-versal2-virt")
#define XLNX_VERSAL_NUM_OSPI_FLASH 4
@@ -35,28 +40,27 @@
void *fdt;
int fdt_size;
- struct {
- uint32_t gic;
- uint32_t ethernet_phy[2];
- uint32_t clk_125Mhz;
- uint32_t clk_25Mhz;
- uint32_t usb;
- uint32_t dwc;
- uint32_t canfd[2];
- } phandle;
struct arm_boot_info binfo;
- CanBusState *canbus[XLNX_VERSAL_NR_CANFD];
+ CanBusState **canbus;
+
struct {
- bool secure;
+ char *ospi_model;
} cfg;
- char *ospi_model;
+};
+
+struct VersalVirtClass {
+ MachineClass parent_class;
+
+ VersalVersion version;
};
static void fdt_create(VersalVirt *s)
{
MachineClass *mc = MACHINE_GET_CLASS(s);
- int i;
+ VersalVirtClass *vvc = XLNX_VERSAL_VIRT_BASE_MACHINE_GET_CLASS(s);
+ const char versal_compat[] = "amd-versal-virt\0xlnx-versal-virt";
+ const char versal2_compat[] = "amd-versal2-virt";
s->fdt = create_device_tree(&s->fdt_size);
if (!s->fdt) {
@@ -64,392 +68,26 @@
exit(1);
}
- /* Allocate all phandles. */
- s->phandle.gic = qemu_fdt_alloc_phandle(s->fdt);
- for (i = 0; i < ARRAY_SIZE(s->phandle.ethernet_phy); i++) {
- s->phandle.ethernet_phy[i] = qemu_fdt_alloc_phandle(s->fdt);
- }
- s->phandle.clk_25Mhz = qemu_fdt_alloc_phandle(s->fdt);
- s->phandle.clk_125Mhz = qemu_fdt_alloc_phandle(s->fdt);
-
- s->phandle.usb = qemu_fdt_alloc_phandle(s->fdt);
- s->phandle.dwc = qemu_fdt_alloc_phandle(s->fdt);
/* Create /chosen node for load_dtb. */
qemu_fdt_add_subnode(s->fdt, "/chosen");
+ qemu_fdt_add_subnode(s->fdt, "/aliases");
/* Header */
- qemu_fdt_setprop_cell(s->fdt, "/", "interrupt-parent", s->phandle.gic);
- qemu_fdt_setprop_cell(s->fdt, "/", "#size-cells", 0x2);
- qemu_fdt_setprop_cell(s->fdt, "/", "#address-cells", 0x2);
qemu_fdt_setprop_string(s->fdt, "/", "model", mc->desc);
- qemu_fdt_setprop_string(s->fdt, "/", "compatible", "xlnx-versal-virt");
-}
-static void fdt_add_clk_node(VersalVirt *s, const char *name,
- unsigned int freq_hz, uint32_t phandle)
-{
- qemu_fdt_add_subnode(s->fdt, name);
- qemu_fdt_setprop_cell(s->fdt, name, "phandle", phandle);
- qemu_fdt_setprop_cell(s->fdt, name, "clock-frequency", freq_hz);
- qemu_fdt_setprop_cell(s->fdt, name, "#clock-cells", 0x0);
- qemu_fdt_setprop_string(s->fdt, name, "compatible", "fixed-clock");
- qemu_fdt_setprop(s->fdt, name, "u-boot,dm-pre-reloc", NULL, 0);
-}
+ switch (vvc->version) {
+ case VERSAL_VER_VERSAL:
+ qemu_fdt_setprop(s->fdt, "/", "compatible", versal_compat,
+ sizeof(versal_compat));
+ break;
-static void fdt_add_cpu_nodes(VersalVirt *s, uint32_t psci_conduit)
-{
- int i;
-
- qemu_fdt_add_subnode(s->fdt, "/cpus");
- qemu_fdt_setprop_cell(s->fdt, "/cpus", "#size-cells", 0x0);
- qemu_fdt_setprop_cell(s->fdt, "/cpus", "#address-cells", 1);
-
- for (i = XLNX_VERSAL_NR_ACPUS - 1; i >= 0; i--) {
- char *name = g_strdup_printf("/cpus/cpu@%d", i);
- ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i));
-
- qemu_fdt_add_subnode(s->fdt, name);
- qemu_fdt_setprop_cell(s->fdt, name, "reg",
- arm_cpu_mp_affinity(armcpu));
- if (psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) {
- qemu_fdt_setprop_string(s->fdt, name, "enable-method", "psci");
- }
- qemu_fdt_setprop_string(s->fdt, name, "device_type", "cpu");
- qemu_fdt_setprop_string(s->fdt, name, "compatible",
- armcpu->dtb_compatible);
- g_free(name);
+ case VERSAL_VER_VERSAL2:
+ qemu_fdt_setprop(s->fdt, "/", "compatible", versal2_compat,
+ sizeof(versal2_compat));
+ break;
}
}
-static void fdt_add_gic_nodes(VersalVirt *s)
-{
- char *nodename;
-
- nodename = g_strdup_printf("/gic@%x", MM_GIC_APU_DIST_MAIN);
- qemu_fdt_add_subnode(s->fdt, nodename);
- qemu_fdt_setprop_cell(s->fdt, nodename, "phandle", s->phandle.gic);
- qemu_fdt_setprop_cells(s->fdt, nodename, "interrupts",
- GIC_FDT_IRQ_TYPE_PPI, VERSAL_GIC_MAINT_IRQ,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop(s->fdt, nodename, "interrupt-controller", NULL, 0);
- qemu_fdt_setprop_sized_cells(s->fdt, nodename, "reg",
- 2, MM_GIC_APU_DIST_MAIN,
- 2, MM_GIC_APU_DIST_MAIN_SIZE,
- 2, MM_GIC_APU_REDIST_0,
- 2, MM_GIC_APU_REDIST_0_SIZE);
- qemu_fdt_setprop_cell(s->fdt, nodename, "#interrupt-cells", 3);
- qemu_fdt_setprop_string(s->fdt, nodename, "compatible", "arm,gic-v3");
- g_free(nodename);
-}
-
-static void fdt_add_timer_nodes(VersalVirt *s)
-{
- const char compat[] = "arm,armv8-timer";
- uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI;
-
- qemu_fdt_add_subnode(s->fdt, "/timer");
- qemu_fdt_setprop_cells(s->fdt, "/timer", "interrupts",
- GIC_FDT_IRQ_TYPE_PPI, VERSAL_TIMER_S_EL1_IRQ, irqflags,
- GIC_FDT_IRQ_TYPE_PPI, VERSAL_TIMER_NS_EL1_IRQ, irqflags,
- GIC_FDT_IRQ_TYPE_PPI, VERSAL_TIMER_VIRT_IRQ, irqflags,
- GIC_FDT_IRQ_TYPE_PPI, VERSAL_TIMER_NS_EL2_IRQ, irqflags);
- qemu_fdt_setprop(s->fdt, "/timer", "compatible",
- compat, sizeof(compat));
-}
-
-static void fdt_add_usb_xhci_nodes(VersalVirt *s)
-{
- const char clocknames[] = "bus_clk\0ref_clk";
- const char irq_name[] = "dwc_usb3";
- const char compatVersalDWC3[] = "xlnx,versal-dwc3";
- const char compatDWC3[] = "snps,dwc3";
- char *name = g_strdup_printf("/usb@%" PRIx32, MM_USB2_CTRL_REGS);
-
- qemu_fdt_add_subnode(s->fdt, name);
- qemu_fdt_setprop(s->fdt, name, "compatible",
- compatVersalDWC3, sizeof(compatVersalDWC3));
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, MM_USB2_CTRL_REGS,
- 2, MM_USB2_CTRL_REGS_SIZE);
- qemu_fdt_setprop(s->fdt, name, "clock-names",
- clocknames, sizeof(clocknames));
- qemu_fdt_setprop_cells(s->fdt, name, "clocks",
- s->phandle.clk_25Mhz, s->phandle.clk_125Mhz);
- qemu_fdt_setprop(s->fdt, name, "ranges", NULL, 0);
- qemu_fdt_setprop_cell(s->fdt, name, "#address-cells", 2);
- qemu_fdt_setprop_cell(s->fdt, name, "#size-cells", 2);
- qemu_fdt_setprop_cell(s->fdt, name, "phandle", s->phandle.usb);
- g_free(name);
-
- name = g_strdup_printf("/usb@%" PRIx32 "/dwc3@%" PRIx32,
- MM_USB2_CTRL_REGS, MM_USB_0);
- qemu_fdt_add_subnode(s->fdt, name);
- qemu_fdt_setprop(s->fdt, name, "compatible",
- compatDWC3, sizeof(compatDWC3));
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, MM_USB_0, 2, MM_USB_0_SIZE);
- qemu_fdt_setprop(s->fdt, name, "interrupt-names",
- irq_name, sizeof(irq_name));
- qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, VERSAL_USB0_IRQ_0,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop_cell(s->fdt, name,
- "snps,quirk-frame-length-adjustment", 0x20);
- qemu_fdt_setprop_cells(s->fdt, name, "#stream-id-cells", 1);
- qemu_fdt_setprop_string(s->fdt, name, "dr_mode", "host");
- qemu_fdt_setprop_string(s->fdt, name, "phy-names", "usb3-phy");
- qemu_fdt_setprop(s->fdt, name, "snps,dis_u2_susphy_quirk", NULL, 0);
- qemu_fdt_setprop(s->fdt, name, "snps,dis_u3_susphy_quirk", NULL, 0);
- qemu_fdt_setprop(s->fdt, name, "snps,refclk_fladj", NULL, 0);
- qemu_fdt_setprop(s->fdt, name, "snps,mask_phy_reset", NULL, 0);
- qemu_fdt_setprop_cell(s->fdt, name, "phandle", s->phandle.dwc);
- qemu_fdt_setprop_string(s->fdt, name, "maximum-speed", "high-speed");
- g_free(name);
-}
-
-static void fdt_add_uart_nodes(VersalVirt *s)
-{
- uint64_t addrs[] = { MM_UART1, MM_UART0 };
- unsigned int irqs[] = { VERSAL_UART1_IRQ_0, VERSAL_UART0_IRQ_0 };
- const char compat[] = "arm,pl011\0arm,sbsa-uart";
- const char clocknames[] = "uartclk\0apb_pclk";
- int i;
-
- for (i = 0; i < ARRAY_SIZE(addrs); i++) {
- char *name = g_strdup_printf("/uart@%" PRIx64, addrs[i]);
- qemu_fdt_add_subnode(s->fdt, name);
- qemu_fdt_setprop_cell(s->fdt, name, "current-speed", 115200);
- qemu_fdt_setprop_cells(s->fdt, name, "clocks",
- s->phandle.clk_125Mhz, s->phandle.clk_125Mhz);
- qemu_fdt_setprop(s->fdt, name, "clock-names",
- clocknames, sizeof(clocknames));
-
- qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, irqs[i],
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, addrs[i], 2, 0x1000);
- qemu_fdt_setprop(s->fdt, name, "compatible",
- compat, sizeof(compat));
- qemu_fdt_setprop(s->fdt, name, "u-boot,dm-pre-reloc", NULL, 0);
-
- if (addrs[i] == MM_UART0) {
- /* Select UART0. */
- qemu_fdt_setprop_string(s->fdt, "/chosen", "stdout-path", name);
- }
- g_free(name);
- }
-}
-
-static void fdt_add_canfd_nodes(VersalVirt *s)
-{
- uint64_t addrs[] = { MM_CANFD1, MM_CANFD0 };
- uint32_t size[] = { MM_CANFD1_SIZE, MM_CANFD0_SIZE };
- unsigned int irqs[] = { VERSAL_CANFD1_IRQ_0, VERSAL_CANFD0_IRQ_0 };
- const char clocknames[] = "can_clk\0s_axi_aclk";
- int i;
-
- /* Create and connect CANFD0 and CANFD1 nodes to canbus0. */
- for (i = 0; i < ARRAY_SIZE(addrs); i++) {
- char *name = g_strdup_printf("/canfd@%" PRIx64, addrs[i]);
- qemu_fdt_add_subnode(s->fdt, name);
-
- qemu_fdt_setprop_cell(s->fdt, name, "rx-fifo-depth", 0x40);
- qemu_fdt_setprop_cell(s->fdt, name, "tx-mailbox-count", 0x20);
-
- qemu_fdt_setprop_cells(s->fdt, name, "clocks",
- s->phandle.clk_25Mhz, s->phandle.clk_25Mhz);
- qemu_fdt_setprop(s->fdt, name, "clock-names",
- clocknames, sizeof(clocknames));
- qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, irqs[i],
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, addrs[i], 2, size[i]);
- qemu_fdt_setprop_string(s->fdt, name, "compatible",
- "xlnx,canfd-2.0");
-
- g_free(name);
- }
-}
-
-static void fdt_add_fixed_link_nodes(VersalVirt *s, char *gemname,
- uint32_t phandle)
-{
- char *name = g_strdup_printf("%s/fixed-link", gemname);
-
- qemu_fdt_add_subnode(s->fdt, name);
- qemu_fdt_setprop_cell(s->fdt, name, "phandle", phandle);
- qemu_fdt_setprop(s->fdt, name, "full-duplex", NULL, 0);
- qemu_fdt_setprop_cell(s->fdt, name, "speed", 1000);
- g_free(name);
-}
-
-static void fdt_add_gem_nodes(VersalVirt *s)
-{
- uint64_t addrs[] = { MM_GEM1, MM_GEM0 };
- unsigned int irqs[] = { VERSAL_GEM1_IRQ_0, VERSAL_GEM0_IRQ_0 };
- const char clocknames[] = "pclk\0hclk\0tx_clk\0rx_clk";
- const char compat_gem[] = "cdns,zynqmp-gem\0cdns,gem";
- int i;
-
- for (i = 0; i < ARRAY_SIZE(addrs); i++) {
- char *name = g_strdup_printf("/ethernet@%" PRIx64, addrs[i]);
- qemu_fdt_add_subnode(s->fdt, name);
-
- fdt_add_fixed_link_nodes(s, name, s->phandle.ethernet_phy[i]);
- qemu_fdt_setprop_string(s->fdt, name, "phy-mode", "rgmii-id");
- qemu_fdt_setprop_cell(s->fdt, name, "phy-handle",
- s->phandle.ethernet_phy[i]);
- qemu_fdt_setprop_cells(s->fdt, name, "clocks",
- s->phandle.clk_25Mhz, s->phandle.clk_25Mhz,
- s->phandle.clk_125Mhz, s->phandle.clk_125Mhz);
- qemu_fdt_setprop(s->fdt, name, "clock-names",
- clocknames, sizeof(clocknames));
- qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, irqs[i],
- GIC_FDT_IRQ_FLAGS_LEVEL_HI,
- GIC_FDT_IRQ_TYPE_SPI, irqs[i],
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, addrs[i], 2, 0x1000);
- qemu_fdt_setprop(s->fdt, name, "compatible",
- compat_gem, sizeof(compat_gem));
- qemu_fdt_setprop_cell(s->fdt, name, "#address-cells", 1);
- qemu_fdt_setprop_cell(s->fdt, name, "#size-cells", 0);
- g_free(name);
- }
-}
-
-static void fdt_add_zdma_nodes(VersalVirt *s)
-{
- const char clocknames[] = "clk_main\0clk_apb";
- const char compat[] = "xlnx,zynqmp-dma-1.0";
- int i;
-
- for (i = XLNX_VERSAL_NR_ADMAS - 1; i >= 0; i--) {
- uint64_t addr = MM_ADMA_CH0 + MM_ADMA_CH0_SIZE * i;
- char *name = g_strdup_printf("/dma@%" PRIx64, addr);
-
- qemu_fdt_add_subnode(s->fdt, name);
-
- qemu_fdt_setprop_cell(s->fdt, name, "xlnx,bus-width", 64);
- qemu_fdt_setprop_cells(s->fdt, name, "clocks",
- s->phandle.clk_25Mhz, s->phandle.clk_25Mhz);
- qemu_fdt_setprop(s->fdt, name, "clock-names",
- clocknames, sizeof(clocknames));
- qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, VERSAL_ADMA_IRQ_0 + i,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, addr, 2, 0x1000);
- qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
- g_free(name);
- }
-}
-
-static void fdt_add_sd_nodes(VersalVirt *s)
-{
- const char clocknames[] = "clk_xin\0clk_ahb";
- const char compat[] = "arasan,sdhci-8.9a";
- int i;
-
- for (i = ARRAY_SIZE(s->soc.pmc.iou.sd) - 1; i >= 0; i--) {
- uint64_t addr = MM_PMC_SD0 + MM_PMC_SD0_SIZE * i;
- char *name = g_strdup_printf("/sdhci@%" PRIx64, addr);
-
- qemu_fdt_add_subnode(s->fdt, name);
-
- qemu_fdt_setprop_cells(s->fdt, name, "clocks",
- s->phandle.clk_25Mhz, s->phandle.clk_25Mhz);
- qemu_fdt_setprop(s->fdt, name, "clock-names",
- clocknames, sizeof(clocknames));
- qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, VERSAL_SD0_IRQ_0 + i * 2,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, addr, 2, MM_PMC_SD0_SIZE);
- qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
- g_free(name);
- }
-}
-
-static void fdt_add_rtc_node(VersalVirt *s)
-{
- const char compat[] = "xlnx,zynqmp-rtc";
- const char interrupt_names[] = "alarm\0sec";
- char *name = g_strdup_printf("/rtc@%x", MM_PMC_RTC);
-
- qemu_fdt_add_subnode(s->fdt, name);
-
- qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, VERSAL_RTC_ALARM_IRQ,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI,
- GIC_FDT_IRQ_TYPE_SPI, VERSAL_RTC_SECONDS_IRQ,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop(s->fdt, name, "interrupt-names",
- interrupt_names, sizeof(interrupt_names));
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, MM_PMC_RTC, 2, MM_PMC_RTC_SIZE);
- qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
- g_free(name);
-}
-
-static void fdt_add_bbram_node(VersalVirt *s)
-{
- const char compat[] = TYPE_XLNX_BBRAM;
- const char interrupt_names[] = "bbram-error";
- char *name = g_strdup_printf("/bbram@%x", MM_PMC_BBRAM_CTRL);
-
- qemu_fdt_add_subnode(s->fdt, name);
-
- qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, VERSAL_PMC_APB_IRQ,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop(s->fdt, name, "interrupt-names",
- interrupt_names, sizeof(interrupt_names));
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, MM_PMC_BBRAM_CTRL,
- 2, MM_PMC_BBRAM_CTRL_SIZE);
- qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
- g_free(name);
-}
-
-static void fdt_add_efuse_ctrl_node(VersalVirt *s)
-{
- const char compat[] = TYPE_XLNX_VERSAL_EFUSE_CTRL;
- const char interrupt_names[] = "pmc_efuse";
- char *name = g_strdup_printf("/pmc_efuse@%x", MM_PMC_EFUSE_CTRL);
-
- qemu_fdt_add_subnode(s->fdt, name);
-
- qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, VERSAL_EFUSE_IRQ,
- GIC_FDT_IRQ_FLAGS_LEVEL_HI);
- qemu_fdt_setprop(s->fdt, name, "interrupt-names",
- interrupt_names, sizeof(interrupt_names));
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, MM_PMC_EFUSE_CTRL,
- 2, MM_PMC_EFUSE_CTRL_SIZE);
- qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
- g_free(name);
-}
-
-static void fdt_add_efuse_cache_node(VersalVirt *s)
-{
- const char compat[] = TYPE_XLNX_VERSAL_EFUSE_CACHE;
- char *name = g_strdup_printf("/xlnx_pmc_efuse_cache@%x",
- MM_PMC_EFUSE_CACHE);
-
- qemu_fdt_add_subnode(s->fdt, name);
-
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
- 2, MM_PMC_EFUSE_CACHE,
- 2, MM_PMC_EFUSE_CACHE_SIZE);
- qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat));
- g_free(name);
-}
-
static void fdt_nop_memory_nodes(void *fdt, Error **errp)
{
Error *err = NULL;
@@ -470,88 +108,13 @@
g_strfreev(node_path);
}
-static void fdt_add_memory_nodes(VersalVirt *s, void *fdt, uint64_t ram_size)
-{
- /* Describes the various split DDR access regions. */
- static const struct {
- uint64_t base;
- uint64_t size;
- } addr_ranges[] = {
- { MM_TOP_DDR, MM_TOP_DDR_SIZE },
- { MM_TOP_DDR_2, MM_TOP_DDR_2_SIZE },
- { MM_TOP_DDR_3, MM_TOP_DDR_3_SIZE },
- { MM_TOP_DDR_4, MM_TOP_DDR_4_SIZE }
- };
- uint64_t mem_reg_prop[8] = {0};
- uint64_t size = ram_size;
- Error *err = NULL;
- char *name;
- int i;
-
- fdt_nop_memory_nodes(fdt, &err);
- if (err) {
- error_report_err(err);
- return;
- }
-
- name = g_strdup_printf("/memory@%x", MM_TOP_DDR);
- for (i = 0; i < ARRAY_SIZE(addr_ranges) && size; i++) {
- uint64_t mapsize;
-
- mapsize = size < addr_ranges[i].size ? size : addr_ranges[i].size;
-
- mem_reg_prop[i * 2] = addr_ranges[i].base;
- mem_reg_prop[i * 2 + 1] = mapsize;
- size -= mapsize;
- }
- qemu_fdt_add_subnode(fdt, name);
- qemu_fdt_setprop_string(fdt, name, "device_type", "memory");
-
- switch (i) {
- case 1:
- qemu_fdt_setprop_sized_cells(fdt, name, "reg",
- 2, mem_reg_prop[0],
- 2, mem_reg_prop[1]);
- break;
- case 2:
- qemu_fdt_setprop_sized_cells(fdt, name, "reg",
- 2, mem_reg_prop[0],
- 2, mem_reg_prop[1],
- 2, mem_reg_prop[2],
- 2, mem_reg_prop[3]);
- break;
- case 3:
- qemu_fdt_setprop_sized_cells(fdt, name, "reg",
- 2, mem_reg_prop[0],
- 2, mem_reg_prop[1],
- 2, mem_reg_prop[2],
- 2, mem_reg_prop[3],
- 2, mem_reg_prop[4],
- 2, mem_reg_prop[5]);
- break;
- case 4:
- qemu_fdt_setprop_sized_cells(fdt, name, "reg",
- 2, mem_reg_prop[0],
- 2, mem_reg_prop[1],
- 2, mem_reg_prop[2],
- 2, mem_reg_prop[3],
- 2, mem_reg_prop[4],
- 2, mem_reg_prop[5],
- 2, mem_reg_prop[6],
- 2, mem_reg_prop[7]);
- break;
- default:
- g_assert_not_reached();
- }
- g_free(name);
-}
-
static void versal_virt_modify_dtb(const struct arm_boot_info *binfo,
void *fdt)
{
VersalVirt *s = container_of(binfo, VersalVirt, binfo);
- fdt_add_memory_nodes(s, fdt, binfo->ram_size);
+ fdt_nop_memory_nodes(s->fdt, &error_abort);
+ versal_fdt_add_memory_nodes(&s->soc, binfo->ram_size);
}
static void *versal_virt_get_dtb(const struct arm_boot_info *binfo,
@@ -570,41 +133,34 @@
int i;
for (i = 0; i < NUM_VIRTIO_TRANSPORT; i++) {
- char *name = g_strdup_printf("virtio%d", i);
- hwaddr base = MM_TOP_RSVD + i * virtio_mmio_size;
- int irq = VERSAL_RSVD_IRQ_FIRST + i;
+ hwaddr base = versal_get_reserved_mmio_addr(&s->soc)
+ + i * virtio_mmio_size;
+ g_autofree char *node = g_strdup_printf("/virtio_mmio@%" PRIx64, base);
+ int dtb_irq;
MemoryRegion *mr;
DeviceState *dev;
qemu_irq pic_irq;
- pic_irq = qdev_get_gpio_in(DEVICE(&s->soc.fpd.apu.gic), irq);
+ pic_irq = versal_get_reserved_irq(&s->soc, i, &dtb_irq);
dev = qdev_new("virtio-mmio");
- object_property_add_child(OBJECT(&s->soc), name, OBJECT(dev));
+ object_property_add_child(OBJECT(s), "virtio-mmio[*]", OBJECT(dev));
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic_irq);
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
memory_region_add_subregion(&s->soc.mr_ps, base, mr);
- g_free(name);
- }
- for (i = 0; i < NUM_VIRTIO_TRANSPORT; i++) {
- hwaddr base = MM_TOP_RSVD + i * virtio_mmio_size;
- int irq = VERSAL_RSVD_IRQ_FIRST + i;
- char *name = g_strdup_printf("/virtio_mmio@%" PRIx64, base);
-
- qemu_fdt_add_subnode(s->fdt, name);
- qemu_fdt_setprop(s->fdt, name, "dma-coherent", NULL, 0);
- qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, irq,
+ qemu_fdt_add_subnode(s->fdt, node);
+ qemu_fdt_setprop(s->fdt, node, "dma-coherent", NULL, 0);
+ qemu_fdt_setprop_cells(s->fdt, node, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, dtb_irq,
GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
- qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
+ qemu_fdt_setprop_sized_cells(s->fdt, node, "reg",
2, base, 2, virtio_mmio_size);
- qemu_fdt_setprop_string(s->fdt, name, "compatible", "virtio,mmio");
- g_free(name);
+ qemu_fdt_setprop_string(s->fdt, node, "compatible", "virtio,mmio");
}
}
-static void bbram_attach_drive(XlnxBBRam *dev)
+static void bbram_attach_drive(VersalVirt *s)
{
DriveInfo *dinfo;
BlockBackend *blk;
@@ -612,11 +168,11 @@
dinfo = drive_get_by_index(IF_PFLASH, 0);
blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
if (blk) {
- qdev_prop_set_drive(DEVICE(dev), "drive", blk);
+ versal_bbram_attach_drive(&s->soc, blk);
}
}
-static void efuse_attach_drive(XlnxEFuse *dev)
+static void efuse_attach_drive(VersalVirt *s)
{
DriveInfo *dinfo;
BlockBackend *blk;
@@ -624,41 +180,37 @@
dinfo = drive_get_by_index(IF_PFLASH, 1);
blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
if (blk) {
- qdev_prop_set_drive(DEVICE(dev), "drive", blk);
+ versal_efuse_attach_drive(&s->soc, blk);
}
}
-static void sd_plugin_card(SDHCIState *sd, DriveInfo *di)
+static void sd_plug_card(VersalVirt *s, int idx, DriveInfo *di)
{
BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
- DeviceState *card;
- card = qdev_new(TYPE_SD_CARD);
- object_property_add_child(OBJECT(sd), "card[*]", OBJECT(card));
- qdev_prop_set_drive_err(card, "drive", blk, &error_fatal);
- qdev_realize_and_unref(card, qdev_get_child_bus(DEVICE(sd), "sd-bus"),
- &error_fatal);
+ versal_sdhci_plug_card(&s->soc, idx, blk);
}
static char *versal_get_ospi_model(Object *obj, Error **errp)
{
- VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj);
+ VersalVirt *s = XLNX_VERSAL_VIRT_BASE_MACHINE(obj);
- return g_strdup(s->ospi_model);
+ return g_strdup(s->cfg.ospi_model);
}
static void versal_set_ospi_model(Object *obj, const char *value, Error **errp)
{
- VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj);
+ VersalVirt *s = XLNX_VERSAL_VIRT_BASE_MACHINE(obj);
- g_free(s->ospi_model);
- s->ospi_model = g_strdup(value);
+ g_free(s->cfg.ospi_model);
+ s->cfg.ospi_model = g_strdup(value);
}
static void versal_virt_init(MachineState *machine)
{
- VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(machine);
+ VersalVirt *s = XLNX_VERSAL_VIRT_BASE_MACHINE(machine);
+ VersalVirtClass *vvc = XLNX_VERSAL_VIRT_BASE_MACHINE_GET_CLASS(machine);
int psci_conduit = QEMU_PSCI_CONDUIT_DISABLED;
int i;
@@ -690,48 +242,38 @@
}
object_initialize_child(OBJECT(machine), "xlnx-versal", &s->soc,
- TYPE_XLNX_VERSAL);
+ versal_get_class(vvc->version));
object_property_set_link(OBJECT(&s->soc), "ddr", OBJECT(machine->ram),
&error_abort);
- object_property_set_link(OBJECT(&s->soc), "canbus0", OBJECT(s->canbus[0]),
- &error_abort);
- object_property_set_link(OBJECT(&s->soc), "canbus1", OBJECT(s->canbus[1]),
- &error_abort);
- sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal);
+
+ for (i = 0; i < versal_get_num_can(vvc->version); i++) {
+ g_autofree char *prop_name = g_strdup_printf("canbus%d", i);
+
+ object_property_set_link(OBJECT(&s->soc), prop_name,
+ OBJECT(s->canbus[i]),
+ &error_abort);
+ }
fdt_create(s);
+ versal_set_fdt(&s->soc, s->fdt);
+ sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal);
create_virtio_regions(s);
- fdt_add_gem_nodes(s);
- fdt_add_uart_nodes(s);
- fdt_add_canfd_nodes(s);
- fdt_add_gic_nodes(s);
- fdt_add_timer_nodes(s);
- fdt_add_zdma_nodes(s);
- fdt_add_usb_xhci_nodes(s);
- fdt_add_sd_nodes(s);
- fdt_add_rtc_node(s);
- fdt_add_bbram_node(s);
- fdt_add_efuse_ctrl_node(s);
- fdt_add_efuse_cache_node(s);
- fdt_add_cpu_nodes(s, psci_conduit);
- fdt_add_clk_node(s, "/clk125", 125000000, s->phandle.clk_125Mhz);
- fdt_add_clk_node(s, "/clk25", 25000000, s->phandle.clk_25Mhz);
- /* Make the APU cpu address space visible to virtio and other
- * modules unaware of multiple address-spaces. */
- memory_region_add_subregion_overlap(get_system_memory(),
- 0, &s->soc.fpd.apu.mr, 0);
+ /*
+ * Map the SoC address space onto system memory. This will allow virtio and
+ * other modules unaware of multiple address-spaces to work.
+ */
+ memory_region_add_subregion(get_system_memory(), 0, &s->soc.mr_ps);
/* Attach bbram backend, if given */
- bbram_attach_drive(&s->soc.pmc.bbram);
+ bbram_attach_drive(s);
/* Attach efuse backend, if given */
- efuse_attach_drive(&s->soc.pmc.efuse);
+ efuse_attach_drive(s);
- /* Plugin SD cards. */
- for (i = 0; i < ARRAY_SIZE(s->soc.pmc.iou.sd); i++) {
- sd_plugin_card(&s->soc.pmc.iou.sd[i],
- drive_get(IF_SD, 0, i));
+ /* Plug SD cards */
+ for (i = 0; i < versal_get_num_sdhci(vvc->version); i++) {
+ sd_plug_card(s, i, drive_get(IF_SD, 0, i));
}
s->binfo.ram_size = machine->ram_size;
@@ -745,100 +287,133 @@
s->binfo.loader_start = 0x1000;
s->binfo.dtb_limit = 0x1000000;
}
- arm_load_kernel(&s->soc.fpd.apu.cpu[0], machine, &s->binfo);
+ arm_load_kernel(ARM_CPU(versal_get_boot_cpu(&s->soc)), machine, &s->binfo);
for (i = 0; i < XLNX_VERSAL_NUM_OSPI_FLASH; i++) {
- BusState *spi_bus;
- DeviceState *flash_dev;
ObjectClass *flash_klass;
- qemu_irq cs_line;
DriveInfo *dinfo = drive_get(IF_MTD, 0, i);
+ BlockBackend *blk;
+ const char *mdl;
- spi_bus = qdev_get_child_bus(DEVICE(&s->soc.pmc.iou.ospi), "spi0");
-
- if (s->ospi_model) {
- flash_klass = object_class_by_name(s->ospi_model);
+ if (s->cfg.ospi_model) {
+ flash_klass = object_class_by_name(s->cfg.ospi_model);
if (!flash_klass ||
object_class_is_abstract(flash_klass) ||
!object_class_dynamic_cast(flash_klass, TYPE_M25P80)) {
error_report("'%s' is either abstract or"
- " not a subtype of m25p80", s->ospi_model);
+ " not a subtype of m25p80", s->cfg.ospi_model);
exit(1);
}
+ mdl = s->cfg.ospi_model;
+ } else {
+ mdl = "mt35xu01g";
}
- flash_dev = qdev_new(s->ospi_model ? s->ospi_model : "mt35xu01g");
-
- if (dinfo) {
- qdev_prop_set_drive_err(flash_dev, "drive",
- blk_by_legacy_dinfo(dinfo), &error_fatal);
- }
- qdev_prop_set_uint8(flash_dev, "cs", i);
- qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal);
-
- cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
-
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.pmc.iou.ospi),
- i + 1, cs_line);
+ blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
+ versal_ospi_create_flash(&s->soc, i, mdl, blk);
}
}
static void versal_virt_machine_instance_init(Object *obj)
{
- VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj);
+ VersalVirt *s = XLNX_VERSAL_VIRT_BASE_MACHINE(obj);
+ VersalVirtClass *vvc = XLNX_VERSAL_VIRT_BASE_MACHINE_GET_CLASS(s);
+ size_t i, num_can;
+
+ num_can = versal_get_num_can(vvc->version);
+ s->canbus = g_new0(CanBusState *, num_can);
/*
- * User can set canbus0 and canbus1 properties to can-bus object and connect
- * to socketcan(optional) interface via command line.
+ * User can set canbusx properties to can-bus object and optionally connect
+ * to socketcan interface via command line.
*/
- object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
- (Object **)&s->canbus[0],
- object_property_allow_set_link,
- 0);
- object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
- (Object **)&s->canbus[1],
- object_property_allow_set_link,
- 0);
+ for (i = 0; i < num_can; i++) {
+ g_autofree char *prop_name = g_strdup_printf("canbus%zu", i);
+
+ object_property_add_link(obj, prop_name, TYPE_CAN_BUS,
+ (Object **) &s->canbus[i],
+ object_property_allow_set_link, 0);
+ }
}
static void versal_virt_machine_finalize(Object *obj)
{
- VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj);
+ VersalVirt *s = XLNX_VERSAL_VIRT_BASE_MACHINE(obj);
- g_free(s->ospi_model);
+ g_free(s->cfg.ospi_model);
+ g_free(s->canbus);
}
-static void versal_virt_machine_class_init(ObjectClass *oc, const void *data)
+static void versal_virt_machine_class_init_common(ObjectClass *oc)
{
MachineClass *mc = MACHINE_CLASS(oc);
+ VersalVirtClass *vvc = XLNX_VERSAL_VIRT_BASE_MACHINE_CLASS(mc);
+ int num_cpu = versal_get_num_cpu(vvc->version);
- mc->desc = "Xilinx Versal Virtual development board";
- mc->init = versal_virt_init;
- mc->min_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS;
- mc->max_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS;
- mc->default_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS;
mc->no_cdrom = true;
mc->auto_create_sdcard = true;
mc->default_ram_id = "ddr";
+ mc->min_cpus = num_cpu;
+ mc->max_cpus = num_cpu;
+ mc->default_cpus = num_cpu;
+ mc->init = versal_virt_init;
+
object_class_property_add_str(oc, "ospi-flash", versal_get_ospi_model,
versal_set_ospi_model);
object_class_property_set_description(oc, "ospi-flash",
"Change the OSPI Flash model");
}
-static const TypeInfo versal_virt_machine_init_typeinfo = {
- .name = TYPE_XLNX_VERSAL_VIRT_MACHINE,
+static void versal_virt_machine_class_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ VersalVirtClass *vvc = XLNX_VERSAL_VIRT_BASE_MACHINE_CLASS(oc);
+
+ mc->desc = "AMD Versal Virtual development board";
+ mc->alias = "xlnx-versal-virt";
+ vvc->version = VERSAL_VER_VERSAL;
+
+ versal_virt_machine_class_init_common(oc);
+}
+
+static void versal2_virt_machine_class_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ VersalVirtClass *vvc = XLNX_VERSAL_VIRT_BASE_MACHINE_CLASS(oc);
+
+ mc->desc = "AMD Versal Gen 2 Virtual development board";
+ vvc->version = VERSAL_VER_VERSAL2;
+
+ versal_virt_machine_class_init_common(oc);
+}
+
+static const TypeInfo versal_virt_base_machine_init_typeinfo = {
+ .name = TYPE_XLNX_VERSAL_VIRT_BASE_MACHINE,
.parent = TYPE_MACHINE,
- .class_init = versal_virt_machine_class_init,
+ .class_size = sizeof(VersalVirtClass),
.instance_init = versal_virt_machine_instance_init,
.instance_size = sizeof(VersalVirt),
.instance_finalize = versal_virt_machine_finalize,
+ .abstract = true,
+};
+
+static const TypeInfo versal_virt_machine_init_typeinfo = {
+ .name = TYPE_XLNX_VERSAL_VIRT_MACHINE,
+ .parent = TYPE_XLNX_VERSAL_VIRT_BASE_MACHINE,
+ .class_init = versal_virt_machine_class_init,
+};
+
+static const TypeInfo versal2_virt_machine_init_typeinfo = {
+ .name = TYPE_XLNX_VERSAL2_VIRT_MACHINE,
+ .parent = TYPE_XLNX_VERSAL_VIRT_BASE_MACHINE,
+ .class_init = versal2_virt_machine_class_init,
};
static void versal_virt_machine_init_register_types(void)
{
+ type_register_static(&versal_virt_base_machine_init_typeinfo);
type_register_static(&versal_virt_machine_init_typeinfo);
+ type_register_static(&versal2_virt_machine_init_typeinfo);
}
type_init(versal_virt_machine_init_register_types)
-
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
index a42b9e7..81cb629 100644
--- a/hw/arm/xlnx-versal.c
+++ b/hw/arm/xlnx-versal.c
@@ -1,7 +1,8 @@
/*
- * Xilinx Versal SoC model.
+ * AMD/Xilinx Versal family SoC model.
*
* Copyright (c) 2018 Xilinx Inc.
+ * Copyright (c) 2025 Advanced Micro Devices, Inc.
* Written by Edgar E. Iglesias
*
* This program is free software; you can redistribute it and/or modify
@@ -17,827 +18,1745 @@
#include "hw/sysbus.h"
#include "net/net.h"
#include "system/system.h"
-#include "hw/arm/boot.h"
#include "hw/misc/unimp.h"
#include "hw/arm/xlnx-versal.h"
#include "qemu/log.h"
#include "target/arm/cpu-qom.h"
#include "target/arm/gtimer.h"
+#include "system/device_tree.h"
+#include "hw/arm/fdt.h"
+#include "hw/char/pl011.h"
+#include "hw/net/xlnx-versal-canfd.h"
+#include "hw/sd/sdhci.h"
+#include "hw/net/cadence_gem.h"
+#include "hw/dma/xlnx-zdma.h"
+#include "hw/misc/xlnx-versal-xramc.h"
+#include "hw/usb/xlnx-usb-subsystem.h"
+#include "hw/nvram/xlnx-versal-efuse.h"
+#include "hw/ssi/xlnx-versal-ospi.h"
+#include "hw/misc/xlnx-versal-pmc-iou-slcr.h"
+#include "hw/nvram/xlnx-bbram.h"
+#include "hw/misc/xlnx-versal-trng.h"
+#include "hw/rtc/xlnx-zynqmp-rtc.h"
+#include "hw/misc/xlnx-versal-cfu.h"
+#include "hw/misc/xlnx-versal-cframe-reg.h"
+#include "hw/or-irq.h"
+#include "hw/misc/xlnx-versal-crl.h"
+#include "hw/intc/arm_gicv3_common.h"
+#include "hw/intc/arm_gicv3_its_common.h"
+#include "hw/intc/arm_gic.h"
+#include "hw/core/split-irq.h"
+#include "target/arm/cpu.h"
+#include "hw/cpu/cluster.h"
+#include "hw/arm/bsa.h"
-#define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72")
-#define XLNX_VERSAL_RCPU_TYPE ARM_CPU_TYPE_NAME("cortex-r5f")
-#define GEM_REVISION 0x40070106
+/*
+ * IRQ descriptor to catch the following cases:
+ * - An IRQ can either connect to the GICs, to the PPU1 intc, or the the EAM
+ * - Multiple devices can connect to the same IRQ. They are OR'ed together.
+ */
+FIELD(VERSAL_IRQ, IRQ, 0, 16)
+FIELD(VERSAL_IRQ, TARGET, 16, 2)
+FIELD(VERSAL_IRQ, ORED, 18, 1)
+FIELD(VERSAL_IRQ, OR_IDX, 19, 4) /* input index on the IRQ OR gate */
-#define VERSAL_NUM_PMC_APB_IRQS 18
-#define NUM_OSPI_IRQ_LINES 3
+typedef enum VersalIrqTarget {
+ IRQ_TARGET_GIC,
+ IRQ_TARGET_PPU1,
+ IRQ_TARGET_EAM,
+} VersalIrqTarget;
-static void versal_create_apu_cpus(Versal *s)
+#define PPU1_IRQ(irq) ((IRQ_TARGET_PPU1 << R_VERSAL_IRQ_TARGET_SHIFT) | (irq))
+#define EAM_IRQ(irq) ((IRQ_TARGET_EAM << R_VERSAL_IRQ_TARGET_SHIFT) | (irq))
+#define OR_IRQ(irq, or_idx) \
+ (R_VERSAL_IRQ_ORED_MASK | ((or_idx) << R_VERSAL_IRQ_OR_IDX_SHIFT) | (irq))
+#define PPU1_OR_IRQ(irq, or_idx) \
+ ((IRQ_TARGET_PPU1 << R_VERSAL_IRQ_TARGET_SHIFT) | OR_IRQ(irq, or_idx))
+
+typedef struct VersalSimplePeriphMap {
+ uint64_t addr;
+ int irq;
+} VersalSimplePeriphMap;
+
+typedef struct VersalMemMap {
+ uint64_t addr;
+ uint64_t size;
+} VersalMemMap;
+
+typedef struct VersalGicMap {
+ int version;
+ uint64_t dist;
+ uint64_t redist;
+ uint64_t cpu_iface;
+ uint64_t its;
+ size_t num_irq;
+ bool has_its;
+} VersalGicMap;
+
+enum StartPoweredOffMode {
+ SPO_SECONDARIES,
+ SPO_ALL,
+};
+
+typedef struct VersalCpuClusterMap {
+ VersalGicMap gic;
+ /*
+ * true: one GIC per cluster.
+ * false: one GIC for all CPUs
+ */
+ bool per_cluster_gic;
+
+ const char *name;
+ const char *cpu_model;
+ size_t num_core;
+ size_t num_cluster;
+ uint32_t qemu_cluster_id;
+ bool dtb_expose;
+
+ struct {
+ uint64_t base;
+ uint64_t core_shift;
+ uint64_t cluster_shift;
+ } mp_affinity;
+
+ enum StartPoweredOffMode start_powered_off;
+} VersalCpuClusterMap;
+
+typedef struct VersalMap {
+ VersalMemMap ocm;
+
+ struct VersalDDRMap {
+ VersalMemMap chan[4];
+ size_t num_chan;
+ } ddr;
+
+ VersalCpuClusterMap apu;
+ VersalCpuClusterMap rpu;
+
+ VersalSimplePeriphMap uart[2];
+ size_t num_uart;
+
+ VersalSimplePeriphMap canfd[4];
+ size_t num_canfd;
+
+ VersalSimplePeriphMap sdhci[2];
+ size_t num_sdhci;
+
+ struct VersalGemMap {
+ VersalSimplePeriphMap map;
+ size_t num_prio_queue;
+ const char *phy_mode;
+ const uint32_t speed;
+ } gem[3];
+ size_t num_gem;
+
+ struct VersalZDMAMap {
+ const char *name;
+ VersalSimplePeriphMap map;
+ size_t num_chan;
+ uint64_t chan_stride;
+ int irq_stride;
+ } zdma[2];
+ size_t num_zdma;
+
+ struct VersalXramMap {
+ uint64_t mem;
+ uint64_t mem_stride;
+ uint64_t ctrl;
+ uint64_t ctrl_stride;
+ int irq;
+ size_t num;
+ } xram;
+
+ struct VersalUsbMap {
+ uint64_t xhci;
+ uint64_t ctrl;
+ int irq;
+ } usb[2];
+ size_t num_usb;
+
+ struct VersalEfuseMap {
+ uint64_t ctrl;
+ uint64_t cache;
+ int irq;
+ } efuse;
+
+ struct VersalOspiMap {
+ uint64_t ctrl;
+ uint64_t dac;
+ uint64_t dac_sz;
+ uint64_t dma_src;
+ uint64_t dma_dst;
+ int irq;
+ } ospi;
+
+ VersalSimplePeriphMap pmc_iou_slcr;
+ VersalSimplePeriphMap bbram;
+ VersalSimplePeriphMap trng;
+
+ struct VersalRtcMap {
+ VersalSimplePeriphMap map;
+ int alarm_irq;
+ int second_irq;
+ } rtc;
+
+ struct VersalCfuMap {
+ uint64_t cframe_base;
+ uint64_t cframe_stride;
+ uint64_t cfu_fdro;
+ uint64_t cframe_bcast_reg;
+ uint64_t cframe_bcast_fdri;
+ uint64_t cfu_apb;
+ uint64_t cfu_stream;
+ uint64_t cfu_stream_2;
+ uint64_t cfu_sfr;
+ int cfu_apb_irq;
+ int cframe_irq;
+ size_t num_cframe;
+ struct VersalCfuCframeCfg {
+ uint32_t blktype_frames[7];
+ } cframe_cfg[15];
+ } cfu;
+
+ VersalSimplePeriphMap crl;
+
+ /* reserved MMIO/IRQ space that can safely be used for virtio devices */
+ struct VersalReserved {
+ uint64_t mmio_start;
+ int irq_start;
+ int irq_num;
+ } reserved;
+} VersalMap;
+
+static const VersalMap VERSAL_MAP = {
+ .ocm = {
+ .addr = 0xfffc0000,
+ .size = 0x40000,
+ },
+
+ .ddr = {
+ .chan[0] = { .addr = 0x0, .size = 2 * GiB },
+ .chan[1] = { .addr = 0x800000000ull, .size = 32 * GiB },
+ .chan[2] = { .addr = 0xc00000000ull, .size = 256 * GiB },
+ .chan[3] = { .addr = 0x10000000000ull, .size = 734 * GiB },
+ .num_chan = 4,
+ },
+
+ .apu = {
+ .name = "apu",
+ .cpu_model = ARM_CPU_TYPE_NAME("cortex-a72"),
+ .num_cluster = 1,
+ .num_core = 2,
+ .qemu_cluster_id = 0,
+ .mp_affinity = {
+ .core_shift = ARM_AFF0_SHIFT,
+ .cluster_shift = ARM_AFF1_SHIFT,
+ },
+ .start_powered_off = SPO_SECONDARIES,
+ .dtb_expose = true,
+ .gic = {
+ .version = 3,
+ .dist = 0xf9000000,
+ .redist = 0xf9080000,
+ .num_irq = 192,
+ .has_its = true,
+ .its = 0xf9020000,
+ },
+ },
+
+ .rpu = {
+ .name = "rpu",
+ .cpu_model = ARM_CPU_TYPE_NAME("cortex-r5f"),
+ .num_cluster = 1,
+ .num_core = 2,
+ .qemu_cluster_id = 1,
+ .mp_affinity = {
+ .base = 0x100,
+ .core_shift = ARM_AFF0_SHIFT,
+ .cluster_shift = ARM_AFF1_SHIFT,
+ },
+ .start_powered_off = SPO_ALL,
+ .dtb_expose = false,
+ .gic = {
+ .version = 2,
+ .dist = 0xf9000000,
+ .cpu_iface = 0xf9001000,
+ .num_irq = 192,
+ },
+ },
+
+ .uart[0] = { 0xff000000, 18 },
+ .uart[1] = { 0xff010000, 19 },
+ .num_uart = 2,
+
+ .canfd[0] = { 0xff060000, 20 },
+ .canfd[1] = { 0xff070000, 21 },
+ .num_canfd = 2,
+
+ .sdhci[0] = { 0xf1040000, 126 },
+ .sdhci[1] = { 0xf1050000, 128 },
+ .num_sdhci = 2,
+
+ .gem[0] = { { 0xff0c0000, 56 }, 2, "rgmii-id", 1000 },
+ .gem[1] = { { 0xff0d0000, 58 }, 2, "rgmii-id", 1000 },
+ .num_gem = 2,
+
+ .zdma[0] = { "adma", { 0xffa80000, 60 }, 8, 0x10000, 1 },
+ .num_zdma = 1,
+
+ .xram = {
+ .num = 4,
+ .mem = 0xfe800000, .mem_stride = 1 * MiB,
+ .ctrl = 0xff8e0000, .ctrl_stride = 0x10000,
+ .irq = 79,
+ },
+
+ .usb[0] = { .xhci = 0xfe200000, .ctrl = 0xff9d0000, .irq = 22 },
+ .num_usb = 1,
+
+ .efuse = { .ctrl = 0xf1240000, .cache = 0xf1250000, .irq = 139 },
+
+ .ospi = {
+ .ctrl = 0xf1010000,
+ .dac = 0xc0000000, .dac_sz = 0x20000000,
+ .dma_src = 0xf1011000, .dma_dst = 0xf1011800,
+ .irq = 124,
+ },
+
+ .pmc_iou_slcr = { 0xf1060000, OR_IRQ(121, 0) },
+ .bbram = { 0xf11f0000, OR_IRQ(121, 1) },
+ .trng = { 0xf1230000, 141 },
+ .rtc = {
+ { 0xf12a0000, OR_IRQ(121, 2) },
+ .alarm_irq = 142, .second_irq = 143
+ },
+
+ .cfu = {
+ .cframe_base = 0xf12d0000, .cframe_stride = 0x1000,
+ .cframe_bcast_reg = 0xf12ee000, .cframe_bcast_fdri = 0xf12ef000,
+ .cfu_apb = 0xf12b0000, .cfu_sfr = 0xf12c1000,
+ .cfu_stream = 0xf12c0000, .cfu_stream_2 = 0xf1f80000,
+ .cfu_fdro = 0xf12c2000,
+ .cfu_apb_irq = 120, .cframe_irq = OR_IRQ(121, 3),
+ .num_cframe = 15,
+ .cframe_cfg = {
+ { { 34111, 3528, 12800, 11, 5, 1, 1 } },
+ { { 38498, 3841, 15361, 13, 7, 3, 1 } },
+ { { 38498, 3841, 15361, 13, 7, 3, 1 } },
+ { { 38498, 3841, 15361, 13, 7, 3, 1 } },
+ },
+ },
+
+ .crl = { 0xff5e0000, 10 },
+
+ .reserved = { 0xa0000000, 111, 8 },
+};
+
+static const VersalMap VERSAL2_MAP = {
+ .ocm = {
+ .addr = 0xbbe00000,
+ .size = 2 * MiB,
+ },
+
+ .ddr = {
+ .chan[0] = { .addr = 0x0, .size = 2046 * MiB },
+ .chan[1] = { .addr = 0x800000000ull, .size = 32 * GiB },
+ .chan[2] = { .addr = 0xc00000000ull, .size = 256 * GiB },
+ .chan[3] = { .addr = 0x10000000000ull, .size = 734 * GiB },
+ .num_chan = 4,
+ },
+
+ .apu = {
+ .name = "apu",
+ .cpu_model = ARM_CPU_TYPE_NAME("cortex-a78ae"),
+ .num_cluster = 4,
+ .num_core = 2,
+ .qemu_cluster_id = 0,
+ .mp_affinity = {
+ .base = 0x0, /* TODO: the MT bit should be set */
+ .core_shift = ARM_AFF1_SHIFT,
+ .cluster_shift = ARM_AFF2_SHIFT,
+ },
+ .start_powered_off = SPO_SECONDARIES,
+ .dtb_expose = true,
+ .gic = {
+ .version = 3,
+ .dist = 0xe2000000,
+ .redist = 0xe2060000,
+ .num_irq = 544,
+ .has_its = true,
+ .its = 0xe2040000,
+ },
+ },
+
+ .rpu = {
+ .name = "rpu",
+ .cpu_model = ARM_CPU_TYPE_NAME("cortex-r52"),
+ .num_cluster = 5,
+ .num_core = 2,
+ .qemu_cluster_id = 1,
+ .mp_affinity = {
+ .core_shift = ARM_AFF0_SHIFT,
+ .cluster_shift = ARM_AFF1_SHIFT,
+ },
+ .start_powered_off = SPO_ALL,
+ .dtb_expose = false,
+ .per_cluster_gic = true,
+ .gic = {
+ .version = 3,
+ .dist = 0x0,
+ .redist = 0x100000,
+ .num_irq = 288,
+ },
+ },
+
+ .uart[0] = { 0xf1920000, 25 },
+ .uart[1] = { 0xf1930000, 26 },
+ .num_uart = 2,
+
+ .canfd[0] = { 0xf19e0000, 27 },
+ .canfd[1] = { 0xf19f0000, 28 },
+ .canfd[2] = { 0xf1a00000, 95 },
+ .canfd[3] = { 0xf1a10000, 96 },
+ .num_canfd = 4,
+
+ .gem[0] = { { 0xf1a60000, 39 }, 2, "rgmii-id", 1000 },
+ .gem[1] = { { 0xf1a70000, 41 }, 2, "rgmii-id", 1000 },
+ .gem[2] = { { 0xed920000, 164 }, 4, "usxgmii", 10000 }, /* MMI 10Gb GEM */
+ .num_gem = 3,
+
+ .zdma[0] = { "adma", { 0xebd00000, 72 }, 8, 0x10000, 1 },
+ .zdma[1] = { "sdma", { 0xebd80000, 112 }, 8, 0x10000, 1 },
+ .num_zdma = 2,
+
+ .usb[0] = { .xhci = 0xf1b00000, .ctrl = 0xf1ee0000, .irq = 29 },
+ .usb[1] = { .xhci = 0xf1c00000, .ctrl = 0xf1ef0000, .irq = 34 },
+ .num_usb = 2,
+
+ .efuse = { .ctrl = 0xf1240000, .cache = 0xf1250000, .irq = 230 },
+
+ .ospi = {
+ .ctrl = 0xf1010000,
+ .dac = 0xc0000000, .dac_sz = 0x20000000,
+ .dma_src = 0xf1011000, .dma_dst = 0xf1011800,
+ .irq = 216,
+ },
+
+ .sdhci[0] = { 0xf1040000, 218 },
+ .sdhci[1] = { 0xf1050000, 220 }, /* eMMC */
+ .num_sdhci = 2,
+
+ .pmc_iou_slcr = { 0xf1060000, 222 },
+ .bbram = { 0xf11f0000, PPU1_OR_IRQ(18, 0) },
+ .crl = { 0xeb5e0000 },
+ .trng = { 0xf1230000, 233 },
+ .rtc = {
+ { 0xf12a0000, PPU1_OR_IRQ(18, 1) },
+ .alarm_irq = 200, .second_irq = 201
+ },
+
+ .cfu = {
+ .cframe_base = 0xf12d0000, .cframe_stride = 0x1000,
+ .cframe_bcast_reg = 0xf12ee000, .cframe_bcast_fdri = 0xf12ef000,
+ .cfu_apb = 0xf12b0000, .cfu_sfr = 0xf12c1000,
+ .cfu_stream = 0xf12c0000, .cfu_stream_2 = 0xf1f80000,
+ .cfu_fdro = 0xf12c2000,
+ .cfu_apb_irq = 235, .cframe_irq = EAM_IRQ(7),
+ },
+
+ .reserved = { 0xf5e00000, 270, 8 },
+};
+
+static const VersalMap *VERSION_TO_MAP[] = {
+ [VERSAL_VER_VERSAL] = &VERSAL_MAP,
+ [VERSAL_VER_VERSAL2] = &VERSAL2_MAP,
+};
+
+static inline VersalVersion versal_get_version(Versal *s)
{
- int i;
-
- object_initialize_child(OBJECT(s), "apu-cluster", &s->fpd.apu.cluster,
- TYPE_CPU_CLUSTER);
- qdev_prop_set_uint32(DEVICE(&s->fpd.apu.cluster), "cluster-id", 0);
-
- for (i = 0; i < ARRAY_SIZE(s->fpd.apu.cpu); i++) {
- Object *obj;
-
- object_initialize_child(OBJECT(&s->fpd.apu.cluster),
- "apu-cpu[*]", &s->fpd.apu.cpu[i],
- XLNX_VERSAL_ACPU_TYPE);
- obj = OBJECT(&s->fpd.apu.cpu[i]);
- if (i) {
- /* Secondary CPUs start in powered-down state */
- object_property_set_bool(obj, "start-powered-off", true,
- &error_abort);
- }
-
- object_property_set_int(obj, "core-count", ARRAY_SIZE(s->fpd.apu.cpu),
- &error_abort);
- object_property_set_link(obj, "memory", OBJECT(&s->fpd.apu.mr),
- &error_abort);
- qdev_realize(DEVICE(obj), NULL, &error_fatal);
- }
-
- qdev_realize(DEVICE(&s->fpd.apu.cluster), NULL, &error_fatal);
+ return XLNX_VERSAL_BASE_GET_CLASS(s)->version;
}
-static void versal_create_apu_gic(Versal *s, qemu_irq *pic)
+static inline const VersalMap *versal_get_map(Versal *s)
{
- static const uint64_t addrs[] = {
- MM_GIC_APU_DIST_MAIN,
- MM_GIC_APU_REDIST_0
- };
- SysBusDevice *gicbusdev;
- DeviceState *gicdev;
- QList *redist_region_count;
- int nr_apu_cpus = ARRAY_SIZE(s->fpd.apu.cpu);
- int i;
+ return VERSION_TO_MAP[versal_get_version(s)];
+}
- object_initialize_child(OBJECT(s), "apu-gic", &s->fpd.apu.gic,
- gicv3_class_name());
- gicbusdev = SYS_BUS_DEVICE(&s->fpd.apu.gic);
- gicdev = DEVICE(&s->fpd.apu.gic);
- qdev_prop_set_uint32(gicdev, "revision", 3);
- qdev_prop_set_uint32(gicdev, "num-cpu", nr_apu_cpus);
- qdev_prop_set_uint32(gicdev, "num-irq", XLNX_VERSAL_NR_IRQS + 32);
+static inline Object *versal_get_child(Versal *s, const char *child)
+{
+ return object_resolve_path_at(OBJECT(s), child);
+}
- redist_region_count = qlist_new();
- qlist_append_int(redist_region_count, nr_apu_cpus);
- qdev_prop_set_array(gicdev, "redist-region-count", redist_region_count);
+static inline Object *versal_get_child_idx(Versal *s, const char *child,
+ size_t idx)
+{
+ g_autofree char *n = g_strdup_printf("%s[%zu]", child, idx);
- qdev_prop_set_bit(gicdev, "has-security-extensions", true);
+ return versal_get_child(s, n);
+}
- sysbus_realize(SYS_BUS_DEVICE(&s->fpd.apu.gic), &error_fatal);
+/*
+ * The SoC embeds multiple GICs. They all receives the same IRQ lines at the
+ * same index. This function creates a TYPE_SPLIT_IRQ device to fan out the
+ * given IRQ input to all the GICs.
+ *
+ * The TYPE_SPLIT_IRQ devices lie in the /soc/irq-splits QOM container
+ */
+static qemu_irq versal_get_gic_irq(Versal *s, int irq_idx)
+{
+ DeviceState *split;
+ Object *container = versal_get_child(s, "irq-splits");
+ int idx = FIELD_EX32(irq_idx, VERSAL_IRQ, IRQ);
+ g_autofree char *name = g_strdup_printf("irq[%d]", idx);
- for (i = 0; i < ARRAY_SIZE(addrs); i++) {
- MemoryRegion *mr;
+ split = DEVICE(object_resolve_path_at(container, name));
- mr = sysbus_mmio_get_region(gicbusdev, i);
- memory_region_add_subregion(&s->fpd.apu.mr, addrs[i], mr);
+ if (split == NULL) {
+ size_t i;
+
+ split = qdev_new(TYPE_SPLIT_IRQ);
+ qdev_prop_set_uint16(split, "num-lines", s->intc->len);
+ object_property_add_child(container, name, OBJECT(split));
+ qdev_realize_and_unref(split, NULL, &error_abort);
+
+ for (i = 0; i < s->intc->len; i++) {
+ DeviceState *gic;
+
+ gic = g_array_index(s->intc, DeviceState *, i);
+ qdev_connect_gpio_out(split, i, qdev_get_gpio_in(gic, idx));
+ }
+ } else {
+ g_assert(FIELD_EX32(irq_idx, VERSAL_IRQ, ORED));
}
- for (i = 0; i < nr_apu_cpus; i++) {
- DeviceState *cpudev = DEVICE(&s->fpd.apu.cpu[i]);
- int ppibase = XLNX_VERSAL_NR_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
- qemu_irq maint_irq;
- int ti;
- /* Mapping from the output timer irq lines from the CPU to the
- * GIC PPI inputs.
- */
- const int timer_irq[] = {
- [GTIMER_PHYS] = VERSAL_TIMER_NS_EL1_IRQ,
- [GTIMER_VIRT] = VERSAL_TIMER_VIRT_IRQ,
- [GTIMER_HYP] = VERSAL_TIMER_NS_EL2_IRQ,
- [GTIMER_SEC] = VERSAL_TIMER_S_EL1_IRQ,
- };
+ return qdev_get_gpio_in(split, 0);
+}
+/*
+ * When the R_VERSAL_IRQ_ORED flag is set on an IRQ descriptor, this function is
+ * used to return the corresponding or gate input IRQ. The or gate is created if
+ * not already existant.
+ *
+ * Or gates are placed under the /soc/irq-or-gates QOM container.
+ */
+static qemu_irq versal_get_irq_or_gate_in(Versal *s, int irq_idx,
+ qemu_irq target_irq)
+{
+ static const char *TARGET_STR[] = {
+ [IRQ_TARGET_GIC] = "gic",
+ [IRQ_TARGET_PPU1] = "ppu1",
+ [IRQ_TARGET_EAM] = "eam",
+ };
+
+ VersalIrqTarget target;
+ Object *container = versal_get_child(s, "irq-or-gates");
+ DeviceState *dev;
+ g_autofree char *name;
+ int idx, or_idx;
+
+ idx = FIELD_EX32(irq_idx, VERSAL_IRQ, IRQ);
+ or_idx = FIELD_EX32(irq_idx, VERSAL_IRQ, OR_IDX);
+ target = FIELD_EX32(irq_idx, VERSAL_IRQ, TARGET);
+
+ name = g_strdup_printf("%s-irq[%d]", TARGET_STR[target], idx);
+ dev = DEVICE(object_resolve_path_at(container, name));
+
+ if (dev == NULL) {
+ dev = qdev_new(TYPE_OR_IRQ);
+ object_property_add_child(container, name, OBJECT(dev));
+ qdev_prop_set_uint16(dev, "num-lines", 1 << R_VERSAL_IRQ_OR_IDX_LENGTH);
+ qdev_realize_and_unref(dev, NULL, &error_abort);
+ qdev_connect_gpio_out(dev, 0, target_irq);
+ }
+
+ return qdev_get_gpio_in(dev, or_idx);
+}
+
+static qemu_irq versal_get_irq(Versal *s, int irq_idx)
+{
+ VersalIrqTarget target;
+ qemu_irq irq;
+ bool ored;
+
+ target = FIELD_EX32(irq_idx, VERSAL_IRQ, TARGET);
+ ored = FIELD_EX32(irq_idx, VERSAL_IRQ, ORED);
+
+ switch (target) {
+ case IRQ_TARGET_EAM:
+ /* EAM not implemented */
+ return NULL;
+
+ case IRQ_TARGET_PPU1:
+ /* PPU1 CPU not implemented */
+ return NULL;
+
+ case IRQ_TARGET_GIC:
+ irq = versal_get_gic_irq(s, irq_idx);
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ if (ored) {
+ irq = versal_get_irq_or_gate_in(s, irq_idx, irq);
+ }
+
+ return irq;
+}
+
+static void versal_sysbus_connect_irq(Versal *s, SysBusDevice *sbd,
+ int sbd_idx, int irq_idx)
+{
+ qemu_irq irq = versal_get_irq(s, irq_idx);
+
+ if (irq == NULL) {
+ return;
+ }
+
+ sysbus_connect_irq(sbd, sbd_idx, irq);
+}
+
+static void versal_qdev_connect_gpio_out(Versal *s, DeviceState *dev,
+ int dev_idx, int irq_idx)
+{
+ qemu_irq irq = versal_get_irq(s, irq_idx);
+
+ if (irq == NULL) {
+ return;
+ }
+
+ qdev_connect_gpio_out(dev, dev_idx, irq);
+}
+
+static inline char *versal_fdt_add_subnode(Versal *s, const char *path,
+ uint64_t at, const char *compat,
+ size_t compat_sz)
+{
+ char *p;
+
+ p = g_strdup_printf("%s@%" PRIx64, path, at);
+ qemu_fdt_add_subnode(s->cfg.fdt, p);
+
+ if (!strncmp(compat, "memory", compat_sz)) {
+ qemu_fdt_setprop(s->cfg.fdt, p, "device_type", compat, compat_sz);
+ } else {
+ qemu_fdt_setprop(s->cfg.fdt, p, "compatible", compat, compat_sz);
+ }
+
+ return p;
+}
+
+static inline char *versal_fdt_add_simple_subnode(Versal *s, const char *path,
+ uint64_t addr, uint64_t len,
+ const char *compat,
+ size_t compat_sz)
+{
+ char *p = versal_fdt_add_subnode(s, path, addr, compat, compat_sz);
+
+ qemu_fdt_setprop_sized_cells(s->cfg.fdt, p, "reg", 2, addr, 2, len);
+ return p;
+}
+
+static inline DeviceState *create_or_gate(Versal *s, Object *parent,
+ const char *name, uint16_t num_lines,
+ int irq_idx)
+{
+ DeviceState *or;
+
+ or = qdev_new(TYPE_OR_IRQ);
+ qdev_prop_set_uint16(or, "num-lines", num_lines);
+ object_property_add_child(parent, name, OBJECT(or));
+ qdev_realize_and_unref(or, NULL, &error_abort);
+ versal_qdev_connect_gpio_out(s, or, 0, irq_idx);
+
+ return or;
+}
+
+static MemoryRegion *create_cpu_mr(Versal *s, DeviceState *cluster,
+ const VersalCpuClusterMap *map)
+{
+ MemoryRegion *mr, *root_alias;
+ char *name;
+
+ mr = g_new(MemoryRegion, 1);
+ name = g_strdup_printf("%s-mr", map->name);
+ memory_region_init(mr, OBJECT(cluster), name, UINT64_MAX);
+ g_free(name);
+
+ root_alias = g_new(MemoryRegion, 1);
+ name = g_strdup_printf("ps-alias-for-%s", map->name);
+ memory_region_init_alias(root_alias, OBJECT(cluster), name,
+ &s->mr_ps, 0, UINT64_MAX);
+ g_free(name);
+ memory_region_add_subregion(mr, 0, root_alias);
+
+ return mr;
+}
+
+static void versal_create_gic_its(Versal *s,
+ const VersalCpuClusterMap *map,
+ DeviceState *gic,
+ MemoryRegion *mr,
+ char *gic_node)
+{
+ DeviceState *dev;
+ SysBusDevice *sbd;
+ g_autofree char *node_pat = NULL, *node = NULL;
+ const char compatible[] = "arm,gic-v3-its";
+
+ if (map->gic.version != 3) {
+ return;
+ }
+
+ if (!map->gic.has_its) {
+ return;
+ }
+
+ dev = qdev_new(TYPE_ARM_GICV3_ITS);
+ sbd = SYS_BUS_DEVICE(dev);
+
+ object_property_add_child(OBJECT(gic), "its", OBJECT(dev));
+ object_property_set_link(OBJECT(dev), "parent-gicv3", OBJECT(gic),
+ &error_abort);
+
+ sysbus_realize_and_unref(sbd, &error_abort);
+
+ memory_region_add_subregion(mr, map->gic.its,
+ sysbus_mmio_get_region(sbd, 0));
+
+ if (!map->dtb_expose) {
+ return;
+ }
+
+ qemu_fdt_setprop(s->cfg.fdt, gic_node, "ranges", NULL, 0);
+ qemu_fdt_setprop_cell(s->cfg.fdt, gic_node, "#address-cells", 2);
+ qemu_fdt_setprop_cell(s->cfg.fdt, gic_node, "#size-cells", 2);
+
+ node_pat = g_strdup_printf("%s/its", gic_node);
+ node = versal_fdt_add_simple_subnode(s, node_pat, map->gic.its, 0x20000,
+ compatible, sizeof(compatible));
+ qemu_fdt_setprop(s->cfg.fdt, node, "msi-controller", NULL, 0);
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "#msi-cells", 1);
+}
+
+static DeviceState *versal_create_gic(Versal *s,
+ const VersalCpuClusterMap *map,
+ MemoryRegion *mr,
+ int first_cpu_idx,
+ size_t num_cpu)
+{
+ DeviceState *dev;
+ SysBusDevice *sbd;
+ g_autofree char *node = NULL;
+ g_autofree char *name = NULL;
+ const char gicv3_compat[] = "arm,gic-v3";
+ const char gicv2_compat[] = "arm,cortex-a15-gic";
+
+ switch (map->gic.version) {
+ case 2:
+ dev = qdev_new(gic_class_name());
+ break;
+
+ case 3:
+ dev = qdev_new(gicv3_class_name());
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ name = g_strdup_printf("%s-gic[*]", map->name);
+ object_property_add_child(OBJECT(s), name, OBJECT(dev));
+ sbd = SYS_BUS_DEVICE(dev);
+ qdev_prop_set_uint32(dev, "revision", map->gic.version);
+ qdev_prop_set_uint32(dev, "num-cpu", num_cpu);
+ qdev_prop_set_uint32(dev, "num-irq", map->gic.num_irq + 32);
+ qdev_prop_set_bit(dev, "has-security-extensions", true);
+ qdev_prop_set_uint32(dev, "first-cpu-index", first_cpu_idx);
+
+ if (map->gic.version == 3) {
+ QList *redist_region_count;
+
+ redist_region_count = qlist_new();
+ qlist_append_int(redist_region_count, num_cpu);
+ qdev_prop_set_array(dev, "redist-region-count", redist_region_count);
+ qdev_prop_set_bit(dev, "has-lpi", map->gic.has_its);
+ object_property_set_link(OBJECT(dev), "sysmem", OBJECT(mr),
+ &error_abort);
+
+ }
+
+ sysbus_realize_and_unref(sbd, &error_fatal);
+
+ memory_region_add_subregion(mr, map->gic.dist,
+ sysbus_mmio_get_region(sbd, 0));
+
+ if (map->gic.version == 3) {
+ memory_region_add_subregion(mr, map->gic.redist,
+ sysbus_mmio_get_region(sbd, 1));
+ } else {
+ memory_region_add_subregion(mr, map->gic.cpu_iface,
+ sysbus_mmio_get_region(sbd, 1));
+ }
+
+ if (map->dtb_expose) {
+ if (map->gic.version == 3) {
+ node = versal_fdt_add_subnode(s, "/gic", map->gic.dist,
+ gicv3_compat,
+ sizeof(gicv3_compat));
+ qemu_fdt_setprop_sized_cells(s->cfg.fdt, node, "reg",
+ 2, map->gic.dist,
+ 2, 0x10000,
+ 2, map->gic.redist,
+ 2, GICV3_REDIST_SIZE * num_cpu);
+ } else {
+ node = versal_fdt_add_subnode(s, "/gic", map->gic.dist,
+ gicv2_compat,
+ sizeof(gicv2_compat));
+ qemu_fdt_setprop_sized_cells(s->cfg.fdt, node, "reg",
+ 2, map->gic.dist,
+ 2, 0x1000,
+ 2, map->gic.cpu_iface,
+ 2, 0x1000);
+ }
+
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "phandle", s->phandle.gic);
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "#interrupt-cells", 3);
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "interrupts",
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_GIC_MAINT_IRQ),
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop(s->cfg.fdt, node, "interrupt-controller", NULL, 0);
+ }
+
+ versal_create_gic_its(s, map, dev, mr, node);
+
+ g_array_append_val(s->intc, dev);
+
+ return dev;
+}
+
+static void connect_gic_to_cpu(const VersalCpuClusterMap *map,
+ DeviceState *gic, DeviceState *cpu, size_t idx,
+ size_t num_cpu)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(gic);
+ int ppibase = map->gic.num_irq + idx * GIC_INTERNAL + GIC_NR_SGIS;
+ int ti;
+ bool has_gtimer;
+ /*
+ * Mapping from the output timer irq lines from the CPU to the
+ * GIC PPI inputs.
+ */
+ const int timer_irq[] = {
+ [GTIMER_PHYS] = INTID_TO_PPI(ARCH_TIMER_NS_EL1_IRQ),
+ [GTIMER_VIRT] = INTID_TO_PPI(ARCH_TIMER_VIRT_IRQ),
+ [GTIMER_HYP] = INTID_TO_PPI(ARCH_TIMER_NS_EL2_IRQ),
+ [GTIMER_SEC] = INTID_TO_PPI(ARCH_TIMER_S_EL1_IRQ),
+ };
+
+ has_gtimer = arm_feature(&ARM_CPU(cpu)->env, ARM_FEATURE_GENERIC_TIMER);
+
+ if (has_gtimer) {
for (ti = 0; ti < ARRAY_SIZE(timer_irq); ti++) {
- qdev_connect_gpio_out(cpudev, ti,
- qdev_get_gpio_in(gicdev,
+ qdev_connect_gpio_out(cpu, ti,
+ qdev_get_gpio_in(gic,
ppibase + timer_irq[ti]));
}
- maint_irq = qdev_get_gpio_in(gicdev,
- ppibase + VERSAL_GIC_MAINT_IRQ);
- qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
+ }
+
+ if (map->gic.version == 3) {
+ qemu_irq maint_irq;
+ int maint_idx = ppibase + INTID_TO_PPI(ARCH_GIC_MAINT_IRQ);
+
+ maint_irq = qdev_get_gpio_in(gic, maint_idx);
+ qdev_connect_gpio_out_named(cpu, "gicv3-maintenance-interrupt",
0, maint_irq);
- sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
- sysbus_connect_irq(gicbusdev, i + nr_apu_cpus,
- qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
- sysbus_connect_irq(gicbusdev, i + 2 * nr_apu_cpus,
- qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
- sysbus_connect_irq(gicbusdev, i + 3 * nr_apu_cpus,
- qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
}
- for (i = 0; i < XLNX_VERSAL_NR_IRQS; i++) {
- pic[i] = qdev_get_gpio_in(gicdev, i);
- }
+ sysbus_connect_irq(sbd, idx, qdev_get_gpio_in(cpu, ARM_CPU_IRQ));
+ sysbus_connect_irq(sbd, idx + num_cpu,
+ qdev_get_gpio_in(cpu, ARM_CPU_FIQ));
+ sysbus_connect_irq(sbd, idx + 2 * num_cpu,
+ qdev_get_gpio_in(cpu, ARM_CPU_VIRQ));
+ sysbus_connect_irq(sbd, idx + 3 * num_cpu,
+ qdev_get_gpio_in(cpu, ARM_CPU_VFIQ));
}
-static void versal_create_rpu_cpus(Versal *s)
+static inline void versal_create_and_connect_gic(Versal *s,
+ const VersalCpuClusterMap *map,
+ MemoryRegion *mr,
+ DeviceState **cpus,
+ size_t num_cpu)
{
- int i;
+ DeviceState *gic;
+ int first_cpu_idx;
+ size_t i;
- object_initialize_child(OBJECT(s), "rpu-cluster", &s->lpd.rpu.cluster,
- TYPE_CPU_CLUSTER);
- qdev_prop_set_uint32(DEVICE(&s->lpd.rpu.cluster), "cluster-id", 1);
+ first_cpu_idx = CPU(cpus[0])->cpu_index;
+ gic = versal_create_gic(s, map, mr, first_cpu_idx, num_cpu);
- for (i = 0; i < ARRAY_SIZE(s->lpd.rpu.cpu); i++) {
- Object *obj;
-
- object_initialize_child(OBJECT(&s->lpd.rpu.cluster),
- "rpu-cpu[*]", &s->lpd.rpu.cpu[i],
- XLNX_VERSAL_RCPU_TYPE);
- obj = OBJECT(&s->lpd.rpu.cpu[i]);
- object_property_set_bool(obj, "start-powered-off", true,
- &error_abort);
-
- object_property_set_int(obj, "mp-affinity", 0x100 | i, &error_abort);
- object_property_set_int(obj, "core-count", ARRAY_SIZE(s->lpd.rpu.cpu),
- &error_abort);
- object_property_set_link(obj, "memory", OBJECT(&s->lpd.rpu.mr),
- &error_abort);
- qdev_realize(DEVICE(obj), NULL, &error_fatal);
+ for (i = 0; i < num_cpu; i++) {
+ connect_gic_to_cpu(map, gic, cpus[i], i, num_cpu);
}
-
- qdev_realize(DEVICE(&s->lpd.rpu.cluster), NULL, &error_fatal);
}
-static void versal_create_uarts(Versal *s, qemu_irq *pic)
+static DeviceState *versal_create_cpu(Versal *s,
+ const VersalCpuClusterMap *map,
+ DeviceState *qemu_cluster,
+ MemoryRegion *cpu_mr,
+ size_t cluster_idx,
+ size_t core_idx)
{
- int i;
+ DeviceState *cpu = qdev_new(map->cpu_model);
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ Object *obj = OBJECT(cpu);
+ uint64_t affinity;
+ bool start_off;
+ size_t idx = cluster_idx * map->num_core + core_idx;
+ g_autofree char *name;
+ g_autofree char *node = NULL;
- for (i = 0; i < ARRAY_SIZE(s->lpd.iou.uart); i++) {
- static const int irqs[] = { VERSAL_UART0_IRQ_0, VERSAL_UART1_IRQ_0};
- static const uint64_t addrs[] = { MM_UART0, MM_UART1 };
- char *name = g_strdup_printf("uart%d", i);
- DeviceState *dev;
- MemoryRegion *mr;
+ affinity = map->mp_affinity.base;
+ affinity |= (cluster_idx & 0xff) << map->mp_affinity.cluster_shift;
+ affinity |= (core_idx & 0xff) << map->mp_affinity.core_shift;
- object_initialize_child(OBJECT(s), name, &s->lpd.iou.uart[i],
- TYPE_PL011);
- dev = DEVICE(&s->lpd.iou.uart[i]);
- qdev_prop_set_chr(dev, "chardev", serial_hd(i));
- sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
+ start_off = map->start_powered_off == SPO_ALL
+ || ((map->start_powered_off == SPO_SECONDARIES)
+ && (cluster_idx || core_idx));
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
- memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
+ name = g_strdup_printf("%s[*]", map->name);
+ object_property_add_child(OBJECT(qemu_cluster), name, obj);
+ object_property_set_bool(obj, "start-powered-off", start_off,
+ &error_abort);
+ qdev_prop_set_uint64(cpu, "mp-affinity", affinity);
+ qdev_prop_set_int32(cpu, "core-count", map->num_core);
+ object_property_set_link(obj, "memory", OBJECT(cpu_mr), &error_abort);
+ qdev_realize_and_unref(cpu, NULL, &error_fatal);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irqs[i]]);
- g_free(name);
+ if (!map->dtb_expose) {
+ return cpu;
}
+
+ node = versal_fdt_add_subnode(s, "/cpus/cpu", idx,
+ arm_cpu->dtb_compatible,
+ strlen(arm_cpu->dtb_compatible) + 1);
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "reg",
+ arm_cpu_mp_affinity(arm_cpu) & ARM64_AFFINITY_MASK);
+ qemu_fdt_setprop_string(s->cfg.fdt, node, "device_type", "cpu");
+ qemu_fdt_setprop_string(s->cfg.fdt, node, "enable-method", "psci");
+
+ return cpu;
}
-static void versal_create_canfds(Versal *s, qemu_irq *pic)
+static void versal_create_cpu_cluster(Versal *s, const VersalCpuClusterMap *map)
{
- int i;
- uint32_t irqs[] = { VERSAL_CANFD0_IRQ_0, VERSAL_CANFD1_IRQ_0};
- uint64_t addrs[] = { MM_CANFD0, MM_CANFD1 };
+ size_t i, j;
+ DeviceState *cluster;
+ MemoryRegion *mr;
+ char *name;
+ g_autofree DeviceState **cpus;
+ const char compatible[] = "arm,armv8-timer";
+ bool has_gtimer;
- for (i = 0; i < ARRAY_SIZE(s->lpd.iou.canfd); i++) {
- char *name = g_strdup_printf("canfd%d", i);
- SysBusDevice *sbd;
- MemoryRegion *mr;
+ cluster = qdev_new(TYPE_CPU_CLUSTER);
+ name = g_strdup_printf("%s-cluster", map->name);
+ object_property_add_child(OBJECT(s), name, OBJECT(cluster));
+ g_free(name);
+ qdev_prop_set_uint32(cluster, "cluster-id", map->qemu_cluster_id);
- object_initialize_child(OBJECT(s), name, &s->lpd.iou.canfd[i],
- TYPE_XILINX_CANFD);
- sbd = SYS_BUS_DEVICE(&s->lpd.iou.canfd[i]);
+ mr = create_cpu_mr(s, cluster, map);
- object_property_set_int(OBJECT(&s->lpd.iou.canfd[i]), "ext_clk_freq",
- XLNX_VERSAL_CANFD_REF_CLK , &error_abort);
+ cpus = g_new(DeviceState *, map->num_cluster * map->num_core);
- object_property_set_link(OBJECT(&s->lpd.iou.canfd[i]), "canfdbus",
- OBJECT(s->lpd.iou.canbus[i]),
- &error_abort);
+ if (map->dtb_expose) {
+ qemu_fdt_add_subnode(s->cfg.fdt, "/cpus");
+ qemu_fdt_setprop_cell(s->cfg.fdt, "/cpus", "#size-cells", 0);
+ qemu_fdt_setprop_cell(s->cfg.fdt, "/cpus", "#address-cells", 1);
+ }
- sysbus_realize(sbd, &error_fatal);
+ for (i = 0; i < map->num_cluster; i++) {
+ for (j = 0; j < map->num_core; j++) {
+ DeviceState *cpu = versal_create_cpu(s, map, cluster, mr, i, j);
- mr = sysbus_mmio_get_region(sbd, 0);
- memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
+ cpus[i * map->num_core + j] = cpu;
+ }
- sysbus_connect_irq(sbd, 0, pic[irqs[i]]);
- g_free(name);
+ if (map->per_cluster_gic) {
+ versal_create_and_connect_gic(s, map, mr, &cpus[i * map->num_core],
+ map->num_core);
+ }
+ }
+
+ qdev_realize_and_unref(cluster, NULL, &error_fatal);
+
+ if (!map->per_cluster_gic) {
+ versal_create_and_connect_gic(s, map, mr, cpus,
+ map->num_cluster * map->num_core);
+ }
+
+ has_gtimer = arm_feature(&ARM_CPU(cpus[0])->env, ARM_FEATURE_GENERIC_TIMER);
+ if (map->dtb_expose && has_gtimer) {
+ qemu_fdt_add_subnode(s->cfg.fdt, "/timer");
+ qemu_fdt_setprop_cells(s->cfg.fdt, "/timer", "interrupts",
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_S_EL1_IRQ),
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI,
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_NS_EL1_IRQ),
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI,
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_VIRT_IRQ),
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI,
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_NS_EL2_IRQ),
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop(s->cfg.fdt, "/timer", "compatible",
+ compatible, sizeof(compatible));
}
}
-static void versal_create_usbs(Versal *s, qemu_irq *pic)
+static void versal_create_uart(Versal *s,
+ const VersalSimplePeriphMap *map,
+ int chardev_idx)
{
DeviceState *dev;
MemoryRegion *mr;
+ g_autofree char *node;
+ g_autofree char *alias;
+ const char compatible[] = "arm,pl011\0arm,sbsa-uart";
+ const char clocknames[] = "uartclk\0apb_pclk";
- object_initialize_child(OBJECT(s), "usb2", &s->lpd.iou.usb,
- TYPE_XILINX_VERSAL_USB2);
- dev = DEVICE(&s->lpd.iou.usb);
+ dev = qdev_new(TYPE_PL011);
+ object_property_add_child(OBJECT(s), "uart[*]", OBJECT(dev));
+ qdev_prop_set_chr(dev, "chardev", serial_hd(chardev_idx));
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_add_subregion(&s->mr_ps, map->addr, mr);
+
+ versal_sysbus_connect_irq(s, SYS_BUS_DEVICE(dev), 0, map->irq);
+
+ node = versal_fdt_add_simple_subnode(s, "/uart", map->addr, 0x1000,
+ compatible, sizeof(compatible));
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "current-speed", 115200);
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "clocks",
+ s->phandle.clk_125mhz, s->phandle.clk_125mhz);
+ qemu_fdt_setprop(s->cfg.fdt, node, "clock-names", clocknames,
+ sizeof(clocknames));
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, map->irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop(s->cfg.fdt, node, "u-boot,dm-pre-reloc", NULL, 0);
+
+ alias = g_strdup_printf("serial%d", chardev_idx);
+ qemu_fdt_setprop_string(s->cfg.fdt, "/aliases", alias, node);
+
+ if (chardev_idx == 0) {
+ qemu_fdt_setprop_string(s->cfg.fdt, "/chosen", "stdout-path", node);
+ }
+}
+
+static void versal_create_canfd(Versal *s, const VersalSimplePeriphMap *map,
+ CanBusState *bus)
+{
+ SysBusDevice *sbd;
+ MemoryRegion *mr;
+ g_autofree char *node;
+ const char compatible[] = "xlnx,canfd-2.0";
+ const char clocknames[] = "can_clk\0s_axi_aclk";
+
+ sbd = SYS_BUS_DEVICE(qdev_new(TYPE_XILINX_CANFD));
+ object_property_add_child(OBJECT(s), "canfd[*]", OBJECT(sbd));
+
+ object_property_set_int(OBJECT(sbd), "ext_clk_freq",
+ 25 * 1000 * 1000 , &error_abort);
+
+ object_property_set_link(OBJECT(sbd), "canfdbus", OBJECT(bus),
+ &error_abort);
+
+ sysbus_realize_and_unref(sbd, &error_fatal);
+
+ mr = sysbus_mmio_get_region(sbd, 0);
+ memory_region_add_subregion(&s->mr_ps, map->addr, mr);
+
+ versal_sysbus_connect_irq(s, sbd, 0, map->irq);
+
+ node = versal_fdt_add_simple_subnode(s, "/canfd", map->addr, 0x10000,
+ compatible, sizeof(compatible));
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "rx-fifo-depth", 0x40);
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "tx-mailbox-count", 0x20);
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "clocks",
+ s->phandle.clk_25mhz, s->phandle.clk_25mhz);
+ qemu_fdt_setprop(s->cfg.fdt, node, "clock-names",
+ clocknames, sizeof(clocknames));
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, map->irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+}
+
+static void versal_create_usb(Versal *s,
+ const struct VersalUsbMap *map)
+{
+ DeviceState *dev;
+ MemoryRegion *mr;
+ g_autofree char *node, *subnode;
+ const char clocknames[] = "bus_clk\0ref_clk";
+ const char irq_name[] = "dwc_usb3";
+ const char compat_versal_dwc3[] = "xlnx,versal-dwc3";
+ const char compat_dwc3[] = "snps,dwc3";
+
+ dev = qdev_new(TYPE_XILINX_VERSAL_USB2);
+ object_property_add_child(OBJECT(s), "usb[*]", OBJECT(dev));
object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),
&error_abort);
qdev_prop_set_uint32(dev, "intrs", 1);
qdev_prop_set_uint32(dev, "slots", 2);
- sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
- memory_region_add_subregion(&s->mr_ps, MM_USB_0, mr);
+ memory_region_add_subregion(&s->mr_ps, map->xhci, mr);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[VERSAL_USB0_IRQ_0]);
+ versal_sysbus_connect_irq(s, SYS_BUS_DEVICE(dev), 0, map->irq);
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
- memory_region_add_subregion(&s->mr_ps, MM_USB2_CTRL_REGS, mr);
+ memory_region_add_subregion(&s->mr_ps, map->ctrl, mr);
+
+ node = versal_fdt_add_simple_subnode(s, "/usb", map->ctrl, 0x10000,
+ compat_versal_dwc3,
+ sizeof(compat_versal_dwc3));
+ qemu_fdt_setprop(s->cfg.fdt, node, "clock-names",
+ clocknames, sizeof(clocknames));
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "clocks",
+ s->phandle.clk_25mhz, s->phandle.clk_125mhz);
+ qemu_fdt_setprop(s->cfg.fdt, node, "ranges", NULL, 0);
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "#address-cells", 2);
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "#size-cells", 2);
+
+ subnode = g_strdup_printf("/%s/dwc3", node);
+ g_free(node);
+
+ node = versal_fdt_add_simple_subnode(s, subnode, map->xhci, 0x10000,
+ compat_dwc3,
+ sizeof(compat_dwc3));
+ qemu_fdt_setprop(s->cfg.fdt, node, "interrupt-names",
+ irq_name, sizeof(irq_name));
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, map->irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop_cell(s->cfg.fdt, node,
+ "snps,quirk-frame-length-adjustment", 0x20);
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "#stream-id-cells", 1);
+ qemu_fdt_setprop_string(s->cfg.fdt, node, "dr_mode", "host");
+ qemu_fdt_setprop_string(s->cfg.fdt, node, "phy-names", "usb3-phy");
+ qemu_fdt_setprop(s->cfg.fdt, node, "snps,dis_u2_susphy_quirk", NULL, 0);
+ qemu_fdt_setprop(s->cfg.fdt, node, "snps,dis_u3_susphy_quirk", NULL, 0);
+ qemu_fdt_setprop(s->cfg.fdt, node, "snps,refclk_fladj", NULL, 0);
+ qemu_fdt_setprop(s->cfg.fdt, node, "snps,mask_phy_reset", NULL, 0);
+ qemu_fdt_setprop_string(s->cfg.fdt, node, "maximum-speed", "high-speed");
}
-static void versal_create_gems(Versal *s, qemu_irq *pic)
+static void versal_create_gem(Versal *s,
+ const struct VersalGemMap *map)
{
+ DeviceState *dev;
+ MemoryRegion *mr;
+ DeviceState *or;
int i;
- for (i = 0; i < ARRAY_SIZE(s->lpd.iou.gem); i++) {
- static const int irqs[] = { VERSAL_GEM0_IRQ_0, VERSAL_GEM1_IRQ_0};
- static const uint64_t addrs[] = { MM_GEM0, MM_GEM1 };
- char *name = g_strdup_printf("gem%d", i);
- DeviceState *dev;
- MemoryRegion *mr;
- OrIRQState *or_irq;
+ dev = qdev_new(TYPE_CADENCE_GEM);
+ object_property_add_child(OBJECT(s), "gem[*]", OBJECT(dev));
- object_initialize_child(OBJECT(s), name, &s->lpd.iou.gem[i],
- TYPE_CADENCE_GEM);
- or_irq = &s->lpd.iou.gem_irq_orgate[i];
- object_initialize_child(OBJECT(s), "gem-irq-orgate[*]",
- or_irq, TYPE_OR_IRQ);
- dev = DEVICE(&s->lpd.iou.gem[i]);
- qemu_configure_nic_device(dev, true, NULL);
- object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
- object_property_set_int(OBJECT(dev), "num-priority-queues", 2,
- &error_abort);
- object_property_set_int(OBJECT(or_irq),
- "num-lines", 2, &error_fatal);
- qdev_realize(DEVICE(or_irq), NULL, &error_fatal);
- qdev_connect_gpio_out(DEVICE(or_irq), 0, pic[irqs[i]]);
+ qemu_configure_nic_device(dev, true, NULL);
+ object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
+ object_property_set_int(OBJECT(dev), "num-priority-queues",
+ map->num_prio_queue, &error_abort);
- object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),
- &error_abort);
- sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
+ object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),
+ &error_abort);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
- memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_add_subregion(&s->mr_ps, map->map.addr, mr);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(or_irq), 0));
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, qdev_get_gpio_in(DEVICE(or_irq), 1));
- g_free(name);
+ /*
+ * The GEM controller exposes one IRQ line per priority queue. In Versal
+ * family devices, those are OR'ed together.
+ */
+ or = create_or_gate(s, OBJECT(dev), "irq-orgate",
+ map->num_prio_queue, map->map.irq);
+
+ for (i = 0; i < map->num_prio_queue; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, qdev_get_gpio_in(or, i));
}
}
-static void versal_create_admas(Versal *s, qemu_irq *pic)
+static void versal_create_gem_fdt(Versal *s,
+ const struct VersalGemMap *map)
{
int i;
+ g_autofree char *node;
+ g_autofree char *phy_node;
+ int phy_phandle;
+ const char compatible[] = "cdns,zynqmp-gem\0cdns,gem";
+ const char clocknames[] = "pclk\0hclk\0tx_clk\0rx_clk";
+ g_autofree uint32_t *irq_prop;
- for (i = 0; i < ARRAY_SIZE(s->lpd.iou.adma); i++) {
- char *name = g_strdup_printf("adma%d", i);
- DeviceState *dev;
- MemoryRegion *mr;
+ node = versal_fdt_add_simple_subnode(s, "/ethernet", map->map.addr, 0x1000,
+ compatible, sizeof(compatible));
+ phy_node = g_strdup_printf("%s/fixed-link", node);
+ phy_phandle = qemu_fdt_alloc_phandle(s->cfg.fdt);
- object_initialize_child(OBJECT(s), name, &s->lpd.iou.adma[i],
- TYPE_XLNX_ZDMA);
- dev = DEVICE(&s->lpd.iou.adma[i]);
+ /* Fixed link PHY node */
+ qemu_fdt_add_subnode(s->cfg.fdt, phy_node);
+ qemu_fdt_setprop_cell(s->cfg.fdt, phy_node, "phandle", phy_phandle);
+ qemu_fdt_setprop(s->cfg.fdt, phy_node, "full-duplex", NULL, 0);
+ qemu_fdt_setprop_cell(s->cfg.fdt, phy_node, "speed", map->speed);
+
+ qemu_fdt_setprop_string(s->cfg.fdt, node, "phy-mode", map->phy_mode);
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "phy-handle", phy_phandle);
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "clocks",
+ s->phandle.clk_25mhz, s->phandle.clk_25mhz,
+ s->phandle.clk_125mhz, s->phandle.clk_125mhz);
+ qemu_fdt_setprop(s->cfg.fdt, node, "clock-names",
+ clocknames, sizeof(clocknames));
+
+ irq_prop = g_new(uint32_t, map->num_prio_queue * 3);
+ for (i = 0; i < map->num_prio_queue; i++) {
+ irq_prop[3 * i] = cpu_to_be32(GIC_FDT_IRQ_TYPE_SPI);
+ irq_prop[3 * i + 1] = cpu_to_be32(map->map.irq);
+ irq_prop[3 * i + 2] = cpu_to_be32(GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ }
+ qemu_fdt_setprop(s->cfg.fdt, node, "interrupts", irq_prop,
+ sizeof(uint32_t) * map->num_prio_queue * 3);
+}
+
+static void versal_create_zdma(Versal *s,
+ const struct VersalZDMAMap *map)
+{
+ DeviceState *dev;
+ MemoryRegion *mr;
+ g_autofree char *name;
+ const char compatible[] = "xlnx,zynqmp-dma-1.0";
+ const char clocknames[] = "clk_main\0clk_apb";
+ size_t i;
+
+ name = g_strdup_printf("%s[*]", map->name);
+
+ for (i = 0; i < map->num_chan; i++) {
+ uint64_t addr = map->map.addr + map->chan_stride * i;
+ int irq = map->map.irq + map->irq_stride * i;
+ g_autofree char *node;
+
+ dev = qdev_new(TYPE_XLNX_ZDMA);
+ object_property_add_child(OBJECT(s), name, OBJECT(dev));
object_property_set_int(OBJECT(dev), "bus-width", 128, &error_abort);
object_property_set_link(OBJECT(dev), "dma",
OBJECT(get_system_memory()), &error_fatal);
- sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
- memory_region_add_subregion(&s->mr_ps,
- MM_ADMA_CH0 + i * MM_ADMA_CH0_SIZE, mr);
+ memory_region_add_subregion(&s->mr_ps, addr, mr);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[VERSAL_ADMA_IRQ_0 + i]);
- g_free(name);
+ versal_sysbus_connect_irq(s, SYS_BUS_DEVICE(dev), 0, irq);
+
+ node = versal_fdt_add_simple_subnode(s, "/dma", addr, 0x1000,
+ compatible, sizeof(compatible));
+ qemu_fdt_setprop_cell(s->cfg.fdt, node, "xlnx,bus-width", 64);
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "clocks",
+ s->phandle.clk_25mhz, s->phandle.clk_25mhz);
+ qemu_fdt_setprop(s->cfg.fdt, node, "clock-names",
+ clocknames, sizeof(clocknames));
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
}
}
#define SDHCI_CAPABILITIES 0x280737ec6481 /* Same as on ZynqMP. */
-static void versal_create_sds(Versal *s, qemu_irq *pic)
+static void versal_create_sdhci(Versal *s,
+ const VersalSimplePeriphMap *map)
{
- int i;
+ DeviceState *dev;
+ MemoryRegion *mr;
+ g_autofree char *node;
+ const char compatible[] = "arasan,sdhci-8.9a";
+ const char clocknames[] = "clk_xin\0clk_ahb";
- for (i = 0; i < ARRAY_SIZE(s->pmc.iou.sd); i++) {
- DeviceState *dev;
- MemoryRegion *mr;
+ dev = qdev_new(TYPE_SYSBUS_SDHCI);
+ object_property_add_child(OBJECT(s), "sdhci[*]", OBJECT(dev));
- object_initialize_child(OBJECT(s), "sd[*]", &s->pmc.iou.sd[i],
- TYPE_SYSBUS_SDHCI);
- dev = DEVICE(&s->pmc.iou.sd[i]);
+ object_property_set_uint(OBJECT(dev), "sd-spec-version", 3,
+ &error_fatal);
+ object_property_set_uint(OBJECT(dev), "capareg", SDHCI_CAPABILITIES,
+ &error_fatal);
+ object_property_set_uint(OBJECT(dev), "uhs", UHS_I, &error_fatal);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- object_property_set_uint(OBJECT(dev), "sd-spec-version", 3,
- &error_fatal);
- object_property_set_uint(OBJECT(dev), "capareg", SDHCI_CAPABILITIES,
- &error_fatal);
- object_property_set_uint(OBJECT(dev), "uhs", UHS_I, &error_fatal);
- sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_add_subregion(&s->mr_ps, map->addr, mr);
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
- memory_region_add_subregion(&s->mr_ps,
- MM_PMC_SD0 + i * MM_PMC_SD0_SIZE, mr);
+ versal_sysbus_connect_irq(s, SYS_BUS_DEVICE(dev), 0, map->irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
- pic[VERSAL_SD0_IRQ_0 + i * 2]);
- }
+ node = versal_fdt_add_simple_subnode(s, "/sdhci", map->addr, 0x10000,
+ compatible, sizeof(compatible));
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "clocks",
+ s->phandle.clk_25mhz, s->phandle.clk_25mhz);
+ qemu_fdt_setprop(s->cfg.fdt, node, "clock-names",
+ clocknames, sizeof(clocknames));
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, map->irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
}
-static void versal_create_pmc_apb_irq_orgate(Versal *s, qemu_irq *pic)
-{
- DeviceState *orgate;
-
- /*
- * The VERSAL_PMC_APB_IRQ is an 'or' of the interrupts from the following
- * models:
- * - RTC
- * - BBRAM
- * - PMC SLCR
- * - CFRAME regs (input 3 - 17 to the orgate)
- */
- object_initialize_child(OBJECT(s), "pmc-apb-irq-orgate",
- &s->pmc.apb_irq_orgate, TYPE_OR_IRQ);
- orgate = DEVICE(&s->pmc.apb_irq_orgate);
- object_property_set_int(OBJECT(orgate),
- "num-lines", VERSAL_NUM_PMC_APB_IRQS, &error_fatal);
- qdev_realize(orgate, NULL, &error_fatal);
- qdev_connect_gpio_out(orgate, 0, pic[VERSAL_PMC_APB_IRQ]);
-}
-
-static void versal_create_rtc(Versal *s, qemu_irq *pic)
+static void versal_create_rtc(Versal *s, const struct VersalRtcMap *map)
{
SysBusDevice *sbd;
MemoryRegion *mr;
+ g_autofree char *node;
+ const char compatible[] = "xlnx,zynqmp-rtc";
+ const char interrupt_names[] = "alarm\0sec";
- object_initialize_child(OBJECT(s), "rtc", &s->pmc.rtc,
- TYPE_XLNX_ZYNQMP_RTC);
- sbd = SYS_BUS_DEVICE(&s->pmc.rtc);
- sysbus_realize(sbd, &error_fatal);
+ sbd = SYS_BUS_DEVICE(qdev_new(TYPE_XLNX_ZYNQMP_RTC));
+ object_property_add_child(OBJECT(s), "rtc", OBJECT(sbd));
+ sysbus_realize_and_unref(sbd, &error_abort);
mr = sysbus_mmio_get_region(sbd, 0);
- memory_region_add_subregion(&s->mr_ps, MM_PMC_RTC, mr);
+ memory_region_add_subregion(&s->mr_ps, map->map.addr, mr);
/*
* TODO: Connect the ALARM and SECONDS interrupts once our RTC model
* supports them.
*/
- sysbus_connect_irq(sbd, 1,
- qdev_get_gpio_in(DEVICE(&s->pmc.apb_irq_orgate), 0));
+ versal_sysbus_connect_irq(s, sbd, 0, map->map.irq);
+
+ node = versal_fdt_add_simple_subnode(s, "/rtc", map->map.addr, 0x10000,
+ compatible, sizeof(compatible));
+ qemu_fdt_setprop_cells(s->cfg.fdt, node, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, map->alarm_irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI,
+ GIC_FDT_IRQ_TYPE_SPI, map->second_irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop(s->cfg.fdt, node, "interrupt-names",
+ interrupt_names, sizeof(interrupt_names));
}
-static void versal_create_trng(Versal *s, qemu_irq *pic)
+static void versal_create_trng(Versal *s, const VersalSimplePeriphMap *map)
{
SysBusDevice *sbd;
MemoryRegion *mr;
- object_initialize_child(OBJECT(s), "trng", &s->pmc.trng,
- TYPE_XLNX_VERSAL_TRNG);
- sbd = SYS_BUS_DEVICE(&s->pmc.trng);
- sysbus_realize(sbd, &error_fatal);
+ sbd = SYS_BUS_DEVICE(qdev_new(TYPE_XLNX_VERSAL_TRNG));
+ object_property_add_child(OBJECT(s), "trng", OBJECT(sbd));
+ sysbus_realize_and_unref(sbd, &error_abort);
mr = sysbus_mmio_get_region(sbd, 0);
- memory_region_add_subregion(&s->mr_ps, MM_PMC_TRNG, mr);
- sysbus_connect_irq(sbd, 0, pic[VERSAL_TRNG_IRQ]);
+ memory_region_add_subregion(&s->mr_ps, map->addr, mr);
+ versal_sysbus_connect_irq(s, sbd, 0, map->irq);
}
-static void versal_create_xrams(Versal *s, qemu_irq *pic)
+static void versal_create_xrams(Versal *s, const struct VersalXramMap *map)
{
- int nr_xrams = ARRAY_SIZE(s->lpd.xram.ctrl);
- DeviceState *orgate;
- int i;
+ SysBusDevice *sbd;
+ MemoryRegion *mr;
+ DeviceState *or;
+ size_t i;
- /* XRAM IRQs get ORed into a single line. */
- object_initialize_child(OBJECT(s), "xram-irq-orgate",
- &s->lpd.xram.irq_orgate, TYPE_OR_IRQ);
- orgate = DEVICE(&s->lpd.xram.irq_orgate);
- object_property_set_int(OBJECT(orgate),
- "num-lines", nr_xrams, &error_fatal);
- qdev_realize(orgate, NULL, &error_fatal);
- qdev_connect_gpio_out(orgate, 0, pic[VERSAL_XRAM_IRQ_0]);
+ or = create_or_gate(s, OBJECT(s), "xram-orgate", map->num, map->irq);
- for (i = 0; i < ARRAY_SIZE(s->lpd.xram.ctrl); i++) {
- SysBusDevice *sbd;
- MemoryRegion *mr;
+ for (i = 0; i < map->num; i++) {
+ hwaddr ctrl, mem;
- object_initialize_child(OBJECT(s), "xram[*]", &s->lpd.xram.ctrl[i],
- TYPE_XLNX_XRAM_CTRL);
- sbd = SYS_BUS_DEVICE(&s->lpd.xram.ctrl[i]);
- sysbus_realize(sbd, &error_fatal);
+ sbd = SYS_BUS_DEVICE(qdev_new(TYPE_XLNX_XRAM_CTRL));
+ object_property_add_child(OBJECT(s), "xram[*]", OBJECT(sbd));
+ sysbus_realize_and_unref(sbd, &error_fatal);
+
+ ctrl = map->ctrl + map->ctrl_stride * i;
+ mem = map->mem + map->mem_stride * i;
mr = sysbus_mmio_get_region(sbd, 0);
- memory_region_add_subregion(&s->mr_ps,
- MM_XRAMC + i * MM_XRAMC_SIZE, mr);
+ memory_region_add_subregion(&s->mr_ps, ctrl, mr);
mr = sysbus_mmio_get_region(sbd, 1);
- memory_region_add_subregion(&s->mr_ps, MM_XRAM + i * MiB, mr);
+ memory_region_add_subregion(&s->mr_ps, mem, mr);
- sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(orgate, i));
+ sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(or, i));
}
}
-static void versal_create_bbram(Versal *s, qemu_irq *pic)
+static void versal_create_bbram(Versal *s,
+ const VersalSimplePeriphMap *map)
{
+ DeviceState *dev;
SysBusDevice *sbd;
- object_initialize_child_with_props(OBJECT(s), "bbram", &s->pmc.bbram,
- sizeof(s->pmc.bbram), TYPE_XLNX_BBRAM,
- &error_fatal,
- "crc-zpads", "0",
- NULL);
- sbd = SYS_BUS_DEVICE(&s->pmc.bbram);
+ dev = qdev_new(TYPE_XLNX_BBRAM);
+ sbd = SYS_BUS_DEVICE(dev);
- sysbus_realize(sbd, &error_fatal);
- memory_region_add_subregion(&s->mr_ps, MM_PMC_BBRAM_CTRL,
+ object_property_add_child(OBJECT(s), "bbram", OBJECT(dev));
+ qdev_prop_set_uint32(dev, "crc-zpads", 0);
+ sysbus_realize_and_unref(sbd, &error_abort);
+ memory_region_add_subregion(&s->mr_ps, map->addr,
sysbus_mmio_get_region(sbd, 0));
- sysbus_connect_irq(sbd, 0,
- qdev_get_gpio_in(DEVICE(&s->pmc.apb_irq_orgate), 1));
+ versal_sysbus_connect_irq(s, sbd, 0, map->irq);
}
-static void versal_realize_efuse_part(Versal *s, Object *dev, hwaddr base)
+static void versal_create_efuse(Versal *s,
+ const struct VersalEfuseMap *map)
{
- SysBusDevice *part = SYS_BUS_DEVICE(dev);
+ DeviceState *bits;
+ DeviceState *ctrl;
+ DeviceState *cache;
- object_property_set_link(OBJECT(part), "efuse",
- OBJECT(&s->pmc.efuse), &error_abort);
+ if (versal_get_version(s) != VERSAL_VER_VERSAL) {
+ /* TODO for versal2 */
+ return;
+ }
- sysbus_realize(part, &error_abort);
- memory_region_add_subregion(&s->mr_ps, base,
- sysbus_mmio_get_region(part, 0));
-}
+ ctrl = qdev_new(TYPE_XLNX_VERSAL_EFUSE_CTRL);
+ cache = qdev_new(TYPE_XLNX_VERSAL_EFUSE_CACHE);
+ bits = qdev_new(TYPE_XLNX_EFUSE);
-static void versal_create_efuse(Versal *s, qemu_irq *pic)
-{
- Object *bits = OBJECT(&s->pmc.efuse);
- Object *ctrl = OBJECT(&s->pmc.efuse_ctrl);
- Object *cache = OBJECT(&s->pmc.efuse_cache);
+ qdev_prop_set_uint32(bits, "efuse-nr", 3);
+ qdev_prop_set_uint32(bits, "efuse-size", 8192);
- object_initialize_child(OBJECT(s), "efuse-ctrl", &s->pmc.efuse_ctrl,
- TYPE_XLNX_VERSAL_EFUSE_CTRL);
+ object_property_add_child(OBJECT(s), "efuse", OBJECT(bits));
+ qdev_realize_and_unref(bits, NULL, &error_abort);
- object_initialize_child(OBJECT(s), "efuse-cache", &s->pmc.efuse_cache,
- TYPE_XLNX_VERSAL_EFUSE_CACHE);
+ object_property_set_link(OBJECT(ctrl), "efuse", OBJECT(bits), &error_abort);
- object_initialize_child_with_props(ctrl, "xlnx-efuse@0", bits,
- sizeof(s->pmc.efuse),
- TYPE_XLNX_EFUSE, &error_abort,
- "efuse-nr", "3",
- "efuse-size", "8192",
- NULL);
-
- qdev_realize(DEVICE(bits), NULL, &error_abort);
- versal_realize_efuse_part(s, ctrl, MM_PMC_EFUSE_CTRL);
- versal_realize_efuse_part(s, cache, MM_PMC_EFUSE_CACHE);
-
- sysbus_connect_irq(SYS_BUS_DEVICE(ctrl), 0, pic[VERSAL_EFUSE_IRQ]);
-}
-
-static void versal_create_pmc_iou_slcr(Versal *s, qemu_irq *pic)
-{
- SysBusDevice *sbd;
-
- object_initialize_child(OBJECT(s), "versal-pmc-iou-slcr", &s->pmc.iou.slcr,
- TYPE_XILINX_VERSAL_PMC_IOU_SLCR);
-
- sbd = SYS_BUS_DEVICE(&s->pmc.iou.slcr);
- sysbus_realize(sbd, &error_fatal);
-
- memory_region_add_subregion(&s->mr_ps, MM_PMC_PMC_IOU_SLCR,
- sysbus_mmio_get_region(sbd, 0));
-
- sysbus_connect_irq(sbd, 0,
- qdev_get_gpio_in(DEVICE(&s->pmc.apb_irq_orgate), 2));
-}
-
-static void versal_create_ospi(Versal *s, qemu_irq *pic)
-{
- SysBusDevice *sbd;
- MemoryRegion *mr_dac;
- qemu_irq ospi_mux_sel;
- DeviceState *orgate;
-
- memory_region_init(&s->pmc.iou.ospi.linear_mr, OBJECT(s),
- "versal-ospi-linear-mr" , MM_PMC_OSPI_DAC_SIZE);
-
- object_initialize_child(OBJECT(s), "versal-ospi", &s->pmc.iou.ospi.ospi,
- TYPE_XILINX_VERSAL_OSPI);
-
- mr_dac = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->pmc.iou.ospi.ospi), 1);
- memory_region_add_subregion(&s->pmc.iou.ospi.linear_mr, 0x0, mr_dac);
-
- /* Create the OSPI destination DMA */
- object_initialize_child(OBJECT(s), "versal-ospi-dma-dst",
- &s->pmc.iou.ospi.dma_dst,
- TYPE_XLNX_CSU_DMA);
-
- object_property_set_link(OBJECT(&s->pmc.iou.ospi.dma_dst),
- "dma", OBJECT(get_system_memory()),
+ object_property_set_link(OBJECT(cache), "efuse", OBJECT(bits),
&error_abort);
- sbd = SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_dst);
- sysbus_realize(sbd, &error_fatal);
+ object_property_add_child(OBJECT(s), "efuse-cache", OBJECT(cache));
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(cache), &error_abort);
- memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI_DMA_DST,
- sysbus_mmio_get_region(sbd, 0));
+ object_property_add_child(OBJECT(s), "efuse-ctrl", OBJECT(ctrl));
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ctrl), &error_abort);
- /* Create the OSPI source DMA */
- object_initialize_child(OBJECT(s), "versal-ospi-dma-src",
- &s->pmc.iou.ospi.dma_src,
- TYPE_XLNX_CSU_DMA);
-
- object_property_set_bool(OBJECT(&s->pmc.iou.ospi.dma_src), "is-dst",
- false, &error_abort);
-
- object_property_set_link(OBJECT(&s->pmc.iou.ospi.dma_src),
- "dma", OBJECT(mr_dac), &error_abort);
-
- object_property_set_link(OBJECT(&s->pmc.iou.ospi.dma_src),
- "stream-connected-dma",
- OBJECT(&s->pmc.iou.ospi.dma_dst),
- &error_abort);
-
- sbd = SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_src);
- sysbus_realize(sbd, &error_fatal);
-
- memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI_DMA_SRC,
- sysbus_mmio_get_region(sbd, 0));
-
- /* Realize the OSPI */
- object_property_set_link(OBJECT(&s->pmc.iou.ospi.ospi), "dma-src",
- OBJECT(&s->pmc.iou.ospi.dma_src), &error_abort);
-
- sbd = SYS_BUS_DEVICE(&s->pmc.iou.ospi.ospi);
- sysbus_realize(sbd, &error_fatal);
-
- memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI,
- sysbus_mmio_get_region(sbd, 0));
-
- memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI_DAC,
- &s->pmc.iou.ospi.linear_mr);
-
- /* ospi_mux_sel */
- ospi_mux_sel = qdev_get_gpio_in_named(DEVICE(&s->pmc.iou.ospi.ospi),
- "ospi-mux-sel", 0);
- qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr), "ospi-mux-sel", 0,
- ospi_mux_sel);
-
- /* OSPI irq */
- object_initialize_child(OBJECT(s), "ospi-irq-orgate",
- &s->pmc.iou.ospi.irq_orgate, TYPE_OR_IRQ);
- object_property_set_int(OBJECT(&s->pmc.iou.ospi.irq_orgate),
- "num-lines", NUM_OSPI_IRQ_LINES, &error_fatal);
-
- orgate = DEVICE(&s->pmc.iou.ospi.irq_orgate);
- qdev_realize(orgate, NULL, &error_fatal);
-
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->pmc.iou.ospi.ospi), 0,
- qdev_get_gpio_in(orgate, 0));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_src), 0,
- qdev_get_gpio_in(orgate, 1));
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_dst), 0,
- qdev_get_gpio_in(orgate, 2));
-
- qdev_connect_gpio_out(orgate, 0, pic[VERSAL_OSPI_IRQ]);
+ memory_region_add_subregion(&s->mr_ps, map->ctrl,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ctrl),
+ 0));
+ memory_region_add_subregion(&s->mr_ps, map->cache,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(cache),
+ 0));
+ versal_sysbus_connect_irq(s, SYS_BUS_DEVICE(ctrl), 0, map->irq);
}
-static void versal_create_cfu(Versal *s, qemu_irq *pic)
+static DeviceState *versal_create_pmc_iou_slcr(Versal *s,
+ const VersalSimplePeriphMap *map)
{
SysBusDevice *sbd;
DeviceState *dev;
- int i;
- const struct {
- uint64_t reg_base;
- uint64_t fdri_base;
- } cframe_addr[] = {
- { MM_PMC_CFRAME0_REG, MM_PMC_CFRAME0_FDRI },
- { MM_PMC_CFRAME1_REG, MM_PMC_CFRAME1_FDRI },
- { MM_PMC_CFRAME2_REG, MM_PMC_CFRAME2_FDRI },
- { MM_PMC_CFRAME3_REG, MM_PMC_CFRAME3_FDRI },
- { MM_PMC_CFRAME4_REG, MM_PMC_CFRAME4_FDRI },
- { MM_PMC_CFRAME5_REG, MM_PMC_CFRAME5_FDRI },
- { MM_PMC_CFRAME6_REG, MM_PMC_CFRAME6_FDRI },
- { MM_PMC_CFRAME7_REG, MM_PMC_CFRAME7_FDRI },
- { MM_PMC_CFRAME8_REG, MM_PMC_CFRAME8_FDRI },
- { MM_PMC_CFRAME9_REG, MM_PMC_CFRAME9_FDRI },
- { MM_PMC_CFRAME10_REG, MM_PMC_CFRAME10_FDRI },
- { MM_PMC_CFRAME11_REG, MM_PMC_CFRAME11_FDRI },
- { MM_PMC_CFRAME12_REG, MM_PMC_CFRAME12_FDRI },
- { MM_PMC_CFRAME13_REG, MM_PMC_CFRAME13_FDRI },
- { MM_PMC_CFRAME14_REG, MM_PMC_CFRAME14_FDRI },
- };
- const struct {
- uint32_t blktype0_frames;
- uint32_t blktype1_frames;
- uint32_t blktype2_frames;
- uint32_t blktype3_frames;
- uint32_t blktype4_frames;
- uint32_t blktype5_frames;
- uint32_t blktype6_frames;
- } cframe_cfg[] = {
- [0] = { 34111, 3528, 12800, 11, 5, 1, 1 },
- [1] = { 38498, 3841, 15361, 13, 7, 3, 1 },
- [2] = { 38498, 3841, 15361, 13, 7, 3, 1 },
- [3] = { 38498, 3841, 15361, 13, 7, 3, 1 },
- };
- /* CFU FDRO */
- object_initialize_child(OBJECT(s), "cfu-fdro", &s->pmc.cfu_fdro,
- TYPE_XLNX_VERSAL_CFU_FDRO);
- sbd = SYS_BUS_DEVICE(&s->pmc.cfu_fdro);
+ dev = qdev_new(TYPE_XILINX_VERSAL_PMC_IOU_SLCR);
+ object_property_add_child(OBJECT(s), "pmc-iou-slcr", OBJECT(dev));
- sysbus_realize(sbd, &error_fatal);
- memory_region_add_subregion(&s->mr_ps, MM_PMC_CFU_FDRO,
+ sbd = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, map->addr,
sysbus_mmio_get_region(sbd, 0));
- /* CFRAME REG */
- for (i = 0; i < ARRAY_SIZE(s->pmc.cframe); i++) {
- g_autofree char *name = g_strdup_printf("cframe%d", i);
+ versal_sysbus_connect_irq(s, sbd, 0, map->irq);
- object_initialize_child(OBJECT(s), name, &s->pmc.cframe[i],
- TYPE_XLNX_VERSAL_CFRAME_REG);
-
- sbd = SYS_BUS_DEVICE(&s->pmc.cframe[i]);
- dev = DEVICE(&s->pmc.cframe[i]);
-
- if (i < ARRAY_SIZE(cframe_cfg)) {
- object_property_set_int(OBJECT(dev), "blktype0-frames",
- cframe_cfg[i].blktype0_frames,
- &error_abort);
- object_property_set_int(OBJECT(dev), "blktype1-frames",
- cframe_cfg[i].blktype1_frames,
- &error_abort);
- object_property_set_int(OBJECT(dev), "blktype2-frames",
- cframe_cfg[i].blktype2_frames,
- &error_abort);
- object_property_set_int(OBJECT(dev), "blktype3-frames",
- cframe_cfg[i].blktype3_frames,
- &error_abort);
- object_property_set_int(OBJECT(dev), "blktype4-frames",
- cframe_cfg[i].blktype4_frames,
- &error_abort);
- object_property_set_int(OBJECT(dev), "blktype5-frames",
- cframe_cfg[i].blktype5_frames,
- &error_abort);
- object_property_set_int(OBJECT(dev), "blktype6-frames",
- cframe_cfg[i].blktype6_frames,
- &error_abort);
- }
- object_property_set_link(OBJECT(dev), "cfu-fdro",
- OBJECT(&s->pmc.cfu_fdro), &error_fatal);
-
- sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
-
- memory_region_add_subregion(&s->mr_ps, cframe_addr[i].reg_base,
- sysbus_mmio_get_region(sbd, 0));
- memory_region_add_subregion(&s->mr_ps, cframe_addr[i].fdri_base,
- sysbus_mmio_get_region(sbd, 1));
- sysbus_connect_irq(sbd, 0,
- qdev_get_gpio_in(DEVICE(&s->pmc.apb_irq_orgate),
- 3 + i));
- }
-
- /* CFRAME BCAST */
- object_initialize_child(OBJECT(s), "cframe_bcast", &s->pmc.cframe_bcast,
- TYPE_XLNX_VERSAL_CFRAME_BCAST_REG);
-
- sbd = SYS_BUS_DEVICE(&s->pmc.cframe_bcast);
- dev = DEVICE(&s->pmc.cframe_bcast);
-
- for (i = 0; i < ARRAY_SIZE(s->pmc.cframe); i++) {
- g_autofree char *propname = g_strdup_printf("cframe%d", i);
- object_property_set_link(OBJECT(dev), propname,
- OBJECT(&s->pmc.cframe[i]), &error_fatal);
- }
-
- sysbus_realize(sbd, &error_fatal);
-
- memory_region_add_subregion(&s->mr_ps, MM_PMC_CFRAME_BCAST_REG,
- sysbus_mmio_get_region(sbd, 0));
- memory_region_add_subregion(&s->mr_ps, MM_PMC_CFRAME_BCAST_FDRI,
- sysbus_mmio_get_region(sbd, 1));
-
- /* CFU APB */
- object_initialize_child(OBJECT(s), "cfu-apb", &s->pmc.cfu_apb,
- TYPE_XLNX_VERSAL_CFU_APB);
- sbd = SYS_BUS_DEVICE(&s->pmc.cfu_apb);
- dev = DEVICE(&s->pmc.cfu_apb);
-
- for (i = 0; i < ARRAY_SIZE(s->pmc.cframe); i++) {
- g_autofree char *propname = g_strdup_printf("cframe%d", i);
- object_property_set_link(OBJECT(dev), propname,
- OBJECT(&s->pmc.cframe[i]), &error_fatal);
- }
-
- sysbus_realize(sbd, &error_fatal);
- memory_region_add_subregion(&s->mr_ps, MM_PMC_CFU_APB,
- sysbus_mmio_get_region(sbd, 0));
- memory_region_add_subregion(&s->mr_ps, MM_PMC_CFU_STREAM,
- sysbus_mmio_get_region(sbd, 1));
- memory_region_add_subregion(&s->mr_ps, MM_PMC_CFU_STREAM_2,
- sysbus_mmio_get_region(sbd, 2));
- sysbus_connect_irq(sbd, 0, pic[VERSAL_CFU_IRQ_0]);
-
- /* CFU SFR */
- object_initialize_child(OBJECT(s), "cfu-sfr", &s->pmc.cfu_sfr,
- TYPE_XLNX_VERSAL_CFU_SFR);
-
- sbd = SYS_BUS_DEVICE(&s->pmc.cfu_sfr);
-
- object_property_set_link(OBJECT(&s->pmc.cfu_sfr),
- "cfu", OBJECT(&s->pmc.cfu_apb), &error_abort);
-
- sysbus_realize(sbd, &error_fatal);
- memory_region_add_subregion(&s->mr_ps, MM_PMC_CFU_SFR,
- sysbus_mmio_get_region(sbd, 0));
+ return dev;
}
-static void versal_create_crl(Versal *s, qemu_irq *pic)
+static DeviceState *versal_create_ospi(Versal *s,
+ const struct VersalOspiMap *map)
{
SysBusDevice *sbd;
- int i;
+ MemoryRegion *mr_dac;
+ DeviceState *dev, *dma_dst, *dma_src, *orgate;
+ MemoryRegion *linear_mr = g_new(MemoryRegion, 1);
- object_initialize_child(OBJECT(s), "crl", &s->lpd.crl,
- TYPE_XLNX_VERSAL_CRL);
- sbd = SYS_BUS_DEVICE(&s->lpd.crl);
+ dev = qdev_new(TYPE_XILINX_VERSAL_OSPI);
+ object_property_add_child(OBJECT(s), "ospi", OBJECT(dev));
- for (i = 0; i < ARRAY_SIZE(s->lpd.rpu.cpu); i++) {
- g_autofree gchar *name = g_strdup_printf("cpu_r5[%d]", i);
+ memory_region_init(linear_mr, OBJECT(dev), "linear-mr", map->dac_sz);
- object_property_set_link(OBJECT(&s->lpd.crl),
- name, OBJECT(&s->lpd.rpu.cpu[i]),
- &error_abort);
- }
+ mr_dac = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+ memory_region_add_subregion(linear_mr, 0x0, mr_dac);
- for (i = 0; i < ARRAY_SIZE(s->lpd.iou.gem); i++) {
- g_autofree gchar *name = g_strdup_printf("gem[%d]", i);
+ /* Create the OSPI destination DMA */
+ dma_dst = qdev_new(TYPE_XLNX_CSU_DMA);
+ object_property_add_child(OBJECT(dev), "dma-dst-dev", OBJECT(dma_dst));
+ object_property_set_link(OBJECT(dma_dst), "dma",
+ OBJECT(get_system_memory()), &error_abort);
- object_property_set_link(OBJECT(&s->lpd.crl),
- name, OBJECT(&s->lpd.iou.gem[i]),
- &error_abort);
- }
+ sbd = SYS_BUS_DEVICE(dma_dst);
+ sysbus_realize_and_unref(sbd, &error_fatal);
- for (i = 0; i < ARRAY_SIZE(s->lpd.iou.adma); i++) {
- g_autofree gchar *name = g_strdup_printf("adma[%d]", i);
+ memory_region_add_subregion(&s->mr_ps, map->dma_dst,
+ sysbus_mmio_get_region(sbd, 0));
- object_property_set_link(OBJECT(&s->lpd.crl),
- name, OBJECT(&s->lpd.iou.adma[i]),
- &error_abort);
- }
+ /* Create the OSPI source DMA */
+ dma_src = qdev_new(TYPE_XLNX_CSU_DMA);
+ object_property_add_child(OBJECT(dev), "dma-src-dev", OBJECT(dma_src));
- for (i = 0; i < ARRAY_SIZE(s->lpd.iou.uart); i++) {
- g_autofree gchar *name = g_strdup_printf("uart[%d]", i);
+ object_property_set_bool(OBJECT(dma_src), "is-dst", false, &error_abort);
- object_property_set_link(OBJECT(&s->lpd.crl),
- name, OBJECT(&s->lpd.iou.uart[i]),
- &error_abort);
- }
-
- object_property_set_link(OBJECT(&s->lpd.crl),
- "usb", OBJECT(&s->lpd.iou.usb),
+ object_property_set_link(OBJECT(dma_src), "dma", OBJECT(mr_dac),
&error_abort);
- sysbus_realize(sbd, &error_fatal);
- memory_region_add_subregion(&s->mr_ps, MM_CRL,
+ object_property_set_link(OBJECT(dma_src), "stream-connected-dma",
+ OBJECT(dma_dst), &error_abort);
+
+ sbd = SYS_BUS_DEVICE(dma_src);
+ sysbus_realize_and_unref(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, map->dma_src,
sysbus_mmio_get_region(sbd, 0));
- sysbus_connect_irq(sbd, 0, pic[VERSAL_CRL_IRQ]);
+
+ /* Realize the OSPI */
+ object_property_set_link(OBJECT(dev), "dma-src",
+ OBJECT(dma_src), &error_abort);
+
+ sbd = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, map->ctrl,
+ sysbus_mmio_get_region(sbd, 0));
+
+ memory_region_add_subregion(&s->mr_ps, map->dac,
+ linear_mr);
+
+ /* OSPI irq */
+ orgate = create_or_gate(s, OBJECT(dev), "irq-orgate", 3,
+ map->irq);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(orgate, 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(dma_src), 0, qdev_get_gpio_in(orgate, 1));
+ sysbus_connect_irq(SYS_BUS_DEVICE(dma_dst), 0, qdev_get_gpio_in(orgate, 2));
+
+ return dev;
}
-/* This takes the board allocated linear DDR memory and creates aliases
+static void versal_create_cfu(Versal *s, const struct VersalCfuMap *map)
+{
+ SysBusDevice *sbd;
+ Object *container;
+ DeviceState *cfu_fdro, *cfu_apb, *cfu_sfr, *cframe_bcast;
+ DeviceState *cframe_irq_or;
+ int i;
+
+ container = object_new(TYPE_CONTAINER);
+ object_property_add_child(OBJECT(s), "cfu", container);
+ object_unref(container);
+
+ /* CFU FDRO */
+ cfu_fdro = qdev_new(TYPE_XLNX_VERSAL_CFU_FDRO);
+ object_property_add_child(container, "cfu-fdro", OBJECT(cfu_fdro));
+ sbd = SYS_BUS_DEVICE(cfu_fdro);
+
+ sysbus_realize_and_unref(sbd, &error_fatal);
+ memory_region_add_subregion(&s->mr_ps, map->cfu_fdro,
+ sysbus_mmio_get_region(sbd, 0));
+
+ /* cframe bcast */
+ cframe_bcast = qdev_new(TYPE_XLNX_VERSAL_CFRAME_BCAST_REG);
+ object_property_add_child(container, "cframe-bcast", OBJECT(cframe_bcast));
+
+ /* CFU APB */
+ cfu_apb = qdev_new(TYPE_XLNX_VERSAL_CFU_APB);
+ object_property_add_child(container, "cfu-apb", OBJECT(cfu_apb));
+
+ /* IRQ or gate for cframes */
+ cframe_irq_or = qdev_new(TYPE_OR_IRQ);
+ object_property_add_child(container, "cframe-irq-or-gate",
+ OBJECT(cframe_irq_or));
+ qdev_prop_set_uint16(cframe_irq_or, "num-lines", map->num_cframe);
+ qdev_realize_and_unref(cframe_irq_or, NULL, &error_abort);
+ versal_qdev_connect_gpio_out(s, cframe_irq_or, 0, map->cframe_irq);
+
+ /* cframe reg */
+ for (i = 0; i < map->num_cframe; i++) {
+ uint64_t reg_base;
+ uint64_t fdri_base;
+ DeviceState *dev;
+ g_autofree char *prop_name;
+ size_t j;
+
+ dev = qdev_new(TYPE_XLNX_VERSAL_CFRAME_REG);
+ object_property_add_child(container, "cframe[*]", OBJECT(dev));
+
+ sbd = SYS_BUS_DEVICE(dev);
+
+ for (j = 0; j < ARRAY_SIZE(map->cframe_cfg[i].blktype_frames); j++) {
+ g_autofree char *blktype_prop_name;
+
+ blktype_prop_name = g_strdup_printf("blktype%zu-frames", j);
+ object_property_set_int(OBJECT(dev), blktype_prop_name,
+ map->cframe_cfg[i].blktype_frames[j],
+ &error_abort);
+ }
+
+ object_property_set_link(OBJECT(dev), "cfu-fdro",
+ OBJECT(cfu_fdro), &error_abort);
+
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_abort);
+
+ reg_base = map->cframe_base + i * map->cframe_stride * 2;
+ fdri_base = reg_base + map->cframe_stride;
+ memory_region_add_subregion(&s->mr_ps, reg_base,
+ sysbus_mmio_get_region(sbd, 0));
+ memory_region_add_subregion(&s->mr_ps, fdri_base,
+ sysbus_mmio_get_region(sbd, 1));
+ sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(cframe_irq_or, i));
+
+ prop_name = g_strdup_printf("cframe%d", i);
+ object_property_set_link(OBJECT(cframe_bcast), prop_name,
+ OBJECT(dev), &error_abort);
+ object_property_set_link(OBJECT(cfu_apb), prop_name,
+ OBJECT(dev), &error_abort);
+ }
+
+ sbd = SYS_BUS_DEVICE(cframe_bcast);
+ sysbus_realize_and_unref(sbd, &error_abort);
+ memory_region_add_subregion(&s->mr_ps, map->cframe_bcast_reg,
+ sysbus_mmio_get_region(sbd, 0));
+ memory_region_add_subregion(&s->mr_ps, map->cframe_bcast_fdri,
+ sysbus_mmio_get_region(sbd, 1));
+
+ sbd = SYS_BUS_DEVICE(cfu_apb);
+ sysbus_realize_and_unref(sbd, &error_fatal);
+ memory_region_add_subregion(&s->mr_ps, map->cfu_apb,
+ sysbus_mmio_get_region(sbd, 0));
+ memory_region_add_subregion(&s->mr_ps, map->cfu_stream,
+ sysbus_mmio_get_region(sbd, 1));
+ memory_region_add_subregion(&s->mr_ps, map->cfu_stream_2,
+ sysbus_mmio_get_region(sbd, 2));
+ versal_sysbus_connect_irq(s, sbd, 0, map->cfu_apb_irq);
+
+ /* CFU SFR */
+ cfu_sfr = qdev_new(TYPE_XLNX_VERSAL_CFU_SFR);
+ object_property_add_child(container, "cfu-sfr", OBJECT(cfu_sfr));
+ sbd = SYS_BUS_DEVICE(cfu_sfr);
+
+ object_property_set_link(OBJECT(cfu_sfr),
+ "cfu", OBJECT(cfu_apb), &error_abort);
+ sysbus_realize_and_unref(sbd, &error_fatal);
+ memory_region_add_subregion(&s->mr_ps, map->cfu_sfr,
+ sysbus_mmio_get_region(sbd, 0));
+}
+
+static inline void crl_connect_dev(Object *crl, Object *dev)
+{
+ const char *prop = object_get_canonical_path_component(dev);
+
+ /* The component part of the device path matches the CRL property name */
+ object_property_set_link(crl, prop, dev, &error_abort);
+}
+
+static inline void crl_connect_dev_by_name(Versal *s, Object *crl,
+ const char *name, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; i++) {
+ Object *dev = versal_get_child_idx(s, name, i);
+
+ crl_connect_dev(crl, dev);
+ }
+}
+
+static inline void versal_create_crl(Versal *s)
+{
+ const VersalMap *map;
+ VersalVersion ver;
+ const char *crl_class;
+ DeviceState *dev;
+ size_t num_gem;
+ Object *obj;
+
+ map = versal_get_map(s);
+ ver = versal_get_version(s);
+
+ crl_class = xlnx_versal_crl_class_name(ver);
+ dev = qdev_new(crl_class);
+ obj = OBJECT(dev);
+ object_property_add_child(OBJECT(s), "crl", obj);
+
+ /*
+ * The 3rd GEM controller on versal2 is in the MMI subsystem.
+ * Its reset line is not connected to the CRL. Consider only the first two
+ * ones.
+ */
+ num_gem = ver == VERSAL_VER_VERSAL2 ? 2 : map->num_gem;
+
+ crl_connect_dev_by_name(s, obj, "rpu-cluster/rpu",
+ map->rpu.num_cluster * map->rpu.num_core);
+ crl_connect_dev_by_name(s, obj, map->zdma[0].name, map->zdma[0].num_chan);
+ crl_connect_dev_by_name(s, obj, "uart", map->num_uart);
+ crl_connect_dev_by_name(s, obj, "gem", num_gem);
+ crl_connect_dev_by_name(s, obj, "usb", map->num_usb);
+
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_abort);
+
+ memory_region_add_subregion(&s->mr_ps, map->crl.addr,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
+
+ if (ver == VERSAL_VER_VERSAL) {
+ /* CRL IRQ line has been removed in versal2 */
+ versal_sysbus_connect_irq(s, SYS_BUS_DEVICE(dev), 0, map->crl.irq);
+ }
+}
+
+/*
+ * This takes the board allocated linear DDR memory and creates aliases
* for each split DDR range/aperture on the Versal address map.
*/
-static void versal_map_ddr(Versal *s)
+static void versal_map_ddr(Versal *s, const struct VersalDDRMap *map)
{
uint64_t size = memory_region_size(s->cfg.mr_ddr);
- /* Describes the various split DDR access regions. */
- static const struct {
- uint64_t base;
- uint64_t size;
- } addr_ranges[] = {
- { MM_TOP_DDR, MM_TOP_DDR_SIZE },
- { MM_TOP_DDR_2, MM_TOP_DDR_2_SIZE },
- { MM_TOP_DDR_3, MM_TOP_DDR_3_SIZE },
- { MM_TOP_DDR_4, MM_TOP_DDR_4_SIZE }
- };
uint64_t offset = 0;
int i;
- assert(ARRAY_SIZE(addr_ranges) == ARRAY_SIZE(s->noc.mr_ddr_ranges));
- for (i = 0; i < ARRAY_SIZE(addr_ranges) && size; i++) {
- char *name;
+ for (i = 0; i < map->num_chan && size; i++) {
uint64_t mapsize;
+ MemoryRegion *alias;
- mapsize = size < addr_ranges[i].size ? size : addr_ranges[i].size;
- name = g_strdup_printf("noc-ddr-range%d", i);
+ mapsize = MIN(size, map->chan[i].size);
+
/* Create the MR alias. */
- memory_region_init_alias(&s->noc.mr_ddr_ranges[i], OBJECT(s),
- name, s->cfg.mr_ddr,
- offset, mapsize);
+ alias = g_new(MemoryRegion, 1);
+ memory_region_init_alias(alias, OBJECT(s), "noc-ddr-range",
+ s->cfg.mr_ddr, offset, mapsize);
/* Map it onto the NoC MR. */
- memory_region_add_subregion(&s->mr_ps, addr_ranges[i].base,
- &s->noc.mr_ddr_ranges[i]);
+ memory_region_add_subregion(&s->mr_ps, map->chan[i].addr, alias);
offset += mapsize;
size -= mapsize;
- g_free(name);
}
}
+void versal_fdt_add_memory_nodes(Versal *s, uint64_t size)
+{
+ const struct VersalDDRMap *map = &versal_get_map(s)->ddr;
+ g_autofree char *node;
+ g_autofree uint64_t *reg;
+ int i;
+
+ reg = g_new(uint64_t, map->num_chan * 2);
+
+ for (i = 0; i < map->num_chan && size; i++) {
+ uint64_t mapsize;
+
+ mapsize = MIN(size, map->chan[i].size);
+
+ reg[i * 2] = cpu_to_be64(map->chan[i].addr);
+ reg[i * 2 + 1] = cpu_to_be64(mapsize);
+
+ size -= mapsize;
+ }
+
+ node = versal_fdt_add_subnode(s, "/memory", 0, "memory", sizeof("memory"));
+ qemu_fdt_setprop(s->cfg.fdt, node, "reg", reg, sizeof(uint64_t) * i * 2);
+}
+
static void versal_unimp_area(Versal *s, const char *name,
MemoryRegion *mr,
hwaddr base, hwaddr size)
@@ -875,22 +1794,12 @@
"is not yet implemented\n");
}
-static void versal_unimp(Versal *s)
+static void versal_unimp_common(Versal *s)
{
+ DeviceState *slcr;
qemu_irq gpio_in;
- versal_unimp_area(s, "psm", &s->mr_ps,
- MM_PSM_START, MM_PSM_END - MM_PSM_START);
- versal_unimp_area(s, "crf", &s->mr_ps,
- MM_FPD_CRF, MM_FPD_CRF_SIZE);
- versal_unimp_area(s, "apu", &s->mr_ps,
- MM_FPD_FPD_APU, MM_FPD_FPD_APU_SIZE);
- versal_unimp_area(s, "crp", &s->mr_ps,
- MM_PMC_CRP, MM_PMC_CRP_SIZE);
- versal_unimp_area(s, "iou-scntr", &s->mr_ps,
- MM_IOU_SCNTR, MM_IOU_SCNTR_SIZE);
- versal_unimp_area(s, "iou-scntr-seucre", &s->mr_ps,
- MM_IOU_SCNTRS, MM_IOU_SCNTRS_SIZE);
+ versal_unimp_area(s, "crp", &s->mr_ps, 0xf1260000, 0x10000);
qdev_init_gpio_in_named(DEVICE(s), versal_unimp_sd_emmc_sel,
"sd-emmc-sel-dummy", 2);
@@ -899,102 +1808,353 @@
qdev_init_gpio_in_named(DEVICE(s), versal_unimp_irq_parity_imr,
"irq-parity-imr-dummy", 1);
+ slcr = DEVICE(versal_get_child(s, "pmc-iou-slcr"));
gpio_in = qdev_get_gpio_in_named(DEVICE(s), "sd-emmc-sel-dummy", 0);
- qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr), "sd-emmc-sel", 0,
- gpio_in);
+ qdev_connect_gpio_out_named(slcr, "sd-emmc-sel", 0, gpio_in);
gpio_in = qdev_get_gpio_in_named(DEVICE(s), "sd-emmc-sel-dummy", 1);
- qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr), "sd-emmc-sel", 1,
- gpio_in);
+ qdev_connect_gpio_out_named(slcr, "sd-emmc-sel", 1, gpio_in);
gpio_in = qdev_get_gpio_in_named(DEVICE(s), "qspi-ospi-mux-sel-dummy", 0);
- qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr),
- "qspi-ospi-mux-sel", 0,
- gpio_in);
+ qdev_connect_gpio_out_named(slcr, "qspi-ospi-mux-sel", 0, gpio_in);
gpio_in = qdev_get_gpio_in_named(DEVICE(s), "irq-parity-imr-dummy", 0);
- qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr),
- SYSBUS_DEVICE_GPIO_IRQ, 0,
- gpio_in);
+ qdev_connect_gpio_out_named(slcr, SYSBUS_DEVICE_GPIO_IRQ, 0, gpio_in);
+}
+
+static void versal_unimp(Versal *s)
+{
+ versal_unimp_area(s, "psm", &s->mr_ps, 0xffc80000, 0x70000);
+ versal_unimp_area(s, "crf", &s->mr_ps, 0xfd1a0000, 0x140000);
+ versal_unimp_area(s, "apu", &s->mr_ps, 0xfd5c0000, 0x100);
+ versal_unimp_area(s, "iou-scntr", &s->mr_ps, 0xff130000, 0x10000);
+ versal_unimp_area(s, "iou-scntr-secure", &s->mr_ps, 0xff140000, 0x10000);
+
+ versal_unimp_common(s);
+}
+
+static void versal2_unimp(Versal *s)
+{
+ versal_unimp_area(s, "fpd-systmr-ctrl", &s->mr_ps, 0xec920000, 0x1000);
+ versal_unimp_area(s, "crf", &s->mr_ps, 0xec200000, 0x100000);
+
+ versal_unimp_common(s);
+}
+
+static uint32_t fdt_add_clk_node(Versal *s, const char *name,
+ unsigned int freq_hz)
+{
+ uint32_t phandle;
+
+ phandle = qemu_fdt_alloc_phandle(s->cfg.fdt);
+
+ qemu_fdt_add_subnode(s->cfg.fdt, name);
+ qemu_fdt_setprop_cell(s->cfg.fdt, name, "phandle", phandle);
+ qemu_fdt_setprop_cell(s->cfg.fdt, name, "clock-frequency", freq_hz);
+ qemu_fdt_setprop_cell(s->cfg.fdt, name, "#clock-cells", 0x0);
+ qemu_fdt_setprop_string(s->cfg.fdt, name, "compatible", "fixed-clock");
+ qemu_fdt_setprop(s->cfg.fdt, name, "u-boot,dm-pre-reloc", NULL, 0);
+
+ return phandle;
+}
+
+static void versal_realize_common(Versal *s)
+{
+ DeviceState *slcr, *ospi;
+ MemoryRegion *ocm;
+ Object *container;
+ const VersalMap *map = versal_get_map(s);
+ size_t i;
+
+ g_assert(s->cfg.fdt != NULL);
+
+ s->phandle.clk_25mhz = fdt_add_clk_node(s, "/clk25", 25 * 1000 * 1000);
+ s->phandle.clk_125mhz = fdt_add_clk_node(s, "/clk125", 125 * 1000 * 1000);
+ s->phandle.gic = qemu_fdt_alloc_phandle(s->cfg.fdt);
+
+ container = object_new(TYPE_CONTAINER);
+ object_property_add_child(OBJECT(s), "irq-splits", container);
+ object_unref(container);
+
+ container = object_new(TYPE_CONTAINER);
+ object_property_add_child(OBJECT(s), "irq-or-gates", container);
+ object_unref(container);
+
+ qemu_fdt_setprop_cell(s->cfg.fdt, "/", "interrupt-parent", s->phandle.gic);
+ qemu_fdt_setprop_cell(s->cfg.fdt, "/", "#size-cells", 0x2);
+ qemu_fdt_setprop_cell(s->cfg.fdt, "/", "#address-cells", 0x2);
+
+ versal_create_cpu_cluster(s, &map->apu);
+ versal_create_cpu_cluster(s, &map->rpu);
+
+ for (i = 0; i < map->num_uart; i++) {
+ versal_create_uart(s, &map->uart[i], i);
+ }
+
+ for (i = 0; i < map->num_canfd; i++) {
+ versal_create_canfd(s, &map->canfd[i], s->cfg.canbus[i]);
+ }
+
+ for (i = 0; i < map->num_sdhci; i++) {
+ versal_create_sdhci(s, &map->sdhci[i]);
+ }
+
+ for (i = 0; i < map->num_gem; i++) {
+ versal_create_gem(s, &map->gem[i]);
+ /*
+ * Create fdt node in reverse order to keep backward compatibility with
+ * previous versions of the generated FDT. This affects Linux kernel
+ * interface naming order when persistent naming scheme is not in use.
+ */
+ versal_create_gem_fdt(s, &map->gem[map->num_gem - 1 - i]);
+ }
+
+ for (i = 0; i < map->num_zdma; i++) {
+ versal_create_zdma(s, &map->zdma[i]);
+ }
+
+ versal_create_xrams(s, &map->xram);
+
+ for (i = 0; i < map->num_usb; i++) {
+ versal_create_usb(s, &map->usb[i]);
+ }
+
+ versal_create_efuse(s, &map->efuse);
+ ospi = versal_create_ospi(s, &map->ospi);
+ slcr = versal_create_pmc_iou_slcr(s, &map->pmc_iou_slcr);
+
+ qdev_connect_gpio_out_named(slcr, "ospi-mux-sel", 0,
+ qdev_get_gpio_in_named(ospi,
+ "ospi-mux-sel", 0));
+
+ versal_create_bbram(s, &map->bbram);
+ versal_create_trng(s, &map->trng);
+ versal_create_rtc(s, &map->rtc);
+ versal_create_cfu(s, &map->cfu);
+ versal_create_crl(s);
+
+ versal_map_ddr(s, &map->ddr);
+
+ /* Create the On Chip Memory (OCM). */
+ ocm = g_new(MemoryRegion, 1);
+ memory_region_init_ram(ocm, OBJECT(s), "ocm", map->ocm.size, &error_fatal);
+ memory_region_add_subregion_overlap(&s->mr_ps, map->ocm.addr, ocm, 0);
}
static void versal_realize(DeviceState *dev, Error **errp)
{
- Versal *s = XLNX_VERSAL(dev);
- qemu_irq pic[XLNX_VERSAL_NR_IRQS];
+ Versal *s = XLNX_VERSAL_BASE(dev);
- versal_create_apu_cpus(s);
- versal_create_apu_gic(s, pic);
- versal_create_rpu_cpus(s);
- versal_create_uarts(s, pic);
- versal_create_canfds(s, pic);
- versal_create_usbs(s, pic);
- versal_create_gems(s, pic);
- versal_create_admas(s, pic);
- versal_create_sds(s, pic);
- versal_create_pmc_apb_irq_orgate(s, pic);
- versal_create_rtc(s, pic);
- versal_create_trng(s, pic);
- versal_create_xrams(s, pic);
- versal_create_bbram(s, pic);
- versal_create_efuse(s, pic);
- versal_create_pmc_iou_slcr(s, pic);
- versal_create_ospi(s, pic);
- versal_create_crl(s, pic);
- versal_create_cfu(s, pic);
- versal_map_ddr(s);
+ versal_realize_common(s);
versal_unimp(s);
-
- /* Create the On Chip Memory (OCM). */
- memory_region_init_ram(&s->lpd.mr_ocm, OBJECT(s), "ocm",
- MM_OCM_SIZE, &error_fatal);
-
- memory_region_add_subregion_overlap(&s->mr_ps, MM_OCM, &s->lpd.mr_ocm, 0);
- memory_region_add_subregion_overlap(&s->fpd.apu.mr, 0, &s->mr_ps, 0);
- memory_region_add_subregion_overlap(&s->lpd.rpu.mr, 0,
- &s->lpd.rpu.mr_ps_alias, 0);
}
-static void versal_init(Object *obj)
+static void versal2_realize(DeviceState *dev, Error **errp)
{
- Versal *s = XLNX_VERSAL(obj);
+ Versal *s = XLNX_VERSAL_BASE(dev);
- memory_region_init(&s->fpd.apu.mr, obj, "mr-apu", UINT64_MAX);
- memory_region_init(&s->lpd.rpu.mr, obj, "mr-rpu", UINT64_MAX);
+ versal_realize_common(s);
+ versal2_unimp(s);
+}
+
+DeviceState *versal_get_boot_cpu(Versal *s)
+{
+ return DEVICE(versal_get_child_idx(s, "apu-cluster/apu", 0));
+}
+
+void versal_sdhci_plug_card(Versal *s, int sd_idx, BlockBackend *blk)
+{
+ DeviceState *sdhci, *card;
+
+ sdhci = DEVICE(versal_get_child_idx(s, "sdhci", sd_idx));
+
+ if (sdhci == NULL) {
+ return;
+ }
+
+ card = qdev_new(TYPE_SD_CARD);
+ object_property_add_child(OBJECT(sdhci), "card[*]", OBJECT(card));
+ qdev_prop_set_drive_err(card, "drive", blk, &error_fatal);
+ qdev_realize_and_unref(card, qdev_get_child_bus(DEVICE(sdhci), "sd-bus"),
+ &error_fatal);
+}
+
+void versal_efuse_attach_drive(Versal *s, BlockBackend *blk)
+{
+ DeviceState *efuse;
+
+ efuse = DEVICE(versal_get_child(s, "efuse"));
+
+ if (efuse == NULL) {
+ return;
+ }
+
+ qdev_prop_set_drive(efuse, "drive", blk);
+}
+
+void versal_bbram_attach_drive(Versal *s, BlockBackend *blk)
+{
+ DeviceState *bbram;
+
+ bbram = DEVICE(versal_get_child(s, "bbram"));
+
+ if (bbram == NULL) {
+ return;
+ }
+
+ qdev_prop_set_drive(bbram, "drive", blk);
+}
+
+void versal_ospi_create_flash(Versal *s, int flash_idx, const char *flash_mdl,
+ BlockBackend *blk)
+{
+ BusState *spi_bus;
+ DeviceState *flash, *ospi;
+ qemu_irq cs_line;
+
+ ospi = DEVICE(versal_get_child(s, "ospi"));
+ spi_bus = qdev_get_child_bus(ospi, "spi0");
+
+ flash = qdev_new(flash_mdl);
+
+ if (blk) {
+ qdev_prop_set_drive_err(flash, "drive", blk, &error_fatal);
+ }
+ qdev_prop_set_uint8(flash, "cs", flash_idx);
+ qdev_realize_and_unref(flash, spi_bus, &error_fatal);
+
+ cs_line = qdev_get_gpio_in_named(flash, SSI_GPIO_CS, 0);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(ospi),
+ flash_idx + 1, cs_line);
+}
+
+qemu_irq versal_get_reserved_irq(Versal *s, int idx, int *dtb_idx)
+{
+ const VersalMap *map = versal_get_map(s);
+
+ g_assert(idx < map->reserved.irq_num);
+
+ *dtb_idx = map->reserved.irq_start + idx;
+ return versal_get_irq(s, *dtb_idx);
+}
+
+hwaddr versal_get_reserved_mmio_addr(Versal *s)
+{
+ const VersalMap *map = versal_get_map(s);
+
+ return map->reserved.mmio_start;
+}
+
+int versal_get_num_cpu(VersalVersion version)
+{
+ const VersalMap *map = VERSION_TO_MAP[version];
+
+ return map->apu.num_cluster * map->apu.num_core
+ + map->rpu.num_cluster * map->rpu.num_core;
+}
+
+int versal_get_num_can(VersalVersion version)
+{
+ const VersalMap *map = VERSION_TO_MAP[version];
+
+ return map->num_canfd;
+}
+
+int versal_get_num_sdhci(VersalVersion version)
+{
+ const VersalMap *map = VERSION_TO_MAP[version];
+
+ return map->num_sdhci;
+}
+
+static void versal_base_init(Object *obj)
+{
+ Versal *s = XLNX_VERSAL_BASE(obj);
+ size_t i, num_can;
+
memory_region_init(&s->mr_ps, obj, "mr-ps-switch", UINT64_MAX);
- memory_region_init_alias(&s->lpd.rpu.mr_ps_alias, OBJECT(s),
- "mr-rpu-ps-alias", &s->mr_ps, 0, UINT64_MAX);
+ s->intc = g_array_new(false, false, sizeof(DeviceState *));
+
+ num_can = versal_get_map(s)->num_canfd;
+ s->cfg.canbus = g_new0(CanBusState *, num_can);
+
+ for (i = 0; i < num_can; i++) {
+ g_autofree char *prop_name = g_strdup_printf("canbus%zu", i);
+
+ object_property_add_link(obj, prop_name, TYPE_CAN_BUS,
+ (Object **) &s->cfg.canbus[i],
+ object_property_allow_set_link, 0);
+ }
+}
+
+static void versal_base_finalize(Object *obj)
+{
+ Versal *s = XLNX_VERSAL_BASE(obj);
+
+ g_array_free(s->intc, true);
+ g_free(s->cfg.canbus);
}
static const Property versal_properties[] = {
DEFINE_PROP_LINK("ddr", Versal, cfg.mr_ddr, TYPE_MEMORY_REGION,
MemoryRegion *),
- DEFINE_PROP_LINK("canbus0", Versal, lpd.iou.canbus[0],
- TYPE_CAN_BUS, CanBusState *),
- DEFINE_PROP_LINK("canbus1", Versal, lpd.iou.canbus[1],
- TYPE_CAN_BUS, CanBusState *),
};
-static void versal_class_init(ObjectClass *klass, const void *data)
+static void versal_base_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->realize = versal_realize;
device_class_set_props(dc, versal_properties);
/* No VMSD since we haven't got any top-level SoC state to save. */
}
-static const TypeInfo versal_info = {
- .name = TYPE_XLNX_VERSAL,
+static void versal_class_init(ObjectClass *klass, const void *data)
+{
+ VersalClass *vc = XLNX_VERSAL_BASE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ vc->version = VERSAL_VER_VERSAL;
+ dc->realize = versal_realize;
+}
+
+static void versal2_class_init(ObjectClass *klass, const void *data)
+{
+ VersalClass *vc = XLNX_VERSAL_BASE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ vc->version = VERSAL_VER_VERSAL2;
+ dc->realize = versal2_realize;
+}
+
+static const TypeInfo versal_base_info = {
+ .name = TYPE_XLNX_VERSAL_BASE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Versal),
- .instance_init = versal_init,
+ .instance_init = versal_base_init,
+ .instance_finalize = versal_base_finalize,
+ .class_init = versal_base_class_init,
+ .class_size = sizeof(VersalClass),
+ .abstract = true,
+};
+
+static const TypeInfo versal_info = {
+ .name = TYPE_XLNX_VERSAL,
+ .parent = TYPE_XLNX_VERSAL_BASE,
.class_init = versal_class_init,
};
+static const TypeInfo versal2_info = {
+ .name = TYPE_XLNX_VERSAL2,
+ .parent = TYPE_XLNX_VERSAL_BASE,
+ .class_init = versal2_class_init,
+};
+
static void versal_register_types(void)
{
+ type_register_static(&versal_base_info);
type_register_static(&versal_info);
+ type_register_static(&versal2_info);
}
type_init(versal_register_types);
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index ec96a46..ffed6e5 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -26,8 +26,6 @@
#include "target/arm/cpu-qom.h"
#include "target/arm/gtimer.h"
-#define GIC_NUM_SPI_INTR 160
-
#define ARM_PHYS_TIMER_PPI 30
#define ARM_VIRT_TIMER_PPI 27
#define ARM_HYP_TIMER_PPI 26
@@ -206,17 +204,26 @@
static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index)
{
- return GIC_NUM_SPI_INTR + cpu_nr * GIC_INTERNAL + ppi_index;
+ return XLNX_ZYNQMP_GIC_NUM_SPI_INTR + cpu_nr * GIC_INTERNAL + ppi_index;
+}
+
+static unsigned int xlnx_zynqmp_get_rpu_number(MachineState *ms)
+{
+ /*
+ * RPUs will be created only if "-smp" is higher than the maximum
+ * of APUs. Round it up to 0 to avoid dealing with negative values.
+ */
+ return MAX(0, MIN((int)(ms->smp.cpus - XLNX_ZYNQMP_NUM_APU_CPUS),
+ XLNX_ZYNQMP_NUM_RPU_CPUS));
}
static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s,
const char *boot_cpu, Error **errp)
{
int i;
- int num_rpus = MIN((int)(ms->smp.cpus - XLNX_ZYNQMP_NUM_APU_CPUS),
- XLNX_ZYNQMP_NUM_RPU_CPUS);
+ int num_rpus = xlnx_zynqmp_get_rpu_number(ms);
- if (num_rpus <= 0) {
+ if (!num_rpus) {
/* Don't create rpu-cluster object if there's nothing to put in it */
return;
}
@@ -377,6 +384,7 @@
XlnxZynqMPState *s = XLNX_ZYNQMP(obj);
int i;
int num_apus = MIN(ms->smp.cpus, XLNX_ZYNQMP_NUM_APU_CPUS);
+ int num_rpus = xlnx_zynqmp_get_rpu_number(ms);
object_initialize_child(obj, "apu-cluster", &s->apu_cluster,
TYPE_CPU_CLUSTER);
@@ -390,6 +398,12 @@
object_initialize_child(obj, "gic", &s->gic, gic_class_name());
+ if (num_rpus) {
+ /* Do not create the rpu_gic if we don't have rpus */
+ object_initialize_child(obj, "rpu_gic", &s->rpu_gic,
+ gic_class_name());
+ }
+
for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
object_initialize_child(obj, "gem[*]", &s->gem[i], TYPE_CADENCE_GEM);
object_initialize_child(obj, "gem-irq-orgate[*]",
@@ -439,6 +453,15 @@
object_initialize_child(obj, "qspi-irq-orgate",
&s->qspi_irq_orgate, TYPE_OR_IRQ);
+ if (num_rpus) {
+ for (i = 0; i < ARRAY_SIZE(s->splitter); i++) {
+ g_autofree char *name = g_strdup_printf("irq-splitter%d", i);
+ object_initialize_child(obj, name, &s->splitter[i], TYPE_SPLIT_IRQ);
+ }
+ }
+
+
+
for (i = 0; i < XLNX_ZYNQMP_NUM_USB; i++) {
object_initialize_child(obj, "usb[*]", &s->usb[i], TYPE_USB_DWC3);
}
@@ -452,9 +475,10 @@
uint8_t i;
uint64_t ram_size;
int num_apus = MIN(ms->smp.cpus, XLNX_ZYNQMP_NUM_APU_CPUS);
+ int num_rpus = xlnx_zynqmp_get_rpu_number(ms);
const char *boot_cpu = s->boot_cpu ? s->boot_cpu : "apu-cpu[0]";
ram_addr_t ddr_low_size, ddr_high_size;
- qemu_irq gic_spi[GIC_NUM_SPI_INTR];
+ qemu_irq gic_spi[XLNX_ZYNQMP_GIC_NUM_SPI_INTR];
Error *err = NULL;
ram_size = memory_region_size(s->ddr_ram);
@@ -502,13 +526,22 @@
g_free(ocm_name);
}
- qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32);
+ qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq",
+ XLNX_ZYNQMP_GIC_NUM_SPI_INTR + 32);
qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2);
qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", num_apus);
qdev_prop_set_bit(DEVICE(&s->gic), "has-security-extensions", s->secure);
qdev_prop_set_bit(DEVICE(&s->gic),
"has-virtualization-extensions", s->virt);
+ if (num_rpus) {
+ qdev_prop_set_uint32(DEVICE(&s->rpu_gic), "num-irq",
+ XLNX_ZYNQMP_GIC_NUM_SPI_INTR + 32);
+ qdev_prop_set_uint32(DEVICE(&s->rpu_gic), "revision", 1);
+ qdev_prop_set_uint32(DEVICE(&s->rpu_gic), "num-cpu", num_rpus);
+ qdev_prop_set_uint32(DEVICE(&s->rpu_gic), "first-cpu-index", 4);
+ }
+
qdev_realize(DEVICE(&s->apu_cluster), NULL, &error_fatal);
/* Realize APUs before realizing the GIC. KVM requires this. */
@@ -608,13 +641,63 @@
return;
}
+ if (num_rpus) {
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->rpu_gic), errp)) {
+ return;
+ }
+
+ for (i = 0; i < num_rpus; i++) {
+ qemu_irq irq;
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rpu_gic), i + 1,
+ GIC_BASE_ADDR + i * 0x1000);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rpu_gic), i,
+ qdev_get_gpio_in(DEVICE(&s->rpu_cpu[i]),
+ ARM_CPU_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rpu_gic), i + num_rpus,
+ qdev_get_gpio_in(DEVICE(&s->rpu_cpu[i]),
+ ARM_CPU_FIQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rpu_gic), i + num_rpus * 2,
+ qdev_get_gpio_in(DEVICE(&s->rpu_cpu[i]),
+ ARM_CPU_VIRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rpu_gic), i + num_rpus * 3,
+ qdev_get_gpio_in(DEVICE(&s->rpu_cpu[i]),
+ ARM_CPU_VFIQ));
+ irq = qdev_get_gpio_in(DEVICE(&s->rpu_gic),
+ arm_gic_ppi_index(i, ARM_PHYS_TIMER_PPI));
+ qdev_connect_gpio_out(DEVICE(&s->rpu_cpu[i]), GTIMER_PHYS, irq);
+ irq = qdev_get_gpio_in(DEVICE(&s->rpu_gic),
+ arm_gic_ppi_index(i, ARM_VIRT_TIMER_PPI));
+ qdev_connect_gpio_out(DEVICE(&s->rpu_cpu[i]), GTIMER_VIRT, irq);
+ irq = qdev_get_gpio_in(DEVICE(&s->rpu_gic),
+ arm_gic_ppi_index(i, ARM_HYP_TIMER_PPI));
+ qdev_connect_gpio_out(DEVICE(&s->rpu_cpu[i]), GTIMER_HYP, irq);
+ irq = qdev_get_gpio_in(DEVICE(&s->rpu_gic),
+ arm_gic_ppi_index(i, ARM_SEC_TIMER_PPI));
+ qdev_connect_gpio_out(DEVICE(&s->rpu_cpu[i]), GTIMER_SEC, irq);
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rpu_gic), 0, GIC_BASE_ADDR);
+ }
+
if (!s->boot_cpu_ptr) {
error_setg(errp, "ZynqMP Boot cpu %s not found", boot_cpu);
return;
}
- for (i = 0; i < GIC_NUM_SPI_INTR; i++) {
- gic_spi[i] = qdev_get_gpio_in(DEVICE(&s->gic), i);
+ for (i = 0; i < XLNX_ZYNQMP_GIC_NUM_SPI_INTR; i++) {
+ if (num_rpus) {
+ DeviceState *splitter = DEVICE(&s->splitter[i]);
+ qdev_prop_set_uint16(splitter, "num-lines", 2);
+ qdev_realize(splitter, NULL, &error_abort);
+ gic_spi[i] = qdev_get_gpio_in(splitter, 0);
+ qdev_connect_gpio_out(splitter, 0,
+ qdev_get_gpio_in(DEVICE(&s->gic), i));
+ qdev_connect_gpio_out(splitter, 1,
+ qdev_get_gpio_in(DEVICE(&s->rpu_gic), i));
+ } else {
+ gic_spi[i] = qdev_get_gpio_in(DEVICE(&s->gic), i);
+ }
}
for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 524af6f..477661a 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -1242,7 +1242,7 @@
* that the instruction cache for that new region is clear, so that the
* CPU definitely fetches its instructions from the just written data.
*/
- cpu_flush_icache_range(rom->addr, rom->datasize);
+ address_space_flush_icache_range(rom->as, rom->addr, rom->datasize);
trace_loader_write_rom(rom->name, rom->addr, rom->datasize, rom->isrom);
}
diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c
index b8d27f5..590ffde 100644
--- a/hw/gpio/zaurus.c
+++ b/hw/gpio/zaurus.c
@@ -18,7 +18,6 @@
#include "qemu/osdep.h"
#include "hw/irq.h"
-#include "hw/arm/sharpsl.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
@@ -265,44 +264,3 @@
}
type_init(scoop_register_types)
-
-/* Write the bootloader parameters memory area. */
-
-#define MAGIC_CHG(a, b, c, d) ((d << 24) | (c << 16) | (b << 8) | a)
-
-static struct QEMU_PACKED sl_param_info {
- uint32_t comadj_keyword;
- int32_t comadj;
-
- uint32_t uuid_keyword;
- char uuid[16];
-
- uint32_t touch_keyword;
- int32_t touch_xp;
- int32_t touch_yp;
- int32_t touch_xd;
- int32_t touch_yd;
-
- uint32_t adadj_keyword;
- int32_t adadj;
-
- uint32_t phad_keyword;
- int32_t phadadj;
-} zaurus_bootparam = {
- .comadj_keyword = MAGIC_CHG('C', 'M', 'A', 'D'),
- .comadj = 125,
- .uuid_keyword = MAGIC_CHG('U', 'U', 'I', 'D'),
- .uuid = { -1 },
- .touch_keyword = MAGIC_CHG('T', 'U', 'C', 'H'),
- .touch_xp = -1,
- .adadj_keyword = MAGIC_CHG('B', 'V', 'A', 'D'),
- .adadj = -1,
- .phad_keyword = MAGIC_CHG('P', 'H', 'A', 'D'),
- .phadadj = 0x01,
-};
-
-void sl_bootparam_write(hwaddr ptr)
-{
- cpu_physical_memory_write(ptr, &zaurus_bootparam,
- sizeof(struct sl_param_info));
-}
diff --git a/hw/hyperv/hv-balloon-our_range_memslots.c b/hw/hyperv/hv-balloon-our_range_memslots.c
index 1505a39..1fc95e1 100644
--- a/hw/hyperv/hv-balloon-our_range_memslots.c
+++ b/hw/hyperv/hv-balloon-our_range_memslots.c
@@ -8,6 +8,7 @@
*/
#include "qemu/osdep.h"
+#include "system/ramblock.h"
#include "hv-balloon-internal.h"
#include "hv-balloon-our_range_memslots.h"
#include "trace.h"
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index e438d8c..2d0df6d 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -436,7 +436,7 @@
s->cpu = g_new0(GICv3CPUState, s->num_cpu);
for (i = 0; i < s->num_cpu; i++) {
- CPUState *cpu = qemu_get_cpu(i);
+ CPUState *cpu = qemu_get_cpu(s->first_cpu_idx + i);
uint64_t cpu_affid;
s->cpu[i].cpu = cpu;
@@ -622,6 +622,7 @@
redist_region_count, qdev_prop_uint32, uint32_t),
DEFINE_PROP_LINK("sysmem", GICv3State, dma, TYPE_MEMORY_REGION,
MemoryRegion *),
+ DEFINE_PROP_UINT32("first-cpu-index", GICv3State, first_cpu_idx, 0),
};
static void arm_gicv3_common_class_init(ObjectClass *klass, const void *data)
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 72e91f9..2e6c1f7 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -3024,7 +3024,7 @@
int i;
for (i = 0; i < s->num_cpu; i++) {
- ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
+ ARMCPU *cpu = ARM_CPU(qemu_get_cpu(s->first_cpu_idx + i));
GICv3CPUState *cs = &s->cpu[i];
/*
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index 0cd14d7..9829e21 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -821,6 +821,12 @@
return;
}
+ if (s->first_cpu_idx != 0) {
+ error_setg(errp, "Non-zero first-cpu-idx is unsupported with the "
+ "in-kernel GIC");
+ return;
+ }
+
gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL);
for (i = 0; i < s->num_cpu; i++) {
diff --git a/hw/misc/xlnx-versal-crl.c b/hw/misc/xlnx-versal-crl.c
index 08ff2fc..10e6af0 100644
--- a/hw/misc/xlnx-versal-crl.c
+++ b/hw/misc/xlnx-versal-crl.c
@@ -1,16 +1,13 @@
/*
* QEMU model of the Clock-Reset-LPD (CRL).
*
- * Copyright (c) 2022 Advanced Micro Devices, Inc.
+ * Copyright (c) 2022-2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Written by Edgar E. Iglesias <edgar.iglesias@amd.com>
*/
#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/log.h"
-#include "qemu/bitops.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
@@ -58,90 +55,144 @@
return 0;
}
-static void crl_reset_dev(XlnxVersalCRL *s, DeviceState *dev,
- bool rst_old, bool rst_new)
+static DeviceState **versal_decode_periph_rst(XlnxVersalCRLBase *s,
+ hwaddr addr, size_t *count)
{
- device_cold_reset(dev);
-}
+ size_t idx;
+ XlnxVersalCRL *xvc = XLNX_VERSAL_CRL(s);
-static void crl_reset_cpu(XlnxVersalCRL *s, ARMCPU *armcpu,
- bool rst_old, bool rst_new)
-{
- if (rst_new) {
- arm_set_cpu_off(arm_cpu_mp_affinity(armcpu));
- } else {
- arm_set_cpu_on_and_reset(arm_cpu_mp_affinity(armcpu));
+ *count = 1;
+
+ switch (addr) {
+ case A_RST_CPU_R5:
+ return xvc->cfg.rpu;
+
+ case A_RST_ADMA:
+ /* A single register fans out to all DMA reset inputs */
+ *count = ARRAY_SIZE(xvc->cfg.adma);
+ return xvc->cfg.adma;
+
+ case A_RST_UART0 ... A_RST_UART1:
+ idx = (addr - A_RST_UART0) / sizeof(uint32_t);
+ return xvc->cfg.uart + idx;
+
+ case A_RST_GEM0 ... A_RST_GEM1:
+ idx = (addr - A_RST_GEM0) / sizeof(uint32_t);
+ return xvc->cfg.gem + idx;
+
+ case A_RST_USB0:
+ return xvc->cfg.usb;
+
+ default:
+ /* invalid or unimplemented */
+ g_assert_not_reached();
}
}
-#define REGFIELD_RESET(type, s, reg, f, new_val, dev) { \
- bool old_f = ARRAY_FIELD_EX32((s)->regs, reg, f); \
- bool new_f = FIELD_EX32(new_val, reg, f); \
- \
- /* Detect edges. */ \
- if (dev && old_f != new_f) { \
- crl_reset_ ## type(s, dev, old_f, new_f); \
- } \
-}
-
-static uint64_t crl_rst_r5_prew(RegisterInfo *reg, uint64_t val64)
+static DeviceState **versal2_decode_periph_rst(XlnxVersalCRLBase *s,
+ hwaddr addr, size_t *count)
{
- XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
+ size_t idx;
+ XlnxVersal2CRL *xvc = XLNX_VERSAL2_CRL(s);
- REGFIELD_RESET(cpu, s, RST_CPU_R5, RESET_CPU0, val64, s->cfg.cpu_r5[0]);
- REGFIELD_RESET(cpu, s, RST_CPU_R5, RESET_CPU1, val64, s->cfg.cpu_r5[1]);
- return val64;
-}
+ *count = 1;
-static uint64_t crl_rst_adma_prew(RegisterInfo *reg, uint64_t val64)
-{
- XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
- int i;
+ switch (addr) {
+ case A_VERSAL2_RST_RPU_A ... A_VERSAL2_RST_RPU_E:
+ idx = (addr - A_VERSAL2_RST_RPU_A) / sizeof(uint32_t);
+ idx *= 2; /* two RPUs per RST_RPU_x registers */
+ return xvc->cfg.rpu + idx;
- /* A single register fans out to all ADMA reset inputs. */
- for (i = 0; i < ARRAY_SIZE(s->cfg.adma); i++) {
- REGFIELD_RESET(dev, s, RST_ADMA, RESET, val64, s->cfg.adma[i]);
+ case A_VERSAL2_RST_ADMA:
+ /* A single register fans out to all DMA reset inputs */
+ *count = ARRAY_SIZE(xvc->cfg.adma);
+ return xvc->cfg.adma;
+
+ case A_VERSAL2_RST_SDMA:
+ *count = ARRAY_SIZE(xvc->cfg.sdma);
+ return xvc->cfg.sdma;
+
+ case A_VERSAL2_RST_UART0 ... A_VERSAL2_RST_UART1:
+ idx = (addr - A_VERSAL2_RST_UART0) / sizeof(uint32_t);
+ return xvc->cfg.uart + idx;
+
+ case A_VERSAL2_RST_GEM0 ... A_VERSAL2_RST_GEM1:
+ idx = (addr - A_VERSAL2_RST_GEM0) / sizeof(uint32_t);
+ return xvc->cfg.gem + idx;
+
+ case A_VERSAL2_RST_USB0 ... A_VERSAL2_RST_USB1:
+ idx = (addr - A_VERSAL2_RST_USB0) / sizeof(uint32_t);
+ return xvc->cfg.usb + idx;
+
+ case A_VERSAL2_RST_CAN0 ... A_VERSAL2_RST_CAN3:
+ idx = (addr - A_VERSAL2_RST_CAN0) / sizeof(uint32_t);
+ return xvc->cfg.can + idx;
+
+ default:
+ /* invalid or unimplemented */
+ return NULL;
}
+}
+
+static uint64_t crl_rst_cpu_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalCRLBase *s = XLNX_VERSAL_CRL_BASE(reg->opaque);
+ XlnxVersalCRLBaseClass *xvcbc = XLNX_VERSAL_CRL_BASE_GET_CLASS(s);
+ DeviceState **dev;
+ size_t i, count;
+
+ dev = xvcbc->decode_periph_rst(s, reg->access->addr, &count);
+
+ for (i = 0; i < 2; i++) {
+ bool prev, new;
+ uint64_t aff;
+
+ prev = extract32(s->regs[reg->access->addr / 4], i, 1);
+ new = extract32(val64, i, 1);
+
+ if (prev == new) {
+ continue;
+ }
+
+ aff = arm_cpu_mp_affinity(ARM_CPU(dev[i]));
+
+ if (new) {
+ arm_set_cpu_off(aff);
+ } else {
+ arm_set_cpu_on_and_reset(aff);
+ }
+ }
+
return val64;
}
-static uint64_t crl_rst_uart0_prew(RegisterInfo *reg, uint64_t val64)
+static uint64_t crl_rst_dev_prew(RegisterInfo *reg, uint64_t val64)
{
- XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
+ XlnxVersalCRLBase *s = XLNX_VERSAL_CRL_BASE(reg->opaque);
+ XlnxVersalCRLBaseClass *xvcbc = XLNX_VERSAL_CRL_BASE_GET_CLASS(s);
+ DeviceState **dev;
+ bool prev, new;
+ size_t i, count;
- REGFIELD_RESET(dev, s, RST_UART0, RESET, val64, s->cfg.uart[0]);
- return val64;
-}
+ dev = xvcbc->decode_periph_rst(s, reg->access->addr, &count);
-static uint64_t crl_rst_uart1_prew(RegisterInfo *reg, uint64_t val64)
-{
- XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
+ if (dev == NULL) {
+ return val64;
+ }
- REGFIELD_RESET(dev, s, RST_UART1, RESET, val64, s->cfg.uart[1]);
- return val64;
-}
+ prev = s->regs[reg->access->addr / 4] & 0x1;
+ new = val64 & 0x1;
-static uint64_t crl_rst_gem0_prew(RegisterInfo *reg, uint64_t val64)
-{
- XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
+ if (prev == new) {
+ return val64;
+ }
- REGFIELD_RESET(dev, s, RST_GEM0, RESET, val64, s->cfg.gem[0]);
- return val64;
-}
+ for (i = 0; i < count; i++) {
+ if (dev[i]) {
+ device_cold_reset(dev[i]);
+ }
+ }
-static uint64_t crl_rst_gem1_prew(RegisterInfo *reg, uint64_t val64)
-{
- XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
-
- REGFIELD_RESET(dev, s, RST_GEM1, RESET, val64, s->cfg.gem[1]);
- return val64;
-}
-
-static uint64_t crl_rst_usb_prew(RegisterInfo *reg, uint64_t val64)
-{
- XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
-
- REGFIELD_RESET(dev, s, RST_USB0, RESET, val64, s->cfg.usb);
return val64;
}
@@ -247,27 +298,27 @@
},{ .name = "RST_CPU_R5", .addr = A_RST_CPU_R5,
.reset = 0x17,
.rsvd = 0x8,
- .pre_write = crl_rst_r5_prew,
+ .pre_write = crl_rst_cpu_prew,
},{ .name = "RST_ADMA", .addr = A_RST_ADMA,
.reset = 0x1,
- .pre_write = crl_rst_adma_prew,
+ .pre_write = crl_rst_dev_prew,
},{ .name = "RST_GEM0", .addr = A_RST_GEM0,
.reset = 0x1,
- .pre_write = crl_rst_gem0_prew,
+ .pre_write = crl_rst_dev_prew,
},{ .name = "RST_GEM1", .addr = A_RST_GEM1,
.reset = 0x1,
- .pre_write = crl_rst_gem1_prew,
+ .pre_write = crl_rst_dev_prew,
},{ .name = "RST_SPARE", .addr = A_RST_SPARE,
.reset = 0x1,
},{ .name = "RST_USB0", .addr = A_RST_USB0,
.reset = 0x1,
- .pre_write = crl_rst_usb_prew,
+ .pre_write = crl_rst_dev_prew,
},{ .name = "RST_UART0", .addr = A_RST_UART0,
.reset = 0x1,
- .pre_write = crl_rst_uart0_prew,
+ .pre_write = crl_rst_dev_prew,
},{ .name = "RST_UART1", .addr = A_RST_UART1,
.reset = 0x1,
- .pre_write = crl_rst_uart1_prew,
+ .pre_write = crl_rst_dev_prew,
},{ .name = "RST_SPI0", .addr = A_RST_SPI0,
.reset = 0x1,
},{ .name = "RST_SPI1", .addr = A_RST_SPI1,
@@ -301,7 +352,247 @@
}
};
-static void crl_reset_enter(Object *obj, ResetType type)
+static const RegisterAccessInfo versal2_crl_regs_info[] = {
+ { .name = "ERR_CTRL", .addr = A_VERSAL2_ERR_CTRL,
+ .reset = 0x1,
+ },{ .name = "WPROT", .addr = A_VERSAL2_WPROT,
+ },{ .name = "RPLL_CTRL", .addr = A_VERSAL2_RPLL_CTRL,
+ .reset = 0x24809,
+ .rsvd = 0xf88c00f6,
+ },{ .name = "RPLL_CFG", .addr = A_VERSAL2_RPLL_CFG,
+ .reset = 0x7e5dcc6c,
+ .rsvd = 0x1801210,
+ },{ .name = "FLXPLL_CTRL", .addr = A_VERSAL2_FLXPLL_CTRL,
+ .reset = 0x24809,
+ .rsvd = 0xf88c00f6,
+ },{ .name = "FLXPLL_CFG", .addr = A_VERSAL2_FLXPLL_CFG,
+ .reset = 0x7e5dcc6c,
+ .rsvd = 0x1801210,
+ },{ .name = "PLL_STATUS", .addr = A_VERSAL2_PLL_STATUS,
+ .reset = 0xf,
+ .rsvd = 0xf0,
+ .ro = 0xf,
+ },{ .name = "RPLL_TO_XPD_CTRL", .addr = A_VERSAL2_RPLL_TO_XPD_CTRL,
+ .reset = 0x2000100,
+ .rsvd = 0xfdfc00ff,
+ },{ .name = "LPX_TOP_SWITCH_CTRL", .addr = A_VERSAL2_LPX_TOP_SWITCH_CTRL,
+ .reset = 0xe000300,
+ .rsvd = 0xf1fc00f8,
+ },{ .name = "LPX_LSBUS_CLK_CTRL", .addr = A_VERSAL2_LPX_LSBUS_CLK_CTRL,
+ .reset = 0x2000800,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "RPU_CLK_CTRL", .addr = A_VERSAL2_RPU_CLK_CTRL,
+ .reset = 0x3f00300,
+ .rsvd = 0xfc0c00f8,
+ },{ .name = "OCM_CLK_CTRL", .addr = A_VERSAL2_OCM_CLK_CTRL,
+ .reset = 0x1e00000,
+ .rsvd = 0xfe1fffff,
+ },{ .name = "IOU_SWITCH_CLK_CTRL", .addr = A_VERSAL2_IOU_SWITCH_CLK_CTRL,
+ .reset = 0x2000500,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "GEM0_REF_CTRL", .addr = A_VERSAL2_GEM0_REF_CTRL,
+ .reset = 0xe000a00,
+ .rsvd = 0xf1fc00f8,
+ },{ .name = "GEM1_REF_CTRL", .addr = A_VERSAL2_GEM1_REF_CTRL,
+ .reset = 0xe000a00,
+ .rsvd = 0xf1fc00f8,
+ },{ .name = "GEM_TSU_REF_CLK_CTRL", .addr = A_VERSAL2_GEM_TSU_REF_CLK_CTRL,
+ .reset = 0x300,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "USB0_BUS_REF_CLK_CTRL",
+ .addr = A_VERSAL2_USB0_BUS_REF_CLK_CTRL,
+ .reset = 0x2001900,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "USB1_BUS_REF_CLK_CTRL",
+ .addr = A_VERSAL2_USB1_BUS_REF_CLK_CTRL,
+ .reset = 0x2001900,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "UART0_REF_CLK_CTRL", .addr = A_VERSAL2_UART0_REF_CLK_CTRL,
+ .reset = 0xc00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "UART1_REF_CLK_CTRL", .addr = A_VERSAL2_UART1_REF_CLK_CTRL,
+ .reset = 0xc00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "SPI0_REF_CLK_CTRL", .addr = A_VERSAL2_SPI0_REF_CLK_CTRL,
+ .reset = 0x600,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "SPI1_REF_CLK_CTRL", .addr = A_VERSAL2_SPI1_REF_CLK_CTRL,
+ .reset = 0x600,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "CAN0_REF_2X_CTRL", .addr = A_VERSAL2_CAN0_REF_2X_CTRL,
+ .reset = 0xc00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "CAN1_REF_2X_CTRL", .addr = A_VERSAL2_CAN1_REF_2X_CTRL,
+ .reset = 0xc00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "CAN2_REF_2X_CTRL", .addr = A_VERSAL2_CAN2_REF_2X_CTRL,
+ .reset = 0xc00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "CAN3_REF_2X_CTRL", .addr = A_VERSAL2_CAN3_REF_2X_CTRL,
+ .reset = 0xc00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "I3C0_REF_CTRL", .addr = A_VERSAL2_I3C0_REF_CTRL,
+ .reset = 0x2000c00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "I3C1_REF_CTRL", .addr = A_VERSAL2_I3C1_REF_CTRL,
+ .reset = 0x2000c00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "I3C2_REF_CTRL", .addr = A_VERSAL2_I3C2_REF_CTRL,
+ .reset = 0x2000c00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "I3C3_REF_CTRL", .addr = A_VERSAL2_I3C3_REF_CTRL,
+ .reset = 0x2000c00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "I3C4_REF_CTRL", .addr = A_VERSAL2_I3C4_REF_CTRL,
+ .reset = 0x2000c00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "I3C5_REF_CTRL", .addr = A_VERSAL2_I3C5_REF_CTRL,
+ .reset = 0x2000c00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "I3C6_REF_CTRL", .addr = A_VERSAL2_I3C6_REF_CTRL,
+ .reset = 0x2000c00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "I3C7_REF_CTRL", .addr = A_VERSAL2_I3C7_REF_CTRL,
+ .reset = 0x2000c00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "DBG_LPX_CTRL", .addr = A_VERSAL2_DBG_LPX_CTRL,
+ .reset = 0x300,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "TIMESTAMP_REF_CTRL", .addr = A_VERSAL2_TIMESTAMP_REF_CTRL,
+ .reset = 0x2000c00,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "SAFETY_CHK", .addr = A_VERSAL2_SAFETY_CHK,
+ },{ .name = "ASU_CLK_CTRL", .addr = A_VERSAL2_ASU_CLK_CTRL,
+ .reset = 0x2000f04,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "DBG_TSTMP_CLK_CTRL", .addr = A_VERSAL2_DBG_TSTMP_CLK_CTRL,
+ .reset = 0x300,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "MMI_TOPSW_CLK_CTRL", .addr = A_VERSAL2_MMI_TOPSW_CLK_CTRL,
+ .reset = 0x2000300,
+ .rsvd = 0xfdfc00f8,
+ },{ .name = "WWDT_PLL_CLK_CTRL", .addr = A_VERSAL2_WWDT_PLL_CLK_CTRL,
+ .reset = 0xc00,
+ .rsvd = 0xfffc00f8,
+ },{ .name = "RCLK_CTRL", .addr = A_VERSAL2_RCLK_CTRL,
+ .rsvd = 0xc040,
+ },{ .name = "RST_RPU_A", .addr = A_VERSAL2_RST_RPU_A,
+ .reset = 0x10303,
+ .rsvd = 0xfffefcfc,
+ .pre_write = crl_rst_cpu_prew,
+ },{ .name = "RST_RPU_B", .addr = A_VERSAL2_RST_RPU_B,
+ .reset = 0x10303,
+ .rsvd = 0xfffefcfc,
+ .pre_write = crl_rst_cpu_prew,
+ },{ .name = "RST_RPU_C", .addr = A_VERSAL2_RST_RPU_C,
+ .reset = 0x10303,
+ .rsvd = 0xfffefcfc,
+ .pre_write = crl_rst_cpu_prew,
+ },{ .name = "RST_RPU_D", .addr = A_VERSAL2_RST_RPU_D,
+ .reset = 0x10303,
+ .rsvd = 0xfffefcfc,
+ .pre_write = crl_rst_cpu_prew,
+ },{ .name = "RST_RPU_E", .addr = A_VERSAL2_RST_RPU_E,
+ .reset = 0x10303,
+ .rsvd = 0xfffefcfc,
+ .pre_write = crl_rst_cpu_prew,
+ },{ .name = "RST_RPU_GD_0", .addr = A_VERSAL2_RST_RPU_GD_0,
+ .reset = 0x3,
+ },{ .name = "RST_RPU_GD_1", .addr = A_VERSAL2_RST_RPU_GD_1,
+ .reset = 0x3,
+ },{ .name = "RST_ASU_GD", .addr = A_VERSAL2_RST_ASU_GD,
+ .reset = 0x3,
+ },{ .name = "RST_ADMA", .addr = A_VERSAL2_RST_ADMA,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_SDMA", .addr = A_VERSAL2_RST_SDMA,
+ .pre_write = crl_rst_dev_prew,
+ .reset = 0x1,
+ },{ .name = "RST_GEM0", .addr = A_VERSAL2_RST_GEM0,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_GEM1", .addr = A_VERSAL2_RST_GEM1,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_USB0", .addr = A_VERSAL2_RST_USB0,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_USB1", .addr = A_VERSAL2_RST_USB1,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_UART0", .addr = A_VERSAL2_RST_UART0,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_UART1", .addr = A_VERSAL2_RST_UART1,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_SPI0", .addr = A_VERSAL2_RST_SPI0,
+ .reset = 0x1,
+ },{ .name = "RST_SPI1", .addr = A_VERSAL2_RST_SPI1,
+ .reset = 0x1,
+ },{ .name = "RST_CAN0", .addr = A_VERSAL2_RST_CAN0,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_CAN1", .addr = A_VERSAL2_RST_CAN1,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_CAN2", .addr = A_VERSAL2_RST_CAN2,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_CAN3", .addr = A_VERSAL2_RST_CAN3,
+ .reset = 0x1,
+ .pre_write = crl_rst_dev_prew,
+ },{ .name = "RST_I3C0", .addr = A_VERSAL2_RST_I3C0,
+ .reset = 0x1,
+ },{ .name = "RST_I3C1", .addr = A_VERSAL2_RST_I3C1,
+ .reset = 0x1,
+ },{ .name = "RST_I3C2", .addr = A_VERSAL2_RST_I3C2,
+ .reset = 0x1,
+ },{ .name = "RST_I3C3", .addr = A_VERSAL2_RST_I3C3,
+ .reset = 0x1,
+ },{ .name = "RST_I3C4", .addr = A_VERSAL2_RST_I3C4,
+ .reset = 0x1,
+ },{ .name = "RST_I3C5", .addr = A_VERSAL2_RST_I3C5,
+ .reset = 0x1,
+ },{ .name = "RST_I3C6", .addr = A_VERSAL2_RST_I3C6,
+ .reset = 0x1,
+ },{ .name = "RST_I3C7", .addr = A_VERSAL2_RST_I3C7,
+ .reset = 0x1,
+ },{ .name = "RST_DBG_LPX", .addr = A_VERSAL2_RST_DBG_LPX,
+ .reset = 0x3,
+ .rsvd = 0xfc,
+ },{ .name = "RST_GPIO", .addr = A_VERSAL2_RST_GPIO,
+ .reset = 0x1,
+ },{ .name = "RST_TTC", .addr = A_VERSAL2_RST_TTC,
+ .reset = 0xff,
+ },{ .name = "RST_TIMESTAMP", .addr = A_VERSAL2_RST_TIMESTAMP,
+ .reset = 0x1,
+ },{ .name = "RST_SWDT0", .addr = A_VERSAL2_RST_SWDT0,
+ .reset = 0x1,
+ },{ .name = "RST_SWDT1", .addr = A_VERSAL2_RST_SWDT1,
+ .reset = 0x1,
+ },{ .name = "RST_SWDT2", .addr = A_VERSAL2_RST_SWDT2,
+ .reset = 0x1,
+ },{ .name = "RST_SWDT3", .addr = A_VERSAL2_RST_SWDT3,
+ .reset = 0x1,
+ },{ .name = "RST_SWDT4", .addr = A_VERSAL2_RST_SWDT4,
+ .reset = 0x1,
+ },{ .name = "RST_IPI", .addr = A_VERSAL2_RST_IPI,
+ },{ .name = "RST_SYSMON", .addr = A_VERSAL2_RST_SYSMON,
+ },{ .name = "ASU_MB_RST_MODE", .addr = A_VERSAL2_ASU_MB_RST_MODE,
+ .reset = 0x1,
+ .rsvd = 0xf8,
+ },{ .name = "FPX_TOPSW_MUX_CTRL", .addr = A_VERSAL2_FPX_TOPSW_MUX_CTRL,
+ .reset = 0x1,
+ },{ .name = "RST_FPX", .addr = A_VERSAL2_RST_FPX,
+ .reset = 0x3,
+ },{ .name = "RST_MMI", .addr = A_VERSAL2_RST_MMI,
+ .reset = 0x1,
+ },{ .name = "RST_OCM", .addr = A_VERSAL2_RST_OCM,
+ }
+};
+
+static void versal_crl_reset_enter(Object *obj, ResetType type)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
unsigned int i;
@@ -311,7 +602,17 @@
}
}
-static void crl_reset_hold(Object *obj, ResetType type)
+static void versal2_crl_reset_enter(Object *obj, ResetType type)
+{
+ XlnxVersal2CRL *s = XLNX_VERSAL2_CRL(obj);
+ size_t i;
+
+ for (i = 0; i < VERSAL2_CRL_R_MAX; ++i) {
+ register_reset(&s->regs_info[i]);
+ }
+}
+
+static void versal_crl_reset_hold(Object *obj, ResetType type)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
@@ -328,25 +629,27 @@
},
};
-static void crl_init(Object *obj)
+static void versal_crl_init(Object *obj)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
+ XlnxVersalCRLBase *xvcb = XLNX_VERSAL_CRL_BASE(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
int i;
- s->reg_array =
+ xvcb->reg_array =
register_init_block32(DEVICE(obj), crl_regs_info,
ARRAY_SIZE(crl_regs_info),
s->regs_info, s->regs,
&crl_ops,
XLNX_VERSAL_CRL_ERR_DEBUG,
CRL_R_MAX * 4);
- sysbus_init_mmio(sbd, &s->reg_array->mem);
+ xvcb->regs = s->regs;
+ sysbus_init_mmio(sbd, &xvcb->reg_array->mem);
sysbus_init_irq(sbd, &s->irq);
- for (i = 0; i < ARRAY_SIZE(s->cfg.cpu_r5); ++i) {
- object_property_add_link(obj, "cpu_r5[*]", TYPE_ARM_CPU,
- (Object **)&s->cfg.cpu_r5[i],
+ for (i = 0; i < ARRAY_SIZE(s->cfg.rpu); ++i) {
+ object_property_add_link(obj, "rpu[*]", TYPE_ARM_CPU,
+ (Object **)&s->cfg.rpu[i],
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_STRONG);
}
@@ -372,19 +675,88 @@
OBJ_PROP_LINK_STRONG);
}
- object_property_add_link(obj, "usb", TYPE_DEVICE,
- (Object **)&s->cfg.gem[i],
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_STRONG);
+ for (i = 0; i < ARRAY_SIZE(s->cfg.usb); ++i) {
+ object_property_add_link(obj, "usb[*]", TYPE_DEVICE,
+ (Object **)&s->cfg.usb[i],
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+ }
+}
+
+static void versal2_crl_init(Object *obj)
+{
+ XlnxVersal2CRL *s = XLNX_VERSAL2_CRL(obj);
+ XlnxVersalCRLBase *xvcb = XLNX_VERSAL_CRL_BASE(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ size_t i;
+
+ xvcb->reg_array = register_init_block32(DEVICE(obj), versal2_crl_regs_info,
+ ARRAY_SIZE(versal2_crl_regs_info),
+ s->regs_info, s->regs,
+ &crl_ops,
+ XLNX_VERSAL_CRL_ERR_DEBUG,
+ VERSAL2_CRL_R_MAX * 4);
+ xvcb->regs = s->regs;
+
+ sysbus_init_mmio(sbd, &xvcb->reg_array->mem);
+
+ for (i = 0; i < ARRAY_SIZE(s->cfg.rpu); ++i) {
+ object_property_add_link(obj, "rpu[*]", TYPE_ARM_CPU,
+ (Object **)&s->cfg.rpu[i],
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->cfg.adma); ++i) {
+ object_property_add_link(obj, "adma[*]", TYPE_DEVICE,
+ (Object **)&s->cfg.adma[i],
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->cfg.sdma); ++i) {
+ object_property_add_link(obj, "sdma[*]", TYPE_DEVICE,
+ (Object **)&s->cfg.sdma[i],
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->cfg.uart); ++i) {
+ object_property_add_link(obj, "uart[*]", TYPE_DEVICE,
+ (Object **)&s->cfg.uart[i],
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->cfg.gem); ++i) {
+ object_property_add_link(obj, "gem[*]", TYPE_DEVICE,
+ (Object **)&s->cfg.gem[i],
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->cfg.usb); ++i) {
+ object_property_add_link(obj, "usb[*]", TYPE_DEVICE,
+ (Object **)&s->cfg.usb[i],
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->cfg.can); ++i) {
+ object_property_add_link(obj, "can[*]", TYPE_DEVICE,
+ (Object **)&s->cfg.can[i],
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+ }
}
static void crl_finalize(Object *obj)
{
- XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
+ XlnxVersalCRLBase *s = XLNX_VERSAL_CRL_BASE(obj);
register_finalize_block(s->reg_array);
}
-static const VMStateDescription vmstate_crl = {
+static const VMStateDescription vmstate_versal_crl = {
.name = TYPE_XLNX_VERSAL_CRL,
.version_id = 1,
.minimum_version_id = 1,
@@ -394,29 +766,69 @@
}
};
-static void crl_class_init(ObjectClass *klass, const void *data)
+static const VMStateDescription vmstate_versal2_crl = {
+ .name = TYPE_XLNX_VERSAL2_CRL,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, XlnxVersal2CRL, VERSAL2_CRL_R_MAX),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static void versal_crl_class_init(ObjectClass *klass, const void *data)
{
- ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
+ XlnxVersalCRLBaseClass *xvcc = XLNX_VERSAL_CRL_BASE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
- dc->vmsd = &vmstate_crl;
-
- rc->phases.enter = crl_reset_enter;
- rc->phases.hold = crl_reset_hold;
+ dc->vmsd = &vmstate_versal_crl;
+ rc->phases.enter = versal_crl_reset_enter;
+ rc->phases.hold = versal_crl_reset_hold;
+ xvcc->decode_periph_rst = versal_decode_periph_rst;
}
-static const TypeInfo crl_info = {
- .name = TYPE_XLNX_VERSAL_CRL,
+static void versal2_crl_class_init(ObjectClass *klass, const void *data)
+{
+ XlnxVersalCRLBaseClass *xvcc = XLNX_VERSAL_CRL_BASE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->vmsd = &vmstate_versal2_crl;
+ rc->phases.enter = versal2_crl_reset_enter;
+ xvcc->decode_periph_rst = versal2_decode_periph_rst;
+}
+
+static const TypeInfo crl_base_info = {
+ .name = TYPE_XLNX_VERSAL_CRL_BASE,
.parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(XlnxVersalCRL),
- .class_init = crl_class_init,
- .instance_init = crl_init,
+ .instance_size = sizeof(XlnxVersalCRLBase),
+ .class_size = sizeof(XlnxVersalCRLBaseClass),
.instance_finalize = crl_finalize,
+ .abstract = true,
+};
+
+static const TypeInfo versal_crl_info = {
+ .name = TYPE_XLNX_VERSAL_CRL,
+ .parent = TYPE_XLNX_VERSAL_CRL_BASE,
+ .instance_size = sizeof(XlnxVersalCRL),
+ .instance_init = versal_crl_init,
+ .class_init = versal_crl_class_init,
+};
+
+static const TypeInfo versal2_crl_info = {
+ .name = TYPE_XLNX_VERSAL2_CRL,
+ .parent = TYPE_XLNX_VERSAL_CRL_BASE,
+ .instance_size = sizeof(XlnxVersal2CRL),
+ .instance_init = versal2_crl_init,
+ .class_init = versal2_crl_class_init,
};
static void crl_register_types(void)
{
- type_register_static(&crl_info);
+ type_register_static(&crl_base_info);
+ type_register_static(&versal_crl_info);
+ type_register_static(&versal2_crl_info);
}
type_init(crl_register_types)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 82fb23b..97ab6be 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -77,7 +77,6 @@
#include "hw/virtio/virtio-scsi.h"
#include "hw/virtio/vhost-scsi-common.h"
-#include "system/ram_addr.h"
#include "system/confidential-guest-support.h"
#include "hw/usb.h"
#include "qemu/config-file.h"
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index f2f5722..0f94c19 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -27,7 +27,6 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "system/hw_accel.h"
-#include "system/ram_addr.h"
#include "target/ppc/cpu.h"
#include "target/ppc/mmu-hash64.h"
#include "cpu-models.h"
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 1ac1185..f909555 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -34,7 +34,6 @@
#include "hw/pci/pci_host.h"
#include "hw/ppc/spapr.h"
#include "hw/pci-host/spapr.h"
-#include "system/ram_addr.h"
#include <libfdt.h>
#include "trace.h"
#include "qemu/error-report.h"
diff --git a/hw/remote/memory.c b/hw/remote/memory.c
index 00193a5..8195aa5 100644
--- a/hw/remote/memory.c
+++ b/hw/remote/memory.c
@@ -11,7 +11,6 @@
#include "qemu/osdep.h"
#include "hw/remote/memory.h"
-#include "system/ram_addr.h"
#include "qapi/error.h"
static void remote_sysmem_reset(void)
diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c
index 30ac749..e1a52d2 100644
--- a/hw/remote/proxy-memory-listener.c
+++ b/hw/remote/proxy-memory-listener.c
@@ -12,7 +12,6 @@
#include "qemu/range.h"
#include "system/memory.h"
#include "exec/cpu-common.h"
-#include "system/ram_addr.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/remote/mpqemu-link.h"
diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c
index e1fee36..73df1f6 100644
--- a/hw/s390x/s390-stattrib-kvm.c
+++ b/hw/s390x/s390-stattrib-kvm.c
@@ -10,13 +10,13 @@
*/
#include "qemu/osdep.h"
+#include "exec/target_page.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "migration/qemu-file.h"
#include "hw/s390x/storage-attributes.h"
#include "qemu/error-report.h"
#include "system/kvm.h"
#include "system/memory_mapping.h"
-#include "system/ram_addr.h"
#include "kvm/kvm_s390x.h"
#include "qapi/error.h"
diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c
index 13a678a..aa18537 100644
--- a/hw/s390x/s390-stattrib.c
+++ b/hw/s390x/s390-stattrib.c
@@ -11,12 +11,12 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
+#include "exec/target_page.h"
#include "migration/qemu-file.h"
#include "migration/register.h"
#include "hw/qdev-properties.h"
#include "hw/s390x/storage-attributes.h"
#include "qemu/error-report.h"
-#include "system/ram_addr.h"
#include "qapi/error.h"
#include "qobject/qdict.h"
#include "cpu.h"
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index d0c6e80..ad2c481 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -13,7 +13,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "system/ram_addr.h"
#include "system/confidential-guest-support.h"
#include "hw/boards.h"
#include "hw/s390x/sclp.h"
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 9718564..51e88ba 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -16,6 +16,7 @@
#include "qemu/units.h"
#include "qapi/error.h"
#include "hw/boards.h"
+#include "system/memory.h"
#include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h"
#include "hw/s390x/s390-pci-bus.h"
@@ -303,12 +304,14 @@
SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
SCCBHeader header;
g_autofree SCCB *work_sccb = NULL;
+ AddressSpace *as = CPU(cpu)->as;
+ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
/* first some basic checks on program checks */
if (env->psw.mask & PSW_MASK_PSTATE) {
return -PGM_PRIVILEGED;
}
- if (cpu_physical_memory_is_io(sccb)) {
+ if (address_space_is_io(CPU(cpu)->as, sccb)) {
return -PGM_ADDRESSING;
}
if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa
@@ -317,7 +320,7 @@
}
/* the header contains the actual length of the sccb */
- cpu_physical_memory_read(sccb, &header, sizeof(SCCBHeader));
+ address_space_read(as, sccb, attrs, &header, sizeof(SCCBHeader));
/* Valid sccb sizes */
if (be16_to_cpu(header.length) < sizeof(SCCBHeader)) {
@@ -330,7 +333,7 @@
* the host has checked the values
*/
work_sccb = g_malloc0(be16_to_cpu(header.length));
- cpu_physical_memory_read(sccb, work_sccb, be16_to_cpu(header.length));
+ address_space_read(as, sccb, attrs, work_sccb, be16_to_cpu(header.length));
if (!sclp_command_code_valid(code)) {
work_sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
@@ -344,8 +347,7 @@
sclp_c->execute(sclp, work_sccb, code);
out_write:
- cpu_physical_memory_write(sccb, work_sccb,
- be16_to_cpu(work_sccb->h.length));
+ address_space_write(as, sccb, attrs, work_sccb, be16_to_cpu(header.length));
sclp_c->service_interrupt(sclp, sccb);
diff --git a/hw/vfio/container-legacy.c b/hw/vfio/container-legacy.c
index 629ff23..a3615d7 100644
--- a/hw/vfio/container-legacy.c
+++ b/hw/vfio/container-legacy.c
@@ -25,7 +25,7 @@
#include "hw/vfio/vfio-device.h"
#include "system/address-spaces.h"
#include "system/memory.h"
-#include "system/ram_addr.h"
+#include "system/physmem.h"
#include "qemu/error-report.h"
#include "qemu/range.h"
#include "system/reset.h"
@@ -92,7 +92,7 @@
bitmap = (struct vfio_bitmap *)&unmap->data;
/*
- * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of
+ * physical_memory_set_dirty_lebitmap() supports pages in bitmap of
* qemu_real_host_page_size to mark those dirty. Hence set bitmap_pgsize
* to qemu_real_host_page_size.
*/
@@ -108,7 +108,7 @@
ret = ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, unmap);
if (!ret) {
- cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap,
+ physical_memory_set_dirty_lebitmap(vbmap.bitmap,
iotlb->translated_addr, vbmap.pages);
} else {
error_report("VFIO_UNMAP_DMA with DIRTY_BITMAP : %m");
@@ -266,7 +266,7 @@
range->size = size;
/*
- * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of
+ * physical_memory_set_dirty_lebitmap() supports pages in bitmap of
* qemu_real_host_page_size to mark those dirty. Hence set bitmap's pgsize
* to qemu_real_host_page_size.
*/
@@ -485,7 +485,7 @@
header);
/*
- * cpu_physical_memory_set_dirty_lebitmap() supports pages in bitmap of
+ * physical_memory_set_dirty_lebitmap() supports pages in bitmap of
* qemu_real_host_page_size to mark those dirty.
*/
if (cap_mig->pgsize_bitmap & qemu_real_host_page_size()) {
diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 41de343..9ddec30 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -20,6 +20,7 @@
#include "qemu/error-report.h"
#include "hw/vfio/vfio-container.h"
#include "hw/vfio/vfio-device.h" /* vfio_device_reset_handler */
+#include "system/physmem.h"
#include "system/reset.h"
#include "vfio-helpers.h"
@@ -255,7 +256,7 @@
int ret;
if (!bcontainer->dirty_pages_supported && !all_device_dirty_tracking) {
- cpu_physical_memory_set_dirty_range(translated_addr, size,
+ physical_memory_set_dirty_range(translated_addr, size,
tcg_enabled() ? DIRTY_CLIENTS_ALL :
DIRTY_CLIENTS_NOCODE);
return 0;
@@ -280,7 +281,7 @@
goto out;
}
- dirty_pages = cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap,
+ dirty_pages = physical_memory_set_dirty_lebitmap(vbmap.bitmap,
translated_addr,
vbmap.pages);
diff --git a/hw/vfio/listener.c b/hw/vfio/listener.c
index a2c19a3..c6bb58f 100644
--- a/hw/vfio/listener.c
+++ b/hw/vfio/listener.c
@@ -25,11 +25,11 @@
#endif
#include <linux/vfio.h>
+#include "exec/target_page.h"
#include "hw/vfio/vfio-device.h"
#include "hw/vfio/pci.h"
#include "system/address-spaces.h"
#include "system/memory.h"
-#include "system/ram_addr.h"
#include "hw/hw.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c
index 8d9d68d..0f23681 100644
--- a/hw/vfio/spapr.c
+++ b/hw/vfio/spapr.c
@@ -17,7 +17,6 @@
#include "hw/vfio/vfio-container-legacy.h"
#include "hw/hw.h"
-#include "system/ram_addr.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "trace.h"
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index c120ef3..266a115 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -27,6 +27,7 @@
#include "migration/blocker.h"
#include "migration/qemu-file-types.h"
#include "system/dma.h"
+#include "system/memory.h"
#include "trace.h"
/* enabled until disconnected backend stabilizes */
@@ -455,7 +456,8 @@
hwaddr *plen, bool is_write)
{
if (!vhost_dev_has_iommu(dev)) {
- return cpu_physical_memory_map(addr, plen, is_write);
+ return address_space_map(dev->vdev->dma_as, addr, plen, is_write,
+ MEMTXATTRS_UNSPECIFIED);
} else {
return (void *)(uintptr_t)addr;
}
@@ -466,7 +468,8 @@
hwaddr access_len)
{
if (!vhost_dev_has_iommu(dev)) {
- cpu_physical_memory_unmap(buffer, len, is_write, access_len);
+ address_space_unmap(dev->vdev->dma_as, buffer, len, is_write,
+ access_len);
}
}
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index db787d0..02cdd80 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -23,6 +23,7 @@
#include "hw/qdev-properties.h"
#include "hw/boards.h"
#include "system/balloon.h"
+#include "system/ramblock.h"
#include "hw/virtio/virtio-balloon.h"
#include "system/address-spaces.h"
#include "qapi/error.h"
diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
index c46f6f9..15ba679 100644
--- a/hw/virtio/virtio-mem.c
+++ b/hw/virtio/virtio-mem.c
@@ -17,6 +17,7 @@
#include "qemu/units.h"
#include "system/numa.h"
#include "system/system.h"
+#include "system/ramblock.h"
#include "system/reset.h"
#include "system/runstate.h"
#include "hw/virtio/virtio.h"
@@ -24,7 +25,6 @@
#include "hw/virtio/virtio-mem.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
-#include "system/ram_addr.h"
#include "migration/misc.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index be73753..153ee0a 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -32,6 +32,7 @@
#include "hw/virtio/virtio-access.h"
#include "system/dma.h"
#include "system/iothread.h"
+#include "system/memory.h"
#include "system/runstate.h"
#include "virtio-qmp.h"
@@ -1632,7 +1633,8 @@
* virtqueue_unmap_sg() can't be used). Assumes buffers weren't written to
* yet.
*/
-static void virtqueue_undo_map_desc(unsigned int out_num, unsigned int in_num,
+static void virtqueue_undo_map_desc(AddressSpace *as,
+ unsigned int out_num, unsigned int in_num,
struct iovec *iov)
{
unsigned int i;
@@ -1640,7 +1642,7 @@
for (i = 0; i < out_num + in_num; i++) {
int is_write = i >= out_num;
- cpu_physical_memory_unmap(iov->iov_base, iov->iov_len, is_write, 0);
+ address_space_unmap(as, iov->iov_base, iov->iov_len, is_write, 0);
iov++;
}
}
@@ -1842,7 +1844,7 @@
return elem;
err_undo_map:
- virtqueue_undo_map_desc(out_num, in_num, iov);
+ virtqueue_undo_map_desc(vdev->dma_as, out_num, in_num, iov);
goto done;
}
@@ -1992,7 +1994,7 @@
return elem;
err_undo_map:
- virtqueue_undo_map_desc(out_num, in_num, iov);
+ virtqueue_undo_map_desc(vdev->dma_as, out_num, in_num, iov);
goto done;
}
diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c
index 78e0bc8..52e2cce 100644
--- a/hw/xen/xen-hvm-common.c
+++ b/hw/xen/xen-hvm-common.c
@@ -12,6 +12,7 @@
#include "hw/xen/xen-bus.h"
#include "hw/boards.h"
#include "hw/xen/arch_hvm.h"
+#include "system/memory.h"
#include "system/runstate.h"
#include "system/system.h"
#include "system/xen.h"
@@ -279,8 +280,8 @@
* memory, as part of the implementation of an ioreq.
*
* Equivalent to
- * cpu_physical_memory_rw(addr + (req->df ? -1 : +1) * req->size * i,
- * val, req->size, 0/1)
+ * address_space_rw(as, addr + (req->df ? -1 : +1) * req->size * i,
+ * attrs, val, req->size, 0/1)
* except without the integer overflow problems.
*/
static void rw_phys_req_item(hwaddr addr,
@@ -295,7 +296,8 @@
} else {
addr += offset;
}
- cpu_physical_memory_rw(addr, val, req->size, rw);
+ address_space_rw(&address_space_memory, addr, MEMTXATTRS_UNSPECIFIED,
+ val, req->size, rw);
}
static inline void read_phys_req_item(hwaddr addr,
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index b96ac49..67e15c8 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -131,26 +131,14 @@
*/
void cpu_destroy_address_spaces(CPUState *cpu);
-void cpu_physical_memory_rw(hwaddr addr, void *buf,
- hwaddr len, bool is_write);
-static inline void cpu_physical_memory_read(hwaddr addr,
- void *buf, hwaddr len)
-{
- cpu_physical_memory_rw(addr, buf, len, false);
-}
-static inline void cpu_physical_memory_write(hwaddr addr,
- const void *buf, hwaddr len)
-{
- cpu_physical_memory_rw(addr, (void *)buf, len, true);
-}
+void cpu_physical_memory_read(hwaddr addr, void *buf, hwaddr len);
+void cpu_physical_memory_write(hwaddr addr, const void *buf, hwaddr len);
void *cpu_physical_memory_map(hwaddr addr,
hwaddr *plen,
bool is_write);
void cpu_physical_memory_unmap(void *buffer, hwaddr len,
bool is_write, hwaddr access_len);
-bool cpu_physical_memory_is_io(hwaddr phys_addr);
-
/* Coalesced MMIO regions are areas where write operations can be reordered.
* This usually implies that write operations are side-effect free. This allows
* batching which can make a major impact on performance when using
@@ -158,14 +146,9 @@
*/
void qemu_flush_coalesced_mmio_buffer(void);
-void cpu_flush_icache_range(hwaddr start, hwaddr len);
-
typedef int (RAMBlockIterFunc)(RAMBlock *rb, void *opaque);
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
-int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length);
-int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t start,
- size_t length);
/* Returns: 0 on success, -1 on error */
int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
diff --git a/include/hw/arm/sharpsl.h b/include/hw/arm/sharpsl.h
deleted file mode 100644
index 1e3992f..0000000
--- a/include/hw/arm/sharpsl.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Common declarations for the Zaurii.
- *
- * This file is licensed under the GNU GPL.
- */
-
-#ifndef QEMU_SHARPSL_H
-#define QEMU_SHARPSL_H
-
-#include "exec/hwaddr.h"
-
-/* zaurus.c */
-
-#define SL_PXA_PARAM_BASE 0xa0000a00
-void sl_bootparam_write(hwaddr ptr);
-
-#endif
diff --git a/include/hw/arm/xlnx-versal-version.h b/include/hw/arm/xlnx-versal-version.h
new file mode 100644
index 0000000..5b6b6e5
--- /dev/null
+++ b/include/hw/arm/xlnx-versal-version.h
@@ -0,0 +1,16 @@
+/*
+ * AMD Versal versions
+ *
+ * Copyright (c) 2025 Advanced Micro Devices, Inc.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_ARM_XLNX_VERSAL_VERSION_H
+#define HW_ARM_XLNX_VERSAL_VERSION_H
+
+typedef enum VersalVersion {
+ VERSAL_VER_VERSAL,
+ VERSAL_VER_VERSAL2,
+} VersalVersion;
+
+#endif
diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h
index 05ed641..e1fb1f4 100644
--- a/include/hw/arm/xlnx-versal.h
+++ b/include/hw/arm/xlnx-versal.h
@@ -1,7 +1,8 @@
/*
- * Model of the Xilinx Versal
+ * AMD/Xilinx Versal family SoC model.
*
* Copyright (c) 2018 Xilinx Inc.
+ * Copyright (c) 2025 Advanced Micro Devices, Inc.
* Written by Edgar E. Iglesias
*
* This program is free software; you can redistribute it and/or modify
@@ -13,326 +14,77 @@
#define XLNX_VERSAL_H
#include "hw/sysbus.h"
-#include "hw/cpu/cluster.h"
-#include "hw/or-irq.h"
-#include "hw/sd/sdhci.h"
-#include "hw/intc/arm_gicv3.h"
-#include "hw/char/pl011.h"
-#include "hw/dma/xlnx-zdma.h"
-#include "hw/net/cadence_gem.h"
-#include "hw/rtc/xlnx-zynqmp-rtc.h"
#include "qom/object.h"
-#include "hw/usb/xlnx-usb-subsystem.h"
-#include "hw/misc/xlnx-versal-xramc.h"
-#include "hw/nvram/xlnx-bbram.h"
-#include "hw/nvram/xlnx-versal-efuse.h"
-#include "hw/ssi/xlnx-versal-ospi.h"
-#include "hw/dma/xlnx_csu_dma.h"
-#include "hw/misc/xlnx-versal-crl.h"
-#include "hw/misc/xlnx-versal-pmc-iou-slcr.h"
-#include "hw/misc/xlnx-versal-trng.h"
-#include "hw/net/xlnx-versal-canfd.h"
-#include "hw/misc/xlnx-versal-cfu.h"
-#include "hw/misc/xlnx-versal-cframe-reg.h"
-#include "target/arm/cpu.h"
+#include "net/can_emu.h"
+#include "hw/arm/xlnx-versal-version.h"
+
+#define TYPE_XLNX_VERSAL_BASE "xlnx-versal-base"
+OBJECT_DECLARE_TYPE(Versal, VersalClass, XLNX_VERSAL_BASE)
#define TYPE_XLNX_VERSAL "xlnx-versal"
-OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL)
-
-#define XLNX_VERSAL_NR_ACPUS 2
-#define XLNX_VERSAL_NR_RCPUS 2
-#define XLNX_VERSAL_NR_UARTS 2
-#define XLNX_VERSAL_NR_GEMS 2
-#define XLNX_VERSAL_NR_ADMAS 8
-#define XLNX_VERSAL_NR_SDS 2
-#define XLNX_VERSAL_NR_XRAM 4
-#define XLNX_VERSAL_NR_IRQS 192
-#define XLNX_VERSAL_NR_CANFD 2
-#define XLNX_VERSAL_CANFD_REF_CLK (24 * 1000 * 1000)
-#define XLNX_VERSAL_NR_CFRAME 15
+#define TYPE_XLNX_VERSAL2 "xlnx-versal2"
struct Versal {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
- struct {
- struct {
- MemoryRegion mr;
- CPUClusterState cluster;
- ARMCPU cpu[XLNX_VERSAL_NR_ACPUS];
- GICv3State gic;
- } apu;
- } fpd;
-
+ GArray *intc;
MemoryRegion mr_ps;
struct {
- /* 4 ranges to access DDR. */
- MemoryRegion mr_ddr_ranges[4];
- } noc;
-
- struct {
- MemoryRegion mr_ocm;
-
- struct {
- PL011State uart[XLNX_VERSAL_NR_UARTS];
- CadenceGEMState gem[XLNX_VERSAL_NR_GEMS];
- OrIRQState gem_irq_orgate[XLNX_VERSAL_NR_GEMS];
- XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS];
- VersalUsb2 usb;
- CanBusState *canbus[XLNX_VERSAL_NR_CANFD];
- XlnxVersalCANFDState canfd[XLNX_VERSAL_NR_CANFD];
- } iou;
-
- /* Real-time Processing Unit. */
- struct {
- MemoryRegion mr;
- MemoryRegion mr_ps_alias;
-
- CPUClusterState cluster;
- ARMCPU cpu[XLNX_VERSAL_NR_RCPUS];
- } rpu;
-
- struct {
- OrIRQState irq_orgate;
- XlnxXramCtrl ctrl[XLNX_VERSAL_NR_XRAM];
- } xram;
-
- XlnxVersalCRL crl;
- } lpd;
-
- /* The Platform Management Controller subsystem. */
- struct {
- struct {
- SDHCIState sd[XLNX_VERSAL_NR_SDS];
- XlnxVersalPmcIouSlcr slcr;
-
- struct {
- XlnxVersalOspi ospi;
- XlnxCSUDMA dma_src;
- XlnxCSUDMA dma_dst;
- MemoryRegion linear_mr;
- OrIRQState irq_orgate;
- } ospi;
- } iou;
-
- XlnxZynqMPRTC rtc;
- XlnxVersalTRng trng;
- XlnxBBRam bbram;
- XlnxEFuse efuse;
- XlnxVersalEFuseCtrl efuse_ctrl;
- XlnxVersalEFuseCache efuse_cache;
- XlnxVersalCFUAPB cfu_apb;
- XlnxVersalCFUFDRO cfu_fdro;
- XlnxVersalCFUSFR cfu_sfr;
- XlnxVersalCFrameReg cframe[XLNX_VERSAL_NR_CFRAME];
- XlnxVersalCFrameBcastReg cframe_bcast;
-
- OrIRQState apb_irq_orgate;
- } pmc;
+ uint32_t clk_25mhz;
+ uint32_t clk_125mhz;
+ uint32_t gic;
+ } phandle;
struct {
MemoryRegion *mr_ddr;
+ CanBusState **canbus;
+ void *fdt;
} cfg;
};
-/* Memory-map and IRQ definitions. Copied a subset from
- * auto-generated files. */
+struct VersalClass {
+ SysBusDeviceClass parent;
-#define VERSAL_GIC_MAINT_IRQ 9
-#define VERSAL_TIMER_VIRT_IRQ 11
-#define VERSAL_TIMER_S_EL1_IRQ 13
-#define VERSAL_TIMER_NS_EL1_IRQ 14
-#define VERSAL_TIMER_NS_EL2_IRQ 10
+ VersalVersion version;
+};
-#define VERSAL_CRL_IRQ 10
-#define VERSAL_UART0_IRQ_0 18
-#define VERSAL_UART1_IRQ_0 19
-#define VERSAL_CANFD0_IRQ_0 20
-#define VERSAL_CANFD1_IRQ_0 21
-#define VERSAL_USB0_IRQ_0 22
-#define VERSAL_GEM0_IRQ_0 56
-#define VERSAL_GEM0_WAKE_IRQ_0 57
-#define VERSAL_GEM1_IRQ_0 58
-#define VERSAL_GEM1_WAKE_IRQ_0 59
-#define VERSAL_ADMA_IRQ_0 60
-#define VERSAL_XRAM_IRQ_0 79
-#define VERSAL_CFU_IRQ_0 120
-#define VERSAL_PMC_APB_IRQ 121
-#define VERSAL_OSPI_IRQ 124
-#define VERSAL_SD0_IRQ_0 126
-#define VERSAL_EFUSE_IRQ 139
-#define VERSAL_TRNG_IRQ 141
-#define VERSAL_RTC_ALARM_IRQ 142
-#define VERSAL_RTC_SECONDS_IRQ 143
+static inline void versal_set_fdt(Versal *s, void *fdt)
+{
+ g_assert(!qdev_is_realized(DEVICE(s)));
+ s->cfg.fdt = fdt;
+}
-/* Architecturally reserved IRQs suitable for virtualization. */
-#define VERSAL_RSVD_IRQ_FIRST 111
-#define VERSAL_RSVD_IRQ_LAST 118
+void versal_fdt_add_memory_nodes(Versal *s, uint64_t ram_size);
-#define MM_TOP_RSVD 0xa0000000U
-#define MM_TOP_RSVD_SIZE 0x4000000
-#define MM_GIC_APU_DIST_MAIN 0xf9000000U
-#define MM_GIC_APU_DIST_MAIN_SIZE 0x10000
-#define MM_GIC_APU_REDIST_0 0xf9080000U
-#define MM_GIC_APU_REDIST_0_SIZE 0x80000
+DeviceState *versal_get_boot_cpu(Versal *s);
+void versal_sdhci_plug_card(Versal *s, int sd_idx, BlockBackend *blk);
+void versal_efuse_attach_drive(Versal *s, BlockBackend *blk);
+void versal_bbram_attach_drive(Versal *s, BlockBackend *blk);
+void versal_ospi_create_flash(Versal *s, int flash_idx, const char *flash_mdl,
+ BlockBackend *blk);
-#define MM_UART0 0xff000000U
-#define MM_UART0_SIZE 0x10000
-#define MM_UART1 0xff010000U
-#define MM_UART1_SIZE 0x10000
+qemu_irq versal_get_reserved_irq(Versal *s, int idx, int *dtb_idx);
+hwaddr versal_get_reserved_mmio_addr(Versal *s);
-#define MM_CANFD0 0xff060000U
-#define MM_CANFD0_SIZE 0x10000
-#define MM_CANFD1 0xff070000U
-#define MM_CANFD1_SIZE 0x10000
+int versal_get_num_cpu(VersalVersion version);
+int versal_get_num_can(VersalVersion version);
+int versal_get_num_sdhci(VersalVersion version);
-#define MM_GEM0 0xff0c0000U
-#define MM_GEM0_SIZE 0x10000
-#define MM_GEM1 0xff0d0000U
-#define MM_GEM1_SIZE 0x10000
+static inline const char *versal_get_class(VersalVersion version)
+{
+ switch (version) {
+ case VERSAL_VER_VERSAL:
+ return TYPE_XLNX_VERSAL;
-#define MM_ADMA_CH0 0xffa80000U
-#define MM_ADMA_CH0_SIZE 0x10000
+ case VERSAL_VER_VERSAL2:
+ return TYPE_XLNX_VERSAL2;
-#define MM_OCM 0xfffc0000U
-#define MM_OCM_SIZE 0x40000
+ default:
+ g_assert_not_reached();
+ }
+}
-#define MM_XRAM 0xfe800000
-#define MM_XRAMC 0xff8e0000
-#define MM_XRAMC_SIZE 0x10000
-
-#define MM_USB2_CTRL_REGS 0xFF9D0000
-#define MM_USB2_CTRL_REGS_SIZE 0x10000
-
-#define MM_USB_0 0xFE200000
-#define MM_USB_0_SIZE 0x10000
-
-#define MM_TOP_DDR 0x0
-#define MM_TOP_DDR_SIZE 0x80000000U
-#define MM_TOP_DDR_2 0x800000000ULL
-#define MM_TOP_DDR_2_SIZE 0x800000000ULL
-#define MM_TOP_DDR_3 0xc000000000ULL
-#define MM_TOP_DDR_3_SIZE 0x4000000000ULL
-#define MM_TOP_DDR_4 0x10000000000ULL
-#define MM_TOP_DDR_4_SIZE 0xb780000000ULL
-
-#define MM_PSM_START 0xffc80000U
-#define MM_PSM_END 0xffcf0000U
-
-#define MM_CRL 0xff5e0000U
-#define MM_CRL_SIZE 0x300000
-#define MM_IOU_SCNTR 0xff130000U
-#define MM_IOU_SCNTR_SIZE 0x10000
-#define MM_IOU_SCNTRS 0xff140000U
-#define MM_IOU_SCNTRS_SIZE 0x10000
-#define MM_FPD_CRF 0xfd1a0000U
-#define MM_FPD_CRF_SIZE 0x140000
-#define MM_FPD_FPD_APU 0xfd5c0000
-#define MM_FPD_FPD_APU_SIZE 0x100
-
-#define MM_PMC_PMC_IOU_SLCR 0xf1060000
-#define MM_PMC_PMC_IOU_SLCR_SIZE 0x10000
-
-#define MM_PMC_OSPI 0xf1010000
-#define MM_PMC_OSPI_SIZE 0x10000
-
-#define MM_PMC_OSPI_DAC 0xc0000000
-#define MM_PMC_OSPI_DAC_SIZE 0x20000000
-
-#define MM_PMC_OSPI_DMA_DST 0xf1011800
-#define MM_PMC_OSPI_DMA_SRC 0xf1011000
-
-#define MM_PMC_SD0 0xf1040000U
-#define MM_PMC_SD0_SIZE 0x10000
-#define MM_PMC_BBRAM_CTRL 0xf11f0000
-#define MM_PMC_BBRAM_CTRL_SIZE 0x00050
-#define MM_PMC_EFUSE_CTRL 0xf1240000
-#define MM_PMC_EFUSE_CTRL_SIZE 0x00104
-#define MM_PMC_EFUSE_CACHE 0xf1250000
-#define MM_PMC_EFUSE_CACHE_SIZE 0x00C00
-
-#define MM_PMC_CFU_APB 0xf12b0000
-#define MM_PMC_CFU_APB_SIZE 0x10000
-#define MM_PMC_CFU_STREAM 0xf12c0000
-#define MM_PMC_CFU_STREAM_SIZE 0x1000
-#define MM_PMC_CFU_SFR 0xf12c1000
-#define MM_PMC_CFU_SFR_SIZE 0x1000
-#define MM_PMC_CFU_FDRO 0xf12c2000
-#define MM_PMC_CFU_FDRO_SIZE 0x1000
-#define MM_PMC_CFU_STREAM_2 0xf1f80000
-#define MM_PMC_CFU_STREAM_2_SIZE 0x40000
-
-#define MM_PMC_CFRAME0_REG 0xf12d0000
-#define MM_PMC_CFRAME0_REG_SIZE 0x1000
-#define MM_PMC_CFRAME0_FDRI 0xf12d1000
-#define MM_PMC_CFRAME0_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME1_REG 0xf12d2000
-#define MM_PMC_CFRAME1_REG_SIZE 0x1000
-#define MM_PMC_CFRAME1_FDRI 0xf12d3000
-#define MM_PMC_CFRAME1_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME2_REG 0xf12d4000
-#define MM_PMC_CFRAME2_REG_SIZE 0x1000
-#define MM_PMC_CFRAME2_FDRI 0xf12d5000
-#define MM_PMC_CFRAME2_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME3_REG 0xf12d6000
-#define MM_PMC_CFRAME3_REG_SIZE 0x1000
-#define MM_PMC_CFRAME3_FDRI 0xf12d7000
-#define MM_PMC_CFRAME3_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME4_REG 0xf12d8000
-#define MM_PMC_CFRAME4_REG_SIZE 0x1000
-#define MM_PMC_CFRAME4_FDRI 0xf12d9000
-#define MM_PMC_CFRAME4_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME5_REG 0xf12da000
-#define MM_PMC_CFRAME5_REG_SIZE 0x1000
-#define MM_PMC_CFRAME5_FDRI 0xf12db000
-#define MM_PMC_CFRAME5_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME6_REG 0xf12dc000
-#define MM_PMC_CFRAME6_REG_SIZE 0x1000
-#define MM_PMC_CFRAME6_FDRI 0xf12dd000
-#define MM_PMC_CFRAME6_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME7_REG 0xf12de000
-#define MM_PMC_CFRAME7_REG_SIZE 0x1000
-#define MM_PMC_CFRAME7_FDRI 0xf12df000
-#define MM_PMC_CFRAME7_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME8_REG 0xf12e0000
-#define MM_PMC_CFRAME8_REG_SIZE 0x1000
-#define MM_PMC_CFRAME8_FDRI 0xf12e1000
-#define MM_PMC_CFRAME8_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME9_REG 0xf12e2000
-#define MM_PMC_CFRAME9_REG_SIZE 0x1000
-#define MM_PMC_CFRAME9_FDRI 0xf12e3000
-#define MM_PMC_CFRAME9_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME10_REG 0xf12e4000
-#define MM_PMC_CFRAME10_REG_SIZE 0x1000
-#define MM_PMC_CFRAME10_FDRI 0xf12e5000
-#define MM_PMC_CFRAME10_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME11_REG 0xf12e6000
-#define MM_PMC_CFRAME11_REG_SIZE 0x1000
-#define MM_PMC_CFRAME11_FDRI 0xf12e7000
-#define MM_PMC_CFRAME11_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME12_REG 0xf12e8000
-#define MM_PMC_CFRAME12_REG_SIZE 0x1000
-#define MM_PMC_CFRAME12_FDRI 0xf12e9000
-#define MM_PMC_CFRAME12_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME13_REG 0xf12ea000
-#define MM_PMC_CFRAME13_REG_SIZE 0x1000
-#define MM_PMC_CFRAME13_FDRI 0xf12eb000
-#define MM_PMC_CFRAME13_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME14_REG 0xf12ec000
-#define MM_PMC_CFRAME14_REG_SIZE 0x1000
-#define MM_PMC_CFRAME14_FDRI 0xf12ed000
-#define MM_PMC_CFRAME14_FDRI_SIZE 0x1000
-#define MM_PMC_CFRAME_BCAST_REG 0xf12ee000
-#define MM_PMC_CFRAME_BCAST_REG_SIZE 0x1000
-#define MM_PMC_CFRAME_BCAST_FDRI 0xf12ef000
-#define MM_PMC_CFRAME_BCAST_FDRI_SIZE 0x1000
-
-#define MM_PMC_CRP 0xf1260000U
-#define MM_PMC_CRP_SIZE 0x10000
-#define MM_PMC_RTC 0xf12a0000
-#define MM_PMC_RTC_SIZE 0x10000
-#define MM_PMC_TRNG 0xf1230000
-#define MM_PMC_TRNG_SIZE 0x10000
#endif
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index c137ac5..a3117bd 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -42,6 +42,7 @@
#include "hw/misc/xlnx-zynqmp-crf.h"
#include "hw/timer/cadence_ttc.h"
#include "hw/usb/hcd-dwc3.h"
+#include "hw/core/split-irq.h"
#define TYPE_XLNX_ZYNQMP "xlnx-zynqmp"
OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP)
@@ -67,6 +68,7 @@
#define XLNX_ZYNQMP_OCM_RAM_SIZE 0x10000
#define XLNX_ZYNQMP_GIC_REGIONS 6
+#define XLNX_ZYNQMP_GIC_NUM_SPI_INTR 160
/*
* ZynqMP maps the ARM GIC regions (GICC, GICD ...) at consecutive 64k offsets
@@ -105,6 +107,9 @@
GICState gic;
MemoryRegion gic_mr[XLNX_ZYNQMP_GIC_REGIONS][XLNX_ZYNQMP_GIC_ALIASES];
+ GICState rpu_gic;
+ SplitIRQ splitter[XLNX_ZYNQMP_GIC_NUM_SPI_INTR];
+
MemoryRegion ocm_ram[XLNX_ZYNQMP_NUM_OCM_BANKS];
MemoryRegion *ddr_ram;
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index 572d971..38aa196 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -229,6 +229,7 @@
uint32_t *redist_region_count; /* redistributor count within each region */
uint32_t nb_redist_regions; /* number of redist regions */
+ uint32_t first_cpu_idx;
uint32_t num_cpu;
uint32_t num_irq;
uint32_t revision;
diff --git a/include/hw/misc/xlnx-versal-crl.h b/include/hw/misc/xlnx-versal-crl.h
index dba6d35..f6b8694 100644
--- a/include/hw/misc/xlnx-versal-crl.h
+++ b/include/hw/misc/xlnx-versal-crl.h
@@ -2,6 +2,7 @@
* QEMU model of the Clock-Reset-LPD (CRL).
*
* Copyright (c) 2022 Xilinx Inc.
+ * Copyright (c) 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
@@ -12,9 +13,16 @@
#include "hw/sysbus.h"
#include "hw/register.h"
#include "target/arm/cpu-qom.h"
+#include "hw/arm/xlnx-versal-version.h"
+#define TYPE_XLNX_VERSAL_CRL_BASE "xlnx-versal-crl-base"
#define TYPE_XLNX_VERSAL_CRL "xlnx-versal-crl"
+#define TYPE_XLNX_VERSAL2_CRL "xlnx-versal2-crl"
+
+OBJECT_DECLARE_TYPE(XlnxVersalCRLBase, XlnxVersalCRLBaseClass,
+ XLNX_VERSAL_CRL_BASE)
OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersalCRL, XLNX_VERSAL_CRL)
+OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersal2CRL, XLNX_VERSAL2_CRL)
REG32(ERR_CTRL, 0x0)
FIELD(ERR_CTRL, SLVERR_ENABLE, 0, 1)
@@ -214,22 +222,370 @@
#define CRL_R_MAX (R_PSM_RST_MODE + 1)
-#define RPU_MAX_CPU 2
+REG32(VERSAL2_ERR_CTRL, 0x0)
+REG32(VERSAL2_WPROT, 0x1c)
+ FIELD(VERSAL2_WPROT, ACTIVE, 0, 1)
+REG32(VERSAL2_RPLL_CTRL, 0x40)
+ FIELD(VERSAL2_RPLL_CTRL, POST_SRC, 24, 3)
+ FIELD(VERSAL2_RPLL_CTRL, PRE_SRC, 20, 3)
+ FIELD(VERSAL2_RPLL_CTRL, CLKOUTDIV, 16, 2)
+ FIELD(VERSAL2_RPLL_CTRL, FBDIV, 8, 8)
+ FIELD(VERSAL2_RPLL_CTRL, BYPASS, 3, 1)
+ FIELD(VERSAL2_RPLL_CTRL, RESET, 0, 1)
+REG32(VERSAL2_RPLL_CFG, 0x44)
+ FIELD(VERSAL2_RPLL_CFG, LOCK_DLY, 25, 7)
+ FIELD(VERSAL2_RPLL_CFG, LOCK_CNT, 13, 10)
+ FIELD(VERSAL2_RPLL_CFG, LFHF, 10, 2)
+ FIELD(VERSAL2_RPLL_CFG, CP, 5, 4)
+ FIELD(VERSAL2_RPLL_CFG, RES, 0, 4)
+REG32(VERSAL2_FLXPLL_CTRL, 0x50)
+ FIELD(VERSAL2_FLXPLL_CTRL, POST_SRC, 24, 3)
+ FIELD(VERSAL2_FLXPLL_CTRL, PRE_SRC, 20, 3)
+ FIELD(VERSAL2_FLXPLL_CTRL, CLKOUTDIV, 16, 2)
+ FIELD(VERSAL2_FLXPLL_CTRL, FBDIV, 8, 8)
+ FIELD(VERSAL2_FLXPLL_CTRL, BYPASS, 3, 1)
+ FIELD(VERSAL2_FLXPLL_CTRL, RESET, 0, 1)
+REG32(VERSAL2_FLXPLL_CFG, 0x54)
+ FIELD(VERSAL2_FLXPLL_CFG, LOCK_DLY, 25, 7)
+ FIELD(VERSAL2_FLXPLL_CFG, LOCK_CNT, 13, 10)
+ FIELD(VERSAL2_FLXPLL_CFG, LFHF, 10, 2)
+ FIELD(VERSAL2_FLXPLL_CFG, CP, 5, 4)
+ FIELD(VERSAL2_FLXPLL_CFG, RES, 0, 4)
+REG32(VERSAL2_PLL_STATUS, 0x60)
+ FIELD(VERSAL2_PLL_STATUS, FLXPLL_STABLE, 3, 1)
+ FIELD(VERSAL2_PLL_STATUS, RPLL_STABLE, 2, 1)
+ FIELD(VERSAL2_PLL_STATUS, FLXPLL_LOCK, 1, 1)
+ FIELD(VERSAL2_PLL_STATUS, RPLL_LOCK, 0, 1)
+REG32(VERSAL2_RPLL_TO_XPD_CTRL, 0x100)
+ FIELD(VERSAL2_RPLL_TO_XPD_CTRL, DIVISOR0, 8, 10)
+REG32(VERSAL2_LPX_TOP_SWITCH_CTRL, 0x104)
+ FIELD(VERSAL2_LPX_TOP_SWITCH_CTRL, CLKACT_ADMA, 26, 1)
+ FIELD(VERSAL2_LPX_TOP_SWITCH_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_LPX_TOP_SWITCH_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_LPX_TOP_SWITCH_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_LPX_LSBUS_CLK_CTRL, 0x108)
+ FIELD(VERSAL2_LPX_LSBUS_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_LPX_LSBUS_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_LPX_LSBUS_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_RPU_CLK_CTRL, 0x10c)
+ FIELD(VERSAL2_RPU_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_RPU_CLK_CTRL, CLKACT_CLUSTERE, 24, 1)
+ FIELD(VERSAL2_RPU_CLK_CTRL, CLKACT_CLUSTERD, 23, 1)
+ FIELD(VERSAL2_RPU_CLK_CTRL, CLKACT_CLUSTERC, 22, 1)
+ FIELD(VERSAL2_RPU_CLK_CTRL, CLKACT_CLUSTERB, 21, 1)
+ FIELD(VERSAL2_RPU_CLK_CTRL, CLKACT_CLUSTERA, 20, 1)
+ FIELD(VERSAL2_RPU_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_RPU_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_OCM_CLK_CTRL, 0x120)
+ FIELD(VERSAL2_OCM_CLK_CTRL, CLKACT_OCM3, 24, 1)
+ FIELD(VERSAL2_OCM_CLK_CTRL, CLKACT_OCM2, 23, 1)
+ FIELD(VERSAL2_OCM_CLK_CTRL, CLKACT_OCM1, 22, 1)
+ FIELD(VERSAL2_OCM_CLK_CTRL, CLKACT_OCM0, 21, 1)
+REG32(VERSAL2_IOU_SWITCH_CLK_CTRL, 0x124)
+ FIELD(VERSAL2_IOU_SWITCH_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_IOU_SWITCH_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_IOU_SWITCH_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_GEM0_REF_CTRL, 0x128)
+ FIELD(VERSAL2_GEM0_REF_CTRL, CLKACT_RX, 27, 1)
+ FIELD(VERSAL2_GEM0_REF_CTRL, CLKACT_TX, 26, 1)
+ FIELD(VERSAL2_GEM0_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_GEM0_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_GEM0_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_GEM1_REF_CTRL, 0x12c)
+ FIELD(VERSAL2_GEM1_REF_CTRL, CLKACT_RX, 27, 1)
+ FIELD(VERSAL2_GEM1_REF_CTRL, CLKACT_TX, 26, 1)
+ FIELD(VERSAL2_GEM1_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_GEM1_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_GEM1_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_GEM_TSU_REF_CLK_CTRL, 0x130)
+ FIELD(VERSAL2_GEM_TSU_REF_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_GEM_TSU_REF_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_GEM_TSU_REF_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_USB0_BUS_REF_CLK_CTRL, 0x134)
+ FIELD(VERSAL2_USB0_BUS_REF_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_USB0_BUS_REF_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_USB0_BUS_REF_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_USB1_BUS_REF_CLK_CTRL, 0x138)
+ FIELD(VERSAL2_USB1_BUS_REF_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_USB1_BUS_REF_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_USB1_BUS_REF_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_UART0_REF_CLK_CTRL, 0x13c)
+ FIELD(VERSAL2_UART0_REF_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_UART0_REF_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_UART0_REF_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_UART1_REF_CLK_CTRL, 0x140)
+ FIELD(VERSAL2_UART1_REF_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_UART1_REF_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_UART1_REF_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_SPI0_REF_CLK_CTRL, 0x144)
+ FIELD(VERSAL2_SPI0_REF_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_SPI0_REF_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_SPI0_REF_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_SPI1_REF_CLK_CTRL, 0x148)
+ FIELD(VERSAL2_SPI1_REF_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_SPI1_REF_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_SPI1_REF_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_CAN0_REF_2X_CTRL, 0x14c)
+ FIELD(VERSAL2_CAN0_REF_2X_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_CAN0_REF_2X_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_CAN0_REF_2X_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_CAN1_REF_2X_CTRL, 0x150)
+ FIELD(VERSAL2_CAN1_REF_2X_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_CAN1_REF_2X_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_CAN1_REF_2X_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_CAN2_REF_2X_CTRL, 0x154)
+ FIELD(VERSAL2_CAN2_REF_2X_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_CAN2_REF_2X_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_CAN2_REF_2X_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_CAN3_REF_2X_CTRL, 0x158)
+ FIELD(VERSAL2_CAN3_REF_2X_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_CAN3_REF_2X_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_CAN3_REF_2X_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_I3C0_REF_CTRL, 0x15c)
+ FIELD(VERSAL2_I3C0_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_I3C0_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_I3C0_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_I3C1_REF_CTRL, 0x160)
+ FIELD(VERSAL2_I3C1_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_I3C1_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_I3C1_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_I3C2_REF_CTRL, 0x164)
+ FIELD(VERSAL2_I3C2_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_I3C2_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_I3C2_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_I3C3_REF_CTRL, 0x168)
+ FIELD(VERSAL2_I3C3_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_I3C3_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_I3C3_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_I3C4_REF_CTRL, 0x16c)
+ FIELD(VERSAL2_I3C4_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_I3C4_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_I3C4_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_I3C5_REF_CTRL, 0x170)
+ FIELD(VERSAL2_I3C5_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_I3C5_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_I3C5_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_I3C6_REF_CTRL, 0x174)
+ FIELD(VERSAL2_I3C6_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_I3C6_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_I3C6_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_I3C7_REF_CTRL, 0x178)
+ FIELD(VERSAL2_I3C7_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_I3C7_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_I3C7_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_DBG_LPX_CTRL, 0x17c)
+ FIELD(VERSAL2_DBG_LPX_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_DBG_LPX_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_DBG_LPX_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_TIMESTAMP_REF_CTRL, 0x180)
+ FIELD(VERSAL2_TIMESTAMP_REF_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_TIMESTAMP_REF_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_TIMESTAMP_REF_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_SAFETY_CHK, 0x184)
+REG32(VERSAL2_ASU_CLK_CTRL, 0x188)
+ FIELD(VERSAL2_ASU_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_ASU_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_DBG_TSTMP_CLK_CTRL, 0x18c)
+ FIELD(VERSAL2_DBG_TSTMP_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_DBG_TSTMP_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_DBG_TSTMP_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_MMI_TOPSW_CLK_CTRL, 0x190)
+ FIELD(VERSAL2_MMI_TOPSW_CLK_CTRL, CLKACT, 25, 1)
+ FIELD(VERSAL2_MMI_TOPSW_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_MMI_TOPSW_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_WWDT_PLL_CLK_CTRL, 0x194)
+ FIELD(VERSAL2_WWDT_PLL_CLK_CTRL, DIVISOR0, 8, 10)
+ FIELD(VERSAL2_WWDT_PLL_CLK_CTRL, SRCSEL, 0, 3)
+REG32(VERSAL2_RCLK_CTRL, 0x1a0)
+ FIELD(VERSAL2_RCLK_CTRL, CLKACT, 8, 6)
+ FIELD(VERSAL2_RCLK_CTRL, SELECT, 0, 6)
+REG32(VERSAL2_RST_RPU_A, 0x310)
+ FIELD(VERSAL2_RST_RPU_A, TOPRESET, 16, 1)
+ FIELD(VERSAL2_RST_RPU_A, CORE1_POR, 9, 1)
+ FIELD(VERSAL2_RST_RPU_A, CORE0_POR, 8, 1)
+ FIELD(VERSAL2_RST_RPU_A, CORE1_RESET, 1, 1)
+ FIELD(VERSAL2_RST_RPU_A, CORE0_RESET, 0, 1)
+REG32(VERSAL2_RST_RPU_B, 0x314)
+ FIELD(VERSAL2_RST_RPU_B, TOPRESET, 16, 1)
+ FIELD(VERSAL2_RST_RPU_B, CORE1_POR, 9, 1)
+ FIELD(VERSAL2_RST_RPU_B, CORE0_POR, 8, 1)
+ FIELD(VERSAL2_RST_RPU_B, CORE1_RESET, 1, 1)
+ FIELD(VERSAL2_RST_RPU_B, CORE0_RESET, 0, 1)
+REG32(VERSAL2_RST_RPU_C, 0x318)
+ FIELD(VERSAL2_RST_RPU_C, TOPRESET, 16, 1)
+ FIELD(VERSAL2_RST_RPU_C, CORE1_POR, 9, 1)
+ FIELD(VERSAL2_RST_RPU_C, CORE0_POR, 8, 1)
+ FIELD(VERSAL2_RST_RPU_C, CORE1_RESET, 1, 1)
+ FIELD(VERSAL2_RST_RPU_C, CORE0_RESET, 0, 1)
+REG32(VERSAL2_RST_RPU_D, 0x31c)
+ FIELD(VERSAL2_RST_RPU_D, TOPRESET, 16, 1)
+ FIELD(VERSAL2_RST_RPU_D, CORE1_POR, 9, 1)
+ FIELD(VERSAL2_RST_RPU_D, CORE0_POR, 8, 1)
+ FIELD(VERSAL2_RST_RPU_D, CORE1_RESET, 1, 1)
+ FIELD(VERSAL2_RST_RPU_D, CORE0_RESET, 0, 1)
+REG32(VERSAL2_RST_RPU_E, 0x320)
+ FIELD(VERSAL2_RST_RPU_E, TOPRESET, 16, 1)
+ FIELD(VERSAL2_RST_RPU_E, CORE1_POR, 9, 1)
+ FIELD(VERSAL2_RST_RPU_E, CORE0_POR, 8, 1)
+ FIELD(VERSAL2_RST_RPU_E, CORE1_RESET, 1, 1)
+ FIELD(VERSAL2_RST_RPU_E, CORE0_RESET, 0, 1)
+REG32(VERSAL2_RST_RPU_GD_0, 0x324)
+ FIELD(VERSAL2_RST_RPU_GD_0, RESET, 1, 1)
+ FIELD(VERSAL2_RST_RPU_GD_0, TOP_RESET, 0, 1)
+REG32(VERSAL2_RST_RPU_GD_1, 0x328)
+ FIELD(VERSAL2_RST_RPU_GD_1, RESET, 1, 1)
+ FIELD(VERSAL2_RST_RPU_GD_1, TOP_RESET, 0, 1)
+REG32(VERSAL2_RST_ASU_GD, 0x32c)
+ FIELD(VERSAL2_RST_ASU_GD, RESET, 1, 1)
+ FIELD(VERSAL2_RST_ASU_GD, TOP_RESET, 0, 1)
+REG32(VERSAL2_RST_ADMA, 0x334)
+ FIELD(VERSAL2_RST_ADMA, RESET, 0, 1)
+REG32(VERSAL2_RST_SDMA, 0x338)
+ FIELD(VERSAL2_RST_SDMA, RESET, 0, 1)
+REG32(VERSAL2_RST_GEM0, 0x33c)
+ FIELD(VERSAL2_RST_GEM0, RESET, 0, 1)
+REG32(VERSAL2_RST_GEM1, 0x340)
+ FIELD(VERSAL2_RST_GEM1, RESET, 0, 1)
+REG32(VERSAL2_RST_USB0, 0x348)
+ FIELD(VERSAL2_RST_USB0, RESET, 0, 1)
+REG32(VERSAL2_RST_USB1, 0x34c)
+ FIELD(VERSAL2_RST_USB1, RESET, 0, 1)
+REG32(VERSAL2_RST_UART0, 0x350)
+ FIELD(VERSAL2_RST_UART0, RESET, 0, 1)
+REG32(VERSAL2_RST_UART1, 0x354)
+ FIELD(VERSAL2_RST_UART1, RESET, 0, 1)
+REG32(VERSAL2_RST_SPI0, 0x358)
+ FIELD(VERSAL2_RST_SPI0, RESET, 0, 1)
+REG32(VERSAL2_RST_SPI1, 0x35c)
+ FIELD(VERSAL2_RST_SPI1, RESET, 0, 1)
+REG32(VERSAL2_RST_CAN0, 0x360)
+ FIELD(VERSAL2_RST_CAN0, RESET, 0, 1)
+REG32(VERSAL2_RST_CAN1, 0x364)
+ FIELD(VERSAL2_RST_CAN1, RESET, 0, 1)
+REG32(VERSAL2_RST_CAN2, 0x368)
+ FIELD(VERSAL2_RST_CAN2, RESET, 0, 1)
+REG32(VERSAL2_RST_CAN3, 0x36c)
+ FIELD(VERSAL2_RST_CAN3, RESET, 0, 1)
+REG32(VERSAL2_RST_I3C0, 0x374)
+ FIELD(VERSAL2_RST_I3C0, RESET, 0, 1)
+REG32(VERSAL2_RST_I3C1, 0x378)
+ FIELD(VERSAL2_RST_I3C1, RESET, 0, 1)
+REG32(VERSAL2_RST_I3C2, 0x37c)
+ FIELD(VERSAL2_RST_I3C2, RESET, 0, 1)
+REG32(VERSAL2_RST_I3C3, 0x380)
+ FIELD(VERSAL2_RST_I3C3, RESET, 0, 1)
+REG32(VERSAL2_RST_I3C4, 0x384)
+ FIELD(VERSAL2_RST_I3C4, RESET, 0, 1)
+REG32(VERSAL2_RST_I3C5, 0x388)
+ FIELD(VERSAL2_RST_I3C5, RESET, 0, 1)
+REG32(VERSAL2_RST_I3C6, 0x38c)
+ FIELD(VERSAL2_RST_I3C6, RESET, 0, 1)
+REG32(VERSAL2_RST_I3C7, 0x390)
+ FIELD(VERSAL2_RST_I3C7, RESET, 0, 1)
+REG32(VERSAL2_RST_DBG_LPX, 0x398)
+ FIELD(VERSAL2_RST_DBG_LPX, RESET_HSDP, 1, 1)
+ FIELD(VERSAL2_RST_DBG_LPX, RESET, 0, 1)
+REG32(VERSAL2_RST_GPIO, 0x39c)
+ FIELD(VERSAL2_RST_GPIO, RESET, 0, 1)
+REG32(VERSAL2_RST_TTC, 0x3a0)
+ FIELD(VERSAL2_RST_TTC, TTC7_RESET, 7, 1)
+ FIELD(VERSAL2_RST_TTC, TTC6_RESET, 6, 1)
+ FIELD(VERSAL2_RST_TTC, TTC5_RESET, 5, 1)
+ FIELD(VERSAL2_RST_TTC, TTC4_RESET, 4, 1)
+ FIELD(VERSAL2_RST_TTC, TTC3_RESET, 3, 1)
+ FIELD(VERSAL2_RST_TTC, TTC2_RESET, 2, 1)
+ FIELD(VERSAL2_RST_TTC, TTC1_RESET, 1, 1)
+ FIELD(VERSAL2_RST_TTC, TTC0_RESET, 0, 1)
+REG32(VERSAL2_RST_TIMESTAMP, 0x3a4)
+ FIELD(VERSAL2_RST_TIMESTAMP, RESET, 0, 1)
+REG32(VERSAL2_RST_SWDT0, 0x3a8)
+ FIELD(VERSAL2_RST_SWDT0, RESET, 0, 1)
+REG32(VERSAL2_RST_SWDT1, 0x3ac)
+ FIELD(VERSAL2_RST_SWDT1, RESET, 0, 1)
+REG32(VERSAL2_RST_SWDT2, 0x3b0)
+ FIELD(VERSAL2_RST_SWDT2, RESET, 0, 1)
+REG32(VERSAL2_RST_SWDT3, 0x3b4)
+ FIELD(VERSAL2_RST_SWDT3, RESET, 0, 1)
+REG32(VERSAL2_RST_SWDT4, 0x3b8)
+ FIELD(VERSAL2_RST_SWDT4, RESET, 0, 1)
+REG32(VERSAL2_RST_IPI, 0x3bc)
+ FIELD(VERSAL2_RST_IPI, RESET, 0, 1)
+REG32(VERSAL2_RST_SYSMON, 0x3c0)
+ FIELD(VERSAL2_RST_SYSMON, CFG_RST, 0, 1)
+REG32(VERSAL2_ASU_MB_RST_MODE, 0x3c4)
+ FIELD(VERSAL2_ASU_MB_RST_MODE, WAKEUP, 2, 1)
+ FIELD(VERSAL2_ASU_MB_RST_MODE, RST_MODE, 0, 2)
+REG32(VERSAL2_FPX_TOPSW_MUX_CTRL, 0x3c8)
+ FIELD(VERSAL2_FPX_TOPSW_MUX_CTRL, SELECT, 0, 1)
+REG32(VERSAL2_RST_FPX, 0x3d0)
+ FIELD(VERSAL2_RST_FPX, SRST, 1, 1)
+ FIELD(VERSAL2_RST_FPX, POR, 0, 1)
+REG32(VERSAL2_RST_MMI, 0x3d4)
+ FIELD(VERSAL2_RST_MMI, POR, 0, 1)
+REG32(VERSAL2_RST_OCM, 0x3d8)
+ FIELD(VERSAL2_RST_OCM, RESET_OCM3, 3, 1)
+ FIELD(VERSAL2_RST_OCM, RESET_OCM2, 2, 1)
+ FIELD(VERSAL2_RST_OCM, RESET_OCM1, 1, 1)
+ FIELD(VERSAL2_RST_OCM, RESET_OCM0, 0, 1)
+
+#define VERSAL2_CRL_R_MAX (R_VERSAL2_RST_OCM + 1)
+
+struct XlnxVersalCRLBase {
+ SysBusDevice parent_obj;
+
+ RegisterInfoArray *reg_array;
+ uint32_t *regs;
+};
+
+struct XlnxVersalCRLBaseClass {
+ SysBusDeviceClass parent_class;
+
+ DeviceState ** (*decode_periph_rst)(XlnxVersalCRLBase *s, hwaddr, size_t *);
+};
struct XlnxVersalCRL {
- SysBusDevice parent_obj;
+ XlnxVersalCRLBase parent_obj;
qemu_irq irq;
struct {
- ARMCPU *cpu_r5[RPU_MAX_CPU];
+ DeviceState *rpu[2];
DeviceState *adma[8];
DeviceState *uart[2];
DeviceState *gem[2];
- DeviceState *usb;
+ DeviceState *usb[1];
} cfg;
- RegisterInfoArray *reg_array;
uint32_t regs[CRL_R_MAX];
RegisterInfo regs_info[CRL_R_MAX];
};
+
+struct XlnxVersal2CRL {
+ XlnxVersalCRLBase parent_obj;
+
+ struct {
+ DeviceState *rpu[10];
+ DeviceState *adma[8];
+ DeviceState *sdma[8];
+ DeviceState *uart[2];
+ DeviceState *gem[2];
+ DeviceState *usb[2];
+ DeviceState *can[4];
+ } cfg;
+
+ RegisterInfo regs_info[VERSAL2_CRL_R_MAX];
+ uint32_t regs[VERSAL2_CRL_R_MAX];
+};
+
+static inline const char *xlnx_versal_crl_class_name(VersalVersion ver)
+{
+ switch (ver) {
+ case VERSAL_VER_VERSAL:
+ return TYPE_XLNX_VERSAL_CRL;
+ case VERSAL_VER_VERSAL2:
+ return TYPE_XLNX_VERSAL2_CRL;
+ default:
+ g_assert_not_reached();
+ }
+}
+
#endif
diff --git a/include/system/memory.h b/include/system/memory.h
index 08daf0f..3bd5ffa 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -2995,6 +2995,8 @@
*/
void address_space_cache_destroy(MemoryRegionCache *cache);
+void address_space_flush_icache_range(AddressSpace *as, hwaddr addr, hwaddr len);
+
/* address_space_get_iotlb_entry: translate an address into an IOTLB
* entry. Should be called from an RCU critical section.
*/
@@ -3047,6 +3049,15 @@
bool address_space_access_valid(AddressSpace *as, hwaddr addr, hwaddr len,
bool is_write, MemTxAttrs attrs);
+/**
+ * address_space_is_io: check whether an guest physical addresses
+ * whithin an address space is I/O memory.
+ *
+ * @as: #AddressSpace to be accessed
+ * @addr: address within that address space
+ */
+bool address_space_is_io(AddressSpace *as, hwaddr addr);
+
/* address_space_map: map a physical memory region into a host virtual address
*
* May map a subset of the requested range, given by and returned in @plen.
diff --git a/include/system/physmem.h b/include/system/physmem.h
new file mode 100644
index 0000000..879f6ea
--- /dev/null
+++ b/include/system/physmem.h
@@ -0,0 +1,54 @@
+/*
+ * QEMU physical memory interfaces (target independent).
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef QEMU_SYSTEM_PHYSMEM_H
+#define QEMU_SYSTEM_PHYSMEM_H
+
+#include "exec/hwaddr.h"
+#include "exec/ramlist.h"
+
+#define DIRTY_CLIENTS_ALL ((1 << DIRTY_MEMORY_NUM) - 1)
+#define DIRTY_CLIENTS_NOCODE (DIRTY_CLIENTS_ALL & ~(1 << DIRTY_MEMORY_CODE))
+
+bool physical_memory_get_dirty_flag(ram_addr_t addr, unsigned client);
+
+bool physical_memory_is_clean(ram_addr_t addr);
+
+uint8_t physical_memory_range_includes_clean(ram_addr_t start,
+ ram_addr_t length,
+ uint8_t mask);
+
+void physical_memory_set_dirty_flag(ram_addr_t addr, unsigned client);
+
+void physical_memory_set_dirty_range(ram_addr_t start, ram_addr_t length,
+ uint8_t mask);
+
+/*
+ * Contrary to physical_memory_sync_dirty_bitmap() this function returns
+ * the number of dirty pages in @bitmap passed as argument. On the other hand,
+ * physical_memory_sync_dirty_bitmap() returns newly dirtied pages that
+ * weren't set in the global migration bitmap.
+ */
+uint64_t physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
+ ram_addr_t start,
+ ram_addr_t pages);
+
+void physical_memory_dirty_bits_cleared(ram_addr_t start, ram_addr_t length);
+
+bool physical_memory_test_and_clear_dirty(ram_addr_t start,
+ ram_addr_t length,
+ unsigned client);
+
+DirtyBitmapSnapshot *
+physical_memory_snapshot_and_clear_dirty(MemoryRegion *mr, hwaddr offset,
+ hwaddr length, unsigned client);
+
+bool physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
+ ram_addr_t start,
+ ram_addr_t length);
+
+#endif
diff --git a/include/system/ram_addr.h b/include/system/ram_addr.h
index 15a1b1a..6834859 100644
--- a/include/system/ram_addr.h
+++ b/include/system/ram_addr.h
@@ -19,17 +19,9 @@
#ifndef SYSTEM_RAM_ADDR_H
#define SYSTEM_RAM_ADDR_H
-#include "system/xen.h"
-#include "system/tcg.h"
-#include "exec/cputlb.h"
-#include "exec/ramlist.h"
#include "system/ramblock.h"
-#include "system/memory.h"
#include "exec/target_page.h"
-#include "qemu/rcu.h"
-
#include "exec/hwaddr.h"
-#include "exec/cpu-common.h"
extern uint64_t total_dirty_pages;
@@ -80,17 +72,6 @@
return bitmap_test_and_clear(rb->clear_bmap, page >> shift, 1);
}
-static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset)
-{
- return (b && b->host && offset < b->used_length) ? true : false;
-}
-
-static inline void *ramblock_ptr(RAMBlock *block, ram_addr_t offset)
-{
- assert(offset_in_ramblock(block, offset));
- return (char *)block->host + offset;
-}
-
static inline unsigned long int ramblock_recv_bitmap_offset(void *host_addr,
RAMBlock *rb)
{
@@ -99,8 +80,6 @@
return host_addr_offset >> TARGET_PAGE_BITS;
}
-bool ramblock_is_pmem(RAMBlock *rb);
-
/**
* qemu_ram_alloc_from_file,
* qemu_ram_alloc_from_fd: Allocate a ram block from the specified backing
@@ -153,409 +132,4 @@
qemu_ram_msync(block, 0, block->used_length);
}
-#define DIRTY_CLIENTS_ALL ((1 << DIRTY_MEMORY_NUM) - 1)
-#define DIRTY_CLIENTS_NOCODE (DIRTY_CLIENTS_ALL & ~(1 << DIRTY_MEMORY_CODE))
-
-static inline bool cpu_physical_memory_get_dirty(ram_addr_t start,
- ram_addr_t length,
- unsigned client)
-{
- DirtyMemoryBlocks *blocks;
- unsigned long end, page;
- unsigned long idx, offset, base;
- bool dirty = false;
-
- assert(client < DIRTY_MEMORY_NUM);
-
- end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
- page = start >> TARGET_PAGE_BITS;
-
- WITH_RCU_READ_LOCK_GUARD() {
- blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
-
- idx = page / DIRTY_MEMORY_BLOCK_SIZE;
- offset = page % DIRTY_MEMORY_BLOCK_SIZE;
- base = page - offset;
- while (page < end) {
- unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE);
- unsigned long num = next - base;
- unsigned long found = find_next_bit(blocks->blocks[idx],
- num, offset);
- if (found < num) {
- dirty = true;
- break;
- }
-
- page = next;
- idx++;
- offset = 0;
- base += DIRTY_MEMORY_BLOCK_SIZE;
- }
- }
-
- return dirty;
-}
-
-static inline bool cpu_physical_memory_all_dirty(ram_addr_t start,
- ram_addr_t length,
- unsigned client)
-{
- DirtyMemoryBlocks *blocks;
- unsigned long end, page;
- unsigned long idx, offset, base;
- bool dirty = true;
-
- assert(client < DIRTY_MEMORY_NUM);
-
- end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
- page = start >> TARGET_PAGE_BITS;
-
- RCU_READ_LOCK_GUARD();
-
- blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
-
- idx = page / DIRTY_MEMORY_BLOCK_SIZE;
- offset = page % DIRTY_MEMORY_BLOCK_SIZE;
- base = page - offset;
- while (page < end) {
- unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE);
- unsigned long num = next - base;
- unsigned long found = find_next_zero_bit(blocks->blocks[idx], num, offset);
- if (found < num) {
- dirty = false;
- break;
- }
-
- page = next;
- idx++;
- offset = 0;
- base += DIRTY_MEMORY_BLOCK_SIZE;
- }
-
- return dirty;
-}
-
-static inline bool cpu_physical_memory_get_dirty_flag(ram_addr_t addr,
- unsigned client)
-{
- return cpu_physical_memory_get_dirty(addr, 1, client);
-}
-
-static inline bool cpu_physical_memory_is_clean(ram_addr_t addr)
-{
- bool vga = cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_VGA);
- bool code = cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_CODE);
- bool migration =
- cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_MIGRATION);
- return !(vga && code && migration);
-}
-
-static inline uint8_t cpu_physical_memory_range_includes_clean(ram_addr_t start,
- ram_addr_t length,
- uint8_t mask)
-{
- uint8_t ret = 0;
-
- if (mask & (1 << DIRTY_MEMORY_VGA) &&
- !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_VGA)) {
- ret |= (1 << DIRTY_MEMORY_VGA);
- }
- if (mask & (1 << DIRTY_MEMORY_CODE) &&
- !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_CODE)) {
- ret |= (1 << DIRTY_MEMORY_CODE);
- }
- if (mask & (1 << DIRTY_MEMORY_MIGRATION) &&
- !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_MIGRATION)) {
- ret |= (1 << DIRTY_MEMORY_MIGRATION);
- }
- return ret;
-}
-
-static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
- unsigned client)
-{
- unsigned long page, idx, offset;
- DirtyMemoryBlocks *blocks;
-
- assert(client < DIRTY_MEMORY_NUM);
-
- page = addr >> TARGET_PAGE_BITS;
- idx = page / DIRTY_MEMORY_BLOCK_SIZE;
- offset = page % DIRTY_MEMORY_BLOCK_SIZE;
-
- RCU_READ_LOCK_GUARD();
-
- blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
-
- set_bit_atomic(offset, blocks->blocks[idx]);
-}
-
-static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
- ram_addr_t length,
- uint8_t mask)
-{
- DirtyMemoryBlocks *blocks[DIRTY_MEMORY_NUM];
- unsigned long end, page;
- unsigned long idx, offset, base;
- int i;
-
- if (!mask && !xen_enabled()) {
- return;
- }
-
- end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
- page = start >> TARGET_PAGE_BITS;
-
- WITH_RCU_READ_LOCK_GUARD() {
- for (i = 0; i < DIRTY_MEMORY_NUM; i++) {
- blocks[i] = qatomic_rcu_read(&ram_list.dirty_memory[i]);
- }
-
- idx = page / DIRTY_MEMORY_BLOCK_SIZE;
- offset = page % DIRTY_MEMORY_BLOCK_SIZE;
- base = page - offset;
- while (page < end) {
- unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE);
-
- if (likely(mask & (1 << DIRTY_MEMORY_MIGRATION))) {
- bitmap_set_atomic(blocks[DIRTY_MEMORY_MIGRATION]->blocks[idx],
- offset, next - page);
- }
- if (unlikely(mask & (1 << DIRTY_MEMORY_VGA))) {
- bitmap_set_atomic(blocks[DIRTY_MEMORY_VGA]->blocks[idx],
- offset, next - page);
- }
- if (unlikely(mask & (1 << DIRTY_MEMORY_CODE))) {
- bitmap_set_atomic(blocks[DIRTY_MEMORY_CODE]->blocks[idx],
- offset, next - page);
- }
-
- page = next;
- idx++;
- offset = 0;
- base += DIRTY_MEMORY_BLOCK_SIZE;
- }
- }
-
- if (xen_enabled()) {
- xen_hvm_modified_memory(start, length);
- }
-}
-
-#if !defined(_WIN32)
-
-/*
- * Contrary to cpu_physical_memory_sync_dirty_bitmap() this function returns
- * the number of dirty pages in @bitmap passed as argument. On the other hand,
- * cpu_physical_memory_sync_dirty_bitmap() returns newly dirtied pages that
- * weren't set in the global migration bitmap.
- */
-static inline
-uint64_t cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
- ram_addr_t start,
- ram_addr_t pages)
-{
- unsigned long i, j;
- unsigned long page_number, c, nbits;
- hwaddr addr;
- ram_addr_t ram_addr;
- uint64_t num_dirty = 0;
- unsigned long len = (pages + HOST_LONG_BITS - 1) / HOST_LONG_BITS;
- unsigned long hpratio = qemu_real_host_page_size() / TARGET_PAGE_SIZE;
- unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
-
- /* start address is aligned at the start of a word? */
- if ((((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) &&
- (hpratio == 1)) {
- unsigned long **blocks[DIRTY_MEMORY_NUM];
- unsigned long idx;
- unsigned long offset;
- long k;
- long nr = BITS_TO_LONGS(pages);
-
- idx = (start >> TARGET_PAGE_BITS) / DIRTY_MEMORY_BLOCK_SIZE;
- offset = BIT_WORD((start >> TARGET_PAGE_BITS) %
- DIRTY_MEMORY_BLOCK_SIZE);
-
- WITH_RCU_READ_LOCK_GUARD() {
- for (i = 0; i < DIRTY_MEMORY_NUM; i++) {
- blocks[i] =
- qatomic_rcu_read(&ram_list.dirty_memory[i])->blocks;
- }
-
- for (k = 0; k < nr; k++) {
- if (bitmap[k]) {
- unsigned long temp = leul_to_cpu(bitmap[k]);
-
- nbits = ctpopl(temp);
- qatomic_or(&blocks[DIRTY_MEMORY_VGA][idx][offset], temp);
-
- if (global_dirty_tracking) {
- qatomic_or(
- &blocks[DIRTY_MEMORY_MIGRATION][idx][offset],
- temp);
- if (unlikely(
- global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE)) {
- total_dirty_pages += nbits;
- }
- }
-
- num_dirty += nbits;
-
- if (tcg_enabled()) {
- qatomic_or(&blocks[DIRTY_MEMORY_CODE][idx][offset],
- temp);
- }
- }
-
- if (++offset >= BITS_TO_LONGS(DIRTY_MEMORY_BLOCK_SIZE)) {
- offset = 0;
- idx++;
- }
- }
- }
-
- if (xen_enabled()) {
- xen_hvm_modified_memory(start, pages << TARGET_PAGE_BITS);
- }
- } else {
- uint8_t clients = tcg_enabled() ? DIRTY_CLIENTS_ALL : DIRTY_CLIENTS_NOCODE;
-
- if (!global_dirty_tracking) {
- clients &= ~(1 << DIRTY_MEMORY_MIGRATION);
- }
-
- /*
- * bitmap-traveling is faster than memory-traveling (for addr...)
- * especially when most of the memory is not dirty.
- */
- for (i = 0; i < len; i++) {
- if (bitmap[i] != 0) {
- c = leul_to_cpu(bitmap[i]);
- nbits = ctpopl(c);
- if (unlikely(global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE)) {
- total_dirty_pages += nbits;
- }
- num_dirty += nbits;
- do {
- j = ctzl(c);
- c &= ~(1ul << j);
- page_number = (i * HOST_LONG_BITS + j) * hpratio;
- addr = page_number * TARGET_PAGE_SIZE;
- ram_addr = start + addr;
- cpu_physical_memory_set_dirty_range(ram_addr,
- TARGET_PAGE_SIZE * hpratio, clients);
- } while (c != 0);
- }
- }
- }
-
- return num_dirty;
-}
-#endif /* not _WIN32 */
-
-static inline void cpu_physical_memory_dirty_bits_cleared(ram_addr_t start,
- ram_addr_t length)
-{
- if (tcg_enabled()) {
- tlb_reset_dirty_range_all(start, length);
- }
-
-}
-bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
- ram_addr_t length,
- unsigned client);
-
-DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
- (MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client);
-
-bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
- ram_addr_t start,
- ram_addr_t length);
-
-static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
- ram_addr_t length)
-{
- cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_MIGRATION);
- cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_VGA);
- cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_CODE);
-}
-
-
-/* Called with RCU critical section */
-static inline
-uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
- ram_addr_t start,
- ram_addr_t length)
-{
- ram_addr_t addr;
- unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS);
- uint64_t num_dirty = 0;
- unsigned long *dest = rb->bmap;
-
- /* start address and length is aligned at the start of a word? */
- if (((word * BITS_PER_LONG) << TARGET_PAGE_BITS) ==
- (start + rb->offset) &&
- !(length & ((BITS_PER_LONG << TARGET_PAGE_BITS) - 1))) {
- int k;
- int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
- unsigned long * const *src;
- unsigned long idx = (word * BITS_PER_LONG) / DIRTY_MEMORY_BLOCK_SIZE;
- unsigned long offset = BIT_WORD((word * BITS_PER_LONG) %
- DIRTY_MEMORY_BLOCK_SIZE);
- unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
-
- src = qatomic_rcu_read(
- &ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION])->blocks;
-
- for (k = page; k < page + nr; k++) {
- if (src[idx][offset]) {
- unsigned long bits = qatomic_xchg(&src[idx][offset], 0);
- unsigned long new_dirty;
- new_dirty = ~dest[k];
- dest[k] |= bits;
- new_dirty &= bits;
- num_dirty += ctpopl(new_dirty);
- }
-
- if (++offset >= BITS_TO_LONGS(DIRTY_MEMORY_BLOCK_SIZE)) {
- offset = 0;
- idx++;
- }
- }
- if (num_dirty) {
- cpu_physical_memory_dirty_bits_cleared(start, length);
- }
-
- if (rb->clear_bmap) {
- /*
- * Postpone the dirty bitmap clear to the point before we
- * really send the pages, also we will split the clear
- * dirty procedure into smaller chunks.
- */
- clear_bmap_set(rb, start >> TARGET_PAGE_BITS,
- length >> TARGET_PAGE_BITS);
- } else {
- /* Slow path - still do that in a huge chunk */
- memory_region_clear_dirty_bitmap(rb->mr, start, length);
- }
- } else {
- ram_addr_t offset = rb->offset;
-
- for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
- if (cpu_physical_memory_test_and_clear_dirty(
- start + addr + offset,
- TARGET_PAGE_SIZE,
- DIRTY_MEMORY_MIGRATION)) {
- long k = (start + addr) >> TARGET_PAGE_BITS;
- if (!test_and_set_bit(k, dest)) {
- num_dirty++;
- }
- }
- }
- }
-
- return num_dirty;
-}
-
#endif
diff --git a/include/system/ramblock.h b/include/system/ramblock.h
index 87e847e..76694fe 100644
--- a/include/system/ramblock.h
+++ b/include/system/ramblock.h
@@ -11,11 +11,6 @@
*
*/
-/*
- * This header is for use by exec.c and memory.c ONLY. Do not include it.
- * The functions declared here will be removed soon.
- */
-
#ifndef SYSTEM_RAMBLOCK_H
#define SYSTEM_RAMBLOCK_H
@@ -108,9 +103,31 @@
QLIST_HEAD(, RamDiscardListener) rdl_list;
};
+/* @offset: the offset within the RAMBlock */
+int ram_block_discard_range(RAMBlock *rb, uint64_t offset, size_t length);
+/* @offset: the offset within the RAMBlock */
+int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t offset,
+ size_t length);
+
RamBlockAttributes *ram_block_attributes_create(RAMBlock *ram_block);
void ram_block_attributes_destroy(RamBlockAttributes *attr);
int ram_block_attributes_state_change(RamBlockAttributes *attr, uint64_t offset,
uint64_t size, bool to_discard);
+/**
+ * ram_block_is_pmem: Whether the RAM block is of persistent memory
+ */
+bool ram_block_is_pmem(RAMBlock *rb);
+
+static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset)
+{
+ return b && b->host && (offset < b->used_length);
+}
+
+static inline void *ramblock_ptr(RAMBlock *block, ram_addr_t offset)
+{
+ assert(offset_in_ramblock(block, offset));
+ return (char *)block->host + offset;
+}
+
#endif
diff --git a/migration/ram.c b/migration/ram.c
index 9aac896..5eef2ef 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -53,6 +53,8 @@
#include "qemu/rcu_queue.h"
#include "migration/colo.h"
#include "system/cpu-throttle.h"
+#include "system/physmem.h"
+#include "system/ramblock.h"
#include "savevm.h"
#include "qemu/iov.h"
#include "multifd.h"
@@ -936,10 +938,85 @@
}
/* Called with RCU critical section */
+static uint64_t physical_memory_sync_dirty_bitmap(RAMBlock *rb,
+ ram_addr_t start,
+ ram_addr_t length)
+{
+ ram_addr_t addr;
+ unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS);
+ uint64_t num_dirty = 0;
+ unsigned long *dest = rb->bmap;
+
+ /* start address and length is aligned at the start of a word? */
+ if (((word * BITS_PER_LONG) << TARGET_PAGE_BITS) ==
+ (start + rb->offset) &&
+ !(length & ((BITS_PER_LONG << TARGET_PAGE_BITS) - 1))) {
+ int k;
+ int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
+ unsigned long * const *src;
+ unsigned long idx = (word * BITS_PER_LONG) / DIRTY_MEMORY_BLOCK_SIZE;
+ unsigned long offset = BIT_WORD((word * BITS_PER_LONG) %
+ DIRTY_MEMORY_BLOCK_SIZE);
+ unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
+
+ src = qatomic_rcu_read(
+ &ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION])->blocks;
+
+ for (k = page; k < page + nr; k++) {
+ if (src[idx][offset]) {
+ unsigned long bits = qatomic_xchg(&src[idx][offset], 0);
+ unsigned long new_dirty;
+ new_dirty = ~dest[k];
+ dest[k] |= bits;
+ new_dirty &= bits;
+ num_dirty += ctpopl(new_dirty);
+ }
+
+ if (++offset >= BITS_TO_LONGS(DIRTY_MEMORY_BLOCK_SIZE)) {
+ offset = 0;
+ idx++;
+ }
+ }
+ if (num_dirty) {
+ physical_memory_dirty_bits_cleared(start, length);
+ }
+
+ if (rb->clear_bmap) {
+ /*
+ * Postpone the dirty bitmap clear to the point before we
+ * really send the pages, also we will split the clear
+ * dirty procedure into smaller chunks.
+ */
+ clear_bmap_set(rb, start >> TARGET_PAGE_BITS,
+ length >> TARGET_PAGE_BITS);
+ } else {
+ /* Slow path - still do that in a huge chunk */
+ memory_region_clear_dirty_bitmap(rb->mr, start, length);
+ }
+ } else {
+ ram_addr_t offset = rb->offset;
+
+ for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
+ if (physical_memory_test_and_clear_dirty(
+ start + addr + offset,
+ TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_MIGRATION)) {
+ long k = (start + addr) >> TARGET_PAGE_BITS;
+ if (!test_and_set_bit(k, dest)) {
+ num_dirty++;
+ }
+ }
+ }
+ }
+
+ return num_dirty;
+}
+
+/* Called with RCU critical section */
static void ramblock_sync_dirty_bitmap(RAMState *rs, RAMBlock *rb)
{
uint64_t new_dirty_pages =
- cpu_physical_memory_sync_dirty_bitmap(rb, 0, rb->used_length);
+ physical_memory_sync_dirty_bitmap(rb, 0, rb->used_length);
rs->migration_dirty_pages += new_dirty_pages;
rs->num_dirty_pages_period += new_dirty_pages;
@@ -4370,7 +4447,7 @@
{
RAMBlock *rb;
RAMBLOCK_FOREACH_NOT_IGNORED(rb) {
- if (ramblock_is_pmem(rb)) {
+ if (ram_block_is_pmem(rb)) {
info_report("Block: %s, host: %p is a nvdimm memory, postcopy"
"is not supported now!", rb->idstr, rb->host);
return false;
diff --git a/scripts/coccinelle/exec_rw_const.cocci b/scripts/coccinelle/exec_rw_const.cocci
index 1a20296..4c02c94 100644
--- a/scripts/coccinelle/exec_rw_const.cocci
+++ b/scripts/coccinelle/exec_rw_const.cocci
@@ -21,13 +21,6 @@
+ address_space_rw(E1, E2, E3, E4, E5, true)
|
-- cpu_physical_memory_rw(E1, E2, E3, 0)
-+ cpu_physical_memory_rw(E1, E2, E3, false)
-|
-- cpu_physical_memory_rw(E1, E2, E3, 1)
-+ cpu_physical_memory_rw(E1, E2, E3, true)
-|
-
- cpu_physical_memory_map(E1, E2, 0)
+ cpu_physical_memory_map(E1, E2, false)
|
@@ -62,18 +55,6 @@
+ address_space_write(E1, E2, E3, E4, E5)
)
-// Avoid uses of cpu_physical_memory_rw() with a constant is_write argument.
-@@
-expression E1, E2, E3;
-@@
-(
-- cpu_physical_memory_rw(E1, E2, E3, false)
-+ cpu_physical_memory_read(E1, E2, E3)
-|
-- cpu_physical_memory_rw(E1, E2, E3, true)
-+ cpu_physical_memory_write(E1, E2, E3)
-)
-
// Remove useless cast
@@
expression E1, E2, E3, E4, E5, E6;
@@ -93,9 +74,6 @@
+ address_space_write_rom(E1, E2, E3, E4, E5)
|
-- cpu_physical_memory_rw(E1, (T *)(E2), E3, E4)
-+ cpu_physical_memory_rw(E1, E2, E3, E4)
-|
- cpu_physical_memory_read(E1, (T *)(E2), E3)
+ cpu_physical_memory_read(E1, E2, E3)
|
diff --git a/system/memory.c b/system/memory.c
index 41797ce..8b84661 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -25,6 +25,7 @@
#include "qemu/target-info.h"
#include "qom/object.h"
#include "trace.h"
+#include "system/physmem.h"
#include "system/ram_addr.h"
#include "system/kvm.h"
#include "system/runstate.h"
@@ -2271,7 +2272,7 @@
hwaddr size)
{
assert(mr->ram_block);
- cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr,
+ physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr,
size,
memory_region_get_dirty_log_mask(mr));
}
@@ -2375,7 +2376,7 @@
DirtyBitmapSnapshot *snapshot;
assert(mr->ram_block);
memory_region_sync_dirty_bitmap(mr, false);
- snapshot = cpu_physical_memory_snapshot_and_clear_dirty(mr, addr, size, client);
+ snapshot = physical_memory_snapshot_and_clear_dirty(mr, addr, size, client);
memory_global_after_dirty_log_sync();
return snapshot;
}
@@ -2384,7 +2385,7 @@
hwaddr addr, hwaddr size)
{
assert(mr->ram_block);
- return cpu_physical_memory_snapshot_get_dirty(snap,
+ return physical_memory_snapshot_get_dirty(snap,
memory_region_get_ram_addr(mr) + addr, size);
}
@@ -2422,7 +2423,7 @@
hwaddr size, unsigned client)
{
assert(mr->ram_block);
- cpu_physical_memory_test_and_clear_dirty(
+ physical_memory_test_and_clear_dirty(
memory_region_get_ram_addr(mr) + addr, size, client);
}
diff --git a/system/memory_ldst.c.inc b/system/memory_ldst.c.inc
index 7f32d3d..333da20 100644
--- a/system/memory_ldst.c.inc
+++ b/system/memory_ldst.c.inc
@@ -287,7 +287,7 @@
dirty_log_mask = memory_region_get_dirty_log_mask(mr);
dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
- cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr,
+ physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr,
4, dirty_log_mask);
r = MEMTX_OK;
}
diff --git a/system/physmem.c b/system/physmem.c
index dbb2a4e..a340ca3 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -43,6 +43,8 @@
#include "system/kvm.h"
#include "system/tcg.h"
#include "system/qtest.h"
+#include "system/physmem.h"
+#include "system/ramblock.h"
#include "qemu/timer.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
@@ -898,8 +900,197 @@
}
}
+void physical_memory_dirty_bits_cleared(ram_addr_t start, ram_addr_t length)
+{
+ if (tcg_enabled()) {
+ tlb_reset_dirty_range_all(start, length);
+ }
+}
+
+static bool physical_memory_get_dirty(ram_addr_t start, ram_addr_t length,
+ unsigned client)
+{
+ DirtyMemoryBlocks *blocks;
+ unsigned long end, page;
+ unsigned long idx, offset, base;
+ bool dirty = false;
+
+ assert(client < DIRTY_MEMORY_NUM);
+
+ end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
+ page = start >> TARGET_PAGE_BITS;
+
+ WITH_RCU_READ_LOCK_GUARD() {
+ blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
+
+ idx = page / DIRTY_MEMORY_BLOCK_SIZE;
+ offset = page % DIRTY_MEMORY_BLOCK_SIZE;
+ base = page - offset;
+ while (page < end) {
+ unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE);
+ unsigned long num = next - base;
+ unsigned long found = find_next_bit(blocks->blocks[idx],
+ num, offset);
+ if (found < num) {
+ dirty = true;
+ break;
+ }
+
+ page = next;
+ idx++;
+ offset = 0;
+ base += DIRTY_MEMORY_BLOCK_SIZE;
+ }
+ }
+
+ return dirty;
+}
+
+bool physical_memory_get_dirty_flag(ram_addr_t addr, unsigned client)
+{
+ return physical_memory_get_dirty(addr, 1, client);
+}
+
+bool physical_memory_is_clean(ram_addr_t addr)
+{
+ bool vga = physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_VGA);
+ bool code = physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_CODE);
+ bool migration =
+ physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_MIGRATION);
+ return !(vga && code && migration);
+}
+
+static bool physical_memory_all_dirty(ram_addr_t start, ram_addr_t length,
+ unsigned client)
+{
+ DirtyMemoryBlocks *blocks;
+ unsigned long end, page;
+ unsigned long idx, offset, base;
+ bool dirty = true;
+
+ assert(client < DIRTY_MEMORY_NUM);
+
+ end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
+ page = start >> TARGET_PAGE_BITS;
+
+ RCU_READ_LOCK_GUARD();
+
+ blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
+
+ idx = page / DIRTY_MEMORY_BLOCK_SIZE;
+ offset = page % DIRTY_MEMORY_BLOCK_SIZE;
+ base = page - offset;
+ while (page < end) {
+ unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE);
+ unsigned long num = next - base;
+ unsigned long found = find_next_zero_bit(blocks->blocks[idx],
+ num, offset);
+ if (found < num) {
+ dirty = false;
+ break;
+ }
+
+ page = next;
+ idx++;
+ offset = 0;
+ base += DIRTY_MEMORY_BLOCK_SIZE;
+ }
+
+ return dirty;
+}
+
+uint8_t physical_memory_range_includes_clean(ram_addr_t start,
+ ram_addr_t length,
+ uint8_t mask)
+{
+ uint8_t ret = 0;
+
+ if (mask & (1 << DIRTY_MEMORY_VGA) &&
+ !physical_memory_all_dirty(start, length, DIRTY_MEMORY_VGA)) {
+ ret |= (1 << DIRTY_MEMORY_VGA);
+ }
+ if (mask & (1 << DIRTY_MEMORY_CODE) &&
+ !physical_memory_all_dirty(start, length, DIRTY_MEMORY_CODE)) {
+ ret |= (1 << DIRTY_MEMORY_CODE);
+ }
+ if (mask & (1 << DIRTY_MEMORY_MIGRATION) &&
+ !physical_memory_all_dirty(start, length, DIRTY_MEMORY_MIGRATION)) {
+ ret |= (1 << DIRTY_MEMORY_MIGRATION);
+ }
+ return ret;
+}
+
+void physical_memory_set_dirty_flag(ram_addr_t addr, unsigned client)
+{
+ unsigned long page, idx, offset;
+ DirtyMemoryBlocks *blocks;
+
+ assert(client < DIRTY_MEMORY_NUM);
+
+ page = addr >> TARGET_PAGE_BITS;
+ idx = page / DIRTY_MEMORY_BLOCK_SIZE;
+ offset = page % DIRTY_MEMORY_BLOCK_SIZE;
+
+ RCU_READ_LOCK_GUARD();
+
+ blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
+
+ set_bit_atomic(offset, blocks->blocks[idx]);
+}
+
+void physical_memory_set_dirty_range(ram_addr_t start, ram_addr_t length,
+ uint8_t mask)
+{
+ DirtyMemoryBlocks *blocks[DIRTY_MEMORY_NUM];
+ unsigned long end, page;
+ unsigned long idx, offset, base;
+ int i;
+
+ if (!mask && !xen_enabled()) {
+ return;
+ }
+
+ end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
+ page = start >> TARGET_PAGE_BITS;
+
+ WITH_RCU_READ_LOCK_GUARD() {
+ for (i = 0; i < DIRTY_MEMORY_NUM; i++) {
+ blocks[i] = qatomic_rcu_read(&ram_list.dirty_memory[i]);
+ }
+
+ idx = page / DIRTY_MEMORY_BLOCK_SIZE;
+ offset = page % DIRTY_MEMORY_BLOCK_SIZE;
+ base = page - offset;
+ while (page < end) {
+ unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE);
+
+ if (likely(mask & (1 << DIRTY_MEMORY_MIGRATION))) {
+ bitmap_set_atomic(blocks[DIRTY_MEMORY_MIGRATION]->blocks[idx],
+ offset, next - page);
+ }
+ if (unlikely(mask & (1 << DIRTY_MEMORY_VGA))) {
+ bitmap_set_atomic(blocks[DIRTY_MEMORY_VGA]->blocks[idx],
+ offset, next - page);
+ }
+ if (unlikely(mask & (1 << DIRTY_MEMORY_CODE))) {
+ bitmap_set_atomic(blocks[DIRTY_MEMORY_CODE]->blocks[idx],
+ offset, next - page);
+ }
+
+ page = next;
+ idx++;
+ offset = 0;
+ base += DIRTY_MEMORY_BLOCK_SIZE;
+ }
+ }
+
+ if (xen_enabled()) {
+ xen_hvm_modified_memory(start, length);
+ }
+}
+
/* Note: start and end must be within the same ram block. */
-bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
+bool physical_memory_test_and_clear_dirty(ram_addr_t start,
ram_addr_t length,
unsigned client)
{
@@ -941,13 +1132,20 @@
}
if (dirty) {
- cpu_physical_memory_dirty_bits_cleared(start, length);
+ physical_memory_dirty_bits_cleared(start, length);
}
return dirty;
}
-DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
+static void physical_memory_clear_dirty_range(ram_addr_t addr, ram_addr_t length)
+{
+ physical_memory_test_and_clear_dirty(addr, length, DIRTY_MEMORY_MIGRATION);
+ physical_memory_test_and_clear_dirty(addr, length, DIRTY_MEMORY_VGA);
+ physical_memory_test_and_clear_dirty(addr, length, DIRTY_MEMORY_CODE);
+}
+
+DirtyBitmapSnapshot *physical_memory_snapshot_and_clear_dirty
(MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client)
{
DirtyMemoryBlocks *blocks;
@@ -994,14 +1192,14 @@
}
}
- cpu_physical_memory_dirty_bits_cleared(start, length);
+ physical_memory_dirty_bits_cleared(start, length);
memory_region_clear_dirty_bitmap(mr, offset, length);
return snap;
}
-bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
+bool physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
ram_addr_t start,
ram_addr_t length)
{
@@ -1022,6 +1220,109 @@
return false;
}
+uint64_t physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
+ ram_addr_t start,
+ ram_addr_t pages)
+{
+ unsigned long i, j;
+ unsigned long page_number, c, nbits;
+ hwaddr addr;
+ ram_addr_t ram_addr;
+ uint64_t num_dirty = 0;
+ unsigned long len = (pages + HOST_LONG_BITS - 1) / HOST_LONG_BITS;
+ unsigned long hpratio = qemu_real_host_page_size() / TARGET_PAGE_SIZE;
+ unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
+
+ /* start address is aligned at the start of a word? */
+ if ((((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) &&
+ (hpratio == 1)) {
+ unsigned long **blocks[DIRTY_MEMORY_NUM];
+ unsigned long idx;
+ unsigned long offset;
+ long k;
+ long nr = BITS_TO_LONGS(pages);
+
+ idx = (start >> TARGET_PAGE_BITS) / DIRTY_MEMORY_BLOCK_SIZE;
+ offset = BIT_WORD((start >> TARGET_PAGE_BITS) %
+ DIRTY_MEMORY_BLOCK_SIZE);
+
+ WITH_RCU_READ_LOCK_GUARD() {
+ for (i = 0; i < DIRTY_MEMORY_NUM; i++) {
+ blocks[i] =
+ qatomic_rcu_read(&ram_list.dirty_memory[i])->blocks;
+ }
+
+ for (k = 0; k < nr; k++) {
+ if (bitmap[k]) {
+ unsigned long temp = leul_to_cpu(bitmap[k]);
+
+ nbits = ctpopl(temp);
+ qatomic_or(&blocks[DIRTY_MEMORY_VGA][idx][offset], temp);
+
+ if (global_dirty_tracking) {
+ qatomic_or(
+ &blocks[DIRTY_MEMORY_MIGRATION][idx][offset],
+ temp);
+ if (unlikely(
+ global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE)) {
+ total_dirty_pages += nbits;
+ }
+ }
+
+ num_dirty += nbits;
+
+ if (tcg_enabled()) {
+ qatomic_or(&blocks[DIRTY_MEMORY_CODE][idx][offset],
+ temp);
+ }
+ }
+
+ if (++offset >= BITS_TO_LONGS(DIRTY_MEMORY_BLOCK_SIZE)) {
+ offset = 0;
+ idx++;
+ }
+ }
+ }
+
+ if (xen_enabled()) {
+ xen_hvm_modified_memory(start, pages << TARGET_PAGE_BITS);
+ }
+ } else {
+ uint8_t clients = tcg_enabled() ? DIRTY_CLIENTS_ALL
+ : DIRTY_CLIENTS_NOCODE;
+
+ if (!global_dirty_tracking) {
+ clients &= ~(1 << DIRTY_MEMORY_MIGRATION);
+ }
+
+ /*
+ * bitmap-traveling is faster than memory-traveling (for addr...)
+ * especially when most of the memory is not dirty.
+ */
+ for (i = 0; i < len; i++) {
+ if (bitmap[i] != 0) {
+ c = leul_to_cpu(bitmap[i]);
+ nbits = ctpopl(c);
+ if (unlikely(global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE)) {
+ total_dirty_pages += nbits;
+ }
+ num_dirty += nbits;
+ do {
+ j = ctzl(c);
+ c &= ~(1ul << j);
+ page_number = (i * HOST_LONG_BITS + j) * hpratio;
+ addr = page_number * TARGET_PAGE_SIZE;
+ ram_addr = start + addr;
+ physical_memory_set_dirty_range(ram_addr,
+ TARGET_PAGE_SIZE * hpratio, clients);
+ } while (c != 0);
+ }
+ }
+ }
+
+ return num_dirty;
+}
+
static int subpage_register(subpage_t *mmio, uint32_t start, uint32_t end,
uint16_t section);
static subpage_t *subpage_init(FlatView *fv, hwaddr base);
@@ -1778,9 +2079,9 @@
ram_block_notify_resize(block->host, oldsize, newsize);
}
- cpu_physical_memory_clear_dirty_range(block->offset, block->used_length);
+ physical_memory_clear_dirty_range(block->offset, block->used_length);
block->used_length = newsize;
- cpu_physical_memory_set_dirty_range(block->offset, block->used_length,
+ physical_memory_set_dirty_range(block->offset, block->used_length,
DIRTY_CLIENTS_ALL);
memory_region_set_size(block->mr, unaligned_size);
if (block->resized) {
@@ -1802,7 +2103,7 @@
#ifdef CONFIG_LIBPMEM
/* The lack of support for pmem should not block the sync */
- if (ramblock_is_pmem(block)) {
+ if (ram_block_is_pmem(block)) {
void *addr = ramblock_ptr(block, start);
pmem_persist(addr, length);
return;
@@ -1985,7 +2286,7 @@
ram_list.version++;
qemu_mutex_unlock_ramlist();
- cpu_physical_memory_set_dirty_range(new_block->offset,
+ physical_memory_set_dirty_range(new_block->offset,
new_block->used_length,
DIRTY_CLIENTS_ALL);
@@ -2834,19 +3135,19 @@
addr += ramaddr;
/* No early return if dirty_log_mask is or becomes 0, because
- * cpu_physical_memory_set_dirty_range will still call
+ * physical_memory_set_dirty_range will still call
* xen_modified_memory.
*/
if (dirty_log_mask) {
dirty_log_mask =
- cpu_physical_memory_range_includes_clean(addr, length, dirty_log_mask);
+ physical_memory_range_includes_clean(addr, length, dirty_log_mask);
}
if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
assert(tcg_enabled());
tb_invalidate_phys_range(NULL, addr, addr + length - 1);
dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
}
- cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
+ physical_memory_set_dirty_range(addr, length, dirty_log_mask);
}
void memory_region_flush_rom_device(MemoryRegion *mr, hwaddr addr, hwaddr size)
@@ -3178,58 +3479,16 @@
return error;
}
-void cpu_physical_memory_rw(hwaddr addr, void *buf,
- hwaddr len, bool is_write)
+void cpu_physical_memory_read(hwaddr addr, void *buf, hwaddr len)
{
- address_space_rw(&address_space_memory, addr, MEMTXATTRS_UNSPECIFIED,
- buf, len, is_write);
+ address_space_read(&address_space_memory, addr,
+ MEMTXATTRS_UNSPECIFIED, buf, len);
}
-enum write_rom_type {
- WRITE_DATA,
- FLUSH_CACHE,
-};
-
-static inline MemTxResult address_space_write_rom_internal(AddressSpace *as,
- hwaddr addr,
- MemTxAttrs attrs,
- const void *ptr,
- hwaddr len,
- enum write_rom_type type)
+void cpu_physical_memory_write(hwaddr addr, const void *buf, hwaddr len)
{
- hwaddr l;
- uint8_t *ram_ptr;
- hwaddr addr1;
- MemoryRegion *mr;
- const uint8_t *buf = ptr;
-
- RCU_READ_LOCK_GUARD();
- while (len > 0) {
- l = len;
- mr = address_space_translate(as, addr, &addr1, &l, true, attrs);
-
- if (!memory_region_supports_direct_access(mr)) {
- l = memory_access_size(mr, l, addr1);
- } else {
- /* ROM/RAM case */
- ram_ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
- switch (type) {
- case WRITE_DATA:
- memcpy(ram_ptr, buf, l);
- invalidate_and_set_dirty(mr, addr1, l);
- break;
- case FLUSH_CACHE:
- flush_idcache_range((uintptr_t)ram_ptr, (uintptr_t)ram_ptr, l);
- break;
- }
- }
- len -= l;
- addr += l;
- if (buf) {
- buf += l;
- }
- }
- return MEMTX_OK;
+ address_space_write(&address_space_memory, addr,
+ MEMTXATTRS_UNSPECIFIED, buf, len);
}
/* used for ROM loading : can write in RAM and ROM */
@@ -3237,11 +3496,28 @@
MemTxAttrs attrs,
const void *buf, hwaddr len)
{
- return address_space_write_rom_internal(as, addr, attrs,
- buf, len, WRITE_DATA);
+ RCU_READ_LOCK_GUARD();
+ while (len > 0) {
+ hwaddr addr1, l = len;
+ MemoryRegion *mr = address_space_translate(as, addr, &addr1, &l,
+ true, attrs);
+
+ if (!memory_region_supports_direct_access(mr)) {
+ l = memory_access_size(mr, l, addr1);
+ } else {
+ /* ROM/RAM case */
+ void *ram_ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
+ memcpy(ram_ptr, buf, l);
+ invalidate_and_set_dirty(mr, addr1, l);
+ }
+ len -= l;
+ addr += l;
+ buf += l;
+ }
+ return MEMTX_OK;
}
-void cpu_flush_icache_range(hwaddr start, hwaddr len)
+void address_space_flush_icache_range(AddressSpace *as, hwaddr addr, hwaddr len)
{
/*
* This function should do the same thing as an icache flush that was
@@ -3253,9 +3529,22 @@
return;
}
- address_space_write_rom_internal(&address_space_memory,
- start, MEMTXATTRS_UNSPECIFIED,
- NULL, len, FLUSH_CACHE);
+ RCU_READ_LOCK_GUARD();
+ while (len > 0) {
+ hwaddr addr1, l = len;
+ MemoryRegion *mr = address_space_translate(as, addr, &addr1, &l, true,
+ MEMTXATTRS_UNSPECIFIED);
+
+ if (!memory_region_supports_direct_access(mr)) {
+ l = memory_access_size(mr, l, addr1);
+ } else {
+ /* ROM/RAM case */
+ void *ram_ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
+ flush_idcache_range((uintptr_t)ram_ptr, (uintptr_t)ram_ptr, l);
+ }
+ len -= l;
+ addr += l;
+ }
}
/*
@@ -3371,6 +3660,17 @@
return flatview_access_valid(fv, addr, len, is_write, attrs);
}
+bool address_space_is_io(AddressSpace *as, hwaddr addr)
+{
+ MemoryRegion *mr;
+
+ RCU_READ_LOCK_GUARD();
+ mr = address_space_translate(as, addr, &addr, NULL, false,
+ MEMTXATTRS_UNSPECIFIED);
+
+ return !(memory_region_is_ram(mr) || memory_region_is_romd(mr));
+}
+
static hwaddr
flatview_extend_translation(FlatView *fv, hwaddr addr,
hwaddr target_len,
@@ -3765,19 +4065,6 @@
return 0;
}
-bool cpu_physical_memory_is_io(hwaddr phys_addr)
-{
- MemoryRegion*mr;
- hwaddr l = 1;
-
- RCU_READ_LOCK_GUARD();
- mr = address_space_translate(&address_space_memory,
- phys_addr, &phys_addr, &l, false,
- MEMTXATTRS_UNSPECIFIED);
-
- return !(memory_region_is_ram(mr) || memory_region_is_romd(mr));
-}
-
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)
{
RAMBlock *block;
@@ -3794,18 +4081,18 @@
}
/*
- * Unmap pages of memory from start to start+length such that
+ * Unmap pages of memory from offset to offset+length such that
* they a) read as 0, b) Trigger whatever fault mechanism
* the OS provides for postcopy.
* The pages must be unmapped by the end of the function.
* Returns: 0 on success, none-0 on failure
*
*/
-int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length)
+int ram_block_discard_range(RAMBlock *rb, uint64_t offset, size_t length)
{
int ret = -1;
- uint8_t *host_startaddr = rb->host + start;
+ uint8_t *host_startaddr = rb->host + offset;
if (!QEMU_PTR_IS_ALIGNED(host_startaddr, rb->page_size)) {
error_report("%s: Unaligned start address: %p",
@@ -3813,7 +4100,7 @@
goto err;
}
- if ((start + length) <= rb->max_length) {
+ if ((offset + length) <= rb->max_length) {
bool need_madvise, need_fallocate;
if (!QEMU_IS_ALIGNED(length, rb->page_size)) {
error_report("%s: Unaligned length: %zx", __func__, length);
@@ -3864,11 +4151,11 @@
}
ret = fallocate(rb->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
- start + rb->fd_offset, length);
+ offset + rb->fd_offset, length);
if (ret) {
ret = -errno;
error_report("%s: Failed to fallocate %s:%" PRIx64 "+%" PRIx64
- " +%zx (%d)", __func__, rb->idstr, start,
+ " +%zx (%d)", __func__, rb->idstr, offset,
rb->fd_offset, length, ret);
goto err;
}
@@ -3876,7 +4163,7 @@
ret = -ENOSYS;
error_report("%s: fallocate not available/file"
"%s:%" PRIx64 "+%" PRIx64 " +%zx (%d)", __func__,
- rb->idstr, start, rb->fd_offset, length, ret);
+ rb->idstr, offset, rb->fd_offset, length, ret);
goto err;
#endif
}
@@ -3896,13 +4183,13 @@
ret = -errno;
error_report("%s: Failed to discard range "
"%s:%" PRIx64 " +%zx (%d)",
- __func__, rb->idstr, start, length, ret);
+ __func__, rb->idstr, offset, length, ret);
goto err;
}
#else
ret = -ENOSYS;
error_report("%s: MADVISE not available %s:%" PRIx64 " +%zx (%d)",
- __func__, rb->idstr, start, length, ret);
+ __func__, rb->idstr, offset, length, ret);
goto err;
#endif
}
@@ -3910,14 +4197,14 @@
need_madvise, need_fallocate, ret);
} else {
error_report("%s: Overrun block '%s' (%" PRIu64 "/%zx/" RAM_ADDR_FMT")",
- __func__, rb->idstr, start, length, rb->max_length);
+ __func__, rb->idstr, offset, length, rb->max_length);
}
err:
return ret;
}
-int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t start,
+int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t offset,
size_t length)
{
int ret = -1;
@@ -3925,23 +4212,23 @@
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE
/* ignore fd_offset with guest_memfd */
ret = fallocate(rb->guest_memfd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
- start, length);
+ offset, length);
if (ret) {
ret = -errno;
error_report("%s: Failed to fallocate %s:%" PRIx64 " +%zx (%d)",
- __func__, rb->idstr, start, length, ret);
+ __func__, rb->idstr, offset, length, ret);
}
#else
ret = -ENOSYS;
error_report("%s: fallocate not available %s:%" PRIx64 " +%zx (%d)",
- __func__, rb->idstr, start, length, ret);
+ __func__, rb->idstr, offset, length, ret);
#endif
return ret;
}
-bool ramblock_is_pmem(RAMBlock *rb)
+bool ram_block_is_pmem(RAMBlock *rb)
{
return rb->flags & RAM_PMEM;
}
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index 602f6a8..f59c18b 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1091,6 +1091,11 @@
return FIELD_EX64_IDREG(id, ID_AA64PFR0, RME) != 0;
}
+static inline bool isar_feature_aa64_rme_gpc2(const ARMISARegisters *id)
+{
+ return FIELD_EX64_IDREG(id, ID_AA64PFR0, RME) >= 2;
+}
+
static inline bool isar_feature_aa64_dit(const ARMISARegisters *id)
{
return FIELD_EX64_IDREG(id, ID_AA64PFR0, DIT) != 0;
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 2b9585d..41414ac 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1995,13 +1995,19 @@
FIELD(V7M_VPR, MASK23, 20, 4)
FIELD(GPCCR, PPS, 0, 3)
+FIELD(GPCCR, RLPAD, 5, 1)
+FIELD(GPCCR, NSPAD, 6, 1)
+FIELD(GPCCR, SPAD, 7, 1)
FIELD(GPCCR, IRGN, 8, 2)
FIELD(GPCCR, ORGN, 10, 2)
FIELD(GPCCR, SH, 12, 2)
FIELD(GPCCR, PGS, 14, 2)
FIELD(GPCCR, GPC, 16, 1)
FIELD(GPCCR, GPCP, 17, 1)
+FIELD(GPCCR, TBGPCD, 18, 1)
+FIELD(GPCCR, NSO, 19, 1)
FIELD(GPCCR, L0GPTSZ, 20, 4)
+FIELD(GPCCR, APPSAA, 24, 1)
FIELD(MFAR, FPA, 12, 40)
FIELD(MFAR, NSE, 62, 1)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index aa730ad..b7bf45a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3742,7 +3742,8 @@
value &= valid_mask;
/* RW is RAO/WI if EL1 is AArch64 only */
- if (!cpu_isar_feature(aa64_aa32_el1, cpu)) {
+ if (arm_feature(env, ARM_FEATURE_AARCH64) &&
+ !cpu_isar_feature(aa64_aa32_el1, cpu)) {
value |= HCR_RW;
}
@@ -4932,6 +4933,11 @@
R_GPCCR_ORGN_MASK | R_GPCCR_SH_MASK | R_GPCCR_PGS_MASK |
R_GPCCR_GPC_MASK | R_GPCCR_GPCP_MASK;
+ if (cpu_isar_feature(aa64_rme_gpc2, env_archcpu(env))) {
+ rw_mask |= R_GPCCR_APPSAA_MASK | R_GPCCR_NSO_MASK |
+ R_GPCCR_SPAD_MASK | R_GPCCR_NSPAD_MASK | R_GPCCR_RLPAD_MASK;
+ }
+
env->cp15.gpccr_el3 = (value & rw_mask) | (env->cp15.gpccr_el3 & ~rw_mask);
}
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 6344971..e03657f 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -36,8 +36,6 @@
/*
* in_space: the security space for this walk. This plus
* the in_mmu_idx specify the architectural translation regime.
- * If a Secure ptw is "downgraded" to NonSecure by an NSTable bit,
- * this field is updated accordingly.
*
* Note that the security space for the in_ptw_idx may be different
* from that for the in_mmu_idx. We do not need to explicitly track
@@ -53,6 +51,11 @@
*/
ARMSecuritySpace in_space;
/*
+ * Like in_space, except this may be "downgraded" to NonSecure
+ * by an NSTable bit.
+ */
+ ARMSecuritySpace cur_space;
+ /*
* in_debug: is this a QEMU debug access (gdbstub, etc)? Debug
* accesses will not update the guest page table access flags
* and will not change the state of the softmmu TLBs.
@@ -315,6 +318,7 @@
static bool granule_protection_check(CPUARMState *env, uint64_t paddress,
ARMSecuritySpace pspace,
+ ARMSecuritySpace ss,
ARMMMUFaultInfo *fi)
{
MemTxAttrs attrs = {
@@ -383,18 +387,37 @@
l0gptsz = 30 + FIELD_EX64(gpccr, GPCCR, L0GPTSZ);
/*
- * GPC Priority 2: Secure, Realm or Root address exceeds PPS.
- * R_CPDSB: A NonSecure physical address input exceeding PPS
- * does not experience any fault.
+ * GPC Priority 2: Access to Secure, NonSecure or Realm is prevented
+ * by one of the GPCCR_EL3 address space disable bits (R_TCWMD).
+ * All of these bits are checked vs aa64_rme_gpc2 in gpccr_write.
*/
- if (paddress & ~pps_mask) {
- if (pspace == ARMSS_NonSecure) {
- return true;
+ {
+ static const uint8_t disable_masks[4] = {
+ [ARMSS_Secure] = R_GPCCR_SPAD_MASK,
+ [ARMSS_NonSecure] = R_GPCCR_NSPAD_MASK,
+ [ARMSS_Root] = 0,
+ [ARMSS_Realm] = R_GPCCR_RLPAD_MASK,
+ };
+
+ if (gpccr & disable_masks[pspace]) {
+ goto fault_fail;
}
- goto fault_size;
}
- /* GPC Priority 3: the base address of GPTBR_EL3 exceeds PPS. */
+ /*
+ * GPC Priority 3: Secure, Realm or Root address exceeds PPS.
+ * R_CPDSB: A NonSecure physical address input exceeding PPS
+ * does not experience any fault.
+ * R_PBPSH: Other address spaces have fault suppressed by APPSAA.
+ */
+ if (paddress & ~pps_mask) {
+ if (pspace == ARMSS_NonSecure || FIELD_EX64(gpccr, GPCCR, APPSAA)) {
+ return true;
+ }
+ goto fault_fail;
+ }
+
+ /* GPC Priority 4: the base address of GPTBR_EL3 exceeds PPS. */
tableaddr = env->cp15.gptbr_el3 << 12;
if (tableaddr & ~pps_mask) {
goto fault_size;
@@ -475,18 +498,30 @@
break;
case 0b1111: /* all access */
return true;
- case 0b1000:
- case 0b1001:
- case 0b1010:
- case 0b1011:
+ case 0b1000: /* secure */
+ if (!cpu_isar_feature(aa64_sel2, cpu)) {
+ goto fault_walk;
+ }
+ /* fall through */
+ case 0b1001: /* non-secure */
+ case 0b1010: /* root */
+ case 0b1011: /* realm */
if (pspace == (gpi & 3)) {
return true;
}
break;
+ case 0b1101: /* non-secure only */
+ /* aa64_rme_gpc2 was checked in gpccr_write */
+ if (FIELD_EX64(gpccr, GPCCR, NSO)) {
+ return (pspace == ARMSS_NonSecure &&
+ (ss == ARMSS_NonSecure || ss == ARMSS_Root));
+ }
+ goto fault_walk;
default:
goto fault_walk; /* reserved */
}
+ fault_fail:
fi->gpcf = GPCF_Fail;
goto fault_common;
fault_eabt:
@@ -587,7 +622,8 @@
* From gdbstub, do not use softmmu so that we don't modify the
* state of the cpu at all, including softmmu tlb contents.
*/
- ARMSecuritySpace s2_space = S2_security_space(ptw->in_space, s2_mmu_idx);
+ ARMSecuritySpace s2_space
+ = S2_security_space(ptw->cur_space, s2_mmu_idx);
S1Translate s2ptw = {
.in_mmu_idx = s2_mmu_idx,
.in_ptw_idx = ptw_idx_for_stage_2(env, s2_mmu_idx),
@@ -630,7 +666,7 @@
}
if (regime_is_stage2(s2_mmu_idx)) {
- uint64_t hcr = arm_hcr_el2_eff_secstate(env, ptw->in_space);
+ uint64_t hcr = arm_hcr_el2_eff_secstate(env, ptw->cur_space);
if ((hcr & HCR_PTW) && S2_attrs_are_device(hcr, pte_attrs)) {
/*
@@ -641,7 +677,7 @@
fi->s2addr = addr;
fi->stage2 = true;
fi->s1ptw = true;
- fi->s1ns = fault_s1ns(ptw->in_space, s2_mmu_idx);
+ fi->s1ns = fault_s1ns(ptw->cur_space, s2_mmu_idx);
return false;
}
}
@@ -657,7 +693,7 @@
fi->s2addr = addr;
fi->stage2 = regime_is_stage2(s2_mmu_idx);
fi->s1ptw = fi->stage2;
- fi->s1ns = fault_s1ns(ptw->in_space, s2_mmu_idx);
+ fi->s1ns = fault_s1ns(ptw->cur_space, s2_mmu_idx);
return false;
}
@@ -844,7 +880,7 @@
fi->s2addr = ptw->out_virt;
fi->stage2 = true;
fi->s1ptw = true;
- fi->s1ns = fault_s1ns(ptw->in_space, ptw->in_ptw_idx);
+ fi->s1ns = fault_s1ns(ptw->cur_space, ptw->in_ptw_idx);
return 0;
}
@@ -1224,7 +1260,7 @@
g_assert_not_reached();
}
}
- out_space = ptw->in_space;
+ out_space = ptw->cur_space;
if (ns) {
/*
* The NS bit will (as required by the architecture) have no effect if
@@ -1254,7 +1290,7 @@
}
result->f.prot = get_S1prot(env, mmu_idx, false, user_rw, prot_rw,
- xn, pxn, result->f.attrs.space, out_space);
+ xn, pxn, ptw->in_space, out_space);
if (ptw->in_prot_check & ~result->f.prot) {
/* Access permission fault. */
fi->type = ARMFault_Permission;
@@ -1857,7 +1893,7 @@
* NonSecure. With RME, the EL3 translation regime does not change
* from Root to NonSecure.
*/
- if (ptw->in_space == ARMSS_Secure
+ if (ptw->cur_space == ARMSS_Secure
&& !regime_is_stage2(mmu_idx)
&& extract32(tableattrs, 4, 1)) {
/*
@@ -1867,7 +1903,7 @@
QEMU_BUILD_BUG_ON(ARMMMUIdx_Phys_S + 1 != ARMMMUIdx_Phys_NS);
QEMU_BUILD_BUG_ON(ARMMMUIdx_Stage2_S + 1 != ARMMMUIdx_Stage2);
ptw->in_ptw_idx += 1;
- ptw->in_space = ARMSS_NonSecure;
+ ptw->cur_space = ARMSS_NonSecure;
}
if (!S1_ptw_translate(env, ptw, descaddr, fi)) {
@@ -1991,7 +2027,7 @@
}
ap = extract32(attrs, 6, 2);
- out_space = ptw->in_space;
+ out_space = ptw->cur_space;
if (regime_is_stage2(mmu_idx)) {
/*
* R_GYNXY: For stage2 in Realm security state, bit 55 is NS.
@@ -2089,12 +2125,8 @@
user_rw = simple_ap_to_rw_prot_is_user(ap, true);
prot_rw = simple_ap_to_rw_prot_is_user(ap, false);
- /*
- * Note that we modified ptw->in_space earlier for NSTable, but
- * result->f.attrs retains a copy of the original security space.
- */
result->f.prot = get_S1prot(env, mmu_idx, aarch64, user_rw, prot_rw,
- xn, pxn, result->f.attrs.space, out_space);
+ xn, pxn, ptw->in_space, out_space);
/* Index into MAIR registers for cache attributes */
attrindx = extract32(attrs, 2, 3);
@@ -2192,7 +2224,7 @@
fi->level = level;
fi->stage2 = regime_is_stage2(mmu_idx);
}
- fi->s1ns = fault_s1ns(ptw->in_space, mmu_idx);
+ fi->s1ns = fault_s1ns(ptw->cur_space, mmu_idx);
return true;
}
@@ -3413,6 +3445,7 @@
* cannot upgrade a NonSecure translation regime's attributes
* to Secure or Realm.
*/
+ ptw->cur_space = ptw->in_space;
result->f.attrs.space = ptw->in_space;
result->f.attrs.secure = arm_space_is_secure(ptw->in_space);
@@ -3548,7 +3581,7 @@
return true;
}
if (!granule_protection_check(env, result->f.phys_addr,
- result->f.attrs.space, fi)) {
+ result->f.attrs.space, ptw->in_space, fi)) {
fi->type = ARMFault_GPCFOnOutput;
return true;
}
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index abef6a2..8c617fe 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -159,7 +159,8 @@
{
ARMCPU *cpu = ARM_CPU(obj);
- FIELD_DP64_IDREG(&cpu->isar, ID_AA64PFR0, RME, value);
+ /* Enable FEAT_RME_GPC2 */
+ FIELD_DP64_IDREG(&cpu->isar, ID_AA64PFR0, RME, value ? 2 : 0);
}
static void cpu_max_set_l0gptsz(Object *obj, Visitor *v, const char *name,
@@ -406,6 +407,79 @@
cpu->isar.reset_pmcr_el0 = 0x410b3000;
}
+static void aarch64_a78ae_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ ARMISARegisters *isar = &cpu->isar;
+
+ cpu->dtb_compatible = "arm,cortex-a78ae";
+ set_feature(&cpu->env, ARM_FEATURE_V8);
+ set_feature(&cpu->env, ARM_FEATURE_NEON);
+ set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
+ set_feature(&cpu->env, ARM_FEATURE_AARCH64);
+ set_feature(&cpu->env, ARM_FEATURE_EL2);
+ set_feature(&cpu->env, ARM_FEATURE_EL3);
+ set_feature(&cpu->env, ARM_FEATURE_PMU);
+
+ /* Ordered by 3.2.4 AArch64 registers by functional group */
+ SET_IDREG(isar, CLIDR, 0x82000023);
+ cpu->ctr = 0x9444c004;
+ cpu->dcz_blocksize = 4;
+ SET_IDREG(isar, ID_AA64DFR0, 0x0000000110305408ull);
+ SET_IDREG(isar, ID_AA64ISAR0, 0x0010100010211120ull);
+ SET_IDREG(isar, ID_AA64ISAR1, 0x0000000001200031ull);
+ SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101125ull);
+ SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull);
+ SET_IDREG(isar, ID_AA64MMFR2, 0x0000000100001011ull);
+ SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */
+ SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull);
+ SET_IDREG(isar, ID_AFR0, 0x00000000);
+ SET_IDREG(isar, ID_DFR0, 0x04010088);
+ SET_IDREG(isar, ID_ISAR0, 0x02101110);
+ SET_IDREG(isar, ID_ISAR1, 0x13112111);
+ SET_IDREG(isar, ID_ISAR2, 0x21232042);
+ SET_IDREG(isar, ID_ISAR3, 0x01112131);
+ SET_IDREG(isar, ID_ISAR4, 0x00010142);
+ SET_IDREG(isar, ID_ISAR5, 0x01011121);
+ SET_IDREG(isar, ID_ISAR6, 0x00000010);
+ SET_IDREG(isar, ID_MMFR0, 0x10201105);
+ SET_IDREG(isar, ID_MMFR1, 0x40000000);
+ SET_IDREG(isar, ID_MMFR2, 0x01260000);
+ SET_IDREG(isar, ID_MMFR3, 0x02122211);
+ SET_IDREG(isar, ID_MMFR4, 0x00021110);
+ SET_IDREG(isar, ID_PFR0, 0x10010131);
+ SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */
+ SET_IDREG(isar, ID_PFR2, 0x00000011);
+ cpu->midr = 0x410fd423; /* r0p3 */
+ cpu->revidr = 0;
+
+ /* From 3.2.33 CCSIDR_EL1 */
+ /* 64KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 7);
+ /* 64KB L1 icache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 2);
+ /* 512KB L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 8, 64, 512 * KiB, 7);
+
+ /* From 3.2.118 SCTLR_EL3 */
+ cpu->reset_sctlr = 0x30c50838;
+
+ /* From 3.4.23 ICH_VTR_EL2 */
+ cpu->gic_num_lrs = 4;
+ cpu->gic_vpribits = 5;
+ cpu->gic_vprebits = 5;
+ /* From 3.4.8 ICC_CTLR_EL3 */
+ cpu->gic_pribits = 5;
+
+ /* From 3.5.1 AdvSIMD AArch64 register summary */
+ cpu->isar.mvfr0 = 0x10110222;
+ cpu->isar.mvfr1 = 0x13211111;
+ cpu->isar.mvfr2 = 0x00000043;
+
+ /* From 5.5.1 AArch64 PMU register summary */
+ cpu->isar.reset_pmcr_el0 = 0x41223000;
+}
+
static void aarch64_a64fx_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -1321,6 +1395,11 @@
{ .name = "cortex-a55", .initfn = aarch64_a55_initfn },
{ .name = "cortex-a72", .initfn = aarch64_a72_initfn },
{ .name = "cortex-a76", .initfn = aarch64_a76_initfn },
+ /*
+ * The Cortex-A78AE differs slightly from the plain Cortex-A78. We don't
+ * currently model the latter.
+ */
+ { .name = "cortex-a78ae", .initfn = aarch64_a78ae_initfn },
{ .name = "cortex-a710", .initfn = aarch64_a710_initfn },
{ .name = "a64fx", .initfn = aarch64_a64fx_initfn },
{ .name = "neoverse-n1", .initfn = aarch64_neoverse_n1_initfn },
diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index 302e899..b96c953 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -21,12 +21,13 @@
#include "qemu/log.h"
#include "cpu.h"
#include "internals.h"
+#include "exec/target_page.h"
#include "exec/page-protection.h"
#ifdef CONFIG_USER_ONLY
#include "user/cpu_loop.h"
#include "user/page-protection.h"
#else
-#include "system/ram_addr.h"
+#include "system/physmem.h"
#endif
#include "accel/tcg/cpu-ldst.h"
#include "accel/tcg/probe.h"
@@ -188,7 +189,7 @@
*/
if (tag_access == MMU_DATA_STORE) {
ram_addr_t tag_ra = memory_region_get_ram_addr(mr) + xlat;
- cpu_physical_memory_set_dirty_flag(tag_ra, DIRTY_MEMORY_MIGRATION);
+ physical_memory_set_dirty_flag(tag_ra, DIRTY_MEMORY_MIGRATION);
}
return memory_region_get_ram_ptr(mr) + xlat;
diff --git a/target/i386/arch_memory_mapping.c b/target/i386/arch_memory_mapping.c
index a2398c2..560f468 100644
--- a/target/i386/arch_memory_mapping.c
+++ b/target/i386/arch_memory_mapping.c
@@ -35,7 +35,7 @@
}
start_paddr = (pte & ~0xfff) & ~(0x1ULL << 63);
- if (cpu_physical_memory_is_io(start_paddr)) {
+ if (address_space_is_io(as, start_paddr)) {
/* I/O region */
continue;
}
@@ -65,7 +65,7 @@
}
start_paddr = pte & ~0xfff;
- if (cpu_physical_memory_is_io(start_paddr)) {
+ if (address_space_is_io(as, start_paddr)) {
/* I/O region */
continue;
}
@@ -100,7 +100,7 @@
if (pde & PG_PSE_MASK) {
/* 2 MB page */
start_paddr = (pde & ~0x1fffff) & ~(0x1ULL << 63);
- if (cpu_physical_memory_is_io(start_paddr)) {
+ if (address_space_is_io(as, start_paddr)) {
/* I/O region */
continue;
}
@@ -142,7 +142,7 @@
*/
high_paddr = ((hwaddr)(pde & 0x1fe000) << 19);
start_paddr = (pde & ~0x3fffff) | high_paddr;
- if (cpu_physical_memory_is_io(start_paddr)) {
+ if (address_space_is_io(as, start_paddr)) {
/* I/O region */
continue;
}
@@ -203,7 +203,7 @@
if (pdpe & PG_PSE_MASK) {
/* 1 GB page */
start_paddr = (pdpe & ~0x3fffffff) & ~(0x1ULL << 63);
- if (cpu_physical_memory_is_io(start_paddr)) {
+ if (address_space_is_io(as, start_paddr)) {
/* I/O region */
continue;
}
diff --git a/target/i386/kvm/xen-emu.c b/target/i386/kvm/xen-emu.c
index 284c5ef..52de019 100644
--- a/target/i386/kvm/xen-emu.c
+++ b/target/i386/kvm/xen-emu.c
@@ -21,6 +21,7 @@
#include "system/address-spaces.h"
#include "xen-emu.h"
#include "trace.h"
+#include "system/memory.h"
#include "system/runstate.h"
#include "hw/pci/msi.h"
@@ -75,6 +76,7 @@
static int kvm_gva_rw(CPUState *cs, uint64_t gva, void *_buf, size_t sz,
bool is_write)
{
+ AddressSpace *as = cpu_addressspace(cs, MEMTXATTRS_UNSPECIFIED);
uint8_t *buf = (uint8_t *)_buf;
uint64_t gpa;
size_t len;
@@ -87,7 +89,7 @@
len = sz;
}
- cpu_physical_memory_rw(gpa, buf, len, is_write);
+ address_space_rw(as, gpa, MEMTXATTRS_UNSPECIFIED, buf, len, is_write);
buf += len;
sz -= len;
diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c
index ed42425..2e442ba 100644
--- a/target/i386/nvmm/nvmm-all.c
+++ b/target/i386/nvmm/nvmm-all.c
@@ -15,6 +15,7 @@
#include "accel/accel-ops.h"
#include "system/nvmm.h"
#include "system/cpus.h"
+#include "system/memory.h"
#include "system/runstate.h"
#include "qemu/main-loop.h"
#include "qemu/error-report.h"
@@ -516,7 +517,9 @@
static void
nvmm_mem_callback(struct nvmm_mem *mem)
{
- cpu_physical_memory_rw(mem->gpa, mem->data, mem->size, mem->write);
+ /* TODO: Get CPUState via mem->vcpu? */
+ address_space_rw(&address_space_memory, mem->gpa, MEMTXATTRS_UNSPECIFIED,
+ mem->data, mem->size, mem->write);
/* Needed, otherwise infinite loop. */
current_cpu->vcpu_dirty = false;
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 2a85168..2567618 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -788,8 +788,11 @@
void *ctx,
WHV_EMULATOR_MEMORY_ACCESS_INFO *ma)
{
- cpu_physical_memory_rw(ma->GpaAddress, ma->Data, ma->AccessSize,
- ma->Direction);
+ CPUState *cs = (CPUState *)ctx;
+ AddressSpace *as = cpu_addressspace(cs, MEMTXATTRS_UNSPECIFIED);
+
+ address_space_rw(as, ma->GpaAddress, MEMTXATTRS_UNSPECIFIED,
+ ma->Data, ma->AccessSize, ma->Direction);
return S_OK;
}
diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c
index 00946e9..487c41b 100644
--- a/target/s390x/mmu_helper.c
+++ b/target/s390x/mmu_helper.c
@@ -23,6 +23,7 @@
#include "kvm/kvm_s390x.h"
#include "system/kvm.h"
#include "system/tcg.h"
+#include "system/memory.h"
#include "exec/page-protection.h"
#include "exec/target_page.h"
#include "hw/hw.h"
@@ -522,6 +523,7 @@
int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
int len, bool is_write)
{
+ const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
int currlen, nr_pages, i;
target_ulong *pages;
uint64_t tec;
@@ -542,11 +544,13 @@
if (ret) {
trigger_access_exception(&cpu->env, ret, tec);
} else if (hostbuf != NULL) {
+ AddressSpace *as = CPU(cpu)->as;
+
/* Copy data by stepping through the area page by page */
for (i = 0; i < nr_pages; i++) {
currlen = MIN(len, TARGET_PAGE_SIZE - (laddr % TARGET_PAGE_SIZE));
- cpu_physical_memory_rw(pages[i] | (laddr & ~TARGET_PAGE_MASK),
- hostbuf, currlen, is_write);
+ address_space_rw(as, pages[i] | (laddr & ~TARGET_PAGE_MASK),
+ attrs, hostbuf, currlen, is_write);
laddr += currlen;
hostbuf += currlen;
len -= currlen;
diff --git a/tests/functional/aarch64/test_xlnx_versal.py b/tests/functional/aarch64/test_xlnx_versal.py
index 4b9c49e..45aa6e1 100755
--- a/tests/functional/aarch64/test_xlnx_versal.py
+++ b/tests/functional/aarch64/test_xlnx_versal.py
@@ -6,7 +6,7 @@
from qemu_test import LinuxKernelTest, Asset
-class XlnxVersalVirtMachine(LinuxKernelTest):
+class AmdVersalVirtMachine(LinuxKernelTest):
ASSET_KERNEL = Asset(
('http://ports.ubuntu.com/ubuntu-ports/dists/bionic-updates/main/'
@@ -20,8 +20,8 @@ class XlnxVersalVirtMachine(LinuxKernelTest):
'/ubuntu-installer/arm64/initrd.gz'),
'e7a5e716b6f516d8be315c06e7331aaf16994fe4222e0e7cfb34bc015698929e')
- def test_aarch64_xlnx_versal_virt(self):
- self.set_machine('xlnx-versal-virt')
+ def common_aarch64_amd_versal_virt(self, machine):
+ self.set_machine(machine)
kernel_path = self.ASSET_KERNEL.fetch()
initrd_path = self.ASSET_INITRD.fetch()
@@ -33,5 +33,11 @@ def test_aarch64_xlnx_versal_virt(self):
self.vm.launch()
self.wait_for_console_pattern('Checked W+X mappings: passed')
+ def test_aarch64_amd_versal_virt(self):
+ self.common_aarch64_amd_versal_virt('amd-versal-virt')
+
+ def test_aarch64_amd_versal2_virt(self):
+ self.common_aarch64_amd_versal_virt('amd-versal2-virt')
+
if __name__ == '__main__':
LinuxKernelTest.main()
diff --git a/tests/tsan/ignore.tsan b/tests/tsan/ignore.tsan
index 423e482..8fa00a2 100644
--- a/tests/tsan/ignore.tsan
+++ b/tests/tsan/ignore.tsan
@@ -4,7 +4,7 @@
# The eventual goal would be to fix these warnings.
# TSan is not happy about setting/getting of dirty bits,
-# for example, cpu_physical_memory_set_dirty_range,
-# and cpu_physical_memory_get_dirty.
+# for example, physical_memory_set_dirty_range,
+# and physical_memory_get_dirty.
src:bitops.c
src:bitmap.c