mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'pull-target-arm-20250916' of https://gitlab.com/pm215/qemu into staging
target-arm queue: * tests, scripts: Don't import print_function from __future__ * Implement FEAT_ATS1A * Remove deprecated pxa CPU family * arm/kvm: report registers we failed to set * Expose SME registers to GDB via gdbstub * linux-user/aarch64: Generate ESR signal records * hw/arm/raspi4b: remove redundant check in raspi_add_memory_node * hw/arm/virt: Allow user-creatable SMMUv3 dev instantiation * system: drop the -old-param option # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmjJpt8ZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3vRGEACO3VrePiMIA9N7egqlUiGn # aRQVqIKeuPVj6TRVG7BSNWlAX8qvnOWOKg1yGVHDZv/nLvRje9UyfUAw7pf6jXod # bzxWBCPJ0J0eOB64Tz87WRCLltKB5pEN+uIG00PtpBcXT1ixYCDgBZXyD3mwuJ4Q # 5Yc5hEwQzpmh+EycLtfCHbmjKDw3x1ncpVlGceOG4h5fvzIvIhcNcZJXfAHhbhyO # Y4c5PELrCkCLZaTtSSxd6VJ+vXQ9bNWyKaSZu2KRRnLcMeAqw2Ic7dLPlkzCVyxM # PTOHy4TuDu+kqCbkxdnhpI6fvq5kcHyfTL6qX6tth8ZZS+qKGtvMEIXnYoy6q1kh # 4jV5vizK8avx31fSiuTKVpttRv4dC+Aq5QrcgYtIVMeOwtkWHv610D8gcFPmXoG+ # uHX9WdzOjrYOzXVKzJaCZF6b7L31ptSEfOrx7asBC9k2wPRwonFXg4JGNq16Yann # aAO5TM7NAUvM2IPgqS+Tf1Bk0iQqORxGfqzCyL76OO/QMMgfBy9elKH0UR0G+ePJ # yjpub1oWIELSXsQGMrdFo1W4/NIpFMTu3DP9W+6XRPu1AvrAx/AsrTuvSvXoeFY9 # d/U3yWAXm5XxRzbCIUg7ke8I8zLwRz924M5PA8vophvSnfDLS3V8CJHLwbz/PqYc # 0P2KCeI6d2NIhVik4mgEoQ== # =5tK3 # -----END PGP SIGNATURE----- # gpg: Signature made Tue 16 Sep 2025 11:05:19 AM PDT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [unknown] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [unknown] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [unknown] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [unknown] # gpg: WARNING: The key's User ID is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * tag 'pull-target-arm-20250916' of https://gitlab.com/pm215/qemu: (36 commits) hw/usb/network: Remove hardcoded 0x40 prefix in STRING_ETHADDR response qtest/bios-tables-test: Update tables for smmuv3 tests qtest/bios-tables-test: Add tests for legacy smmuv3 and smmuv3 device bios-tables-test: Allow for smmuv3 test data. qemu-options.hx: Document the arm-smmuv3 device hw/arm/virt: Allow user-creatable SMMUv3 dev instantiation hw/pci: Introduce pci_setup_iommu_per_bus() for per-bus IOMMU ops retrieval hw/arm/virt: Add an SMMU_IO_LEN macro hw/arm/virt: Factor out common SMMUV3 dt bindings code hw/arm/virt-acpi-build: Update IORT for multiple smmuv3 devices hw/arm/virt-acpi-build: Re-arrange SMMUv3 IORT build hw/arm/smmu-common: Check SMMU has PCIe Root Complex association target/arm: Added test case for SME register exposure to GDB target/arm: Added support for SME register exposure to GDB target/arm: Increase MAX_PACKET_LENGTH for SME ZA remote gdb debugging arm/kvm: report registers we failed to set system: drop the -old-param option target/arm: Drop ARM_FEATURE_IWMMXT handling target/arm: Drop ARM_FEATURE_XSCALE handling target/arm: Remove iwmmxt helper functions ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
@@ -86,7 +86,6 @@ static uint32_t get_elf_hwcap(void)
|
||||
/* probe for the extra features */
|
||||
/* EDSP is in v5TE and above */
|
||||
GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
|
||||
GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
|
||||
GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
|
||||
GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
|
||||
GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
|
||||
|
||||
@@ -1839,6 +1839,12 @@ for target in $target_list; do
|
||||
echo "GDB=$gdb_bin" >> $config_target_mak
|
||||
fi
|
||||
|
||||
if test "${gdb_arches#*$arch}" != "$gdb_arches" && version_ge $gdb_version 14.1; then
|
||||
echo "GDB_HAS_SME_TILES=y" >> $config_target_mak
|
||||
else
|
||||
echo "GDB_HAS_SME_TILES=n" >> $config_target_mak
|
||||
fi
|
||||
|
||||
if test "${gdb_arches#*aarch64}" != "$gdb_arches" && version_ge $gdb_version 15.1; then
|
||||
echo "GDB_HAS_MTE=y" >> $config_target_mak
|
||||
fi
|
||||
|
||||
@@ -68,19 +68,6 @@ configurations (e.g. -smp drawers=1,books=1,clusters=1 for x86 PC machine) is
|
||||
marked deprecated since 9.0, users have to ensure that all the topology members
|
||||
described with -smp are supported by the target machine.
|
||||
|
||||
``-old-param`` option for booting Arm kernels via param_struct (since 10.0)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``-old-param`` command line option is specific to Arm targets:
|
||||
it is used when directly booting a guest kernel to pass it the
|
||||
command line and other information via the old ``param_struct`` ABI,
|
||||
rather than the newer ATAGS or DTB mechanisms. This option was only
|
||||
ever needed to support ancient kernels on some old board types
|
||||
like the ``akita`` or ``terrier``; it has been deprecated in the
|
||||
kernel since 2001. None of the board types QEMU supports need
|
||||
``param_struct`` support, so this option has been deprecated and will
|
||||
be removed in a future QEMU version.
|
||||
|
||||
QEMU Machine Protocol (QMP) commands
|
||||
------------------------------------
|
||||
|
||||
@@ -236,27 +223,6 @@ Keeping 32-bit host support alive is a substantial burden for the
|
||||
QEMU project. Thus QEMU will in future drop the support for all
|
||||
32-bit host systems.
|
||||
|
||||
linux-user mode CPUs
|
||||
--------------------
|
||||
|
||||
iwMMXt emulation and the ``pxa`` CPUs (since 10.0)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``pxa`` CPU family (``pxa250``, ``pxa255``, ``pxa260``,
|
||||
``pxa261``, ``pxa262``, ``pxa270-a0``, ``pxa270-a1``, ``pxa270``,
|
||||
``pxa270-b0``, ``pxa270-b1``, ``pxa270-c0``, ``pxa270-c5``) are no
|
||||
longer used in system emulation, because all the machine types which
|
||||
used these CPUs were removed in the QEMU 9.2 release. These CPUs can
|
||||
now only be used in linux-user mode, and to do that you would have to
|
||||
explicitly select one of these CPUs with the ``-cpu`` command line
|
||||
option or the ``QEMU_CPU`` environment variable.
|
||||
|
||||
We don't believe that anybody is using the iwMMXt emulation, and we do
|
||||
not have any tests to validate it or any real hardware or similar
|
||||
known-good implementation to test against. GCC is in the process of
|
||||
dropping their support for iwMMXt codegen. These CPU types are
|
||||
therefore deprecated in QEMU, and will be removed in a future release.
|
||||
|
||||
System emulator CPUs
|
||||
--------------------
|
||||
|
||||
|
||||
@@ -560,6 +560,18 @@ the options along with the machine models they were intended for.
|
||||
|
||||
Use ``-run-with user=..`` instead.
|
||||
|
||||
``-old-param`` option for booting Arm kernels via param_struct (removed in 10.2)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``-old-param`` command line option was specific to Arm targets:
|
||||
it was used when directly booting a guest kernel to pass it the
|
||||
command line and other information via the old ``param_struct`` ABI,
|
||||
rather than the newer ATAGS or DTB mechanisms. This option was only
|
||||
ever needed to support ancient kernels on some old board types
|
||||
like the ``akita`` or ``terrier``; it has been deprecated in the
|
||||
kernel since 2001. None of the board types QEMU supports need
|
||||
``param_struct`` support, so this option has been removed.
|
||||
|
||||
|
||||
User-mode emulator command line arguments
|
||||
-----------------------------------------
|
||||
@@ -1138,6 +1150,20 @@ reason the maintainers strongly suspected no one actually used it.
|
||||
QEMU Nios II architecture was orphan; Intel has EOL'ed the Nios II
|
||||
processor IP (see `Intel discontinuance notification`_).
|
||||
|
||||
iwMMXt emulation and the ``pxa`` CPUs (removed in 10.2)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``pxa`` CPU family (``pxa250``, ``pxa255``, ``pxa260``,
|
||||
``pxa261``, ``pxa262``, ``pxa270-a0``, ``pxa270-a1``, ``pxa270``,
|
||||
``pxa270-b0``, ``pxa270-b1``, ``pxa270-c0``, ``pxa270-c5``) were
|
||||
not available in system emulation, because all the machine types which
|
||||
used these CPUs were removed in the QEMU 9.2 release. We don't
|
||||
believe that anybody was using the iwMMXt emulation (which you
|
||||
would have to explicitly enable on the command line), and we did
|
||||
not have any tests to validate it or any real hardware or similar
|
||||
known-good implementation to test against. These CPUs have
|
||||
therefore been removed in linux-user mode as well.
|
||||
|
||||
TCG introspection features
|
||||
--------------------------
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ the following architecture extensions:
|
||||
- FEAT_AFP (Alternate floating-point behavior)
|
||||
- FEAT_Armv9_Crypto (Armv9 Cryptographic Extension)
|
||||
- FEAT_ASID16 (16 bit ASID)
|
||||
- FEAT_ATS1A (Address Translation operations that ignore stage 1 permissions)
|
||||
- FEAT_BBM at level 2 (Translation table break-before-make levels)
|
||||
- FEAT_BF16 (AArch64 BFloat16 instructions)
|
||||
- FEAT_BTI (Branch Target Identification)
|
||||
|
||||
+21
-1
@@ -11,7 +11,27 @@
|
||||
|
||||
#include "exec/cpu-common.h"
|
||||
|
||||
#define MAX_PACKET_LENGTH 4096
|
||||
/*
|
||||
* Most "large" transfers (e.g. memory reads, feature XML
|
||||
* transfer) have mechanisms in the gdb protocol for splitting
|
||||
* them. However, register values in particular cannot currently
|
||||
* be split. This packet size must therefore be at least big enough
|
||||
* for the worst-case register size. Currently that is Arm SME
|
||||
* ZA storage with a 256x256 byte value. We also must account
|
||||
* for the conversion from raw data to hex in gdb_memtohex(),
|
||||
* which writes 2 * size bytes, and for other protocol overhead
|
||||
* including command, register number and checksum which add
|
||||
* another 4 bytes of overhead. However, to be consistent with
|
||||
* the changes made in gdbserver to address this same requirement,
|
||||
* we add a total of 32 bytes to account for protocol overhead
|
||||
* (unclear why specifically 32 bytes), bringing the value of
|
||||
* MAX_PACKET_LENGTH to 2 * 256 * 256 + 32 = 131104.
|
||||
*
|
||||
* The commit making this change for gdbserver can be found here:
|
||||
* https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=
|
||||
* b816042e88583f280ad186ff124ab84d31fb592b
|
||||
*/
|
||||
#define MAX_PACKET_LENGTH 131104
|
||||
|
||||
/*
|
||||
* Shared structures and definitions
|
||||
|
||||
+1
-80
@@ -337,81 +337,6 @@ static void set_kernel_args(const struct arm_boot_info *info, AddressSpace *as)
|
||||
WRITE_WORD(p, 0);
|
||||
}
|
||||
|
||||
static void set_kernel_args_old(const struct arm_boot_info *info,
|
||||
AddressSpace *as)
|
||||
{
|
||||
hwaddr p;
|
||||
const char *s;
|
||||
int initrd_size = info->initrd_size;
|
||||
hwaddr base = info->loader_start;
|
||||
|
||||
/* see linux/include/asm-arm/setup.h */
|
||||
p = base + KERNEL_ARGS_ADDR;
|
||||
/* page_size */
|
||||
WRITE_WORD(p, 4096);
|
||||
/* nr_pages */
|
||||
WRITE_WORD(p, info->ram_size / 4096);
|
||||
/* ramdisk_size */
|
||||
WRITE_WORD(p, 0);
|
||||
#define FLAG_READONLY 1
|
||||
#define FLAG_RDLOAD 4
|
||||
#define FLAG_RDPROMPT 8
|
||||
/* flags */
|
||||
WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
|
||||
/* rootdev */
|
||||
WRITE_WORD(p, (31 << 8) | 0); /* /dev/mtdblock0 */
|
||||
/* video_num_cols */
|
||||
WRITE_WORD(p, 0);
|
||||
/* video_num_rows */
|
||||
WRITE_WORD(p, 0);
|
||||
/* video_x */
|
||||
WRITE_WORD(p, 0);
|
||||
/* video_y */
|
||||
WRITE_WORD(p, 0);
|
||||
/* memc_control_reg */
|
||||
WRITE_WORD(p, 0);
|
||||
/* unsigned char sounddefault */
|
||||
/* unsigned char adfsdrives */
|
||||
/* unsigned char bytes_per_char_h */
|
||||
/* unsigned char bytes_per_char_v */
|
||||
WRITE_WORD(p, 0);
|
||||
/* pages_in_bank[4] */
|
||||
WRITE_WORD(p, 0);
|
||||
WRITE_WORD(p, 0);
|
||||
WRITE_WORD(p, 0);
|
||||
WRITE_WORD(p, 0);
|
||||
/* pages_in_vram */
|
||||
WRITE_WORD(p, 0);
|
||||
/* initrd_start */
|
||||
if (initrd_size) {
|
||||
WRITE_WORD(p, info->initrd_start);
|
||||
} else {
|
||||
WRITE_WORD(p, 0);
|
||||
}
|
||||
/* initrd_size */
|
||||
WRITE_WORD(p, initrd_size);
|
||||
/* rd_start */
|
||||
WRITE_WORD(p, 0);
|
||||
/* system_rev */
|
||||
WRITE_WORD(p, 0);
|
||||
/* system_serial_low */
|
||||
WRITE_WORD(p, 0);
|
||||
/* system_serial_high */
|
||||
WRITE_WORD(p, 0);
|
||||
/* mem_fclk_21285 */
|
||||
WRITE_WORD(p, 0);
|
||||
/* zero unused fields */
|
||||
while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) {
|
||||
WRITE_WORD(p, 0);
|
||||
}
|
||||
s = info->kernel_cmdline;
|
||||
if (s) {
|
||||
address_space_write(as, p, MEMTXATTRS_UNSPECIFIED, s, strlen(s) + 1);
|
||||
} else {
|
||||
WRITE_WORD(p, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int fdt_add_memory_node(void *fdt, uint32_t acells, hwaddr mem_base,
|
||||
uint32_t scells, hwaddr mem_len,
|
||||
int numa_node_id)
|
||||
@@ -802,11 +727,7 @@ static void do_cpu_reset(void *opaque)
|
||||
cpu_set_pc(cs, info->loader_start);
|
||||
|
||||
if (!have_dtb(info)) {
|
||||
if (old_param) {
|
||||
set_kernel_args_old(info, as);
|
||||
} else {
|
||||
set_kernel_args(info, as);
|
||||
}
|
||||
set_kernel_args(info, as);
|
||||
}
|
||||
} else if (info->secondary_cpu_reset_hook) {
|
||||
info->secondary_cpu_reset_hook(cpu, info);
|
||||
|
||||
+9
-13
@@ -36,9 +36,8 @@ struct Raspi4bMachineState {
|
||||
* (see https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf
|
||||
* 1.2 Address Map)
|
||||
*/
|
||||
static int raspi_add_memory_node(void *fdt, hwaddr mem_base, hwaddr mem_len)
|
||||
static void raspi_add_memory_node(void *fdt, hwaddr mem_base, hwaddr mem_len)
|
||||
{
|
||||
int ret;
|
||||
uint32_t acells, scells;
|
||||
char *nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);
|
||||
|
||||
@@ -46,19 +45,16 @@ static int raspi_add_memory_node(void *fdt, hwaddr mem_base, hwaddr mem_len)
|
||||
NULL, &error_fatal);
|
||||
scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells",
|
||||
NULL, &error_fatal);
|
||||
if (acells == 0 || scells == 0) {
|
||||
fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n");
|
||||
ret = -1;
|
||||
} else {
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
|
||||
ret = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
|
||||
acells, mem_base,
|
||||
scells, mem_len);
|
||||
}
|
||||
/* validated by arm_load_dtb */
|
||||
g_assert(acells && scells);
|
||||
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
|
||||
qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
|
||||
acells, mem_base,
|
||||
scells, mem_len);
|
||||
|
||||
g_free(nodename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void raspi4_modify_dtb(const struct arm_boot_info *info, void *fdt)
|
||||
|
||||
+34
-3
@@ -20,6 +20,7 @@
|
||||
#include "trace.h"
|
||||
#include "exec/target_page.h"
|
||||
#include "hw/core/cpu.h"
|
||||
#include "hw/pci/pci_bridge.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/jhash.h"
|
||||
@@ -925,6 +926,7 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SMMUState *s = ARM_SMMU(dev);
|
||||
SMMUBaseClass *sbc = ARM_SMMU_GET_CLASS(dev);
|
||||
PCIBus *pci_bus = s->primary_bus;
|
||||
Error *local_err = NULL;
|
||||
|
||||
sbc->parent_realize(dev, &local_err);
|
||||
@@ -937,11 +939,39 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
|
||||
g_free, g_free);
|
||||
s->smmu_pcibus_by_busptr = g_hash_table_new(NULL, NULL);
|
||||
|
||||
if (s->primary_bus) {
|
||||
pci_setup_iommu(s->primary_bus, &smmu_ops, s);
|
||||
} else {
|
||||
if (!pci_bus) {
|
||||
error_setg(errp, "SMMU is not attached to any PCI bus!");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only allow default PCIe Root Complex(pcie.0) or pxb-pcie based extra
|
||||
* root complexes to be associated with SMMU.
|
||||
*/
|
||||
if (pci_bus_is_express(pci_bus) && pci_bus_is_root(pci_bus) &&
|
||||
object_dynamic_cast(OBJECT(pci_bus)->parent, TYPE_PCI_HOST_BRIDGE)) {
|
||||
/*
|
||||
* This condition matches either the default pcie.0, pxb-pcie, or
|
||||
* pxb-cxl. For both pxb-pcie and pxb-cxl, parent_dev will be set.
|
||||
* Currently, we don't allow pxb-cxl as it requires further
|
||||
* verification. Therefore, make sure this is indeed pxb-pcie.
|
||||
*/
|
||||
if (pci_bus->parent_dev) {
|
||||
if (!object_dynamic_cast(OBJECT(pci_bus), TYPE_PXB_PCIE_BUS)) {
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->smmu_per_bus) {
|
||||
pci_setup_iommu_per_bus(pci_bus, &smmu_ops, s);
|
||||
} else {
|
||||
pci_setup_iommu(pci_bus, &smmu_ops, s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
out_err:
|
||||
error_setg(errp, "SMMU should be attached to a default PCIe root complex"
|
||||
"(pcie.0) or a pxb-pcie based root complex");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -961,6 +991,7 @@ static void smmu_base_reset_exit(Object *obj, ResetType type)
|
||||
|
||||
static const Property smmu_dev_properties[] = {
|
||||
DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0),
|
||||
DEFINE_PROP_BOOL("smmu_per_bus", SMMUState, smmu_per_bus, false),
|
||||
DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus,
|
||||
TYPE_PCI_BUS, PCIBus *),
|
||||
};
|
||||
|
||||
@@ -1996,6 +1996,8 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
|
||||
device_class_set_parent_realize(dc, smmu_realize,
|
||||
&c->parent_realize);
|
||||
device_class_set_props(dc, smmuv3_properties);
|
||||
dc->hotpluggable = false;
|
||||
dc->user_creatable = true;
|
||||
}
|
||||
|
||||
static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,
|
||||
|
||||
+156
-45
@@ -45,6 +45,7 @@
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
#include "hw/acpi/tpm.h"
|
||||
#include "hw/acpi/hmat.h"
|
||||
#include "hw/arm/smmuv3.h"
|
||||
#include "hw/cxl/cxl.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci/pci.h"
|
||||
@@ -305,29 +306,126 @@ static int iort_idmap_compare(gconstpointer a, gconstpointer b)
|
||||
return idmap_a->input_base - idmap_b->input_base;
|
||||
}
|
||||
|
||||
typedef struct AcpiIortSMMUv3Dev {
|
||||
int irq;
|
||||
hwaddr base;
|
||||
GArray *rc_smmu_idmaps;
|
||||
/* Offset of the SMMUv3 IORT Node relative to the start of the IORT */
|
||||
size_t offset;
|
||||
} AcpiIortSMMUv3Dev;
|
||||
|
||||
/*
|
||||
* Populate the struct AcpiIortSMMUv3Dev for the legacy SMMUv3 and
|
||||
* return the total number of associated idmaps.
|
||||
*/
|
||||
static int populate_smmuv3_legacy_dev(GArray *sdev_blob)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
|
||||
AcpiIortSMMUv3Dev sdev;
|
||||
|
||||
sdev.rc_smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
|
||||
object_child_foreach_recursive(object_get_root(), iort_host_bridges,
|
||||
sdev.rc_smmu_idmaps);
|
||||
/*
|
||||
* There can be only one legacy SMMUv3("iommu=smmuv3") as it is a machine
|
||||
* wide one. Since it may cover multiple PCIe RCs(based on "bypass_iommu"
|
||||
* property), may have multiple SMMUv3 idmaps. Sort it by input_base.
|
||||
*/
|
||||
g_array_sort(sdev.rc_smmu_idmaps, iort_idmap_compare);
|
||||
|
||||
sdev.base = vms->memmap[VIRT_SMMU].base;
|
||||
sdev.irq = vms->irqmap[VIRT_SMMU] + ARM_SPI_BASE;
|
||||
g_array_append_val(sdev_blob, sdev);
|
||||
return sdev.rc_smmu_idmaps->len;
|
||||
}
|
||||
|
||||
static int smmuv3_dev_idmap_compare(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
AcpiIortSMMUv3Dev *sdev_a = (AcpiIortSMMUv3Dev *)a;
|
||||
AcpiIortSMMUv3Dev *sdev_b = (AcpiIortSMMUv3Dev *)b;
|
||||
AcpiIortIdMapping *map_a = &g_array_index(sdev_a->rc_smmu_idmaps,
|
||||
AcpiIortIdMapping, 0);
|
||||
AcpiIortIdMapping *map_b = &g_array_index(sdev_b->rc_smmu_idmaps,
|
||||
AcpiIortIdMapping, 0);
|
||||
return map_a->input_base - map_b->input_base;
|
||||
}
|
||||
|
||||
static int iort_smmuv3_devices(Object *obj, void *opaque)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
|
||||
GArray *sdev_blob = opaque;
|
||||
AcpiIortIdMapping idmap;
|
||||
PlatformBusDevice *pbus;
|
||||
AcpiIortSMMUv3Dev sdev;
|
||||
int min_bus, max_bus;
|
||||
SysBusDevice *sbdev;
|
||||
PCIBus *bus;
|
||||
|
||||
if (!object_dynamic_cast(obj, TYPE_ARM_SMMUV3)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bus = PCI_BUS(object_property_get_link(obj, "primary-bus", &error_abort));
|
||||
pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
|
||||
sbdev = SYS_BUS_DEVICE(obj);
|
||||
sdev.base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
|
||||
sdev.base += vms->memmap[VIRT_PLATFORM_BUS].base;
|
||||
sdev.irq = platform_bus_get_irqn(pbus, sbdev, 0);
|
||||
sdev.irq += vms->irqmap[VIRT_PLATFORM_BUS];
|
||||
sdev.irq += ARM_SPI_BASE;
|
||||
|
||||
pci_bus_range(bus, &min_bus, &max_bus);
|
||||
sdev.rc_smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
|
||||
idmap.input_base = min_bus << 8,
|
||||
idmap.id_count = (max_bus - min_bus + 1) << 8,
|
||||
g_array_append_val(sdev.rc_smmu_idmaps, idmap);
|
||||
g_array_append_val(sdev_blob, sdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populate the struct AcpiIortSMMUv3Dev for all SMMUv3 devices and
|
||||
* return the total number of idmaps.
|
||||
*/
|
||||
static int populate_smmuv3_dev(GArray *sdev_blob)
|
||||
{
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
iort_smmuv3_devices, sdev_blob);
|
||||
/* Sort the smmuv3 devices(if any) by smmu idmap input_base */
|
||||
g_array_sort(sdev_blob, smmuv3_dev_idmap_compare);
|
||||
/*
|
||||
* Since each SMMUv3 dev is assocaited with specific host bridge,
|
||||
* total number of idmaps equals to total number of smmuv3 devices.
|
||||
*/
|
||||
return sdev_blob->len;
|
||||
}
|
||||
|
||||
/* Compute ID ranges (RIDs) from RC that are directed to the ITS Group node */
|
||||
static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmu_idmaps)
|
||||
static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmuv3_devs)
|
||||
{
|
||||
AcpiIortIdMapping *idmap;
|
||||
AcpiIortIdMapping next_range = {0};
|
||||
AcpiIortSMMUv3Dev *sdev;
|
||||
|
||||
/*
|
||||
* Based on the RID ranges that are directed to the SMMU, determine the
|
||||
* bypassed RID ranges, i.e., the ones that are directed to the ITS Group
|
||||
* node and do not pass through the SMMU, by subtracting the SMMU-bound
|
||||
* ranges from the full RID range (0x0000–0xFFFF).
|
||||
*/
|
||||
for (int i = 0; i < smmu_idmaps->len; i++) {
|
||||
idmap = &g_array_index(smmu_idmaps, AcpiIortIdMapping, i);
|
||||
for (int i = 0; i < smmuv3_devs->len; i++) {
|
||||
sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
|
||||
/*
|
||||
* Based on the RID ranges that are directed to the SMMU, determine the
|
||||
* bypassed RID ranges, i.e., the ones that are directed to the ITS
|
||||
* Group node and do not pass through the SMMU, by subtracting the
|
||||
* SMMU-bound ranges from the full RID range (0x0000–0xFFFF).
|
||||
*/
|
||||
for (int j = 0; j < sdev->rc_smmu_idmaps->len; j++) {
|
||||
idmap = &g_array_index(sdev->rc_smmu_idmaps, AcpiIortIdMapping, j);
|
||||
|
||||
if (next_range.input_base < idmap->input_base) {
|
||||
next_range.id_count = idmap->input_base - next_range.input_base;
|
||||
g_array_append_val(its_idmaps, next_range);
|
||||
if (next_range.input_base < idmap->input_base) {
|
||||
next_range.id_count = idmap->input_base - next_range.input_base;
|
||||
g_array_append_val(its_idmaps, next_range);
|
||||
}
|
||||
|
||||
next_range.input_base = idmap->input_base + idmap->id_count;
|
||||
}
|
||||
|
||||
next_range.input_base = idmap->input_base + idmap->id_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append the last RC -> ITS ID mapping.
|
||||
*
|
||||
@@ -341,7 +439,6 @@ static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmu_idmaps)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Input Output Remapping Table (IORT)
|
||||
* Conforms to "IO Remapping Table System Software on ARM Platforms",
|
||||
@@ -351,9 +448,12 @@ static void
|
||||
build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
int i, nb_nodes, rc_mapping_count;
|
||||
size_t node_size, smmu_offset = 0;
|
||||
AcpiIortSMMUv3Dev *sdev;
|
||||
size_t node_size;
|
||||
int num_smmus = 0;
|
||||
uint32_t id = 0;
|
||||
GArray *rc_smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
|
||||
int rc_smmu_idmaps_len = 0;
|
||||
GArray *smmuv3_devs = g_array_new(false, true, sizeof(AcpiIortSMMUv3Dev));
|
||||
GArray *rc_its_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
|
||||
|
||||
AcpiTable table = { .sig = "IORT", .rev = 3, .oem_id = vms->oem_id,
|
||||
@@ -361,22 +461,23 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
/* Table 2 The IORT */
|
||||
acpi_table_begin(&table, table_data);
|
||||
|
||||
if (vms->iommu == VIRT_IOMMU_SMMUV3) {
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
iort_host_bridges, rc_smmu_idmaps);
|
||||
if (vms->legacy_smmuv3_present) {
|
||||
rc_smmu_idmaps_len = populate_smmuv3_legacy_dev(smmuv3_devs);
|
||||
} else {
|
||||
rc_smmu_idmaps_len = populate_smmuv3_dev(smmuv3_devs);
|
||||
}
|
||||
|
||||
/* Sort the smmu idmap by input_base */
|
||||
g_array_sort(rc_smmu_idmaps, iort_idmap_compare);
|
||||
|
||||
nb_nodes = 2; /* RC and SMMUv3 */
|
||||
rc_mapping_count = rc_smmu_idmaps->len;
|
||||
num_smmus = smmuv3_devs->len;
|
||||
if (num_smmus) {
|
||||
nb_nodes = num_smmus + 1; /* RC and SMMUv3 */
|
||||
rc_mapping_count = rc_smmu_idmaps_len;
|
||||
|
||||
if (vms->its) {
|
||||
/*
|
||||
* Knowing the ID ranges from the RC to the SMMU, it's possible to
|
||||
* determine the ID ranges from RC that go directly to ITS.
|
||||
*/
|
||||
create_rc_its_idmaps(rc_its_idmaps, rc_smmu_idmaps);
|
||||
create_rc_its_idmaps(rc_its_idmaps, smmuv3_devs);
|
||||
|
||||
nb_nodes++; /* ITS */
|
||||
rc_mapping_count += rc_its_idmaps->len;
|
||||
@@ -411,9 +512,10 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
build_append_int_noprefix(table_data, 0 /* MADT translation_id */, 4);
|
||||
}
|
||||
|
||||
if (vms->iommu == VIRT_IOMMU_SMMUV3) {
|
||||
int irq = vms->irqmap[VIRT_SMMU] + ARM_SPI_BASE;
|
||||
for (i = 0; i < num_smmus; i++) {
|
||||
sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
|
||||
int smmu_mapping_count, offset_to_id_array;
|
||||
int irq = sdev->irq;
|
||||
|
||||
if (vms->its) {
|
||||
smmu_mapping_count = 1; /* ITS Group node */
|
||||
@@ -422,7 +524,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
smmu_mapping_count = 0; /* No ID mappings */
|
||||
offset_to_id_array = 0; /* No ID mappings array */
|
||||
}
|
||||
smmu_offset = table_data->len - table.table_offset;
|
||||
sdev->offset = table_data->len - table.table_offset;
|
||||
/* Table 9 SMMUv3 Format */
|
||||
build_append_int_noprefix(table_data, 4 /* SMMUv3 */, 1); /* Type */
|
||||
node_size = SMMU_V3_ENTRY_SIZE +
|
||||
@@ -435,7 +537,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
/* Reference to ID Array */
|
||||
build_append_int_noprefix(table_data, offset_to_id_array, 4);
|
||||
/* Base address */
|
||||
build_append_int_noprefix(table_data, vms->memmap[VIRT_SMMU].base, 8);
|
||||
build_append_int_noprefix(table_data, sdev->base, 8);
|
||||
/* Flags */
|
||||
build_append_int_noprefix(table_data, 1 /* COHACC Override */, 4);
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
|
||||
@@ -486,21 +588,26 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
build_append_int_noprefix(table_data, 0, 3); /* Reserved */
|
||||
|
||||
/* Output Reference */
|
||||
if (vms->iommu == VIRT_IOMMU_SMMUV3) {
|
||||
if (num_smmus) {
|
||||
AcpiIortIdMapping *range;
|
||||
|
||||
/*
|
||||
* Map RIDs (input) from RC to SMMUv3 nodes: RC -> SMMUv3.
|
||||
*
|
||||
* N.B.: The mapping from SMMUv3 to ITS Group node (SMMUv3 -> ITS) is
|
||||
* defined in the SMMUv3 table, where all SMMUv3 IDs are mapped to the
|
||||
* ITS Group node, if ITS is available.
|
||||
*/
|
||||
for (i = 0; i < rc_smmu_idmaps->len; i++) {
|
||||
range = &g_array_index(rc_smmu_idmaps, AcpiIortIdMapping, i);
|
||||
/* Output IORT node is the SMMUv3 node. */
|
||||
build_iort_id_mapping(table_data, range->input_base,
|
||||
range->id_count, smmu_offset);
|
||||
for (i = 0; i < num_smmus; i++) {
|
||||
sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
|
||||
|
||||
/*
|
||||
* Map RIDs (input) from RC to SMMUv3 nodes: RC -> SMMUv3.
|
||||
*
|
||||
* N.B.: The mapping from SMMUv3 to ITS Group node (SMMUv3 -> ITS)
|
||||
* is defined in the SMMUv3 table, where all SMMUv3 IDs are mapped
|
||||
* to the ITS Group node, if ITS is available.
|
||||
*/
|
||||
for (int j = 0; j < sdev->rc_smmu_idmaps->len; j++) {
|
||||
range = &g_array_index(sdev->rc_smmu_idmaps,
|
||||
AcpiIortIdMapping, j);
|
||||
/* Output IORT node is the SMMUv3 node. */
|
||||
build_iort_id_mapping(table_data, range->input_base,
|
||||
range->id_count, sdev->offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (vms->its) {
|
||||
@@ -525,8 +632,12 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
}
|
||||
|
||||
acpi_table_end(linker, &table);
|
||||
g_array_free(rc_smmu_idmaps, true);
|
||||
g_array_free(rc_its_idmaps, true);
|
||||
for (i = 0; i < num_smmus; i++) {
|
||||
sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
|
||||
g_array_free(sdev->rc_smmu_idmaps, true);
|
||||
}
|
||||
g_array_free(smmuv3_devs, true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+85
-26
@@ -55,6 +55,7 @@
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "hw/pci-host/gpex.h"
|
||||
#include "hw/pci-bridge/pci_expander_bridge.h"
|
||||
#include "hw/virtio/virtio-pci.h"
|
||||
@@ -149,6 +150,9 @@ static void arm_virt_compat_set(MachineClass *mc)
|
||||
#define LEGACY_RAMLIMIT_GB 255
|
||||
#define LEGACY_RAMLIMIT_BYTES (LEGACY_RAMLIMIT_GB * GiB)
|
||||
|
||||
/* MMIO region size for SMMUv3 */
|
||||
#define SMMU_IO_LEN 0x20000
|
||||
|
||||
/* Addresses and sizes of our components.
|
||||
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
|
||||
* 128MB..256MB is used for miscellaneous device I/O.
|
||||
@@ -180,7 +184,7 @@ static const MemMapEntry base_memmap[] = {
|
||||
[VIRT_FW_CFG] = { 0x09020000, 0x00000018 },
|
||||
[VIRT_GPIO] = { 0x09030000, 0x00001000 },
|
||||
[VIRT_UART1] = { 0x09040000, 0x00001000 },
|
||||
[VIRT_SMMU] = { 0x09050000, 0x00020000 },
|
||||
[VIRT_SMMU] = { 0x09050000, SMMU_IO_LEN },
|
||||
[VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN },
|
||||
[VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN },
|
||||
[VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN},
|
||||
@@ -1442,19 +1446,66 @@ static void create_pcie_irq_map(const MachineState *ms,
|
||||
0x7 /* PCI irq */);
|
||||
}
|
||||
|
||||
static void create_smmuv3_dt_bindings(const VirtMachineState *vms, hwaddr base,
|
||||
hwaddr size, int irq)
|
||||
{
|
||||
char *node;
|
||||
const char compat[] = "arm,smmu-v3";
|
||||
const char irq_names[] = "eventq\0priq\0cmdq-sync\0gerror";
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
node = g_strdup_printf("/smmuv3@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(ms->fdt, node);
|
||||
qemu_fdt_setprop(ms->fdt, node, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, node, "reg", 2, base, 2, size);
|
||||
|
||||
qemu_fdt_setprop_cells(ms->fdt, node, "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq , GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq + 1, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq + 2, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq + 3, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
|
||||
|
||||
qemu_fdt_setprop(ms->fdt, node, "interrupt-names", irq_names,
|
||||
sizeof(irq_names));
|
||||
|
||||
qemu_fdt_setprop(ms->fdt, node, "dma-coherent", NULL, 0);
|
||||
qemu_fdt_setprop_cell(ms->fdt, node, "#iommu-cells", 1);
|
||||
qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle);
|
||||
g_free(node);
|
||||
}
|
||||
|
||||
static void create_smmuv3_dev_dtb(VirtMachineState *vms,
|
||||
DeviceState *dev, PCIBus *bus)
|
||||
{
|
||||
PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
|
||||
SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
|
||||
int irq = platform_bus_get_irqn(pbus, sbdev, 0);
|
||||
hwaddr base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
if (!(vms->bootinfo.firmware_loaded && virt_is_acpi_enabled(vms)) &&
|
||||
strcmp("pcie.0", bus->qbus.name)) {
|
||||
warn_report("SMMUv3 device only supported with pcie.0 for DT");
|
||||
return;
|
||||
}
|
||||
base += vms->memmap[VIRT_PLATFORM_BUS].base;
|
||||
irq += vms->irqmap[VIRT_PLATFORM_BUS];
|
||||
|
||||
vms->iommu_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
create_smmuv3_dt_bindings(vms, base, SMMU_IO_LEN, irq);
|
||||
qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map",
|
||||
0x0, vms->iommu_phandle, 0x0, 0x10000);
|
||||
}
|
||||
|
||||
static void create_smmu(const VirtMachineState *vms,
|
||||
PCIBus *bus)
|
||||
{
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
|
||||
char *node;
|
||||
const char compat[] = "arm,smmu-v3";
|
||||
int irq = vms->irqmap[VIRT_SMMU];
|
||||
int i;
|
||||
hwaddr base = vms->memmap[VIRT_SMMU].base;
|
||||
hwaddr size = vms->memmap[VIRT_SMMU].size;
|
||||
const char irq_names[] = "eventq\0priq\0cmdq-sync\0gerror";
|
||||
DeviceState *dev;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
if (vms->iommu != VIRT_IOMMU_SMMUV3 || !vms->iommu_phandle) {
|
||||
return;
|
||||
@@ -1473,27 +1524,7 @@ static void create_smmu(const VirtMachineState *vms,
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
|
||||
qdev_get_gpio_in(vms->gic, irq + i));
|
||||
}
|
||||
|
||||
node = g_strdup_printf("/smmuv3@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(ms->fdt, node);
|
||||
qemu_fdt_setprop(ms->fdt, node, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, node, "reg", 2, base, 2, size);
|
||||
|
||||
qemu_fdt_setprop_cells(ms->fdt, node, "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq , GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq + 1, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq + 2, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq + 3, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
|
||||
|
||||
qemu_fdt_setprop(ms->fdt, node, "interrupt-names", irq_names,
|
||||
sizeof(irq_names));
|
||||
|
||||
qemu_fdt_setprop(ms->fdt, node, "dma-coherent", NULL, 0);
|
||||
|
||||
qemu_fdt_setprop_cell(ms->fdt, node, "#iommu-cells", 1);
|
||||
|
||||
qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle);
|
||||
g_free(node);
|
||||
create_smmuv3_dt_bindings(vms, base, size, irq);
|
||||
}
|
||||
|
||||
static void create_virtio_iommu_dt_bindings(VirtMachineState *vms)
|
||||
@@ -1649,6 +1680,7 @@ static void create_pcie(VirtMachineState *vms)
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
|
||||
0x0, vms->iommu_phandle, 0x0, 0x10000);
|
||||
}
|
||||
vms->legacy_smmuv3_present = true;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
@@ -2996,6 +3028,16 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
||||
qlist_append_str(reserved_regions, resv_prop_str);
|
||||
qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
|
||||
g_free(resv_prop_str);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
|
||||
if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
|
||||
error_setg(errp, "virt machine already has %s set. "
|
||||
"Doesn't support incompatible iommus",
|
||||
(vms->legacy_smmuv3_present) ?
|
||||
"iommu=smmuv3" : "virtio-iommu");
|
||||
} else if (vms->iommu == VIRT_IOMMU_NONE) {
|
||||
/* The new SMMUv3 device is specific to the PCI bus */
|
||||
object_property_set_bool(OBJECT(dev), "smmu_per_bus", true, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3019,6 +3061,22 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||
virtio_md_pci_plug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
|
||||
}
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
|
||||
if (!vms->legacy_smmuv3_present && vms->platform_bus_dev) {
|
||||
PCIBus *bus;
|
||||
|
||||
bus = PCI_BUS(object_property_get_link(OBJECT(dev), "primary-bus",
|
||||
&error_abort));
|
||||
if (pci_bus_bypass_iommu(bus)) {
|
||||
error_setg(errp, "Bypass option cannot be set for SMMUv3 "
|
||||
"associated PCIe RC");
|
||||
return;
|
||||
}
|
||||
|
||||
create_smmuv3_dev_dtb(vms, dev, bus);
|
||||
}
|
||||
}
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
|
||||
PCIDevice *pdev = PCI_DEVICE(dev);
|
||||
|
||||
@@ -3218,6 +3276,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
|
||||
mc->max_cpus = 512;
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_ARM_SMMUV3);
|
||||
#ifdef CONFIG_TPM
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "system/device_tree.h"
|
||||
#include "system/tpm.h"
|
||||
#include "hw/arm/smmuv3.h"
|
||||
#include "hw/platform-bus.h"
|
||||
#include "hw/display/ramfb.h"
|
||||
#include "hw/uefi/var-service-api.h"
|
||||
@@ -135,6 +136,8 @@ static const BindingEntry bindings[] = {
|
||||
#ifdef CONFIG_TPM
|
||||
TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node),
|
||||
#endif
|
||||
/* No generic DT support for smmuv3 dev. Support added for arm virt only */
|
||||
TYPE_BINDING(TYPE_ARM_SMMUV3, no_fdt_node),
|
||||
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
|
||||
TYPE_BINDING(TYPE_UEFI_VARS_SYSBUS, add_uefi_vars_node),
|
||||
TYPE_BINDING("", NULL), /* last element */
|
||||
|
||||
@@ -34,7 +34,6 @@ typedef struct PXBBus PXBBus;
|
||||
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS,
|
||||
TYPE_PXB_BUS)
|
||||
|
||||
#define TYPE_PXB_PCIE_BUS "pxb-pcie-bus"
|
||||
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS,
|
||||
TYPE_PXB_PCIE_BUS)
|
||||
|
||||
|
||||
@@ -2912,6 +2912,19 @@ static void pci_device_get_iommu_bus_devfn(PCIDevice *dev,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When multiple PCI Express Root Buses are defined using pxb-pcie,
|
||||
* the IOMMU configuration may be specific to each root bus. However,
|
||||
* pxb-pcie acts as a special root complex whose parent is effectively
|
||||
* the default root complex(pcie.0). Ensure that we retrieve the
|
||||
* correct IOMMU ops(if any) in such cases.
|
||||
*/
|
||||
if (pci_bus_is_express(iommu_bus) && pci_bus_is_root(iommu_bus)) {
|
||||
if (parent_bus->iommu_per_bus) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iommu_bus = parent_bus;
|
||||
}
|
||||
|
||||
@@ -3172,6 +3185,24 @@ void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque)
|
||||
bus->iommu_opaque = opaque;
|
||||
}
|
||||
|
||||
/*
|
||||
* Similar to pci_setup_iommu(), but sets iommu_per_bus to true,
|
||||
* indicating that the IOMMU is specific to this bus. This is used by
|
||||
* IOMMU implementations that are tied to a specific PCIe root complex.
|
||||
*
|
||||
* In QEMU, pxb-pcie behaves as a special root complex whose parent is
|
||||
* effectively the default root complex (pcie.0). The iommu_per_bus
|
||||
* is checked in pci_device_get_iommu_bus_devfn() to ensure the correct
|
||||
* IOMMU ops are returned, avoiding the use of the parent’s IOMMU when
|
||||
* it's not appropriate.
|
||||
*/
|
||||
void pci_setup_iommu_per_bus(PCIBus *bus, const PCIIOMMUOps *ops,
|
||||
void *opaque)
|
||||
{
|
||||
pci_setup_iommu(bus, ops, opaque);
|
||||
bus->iommu_per_bus = true;
|
||||
}
|
||||
|
||||
static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque)
|
||||
{
|
||||
Range *range = opaque;
|
||||
|
||||
@@ -1383,7 +1383,7 @@ static void usb_net_realize(USBDevice *dev, Error **errp)
|
||||
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
||||
snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
|
||||
"%02x%02x%02x%02x%02x%02x",
|
||||
0x40,
|
||||
s->conf.macaddr.a[0],
|
||||
s->conf.macaddr.a[1],
|
||||
s->conf.macaddr.a[2],
|
||||
s->conf.macaddr.a[3],
|
||||
|
||||
@@ -161,6 +161,7 @@ struct SMMUState {
|
||||
QLIST_HEAD(, SMMUDevice) devices_with_notifiers;
|
||||
uint8_t bus_num;
|
||||
PCIBus *primary_bus;
|
||||
bool smmu_per_bus; /* SMMU is specific to the primary_bus */
|
||||
};
|
||||
|
||||
struct SMMUBaseClass {
|
||||
|
||||
@@ -179,6 +179,7 @@ struct VirtMachineState {
|
||||
char *oem_table_id;
|
||||
bool ns_el2_virt_timer_irq;
|
||||
CXLState cxl_devices_state;
|
||||
bool legacy_smmuv3_present;
|
||||
};
|
||||
|
||||
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)
|
||||
|
||||
@@ -773,6 +773,8 @@ int pci_iommu_unregister_iotlb_notifier(PCIDevice *dev, uint32_t pasid,
|
||||
*/
|
||||
void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque);
|
||||
|
||||
void pci_setup_iommu_per_bus(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque);
|
||||
|
||||
pcibus_t pci_bar_address(PCIDevice *d,
|
||||
int reg, uint8_t type, pcibus_t size);
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ typedef struct PXBPCIEDev {
|
||||
PXBDev parent_obj;
|
||||
} PXBPCIEDev;
|
||||
|
||||
#define TYPE_PXB_PCIE_BUS "pxb-pcie-bus"
|
||||
#define TYPE_PXB_CXL_BUS "pxb-cxl-bus"
|
||||
#define TYPE_PXB_DEV "pxb"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PXBDev, PXB_DEV)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user