diff options
-rw-r--r-- | MAINTAINERS | 4 | ||||
-rwxr-xr-x | configure | 57 | ||||
-rw-r--r-- | docs/specs/pci-testdev.txt | 15 | ||||
-rw-r--r-- | hw/block/vhost-user-blk.c | 25 | ||||
-rw-r--r-- | hw/block/virtio-blk.c | 4 | ||||
-rw-r--r-- | hw/i386/acpi-build.c | 31 | ||||
-rw-r--r-- | hw/i386/amd_iommu.c | 414 | ||||
-rw-r--r-- | hw/i386/amd_iommu.h | 96 | ||||
-rw-r--r-- | hw/i386/intel_iommu.c | 127 | ||||
-rw-r--r-- | hw/i386/trace-events | 14 | ||||
-rw-r--r-- | hw/i386/x86-iommu.c | 33 | ||||
-rw-r--r-- | hw/misc/pci-testdev.c | 19 | ||||
-rw-r--r-- | hw/pci-bridge/ioh3420.c | 2 | ||||
-rw-r--r-- | hw/pci-bridge/ioh3420.h | 6 | ||||
-rw-r--r-- | hw/pci-bridge/xio3130_downstream.c | 28 | ||||
-rw-r--r-- | hw/pci-bridge/xio3130_downstream.h | 11 | ||||
-rw-r--r-- | hw/pci-bridge/xio3130_upstream.c | 24 | ||||
-rw-r--r-- | hw/pci-bridge/xio3130_upstream.h | 10 | ||||
-rw-r--r-- | hw/pci-host/piix.c | 34 | ||||
-rw-r--r-- | hw/pci-host/q35.c | 17 | ||||
-rw-r--r-- | hw/pci/pci_bridge.c | 2 | ||||
-rw-r--r-- | hw/scsi/vhost-scsi.c | 2 | ||||
-rw-r--r-- | include/hw/i386/intel_iommu.h | 59 | ||||
-rw-r--r-- | include/hw/i386/x86-iommu.h | 66 | ||||
-rw-r--r-- | include/hw/pci/pci_bus.h | 2 | ||||
-rw-r--r-- | tests/bios-tables-test.c | 18 | ||||
-rw-r--r-- | tests/data/acpi/pc/APIC (renamed from tests/acpi-test-data/pc/APIC) | bin | 120 -> 120 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/APIC.cphp (renamed from tests/acpi-test-data/pc/APIC.cphp) | bin | 160 -> 160 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/APIC.dimmpxm (renamed from tests/acpi-test-data/pc/APIC.dimmpxm) | bin | 144 -> 144 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/DSDT (renamed from tests/acpi-test-data/pc/DSDT) | bin | 5131 -> 5131 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/DSDT.bridge (renamed from tests/acpi-test-data/pc/DSDT.bridge) | bin | 6990 -> 6990 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/DSDT.cphp (renamed from tests/acpi-test-data/pc/DSDT.cphp) | bin | 5594 -> 5594 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/DSDT.dimmpxm (renamed from tests/acpi-test-data/pc/DSDT.dimmpxm) | bin | 6790 -> 6790 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/DSDT.ipmikcs (renamed from tests/acpi-test-data/pc/DSDT.ipmikcs) | bin | 5203 -> 5203 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/DSDT.memhp (renamed from tests/acpi-test-data/pc/DSDT.memhp) | bin | 6496 -> 6496 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/DSDT.numamem (renamed from tests/acpi-test-data/pc/DSDT.numamem) | bin | 5137 -> 5137 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/FACP (renamed from tests/acpi-test-data/pc/FACP) | bin | 116 -> 116 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/FACS (renamed from tests/acpi-test-data/pc/FACS) | bin | 64 -> 64 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/HPET (renamed from tests/acpi-test-data/pc/HPET) | bin | 56 -> 56 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/NFIT.dimmpxm (renamed from tests/acpi-test-data/pc/NFIT.dimmpxm) | bin | 240 -> 240 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/SLIT.cphp (renamed from tests/acpi-test-data/pc/SLIT.cphp) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/SLIT.memhp (renamed from tests/acpi-test-data/pc/SLIT.memhp) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/SRAT.cphp (renamed from tests/acpi-test-data/pc/SRAT.cphp) | bin | 304 -> 304 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/SRAT.dimmpxm (renamed from tests/acpi-test-data/pc/SRAT.dimmpxm) | bin | 392 -> 392 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/SRAT.memhp (renamed from tests/acpi-test-data/pc/SRAT.memhp) | bin | 264 -> 264 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/SRAT.numamem (renamed from tests/acpi-test-data/pc/SRAT.numamem) | bin | 224 -> 224 bytes | |||
-rw-r--r-- | tests/data/acpi/pc/SSDT.dimmpxm (renamed from tests/acpi-test-data/pc/SSDT.dimmpxm) | bin | 685 -> 685 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/APIC (renamed from tests/acpi-test-data/q35/APIC) | bin | 120 -> 120 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/APIC.cphp (renamed from tests/acpi-test-data/q35/APIC.cphp) | bin | 160 -> 160 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/APIC.dimmpxm (renamed from tests/acpi-test-data/q35/APIC.dimmpxm) | bin | 144 -> 144 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/DSDT (renamed from tests/acpi-test-data/q35/DSDT) | bin | 7815 -> 7815 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/DSDT.bridge (renamed from tests/acpi-test-data/q35/DSDT.bridge) | bin | 7832 -> 7832 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/DSDT.cphp (renamed from tests/acpi-test-data/q35/DSDT.cphp) | bin | 8278 -> 8278 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/DSDT.dimmpxm (renamed from tests/acpi-test-data/q35/DSDT.dimmpxm) | bin | 9474 -> 9474 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/DSDT.ipmibt (renamed from tests/acpi-test-data/q35/DSDT.ipmibt) | bin | 7890 -> 7890 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/DSDT.memhp (renamed from tests/acpi-test-data/q35/DSDT.memhp) | bin | 9180 -> 9180 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/DSDT.mmio64 | bin | 0 -> 8947 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/DSDT.numamem (renamed from tests/acpi-test-data/q35/DSDT.numamem) | bin | 7821 -> 7821 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/FACP (renamed from tests/acpi-test-data/q35/FACP) | bin | 244 -> 244 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/FACS (renamed from tests/acpi-test-data/q35/FACS) | bin | 64 -> 64 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/HPET (renamed from tests/acpi-test-data/q35/HPET) | bin | 56 -> 56 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/MCFG (renamed from tests/acpi-test-data/q35/MCFG) | bin | 60 -> 60 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/NFIT.dimmpxm (renamed from tests/acpi-test-data/q35/NFIT.dimmpxm) | bin | 240 -> 240 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/SLIT.cphp (renamed from tests/acpi-test-data/q35/SLIT.cphp) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/SLIT.memhp (renamed from tests/acpi-test-data/q35/SLIT.memhp) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/SRAT.cphp (renamed from tests/acpi-test-data/q35/SRAT.cphp) | bin | 304 -> 304 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/SRAT.dimmpxm (renamed from tests/acpi-test-data/q35/SRAT.dimmpxm) | bin | 392 -> 392 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/SRAT.memhp (renamed from tests/acpi-test-data/q35/SRAT.memhp) | bin | 264 -> 264 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/SRAT.mmio64 | bin | 0 -> 224 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/SRAT.numamem (renamed from tests/acpi-test-data/q35/SRAT.numamem) | bin | 224 -> 224 bytes | |||
-rw-r--r-- | tests/data/acpi/q35/SSDT.dimmpxm (renamed from tests/acpi-test-data/q35/SSDT.dimmpxm) | bin | 685 -> 685 bytes | |||
-rwxr-xr-x | tests/data/acpi/rebuild-expected-aml.sh (renamed from tests/acpi-test-data/rebuild-expected-aml.sh) | 2 | ||||
-rw-r--r-- | tests/data/hex-loader/test.hex (renamed from tests/hex-loader-check-data/test.hex) | 0 | ||||
-rw-r--r-- | tests/hexloader-test.c | 2 |
74 files changed, 836 insertions, 288 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 8ec2281a7e..0499e11593 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1120,6 +1120,8 @@ F: hw/i386/acpi-build.[hc] F: hw/arm/virt-acpi-build.c F: tests/bios-tables-test.c F: tests/acpi-utils.[hc] +F: tests/acpi-test-data/* +F: tests/acpi-test-data/*/* ppc4xx M: Alexander Graf <agraf@suse.de> @@ -1376,7 +1378,7 @@ Intel Hexadecimal Object File Loader M: Su Hang <suhang16@mails.ucas.ac.cn> S: Maintained F: tests/hexloader-test.c -F: tests/hex-loader-check-data/test.hex +F: tests/data/hex-loader/test.hex CHRP NVRAM M: Thomas Huth <thuth@redhat.com> @@ -7392,22 +7392,33 @@ if test "$ccache_cpp2" = "yes"; then echo "export CCACHE_CPP2=y" >> $config_host_mak fi -# build tree in object directory in case the source is not in the current directory +# If we're using a separate build tree, set it up now. +# DIRS are directories which we simply mkdir in the build tree; +# LINKS are things to symlink back into the source tree +# (these can be both files and directories). +# Caution: do not add files or directories here using wildcards. This +# will result in problems later if a new file matching the wildcard is +# added to the source tree -- nothing will cause configure to be rerun +# so the build tree will be missing the link back to the new file, and +# tests might fail. Prefer to keep the relevant files in their own +# directory and symlink the directory instead. DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests tests/vm" DIRS="$DIRS tests/fp" DIRS="$DIRS docs docs/interop fsdev scsi" DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw" DIRS="$DIRS roms/seabios roms/vgabios" -FILES="Makefile tests/tcg/Makefile qdict-test-data.txt" -FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit" -FILES="$FILES tests/tcg/lm32/Makefile tests/tcg/xtensa/Makefile po/Makefile" -FILES="$FILES tests/fp/Makefile" -FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" -FILES="$FILES pc-bios/spapr-rtas/Makefile" -FILES="$FILES pc-bios/s390-ccw/Makefile" -FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile" -FILES="$FILES pc-bios/qemu-icon.bmp" -FILES="$FILES .gdbinit scripts" # scripts needed by relative path in .gdbinit +LINKS="Makefile tests/tcg/Makefile qdict-test-data.txt" +LINKS="$LINKS tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit" +LINKS="$LINKS tests/tcg/lm32/Makefile tests/tcg/xtensa/Makefile po/Makefile" +LINKS="$LINKS tests/fp/Makefile" +LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps" +LINKS="$LINKS pc-bios/spapr-rtas/Makefile" +LINKS="$LINKS pc-bios/s390-ccw/Makefile" +LINKS="$LINKS roms/seabios/Makefile roms/vgabios/Makefile" +LINKS="$LINKS pc-bios/qemu-icon.bmp" +LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit +LINKS="$LINKS tests/acceptance tests/data" +LINKS="$LINKS tests/qemu-iotests/check" for bios_file in \ $source_path/pc-bios/*.bin \ $source_path/pc-bios/*.lid \ @@ -7419,18 +7430,10 @@ for bios_file in \ $source_path/pc-bios/u-boot.* \ $source_path/pc-bios/palcode-* do - FILES="$FILES pc-bios/$(basename $bios_file)" -done -for test_file in $(find $source_path/tests/acpi-test-data -type f) -do - FILES="$FILES tests/acpi-test-data$(echo $test_file | sed -e 's/.*acpi-test-data//')" -done -for test_file in $(find $source_path/tests/hex-loader-check-data -type f) -do - FILES="$FILES tests/hex-loader-check-data$(echo $test_file | sed -e 's/.*hex-loader-check-data//')" + LINKS="$LINKS pc-bios/$(basename $bios_file)" done mkdir -p $DIRS -for f in $FILES ; do +for f in $LINKS ; do if [ -e "$source_path/$f" ] && [ "$pwd_is_source_path" != "y" ]; then symlink "$source_path/$f" "$f" fi @@ -7452,25 +7455,13 @@ for rom in seabios vgabios ; do echo "RANLIB=$ranlib" >> $config_mak done -# set up tests data directory -for tests_subdir in acceptance data; do - if [ ! -e tests/$tests_subdir ]; then - symlink "$source_path/tests/$tests_subdir" tests/$tests_subdir - fi -done - # set up qemu-iotests in this build directory iotests_common_env="tests/qemu-iotests/common.env" -iotests_check="tests/qemu-iotests/check" echo "# Automatically generated by configure - do not modify" > "$iotests_common_env" echo >> "$iotests_common_env" echo "export PYTHON='$python'" >> "$iotests_common_env" -if [ ! -e "$iotests_check" ]; then - symlink "$source_path/$iotests_check" "$iotests_check" -fi - # Save the configure command line for later reuse. cat <<EOD >config.status #!/bin/sh diff --git a/docs/specs/pci-testdev.txt b/docs/specs/pci-testdev.txt index 128ae222ef..4280a1e73c 100644 --- a/docs/specs/pci-testdev.txt +++ b/docs/specs/pci-testdev.txt @@ -1,11 +1,11 @@ pci-test is a device used for testing low level IO -device implements up to two BARs: BAR0 and BAR1. -Each BAR can be memory or IO. Guests must detect -BAR type and act accordingly. +device implements up to three BARs: BAR0, BAR1 and BAR2. +Each of BAR 0+1 can be memory or IO. Guests must detect +BAR types and act accordingly. -Each BAR size is up to 4K bytes. -Each BAR starts with the following header: +BAR 0+1 size is up to 4K bytes each. +BAR 0+1 starts with the following header: typedef struct PCITestDevHdr { uint8_t test; <- write-only, starts a given test number @@ -24,3 +24,8 @@ All registers are little endian. device is expected to always implement tests 0 to N on each BAR, and to add new tests with higher numbers. In this way a guest can scan test numbers until it detects an access type that it does not support on this BAR, then stop. + +BAR2 is a 64bit memory bar, without backing storage. It is disabled +by default and can be enabled using the membar=<size> property. This +can be used to test whether guests handle pci bars of a specific +(possibly quite large) size correctly. diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index d755223643..1451940845 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -217,7 +217,32 @@ static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev, static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) { + VHostUserBlk *s = VHOST_USER_BLK(vdev); + int i; + + if (!(virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1) && + !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1))) { + return; + } + + if (s->dev.started) { + return; + } + + /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start + * vhost here instead of waiting for .set_status(). + */ + vhost_user_blk_start(vdev); + /* Kick right away to begin processing requests already in vring */ + for (i = 0; i < s->dev.nvqs; i++) { + VirtQueue *kick_vq = virtio_get_queue(vdev, i); + + if (!virtio_queue_get_desc_addr(vdev, i)) { + continue; + } + event_notifier_set(virtio_queue_get_host_notifier(kick_vq)); + } } static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 225fe44b7a..83cf5c01f9 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -97,8 +97,8 @@ static void virtio_blk_rw_complete(void *opaque, int ret) if (req->qiov.nalloc != -1) { /* If nalloc is != 1 req->qiov is a local copy of the original - * external iovec. It was allocated in submit_merged_requests - * to be able to merge requests. */ + * external iovec. It was allocated in submit_requests to be + * able to merge requests. */ qemu_iovec_destroy(&req->qiov); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 1599caa7c5..236a20eaa8 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2467,9 +2467,12 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker) * IVRS table as specified in AMD IOMMU Specification v2.62, Section 5.2 * accessible here http://support.amd.com/TechDocs/48882_IOMMU.pdf */ +#define IOAPIC_SB_DEVID (uint64_t)PCI_BUILD_BDF(0, PCI_DEVFN(0x14, 0)) + static void build_amd_iommu(GArray *table_data, BIOSLinker *linker) { + int ivhd_table_len = 28; int iommu_start = table_data->len; AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default()); @@ -2491,8 +2494,16 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker) (1UL << 6) | /* PrefSup */ (1UL << 7), /* PPRSup */ 1); + + /* + * When interrupt remapping is supported, we add a special IVHD device + * for type IO-APIC. + */ + if (x86_iommu_get_default()->intr_supported) { + ivhd_table_len += 8; + } /* IVHD length */ - build_append_int_noprefix(table_data, 28, 2); + build_append_int_noprefix(table_data, ivhd_table_len, 2); /* DeviceID */ build_append_int_noprefix(table_data, s->devid, 2); /* Capability offset */ @@ -2507,7 +2518,8 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker) build_append_int_noprefix(table_data, (48UL << 30) | /* HATS */ (48UL << 28) | /* GATS */ - (1UL << 2), /* GTSup */ + (1UL << 2) | /* GTSup */ + (1UL << 6), /* GASup */ 4); /* * Type 1 device entry reporting all devices @@ -2516,6 +2528,21 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker) */ build_append_int_noprefix(table_data, 0x0000001, 4); + /* + * Add a special IVHD device type. + * Refer to spec - Table 95: IVHD device entry type codes + * + * Linux IOMMU driver checks for the special IVHD device (type IO-APIC). + * See Linux kernel commit 'c2ff5cf5294bcbd7fa50f7d860e90a66db7e5059' + */ + if (x86_iommu_get_default()->intr_supported) { + build_append_int_noprefix(table_data, + (0x1ull << 56) | /* type IOAPIC */ + (IOAPIC_SB_DEVID << 40) | /* IOAPIC devid */ + 0x48, /* special device */ + 8); + } + build_header(linker, table_data, (void *)(table_data->data + iommu_start), "IVRS", table_data->len - iommu_start, 1, NULL, NULL); } diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 1fd669fef8..353a810e6b 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -26,7 +26,9 @@ #include "amd_iommu.h" #include "qapi/error.h" #include "qemu/error-report.h" +#include "hw/i386/apic_internal.h" #include "trace.h" +#include "hw/i386/apic-msidef.h" /* used AMD-Vi MMIO registers */ const char *amdvi_mmio_low[] = { @@ -55,6 +57,7 @@ struct AMDVIAddressSpace { uint8_t bus_num; /* bus number */ uint8_t devfn; /* device function */ AMDVIState *iommu_state; /* AMDVI - one per machine */ + MemoryRegion root; /* AMDVI Root memory map region */ IOMMUMemoryRegion iommu; /* Device's address translation region */ MemoryRegion iommu_ir; /* Device's interrupt remapping region */ AddressSpace as; /* device's corresponding address space */ @@ -605,6 +608,7 @@ static void amdvi_handle_control_write(AMDVIState *s) s->completion_wait_intr = !!(control & AMDVI_MMIO_CONTROL_COMWAITINTEN); s->cmdbuf_enabled = s->enabled && !!(control & AMDVI_MMIO_CONTROL_CMDBUFLEN); + s->ga_enabled = !!(control & AMDVI_MMIO_CONTROL_GAEN); /* update the flags depending on the control register */ if (s->cmdbuf_enabled) { @@ -807,7 +811,7 @@ static inline uint64_t amdvi_get_perms(uint64_t entry) AMDVI_DEV_PERM_SHIFT; } -/* a valid entry should have V = 1 and reserved bits honoured */ +/* validate that reserved bits are honoured */ static bool amdvi_validate_dte(AMDVIState *s, uint16_t devid, uint64_t *dte) { @@ -820,7 +824,7 @@ static bool amdvi_validate_dte(AMDVIState *s, uint16_t devid, return false; } - return dte[0] & AMDVI_DEV_VALID; + return true; } /* get a device table entry given the devid */ @@ -966,8 +970,12 @@ static void amdvi_do_translate(AMDVIAddressSpace *as, hwaddr addr, return; } - /* devices with V = 0 are not translated */ if (!amdvi_get_dte(s, devid, entry)) { + return; + } + + /* devices with V = 0 are not translated */ + if (!(entry[0] & AMDVI_DEV_VALID)) { goto out; } @@ -1026,10 +1034,366 @@ static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr, return ret; } +static int amdvi_get_irte(AMDVIState *s, MSIMessage *origin, uint64_t *dte, + union irte *irte, uint16_t devid) +{ + uint64_t irte_root, offset; + + irte_root = dte[2] & AMDVI_IR_PHYS_ADDR_MASK; + offset = (origin->data & AMDVI_IRTE_OFFSET) << 2; + + trace_amdvi_ir_irte(irte_root, offset); + + if (dma_memory_read(&address_space_memory, irte_root + offset, + irte, sizeof(*irte))) { + trace_amdvi_ir_err("failed to get irte"); + return -AMDVI_IR_GET_IRTE; + } + + trace_amdvi_ir_irte_val(irte->val); + + return 0; +} + +static int amdvi_int_remap_legacy(AMDVIState *iommu, + MSIMessage *origin, + MSIMessage *translated, + uint64_t *dte, + X86IOMMUIrq *irq, + uint16_t sid) +{ + int ret; + union irte irte; + + /* get interrupt remapping table */ + ret = amdvi_get_irte(iommu, origin, dte, &irte, sid); + if (ret < 0) { + return ret; + } + + if (!irte.fields.valid) { + trace_amdvi_ir_target_abort("RemapEn is disabled"); + return -AMDVI_IR_TARGET_ABORT; + } + + if (irte.fields.guest_mode) { + error_report_once("guest mode is not zero"); + return -AMDVI_IR_ERR; + } + + if (irte.fields.int_type > AMDVI_IOAPIC_INT_TYPE_ARBITRATED) { + error_report_once("reserved int_type"); + return -AMDVI_IR_ERR; + } + + irq->delivery_mode = irte.fields.int_type; + irq->vector = irte.fields.vector; + irq->dest_mode = irte.fields.dm; + irq->redir_hint = irte.fields.rq_eoi; + irq->dest = irte.fields.destination; + + return 0; +} + +static int amdvi_get_irte_ga(AMDVIState *s, MSIMessage *origin, uint64_t *dte, + struct irte_ga *irte, uint16_t devid) +{ + uint64_t irte_root, offset; + + irte_root = dte[2] & AMDVI_IR_PHYS_ADDR_MASK; + offset = (origin->data & AMDVI_IRTE_OFFSET) << 4; + trace_amdvi_ir_irte(irte_root, offset); + + if (dma_memory_read(&address_space_memory, irte_root + offset, + irte, sizeof(*irte))) { + trace_amdvi_ir_err("failed to get irte_ga"); + return -AMDVI_IR_GET_IRTE; + } + + trace_amdvi_ir_irte_ga_val(irte->hi.val, irte->lo.val); + return 0; +} + +static int amdvi_int_remap_ga(AMDVIState *iommu, + MSIMessage *origin, + MSIMessage *translated, + uint64_t *dte, + X86IOMMUIrq *irq, + uint16_t sid) +{ + int ret; + struct irte_ga irte; + + /* get interrupt remapping table */ + ret = amdvi_get_irte_ga(iommu, origin, dte, &irte, sid); + if (ret < 0) { + return ret; + } + + if (!irte.lo.fields_remap.valid) { + trace_amdvi_ir_target_abort("RemapEn is disabled"); + return -AMDVI_IR_TARGET_ABORT; + } + + if (irte.lo.fields_remap.guest_mode) { + error_report_once("guest mode is not zero"); + return -AMDVI_IR_ERR; + } + + if (irte.lo.fields_remap.int_type > AMDVI_IOAPIC_INT_TYPE_ARBITRATED) { + error_report_once("reserved int_type is set"); + return -AMDVI_IR_ERR; + } + + irq->delivery_mode = irte.lo.fields_remap.int_type; + irq->vector = irte.hi.fields.vector; + irq->dest_mode = irte.lo.fields_remap.dm; + irq->redir_hint = irte.lo.fields_remap.rq_eoi; + irq->dest = irte.lo.fields_remap.destination; + + return 0; +} + +static int __amdvi_int_remap_msi(AMDVIState *iommu, + MSIMessage *origin, + MSIMessage *translated, + uint64_t *dte, + X86IOMMUIrq *irq, + uint16_t sid) +{ + int ret; + uint8_t int_ctl; + + int_ctl = (dte[2] >> AMDVI_IR_INTCTL_SHIFT) & 3; + trace_amdvi_ir_intctl(int_ctl); + + switch (int_ctl) { + case AMDVI_IR_INTCTL_PASS: + memcpy(translated, origin, sizeof(*origin)); + return 0; + case AMDVI_IR_INTCTL_REMAP: + break; + case AMDVI_IR_INTCTL_ABORT: + trace_amdvi_ir_target_abort("int_ctl abort"); + return -AMDVI_IR_TARGET_ABORT; + default: + trace_amdvi_ir_err("int_ctl reserved"); + return -AMDVI_IR_ERR; + } + + if (iommu->ga_enabled) { + ret = amdvi_int_remap_ga(iommu, origin, translated, dte, irq, sid); + } else { + ret = amdvi_int_remap_legacy(iommu, origin, translated, dte, irq, sid); + } + + return ret; +} + +/* Interrupt remapping for MSI/MSI-X entry */ +static int amdvi_int_remap_msi(AMDVIState *iommu, + MSIMessage *origin, + MSIMessage *translated, + uint16_t sid) +{ + int ret = 0; + uint64_t pass = 0; + uint64_t dte[4] = { 0 }; + X86IOMMUIrq irq = { 0 }; + uint8_t dest_mode, delivery_mode; + + assert(origin && translated); + + /* + * When IOMMU is enabled, interrupt remap request will come either from + * IO-APIC or PCI device. If interrupt is from PCI device then it will + * have a valid requester id but if the interrupt is from IO-APIC + * then requester id will be invalid. + */ + if (sid == X86_IOMMU_SID_INVALID) { + sid = AMDVI_IOAPIC_SB_DEVID; + } + + trace_amdvi_ir_remap_msi_req(origin->address, origin->data, sid); + + /* check if device table entry is set before we go further. */ + if (!iommu || !iommu->devtab_len) { + memcpy(translated, origin, sizeof(*origin)); + goto out; + } + + if (!amdvi_get_dte(iommu, sid, dte)) { + return -AMDVI_IR_ERR; + } + + /* Check if IR is enabled in DTE */ + if (!(dte[2] & AMDVI_IR_REMAP_ENABLE)) { + memcpy(translated, origin, sizeof(*origin)); + goto out; + } + + /* validate that we are configure with intremap=on */ + if (!X86_IOMMU_DEVICE(iommu)->intr_supported) { + trace_amdvi_err("Interrupt remapping is enabled in the guest but " + "not in the host. Use intremap=on to enable interrupt " + "remapping in amd-iommu."); + return -AMDVI_IR_ERR; + } + + if (origin->address & AMDVI_MSI_ADDR_HI_MASK) { + trace_amdvi_err("MSI address high 32 bits non-zero when " + "Interrupt Remapping enabled."); + return -AMDVI_IR_ERR; + } + + if ((origin->address & AMDVI_MSI_ADDR_LO_MASK) != APIC_DEFAULT_ADDRESS) { + trace_amdvi_err("MSI is not from IOAPIC."); + return -AMDVI_IR_ERR; + } + + /* + * The MSI data register [10:8] are used to get the upstream interrupt type. + * + * See MSI/MSI-X format: + * https://pdfs.semanticscholar.org/presentation/9420/c279e942eca568157711ef5c92b800c40a79.pdf + * (page 5) + */ + delivery_mode = (origin->data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 7; + + switch (delivery_mode) { + case AMDVI_IOAPIC_INT_TYPE_FIXED: + case AMDVI_IOAPIC_INT_TYPE_ARBITRATED: + trace_amdvi_ir_delivery_mode("fixed/arbitrated"); + ret = __amdvi_int_remap_msi(iommu, origin, translated, dte, &irq, sid); + if (ret < 0) { + goto remap_fail; + } else { + /* Translate IRQ to MSI messages */ + x86_iommu_irq_to_msi_message(&irq, translated); + goto out; + } + break; + case AMDVI_IOAPIC_INT_TYPE_SMI: + error_report("SMI is not supported!"); + ret = -AMDVI_IR_ERR; + break; + case AMDVI_IOAPIC_INT_TYPE_NMI: + pass = dte[3] & AMDVI_DEV_NMI_PASS_MASK; + trace_amdvi_ir_delivery_mode("nmi"); + break; + case AMDVI_IOAPIC_INT_TYPE_INIT: + pass = dte[3] & AMDVI_DEV_INT_PASS_MASK; + trace_amdvi_ir_delivery_mode("init"); + break; + case AMDVI_IOAPIC_INT_TYPE_EINT: + pass = dte[3] & AMDVI_DEV_EINT_PASS_MASK; + trace_amdvi_ir_delivery_mode("eint"); + break; + default: + trace_amdvi_ir_delivery_mode("unsupported delivery_mode"); + ret = -AMDVI_IR_ERR; + break; + } + + if (ret < 0) { + goto remap_fail; + } + + /* + * The MSI address register bit[2] is used to get the destination + * mode. The dest_mode 1 is valid for fixed and arbitrated interrupts + * only. + */ + dest_mode = (origin->address >> MSI_ADDR_DEST_MODE_SHIFT) & 1; + if (dest_mode) { + trace_amdvi_ir_err("invalid dest_mode"); + ret = -AMDVI_IR_ERR; + goto remap_fail; + } + + if (pass) { + memcpy(translated, origin, sizeof(*origin)); + } else { + trace_amdvi_ir_err("passthrough is not enabled"); + ret = -AMDVI_IR_ERR; + goto remap_fail; + } + +out: + trace_amdvi_ir_remap_msi(origin->address, origin->data, + translated->address, translated->data); + return 0; + +remap_fail: + return ret; +} + +static int amdvi_int_remap(X86IOMMUState *iommu, + MSIMessage *origin, + MSIMessage *translated, + uint16_t sid) +{ + return amdvi_int_remap_msi(AMD_IOMMU_DEVICE(iommu), origin, + translated, sid); +} + +static MemTxResult amdvi_mem_ir_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + int ret; + MSIMessage from = { 0, 0 }, to = { 0, 0 }; + uint16_t sid = AMDVI_IOAPIC_SB_DEVID; + + from.address = (uint64_t) addr + AMDVI_INT_ADDR_FIRST; + from.data = (uint32_t) value; + + trace_amdvi_mem_ir_write_req(addr, value, size); + + if (!attrs.unspecified) { + /* We have explicit Source ID */ + sid = attrs.requester_id; + } + + ret = amdvi_int_remap_msi(opaque, &from, &to, sid); + if (ret < 0) { + /* TODO: log the event using IOMMU log event interface */ + error_report_once("failed to remap interrupt from devid 0x%x", sid); + return MEMTX_ERROR; + } + + apic_get_class()->send_msi(&to); + + trace_amdvi_mem_ir_write(to.address, to.data); + return MEMTX_OK; +} + +static MemTxResult amdvi_mem_ir_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + return MEMTX_OK; +} + +static const MemoryRegionOps amdvi_ir_ops = { + .read_with_attrs = amdvi_mem_ir_read, + .write_with_attrs = amdvi_mem_ir_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) { + char name[128]; AMDVIState *s = opaque; - AMDVIAddressSpace **iommu_as; + AMDVIAddressSpace **iommu_as, *amdvi_dev_as; int bus_num = pci_bus_num(bus); iommu_as = s->address_spaces[bus_num]; @@ -1042,19 +1406,45 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) /* set up AMD-Vi region */ if (!iommu_as[devfn]) { + snprintf(name, sizeof(name), "amd_iommu_devfn_%d", devfn); + iommu_as[devfn] = g_malloc0(sizeof(AMDVIAddressSpace)); iommu_as[devfn]->bus_num = (uint8_t)bus_num; iommu_as[devfn]->devfn = (uint8_t)devfn; iommu_as[devfn]->iommu_state = s; - memory_region_init_iommu(&iommu_as[devfn]->iommu, - sizeof(iommu_as[devfn]->iommu), + amdvi_dev_as = iommu_as[devfn]; + + /* + * Memory region relationships looks like (Address range shows + * only lower 32 bits to make it short in length...): + * + * |-----------------+-------------------+----------| + * | Name | Address range | Priority | + * |-----------------+-------------------+----------+ + * | amdvi_root | 00000000-ffffffff | 0 | + * | amdvi_iommu | 00000000-ffffffff | 1 | + * | amdvi_iommu_ir | fee00000-feefffff | 64 | + * |-----------------+-------------------+----------| + */ + memory_region_init_iommu(&amdvi_dev_as->iommu, + sizeof(amdvi_dev_as->iommu), TYPE_AMD_IOMMU_MEMORY_REGION, OBJECT(s), - "amd-iommu", UINT64_MAX); - address_space_init(&iommu_as[devfn]->as, - MEMORY_REGION(&iommu_as[devfn]->iommu), - "amd-iommu"); + "amd_iommu", UINT64_MAX); + memory_region_init(&amdvi_dev_as->root, OBJECT(s), + "amdvi_root", UINT64_MAX); + address_space_init(&amdvi_dev_as->as, &amdvi_dev_as->root, name); + memory_region_init_io(&amdvi_dev_as->iommu_ir, OBJECT(s), + &amdvi_ir_ops, s, "amd_iommu_ir", + AMDVI_INT_ADDR_SIZE); + memory_region_add_subregion_overlap(&amdvi_dev_as->root, + AMDVI_INT_ADDR_FIRST, + &amdvi_dev_as->iommu_ir, + 64); + memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0, + MEMORY_REGION(&amdvi_dev_as->iommu), + 1); } return &iommu_as[devfn]->as; } @@ -1172,6 +1562,9 @@ static void amdvi_realize(DeviceState *dev, Error **err) return; } + /* Pseudo address space under root PCI bus. */ + pcms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID); + /* set up MMIO */ memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio", AMDVI_MMIO_SIZE); @@ -1205,6 +1598,7 @@ static void amdvi_class_init(ObjectClass *klass, void* data) dc->vmsd = &vmstate_amdvi; dc->hotpluggable = false; dc_class->realize = amdvi_realize; + dc_class->int_remap = amdvi_int_remap; /* Supported by the pc-q35-* machine types */ dc->user_creatable = true; } diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 874030582d..c52886f3ed 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -103,6 +103,7 @@ #define AMDVI_MMIO_CONTROL_EVENTINTEN (1ULL << 3) #define AMDVI_MMIO_CONTROL_COMWAITINTEN (1ULL << 4) #define AMDVI_MMIO_CONTROL_CMDBUFLEN (1ULL << 12) +#define AMDVI_MMIO_CONTROL_GAEN (1ULL << 17) /* MMIO status register bits */ #define AMDVI_MMIO_STATUS_CMDBUF_RUN (1 << 4) @@ -175,7 +176,7 @@ /* extended feature support */ #define AMDVI_EXT_FEATURES (AMDVI_FEATURE_PREFETCH | AMDVI_FEATURE_PPR | \ AMDVI_FEATURE_IA | AMDVI_FEATURE_GT | AMDVI_FEATURE_HE | \ - AMDVI_GATS_MODE | AMDVI_HATS_MODE) + AMDVI_GATS_MODE | AMDVI_HATS_MODE | AMDVI_FEATURE_GA) /* capabilities header */ #define AMDVI_CAPAB_FEATURES (AMDVI_CAPAB_FLAT_EXT | \ @@ -206,8 +207,94 @@ #define AMDVI_COMMAND_SIZE 16 -#define AMDVI_INT_ADDR_FIRST 0xfee00000 -#define AMDVI_INT_ADDR_LAST 0xfeefffff +#define AMDVI_INT_ADDR_FIRST 0xfee00000 +#define AMDVI_INT_ADDR_LAST 0xfeefffff +#define AMDVI_INT_ADDR_SIZE (AMDVI_INT_ADDR_LAST - AMDVI_INT_ADDR_FIRST + 1) +#define AMDVI_MSI_ADDR_HI_MASK (0xffffffff00000000ULL) +#define AMDVI_MSI_ADDR_LO_MASK (0x00000000ffffffffULL) + +/* SB IOAPIC is always on this device in AMD systems */ +#define AMDVI_IOAPIC_SB_DEVID PCI_BUILD_BDF(0, PCI_DEVFN(0x14, 0)) + +/* Interrupt remapping errors */ +#define AMDVI_IR_ERR 0x1 +#define AMDVI_IR_GET_IRTE 0x2 +#define AMDVI_IR_TARGET_ABORT 0x3 + +/* Interrupt remapping */ +#define AMDVI_IR_REMAP_ENABLE 1ULL +#define AMDVI_IR_INTCTL_SHIFT 60 +#define AMDVI_IR_INTCTL_ABORT 0 +#define AMDVI_IR_INTCTL_PASS 1 +#define AMDVI_IR_INTCTL_REMAP 2 + +#define AMDVI_IR_PHYS_ADDR_MASK (((1ULL << 45) - 1) << 6) + +/* MSI data 10:0 bits (section 2.2.5.1 Fig 14) */ +#define AMDVI_IRTE_OFFSET 0x7ff + +/* Delivery mode of MSI data (same as IOAPIC deilver mode encoding) */ +#define AMDVI_IOAPIC_INT_TYPE_FIXED 0x0 +#define AMDVI_IOAPIC_INT_TYPE_ARBITRATED 0x1 +#define AMDVI_IOAPIC_INT_TYPE_SMI 0x2 +#define AMDVI_IOAPIC_INT_TYPE_NMI 0x4 +#define AMDVI_IOAPIC_INT_TYPE_INIT 0x5 +#define AMDVI_IOAPIC_INT_TYPE_EINT 0x7 + +/* Pass through interrupt */ +#define AMDVI_DEV_INT_PASS_MASK (1ULL << 56) +#define AMDVI_DEV_EINT_PASS_MASK (1ULL << 57) +#define AMDVI_DEV_NMI_PASS_MASK (1ULL << 58) +#define AMDVI_DEV_LINT0_PASS_MASK (1ULL << 62) +#define AMDVI_DEV_LINT1_PASS_MASK (1ULL << 63) + +/* Interrupt remapping table fields (Guest VAPIC not enabled) */ +union irte { + uint32_t val; + struct { + uint32_t valid:1, + no_fault:1, + int_type:3, + rq_eoi:1, + dm:1, + guest_mode:1, + destination:8, + vector:8, + rsvd:8; + } fields; +}; + +/* Interrupt remapping table fields (Guest VAPIC is enabled) */ +union irte_ga_lo { + uint64_t val; + + /* For int remapping */ + struct { + uint64_t valid:1, + no_fault:1, + /* ------ */ + int_type:3, + rq_eoi:1, + dm:1, + /* ------ */ + guest_mode:1, + destination:8, + rsvd_1:48; + } fields_remap; +}; + +union irte_ga_hi { + uint64_t val; + struct { + uint64_t vector:8, + rsvd_2:56; + } fields; +}; + +struct irte_ga { + union irte_ga_lo lo; + union irte_ga_hi hi; +}; #define TYPE_AMD_IOMMU_DEVICE "amd-iommu" #define AMD_IOMMU_DEVICE(obj)\ @@ -278,6 +365,9 @@ typedef struct AMDVIState { /* IOTLB */ GHashTable *iotlb; + + /* Interrupt remapping */ + bool ga_enabled; } AMDVIState; #endif diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 3dfada19a6..d97bcbc2f7 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -37,6 +37,9 @@ #include "kvm_i386.h" #include "trace.h" +static void vtd_address_space_refresh_all(IntelIOMMUState *s); +static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n); + static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val, uint64_t wmask, uint64_t w1cmask) { @@ -227,6 +230,14 @@ static void vtd_reset_iotlb(IntelIOMMUState *s) vtd_iommu_unlock(s); } +static void vtd_reset_caches(IntelIOMMUState *s) +{ + vtd_iommu_lock(s); + vtd_reset_iotlb_locked(s); + vtd_reset_context_cache_locked(s); + vtd_iommu_unlock(s); +} + static uint64_t vtd_get_iotlb_key(uint64_t gfn, uint16_t source_id, uint32_t level) { @@ -1035,7 +1046,6 @@ static int vtd_sync_shadow_page_hook(IOMMUTLBEntry *entry, return 0; } -/* If context entry is NULL, we'll try to fetch it on our own. */ static int vtd_sync_shadow_page_table_range(VTDAddressSpace *vtd_as, VTDContextEntry *ce, hwaddr addr, hwaddr size) @@ -1047,39 +1057,41 @@ static int vtd_sync_shadow_page_table_range(VTDAddressSpace *vtd_as, .notify_unmap = true, .aw = s->aw_bits, .as = vtd_as, + .domain_id = VTD_CONTEXT_ENTRY_DID(ce->hi), }; - VTDContextEntry ce_cache; + + return vtd_page_walk(ce, addr, addr + size, &info); +} + +static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as) +{ int ret; + VTDContextEntry ce; + IOMMUNotifier *n; - if (ce) { - /* If the caller provided context entry, use it */ - ce_cache = *ce; - } else { - /* If the caller didn't provide ce, try to fetch */ - ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), - vtd_as->devfn, &ce_cache); - if (ret) { + ret = vtd_dev_to_context_entry(vtd_as->iommu_state, + pci_bus_num(vtd_as->bus), + vtd_as->devfn, &ce); + if (ret) { + if (ret == -VTD_FR_CONTEXT_ENTRY_P) { /* - * This should not really happen, but in case it happens, - * we just skip the sync for this time. After all we even - * don't have the root table pointer! + * It's a valid scenario to have a context entry that is + * not present. For example, when a device is removed + * from an existing domain then the context entry will be + * zeroed by the guest before it was put into another + * domain. When this happens, instead of synchronizing + * the shadow pages we should invalidate all existing + * mappings and notify the backends. */ - error_report_once("%s: invalid context entry for bus 0x%x" - " devfn 0x%x", - __func__, pci_bus_num(vtd_as->bus), - vtd_as->devfn); - return 0; + IOMMU_NOTIFIER_FOREACH(n, &vtd_as->iommu) { + vtd_address_space_unmap(vtd_as, n); + } + ret = 0; } + return ret; } - info.domain_id = VTD_CONTEXT_ENTRY_DID(ce_cache.hi); - - return vtd_page_walk(&ce_cache, addr, addr + size, &info); -} - -static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as) -{ - return vtd_sync_shadow_page_table_range(vtd_as, NULL, 0, UINT64_MAX); + return vtd_sync_shadow_page_table_range(vtd_as, &ce, 0, UINT64_MAX); } /* @@ -1428,7 +1440,7 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s) vtd_reset_context_cache_locked(s); } vtd_iommu_unlock(s); - vtd_switch_address_space_all(s); + vtd_address_space_refresh_all(s); /* * From VT-d spec 6.5.2.1, a global context entry invalidation * should be followed by a IOTLB global invalidation, so we should @@ -1719,6 +1731,8 @@ static void vtd_handle_gcmd_srtp(IntelIOMMUState *s) vtd_root_table_setup(s); /* Ok - report back to driver */ vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_RTPS); + vtd_reset_caches(s); + vtd_address_space_refresh_all(s); } /* Set Interrupt Remap Table Pointer */ @@ -1751,7 +1765,8 @@ static void vtd_handle_gcmd_te(IntelIOMMUState *s, bool en) vtd_set_clear_mask_long(s, DMAR_GSTS_REG, VTD_GSTS_TES, 0); } - vtd_switch_address_space_all(s); + vtd_reset_caches(s); + vtd_address_space_refresh_all(s); } /* Handle Interrupt Remap Enable/Disable */ @@ -2701,7 +2716,7 @@ static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, /* Fetch IRQ information of specific IR index */ static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, - VTDIrq *irq, uint16_t sid) + X86IOMMUIrq *irq, uint16_t sid) { VTD_IR_TableEntry irte = {}; int ret = 0; @@ -2730,30 +2745,6 @@ static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, return 0; } -/* Generate one MSI message from VTDIrq info */ -static void vtd_generate_msi_message(VTDIrq *irq, MSIMessage *msg_out) -{ - VTD_MSIMessage msg = {}; - - /* Generate address bits */ - msg.dest_mode = irq->dest_mode; - msg.redir_hint = irq->redir_hint; - msg.dest = irq->dest; - msg.__addr_hi = irq->dest & 0xffffff00; - msg.__addr_head = cpu_to_le32(0xfee); - /* Keep this from original MSI address bits */ - msg.__not_used = irq->msi_addr_last_bits; - - /* Generate data bits */ - msg.vector = irq->vector; - msg.delivery_mode = irq->delivery_mode; - msg.level = 1; - msg.trigger_mode = irq->trigger_mode; - - msg_out->address = msg.msi_addr; - msg_out->data = msg.msi_data; -} - /* Interrupt remapping for MSI/MSI-X entry */ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, MSIMessage *origin, @@ -2763,7 +2754,7 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, int ret = 0; VTD_IR_MSIAddress addr; uint16_t index; - VTDIrq irq = {}; + X86IOMMUIrq irq = {}; assert(origin && translated); @@ -2842,8 +2833,8 @@ static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, */ irq.msi_addr_last_bits = addr.addr.__not_care; - /* Translate VTDIrq to MSI message */ - vtd_generate_msi_message(&irq, translated); + /* Translate X86IOMMUIrq to MSI message */ + x86_iommu_irq_to_msi_message(&irq, translated); out: trace_vtd_ir_remap_msi(origin->address, origin->data, @@ -3051,6 +3042,12 @@ static void vtd_address_space_unmap_all(IntelIOMMUState *s) } } +static void vtd_address_space_refresh_all(IntelIOMMUState *s) +{ + vtd_address_space_unmap_all(s); + vtd_switch_address_space_all(s); +} + static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private) { memory_region_notify_one((IOMMUNotifier *)private, entry); @@ -3160,10 +3157,7 @@ static void vtd_init(IntelIOMMUState *s) s->cap |= VTD_CAP_CM; } - vtd_iommu_lock(s); - vtd_reset_context_cache_locked(s); - vtd_reset_iotlb_locked(s); - vtd_iommu_unlock(s); + vtd_reset_caches(s); /* Define registers with default values and bit semantics */ vtd_define_long(s, DMAR_VER_REG, 0x10UL, 0, 0); @@ -3226,11 +3220,7 @@ static void vtd_reset(DeviceState *dev) IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev); vtd_init(s); - - /* - * When device reset, throw away all mappings and external caches - */ - vtd_address_space_unmap_all(s); + vtd_address_space_refresh_all(s); } static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) @@ -3248,13 +3238,6 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp) { X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); - /* Currently Intel IOMMU IR only support "kernel-irqchip={off|split}" */ - if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() && - !kvm_irqchip_is_split()) { - error_setg(errp, "Intel Interrupt Remapping cannot work with " - "kernel-irqchip=on, please use 'split|off'."); - return false; - } if (s->intr_eim == ON_OFF_AUTO_ON && !x86_iommu->intr_supported) { error_setg(errp, "eim=on cannot be selected without intremap=on"); return false; diff --git a/hw/i386/trace-events b/hw/i386/trace-events index 9e6fc4dca9..6ac347d18c 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -101,6 +101,20 @@ amdvi_mode_invalid(uint8_t level, uint64_t addr)"error: translation level 0x%"PR amdvi_page_fault(uint64_t addr) "error: page fault accessing guest physical address 0x%"PRIx64 amdvi_iotlb_hit(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "hit iotlb devid %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64 amdvi_translation_result(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "devid: %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64 +amdvi_mem_ir_write_req(uint64_t addr, uint64_t val, uint32_t size) "addr 0x%"PRIx64" data 0x%"PRIx64" size 0x%"PRIx32 +amdvi_mem_ir_write(uint64_t addr, uint64_t val) "addr 0x%"PRIx64" data 0x%"PRIx64 +amdvi_ir_remap_msi_req(uint64_t addr, uint64_t data, uint8_t devid) "addr 0x%"PRIx64" data 0x%"PRIx64" devid 0x%"PRIx8 +amdvi_ir_remap_msi(uint64_t addr, uint64_t data, uint64_t addr2, uint64_t data2) "(addr 0x%"PRIx64", data 0x%"PRIx64") -> (addr 0x%"PRIx64", data 0x%"PRIx64")" +amdvi_err(const char *str) "%s" +amdvi_ir_irte(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" offset 0x%"PRIx64 +amdvi_ir_irte_val(uint32_t data) "data 0x%"PRIx32 +amdvi_ir_err(const char *str) "%s" +amdvi_ir_intctl(uint8_t val) "int_ctl 0x%"PRIx8 +amdvi_ir_target_abort(const char *str) "%s" +amdvi_ir_delivery_mode(const char *str) "%s" +amdvi_ir_generate_msi_message(uint8_t vector, uint8_t delivery_mode, uint8_t dest_mode, uint8_t dest, uint8_t rh) "vector %d delivery-mode %d dest-mode %d dest-id %d rh %d" +amdvi_ir_irte_ga(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" offset 0x%"PRIx64 +amdvi_ir_irte_ga_val(uint64_t hi, uint64_t lo) "hi 0x%"PRIx64" lo 0x%"PRIx64 # hw/i386/vmport.c vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p" diff --git a/hw/i386/x86-iommu.c b/hw/i386/x86-iommu.c index 8a01a2dd25..abc3c03158 100644 --- a/hw/i386/x86-iommu.c +++ b/hw/i386/x86-iommu.c @@ -25,6 +25,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "trace.h" +#include "sysemu/kvm.h" void x86_iommu_iec_register_notifier(X86IOMMUState *iommu, iec_notify_fn fn, void *data) @@ -52,6 +53,30 @@ void x86_iommu_iec_notify_all(X86IOMMUState *iommu, bool global, } } +/* Generate one MSI message from VTDIrq info */ +void x86_iommu_irq_to_msi_message(X86IOMMUIrq *irq, MSIMessage *msg_out) +{ + X86IOMMU_MSIMessage msg = {}; + + /* Generate address bits */ + msg.dest_mode = irq->dest_mode; + msg.redir_hint = irq->redir_hint; + msg.dest = irq->dest; + msg.__addr_hi = irq->dest & 0xffffff00; + msg.__addr_head = cpu_to_le32(0xfee); + /* Keep this from original MSI address bits */ + msg.__not_used = irq->msi_addr_last_bits; + + /* Generate data bits */ + msg.vector = irq->vector; + msg.delivery_mode = irq->delivery_mode; + msg.level = 1; + msg.trigger_mode = irq->trigger_mode; + + msg_out->address = msg.msi_addr; + msg_out->data = msg.msi_data; +} + /* Default X86 IOMMU device */ static X86IOMMUState *x86_iommu_default = NULL; @@ -94,6 +119,14 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp) return; } + /* Both Intel and AMD IOMMU IR only support "kernel-irqchip={off|split}" */ + if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() && + !kvm_irqchip_is_split()) { + error_setg(errp, "Interrupt Remapping cannot work with " + "kernel-irqchip=on, please use 'split|off'."); + return; + } + if (x86_class->realize) { x86_class->realize(dev, errp); } diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c index 32041f535f..1282d151cb 100644 --- a/hw/misc/pci-testdev.c +++ b/hw/misc/pci-testdev.c @@ -85,6 +85,9 @@ typedef struct PCITestDevState { MemoryRegion portio; IOTest *tests; int current; + + uint64_t membar_size; + MemoryRegion membar; } PCITestDevState; #define TYPE_PCI_TEST_DEV "pci-testdev" @@ -253,6 +256,16 @@ static void pci_testdev_realize(PCIDevice *pci_dev, Error **errp) pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->portio); + if (d->membar_size) { + memory_region_init(&d->membar, OBJECT(d), "pci-testdev-membar", + d->membar_size); + pci_register_bar(pci_dev, 2, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_PREFETCH | + PCI_BASE_ADDRESS_MEM_TYPE_64, + &d->membar); + } + d->current = -1; d->tests = g_malloc0(IOTEST_MAX * sizeof *d->tests); for (i = 0; i < IOTEST_MAX; ++i) { @@ -305,6 +318,11 @@ static void qdev_pci_testdev_reset(DeviceState *dev) pci_testdev_reset(d); } +static Property pci_testdev_properties[] = { + DEFINE_PROP_SIZE("membar", PCITestDevState, membar_size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void pci_testdev_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -319,6 +337,7 @@ static void pci_testdev_class_init(ObjectClass *klass, void *data) dc->desc = "PCI Test Device"; set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->reset = qdev_pci_testdev_reset; + dc->props = pci_testdev_properties; } static const TypeInfo pci_testdev_info = { diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index a451d74ee6..81f2de6f07 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -24,7 +24,7 @@ #include "hw/pci/pci_ids.h" #include "hw/pci/msi.h" #include "hw/pci/pcie.h" -#include "ioh3420.h" +#include "hw/pci/pcie_port.h" #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */ #define PCI_DEVICE_ID_IOH_REV 0x2 diff --git a/hw/pci-bridge/ioh3420.h b/hw/pci-bridge/ioh3420.h deleted file mode 100644 index ea423cb991..0000000000 --- a/hw/pci-bridge/ioh3420.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef QEMU_IOH3420_H -#define QEMU_IOH3420_H - -#include "hw/pci/pcie_port.h" - -#endif /* QEMU_IOH3420_H */ diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index b202657954..467bbabe4c 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -23,7 +23,7 @@ #include "hw/pci/pci_ids.h" #include "hw/pci/msi.h" #include "hw/pci/pcie.h" -#include "xio3130_downstream.h" +#include "hw/pci/pcie_port.h" #include "qapi/error.h" #define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */ @@ -127,32 +127,6 @@ static void xio3130_downstream_exitfn(PCIDevice *d) pci_bridge_exitfn(d); } -PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction, - const char *bus_name, pci_map_irq_fn map_irq, - uint8_t port, uint8_t chassis, - uint16_t slot) -{ - PCIDevice *d; - PCIBridge *br; - DeviceState *qdev; - - d = pci_create_multifunction(bus, devfn, multifunction, - "xio3130-downstream"); - if (!d) { - return NULL; - } - br = PCI_BRIDGE(d); - - qdev = DEVICE(d); - pci_bridge_map_irq(br, bus_name, map_irq); - qdev_prop_set_uint8(qdev, "port", port); - qdev_prop_set_uint8(qdev, "chassis", chassis); - qdev_prop_set_uint16(qdev, "slot", slot); - qdev_init_nofail(qdev); - - return PCIE_SLOT(d); -} - static Property xio3130_downstream_props[] = { DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present, QEMU_PCIE_SLTCAP_PCP_BITNR, true), diff --git a/hw/pci-bridge/xio3130_downstream.h b/hw/pci-bridge/xio3130_downstream.h deleted file mode 100644 index 8426d9ffa6..0000000000 --- a/hw/pci-bridge/xio3130_downstream.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef QEMU_XIO3130_DOWNSTREAM_H -#define QEMU_XIO3130_DOWNSTREAM_H - -#include "hw/pci/pcie_port.h" - -PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction, - const char *bus_name, pci_map_irq_fn map_irq, - uint8_t port, uint8_t chassis, - uint16_t slot); - -#endif /* QEMU_XIO3130_DOWNSTREAM_H */ diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index bca2f9a5ea..b524908cf1 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -23,7 +23,7 @@ #include "hw/pci/pci_ids.h" #include "hw/pci/msi.h" #include "hw/pci/pcie.h" -#include "xio3130_upstream.h" +#include "hw/pci/pcie_port.h" #define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */ #define XIO3130_REVISION 0x2 @@ -108,28 +108,6 @@ static void xio3130_upstream_exitfn(PCIDevice *d) pci_bridge_exitfn(d); } -PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction, - const char *bus_name, pci_map_irq_fn map_irq, - uint8_t port) -{ - PCIDevice *d; - PCIBridge *br; - DeviceState *qdev; - - d = pci_create_multifunction(bus, devfn, multifunction, "x3130-upstream"); - if (!d) { - return NULL; - } - br = PCI_BRIDGE(d); - - qdev = DEVICE(d); - pci_bridge_map_irq(br, bus_name, map_irq); - qdev_prop_set_uint8(qdev, "port", port); - qdev_init_nofail(qdev); - - return PCIE_PORT(d); -} - static const VMStateDescription vmstate_xio3130_upstream = { .name = "xio3130-express-upstream-port", .priority = MIG_PRI_PCI_BUS, diff --git a/hw/pci-bridge/xio3130_upstream.h b/hw/pci-bridge/xio3130_upstream.h deleted file mode 100644 index d0ab7577e2..0000000000 --- a/hw/pci-bridge/xio3130_upstream.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef QEMU_XIO3130_UPSTREAM_H -#define QEMU_XIO3130_UPSTREAM_H - -#include "hw/pci/pcie_port.h" - -PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction, - const char *bus_name, pci_map_irq_fn map_irq, - uint8_t port); - -#endif /* QEMU_XIO3130_UPSTREAM_H */ diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 47293a3915..d9c70f7ce6 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -40,7 +40,7 @@ /* * I440FX chipset data sheet. - * http://download.intel.com/design/chipsets/datashts/29054901.pdf + * https://wiki.qemu.org/File:29054901.pdf */ #define I440FX_PCI_HOST_BRIDGE(obj) \ @@ -95,6 +95,9 @@ typedef struct PIIX3State { #define I440FX_PCI_DEVICE(obj) \ OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE) +#define TYPE_PIIX3_DEVICE "PIIX3" +#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen" + struct PCII440FXState { /*< private >*/ PCIDevice parent_obj; @@ -142,7 +145,7 @@ static void i440fx_update_memory_mappings(PCII440FXState *d) PCIDevice *pd = PCI_DEVICE(d); memory_region_transaction_begin(); - for (i = 0; i < 13; i++) { + for (i = 0; i < ARRAY_SIZE(d->pam_regions); i++) { pam_update(&d->pam_regions[i], i, pd->config[I440FX_PAM + DIV_ROUND_UP(i, 2)]); } @@ -249,9 +252,7 @@ static void i440fx_pcihost_get_pci_hole_end(Object *obj, Visitor *v, * the 64bit PCI hole will start after "over 4G RAM" and the * reserved space for memory hotplug if any. */ -static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v, - const char *name, - void *opaque, Error **errp) +static uint64_t i440fx_pcihost_get_pci_hole64_start_value(Object *obj) { PCIHostState *h = PCI_HOST_BRIDGE(obj); I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); @@ -263,7 +264,16 @@ static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v, if (!value && s->pci_hole64_fix) { value = pc_pci_hole64_start(); } - visit_type_uint64(v, name, &value, errp); + return value; +} + +static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v, + const char *name, + void *opaque, Error **errp) +{ + uint64_t hole64_start = i440fx_pcihost_get_pci_hole64_start_value(obj); + + visit_type_uint64(v, name, &hole64_start, errp); } /* @@ -278,7 +288,7 @@ static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v, { PCIHostState *h = PCI_HOST_BRIDGE(obj); I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); - uint64_t hole64_start = pc_pci_hole64_start(); + uint64_t hole64_start = i440fx_pcihost_get_pci_hole64_start_value(obj); Range w64; uint64_t value, hole64_end; @@ -405,7 +415,7 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, init_pam(dev, f->ram_memory, f->system_memory, f->pci_address_space, &f->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE); - for (i = 0; i < 12; ++i) { + for (i = 0; i < ARRAY_SIZE(f->pam_regions) - 1; ++i) { init_pam(dev, f->ram_memory, f->system_memory, f->pci_address_space, &f->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); @@ -417,13 +427,13 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, * These additional routes can be discovered through ACPI. */ if (xen_enabled()) { PCIDevice *pci_dev = pci_create_simple_multifunction(b, - -1, true, "PIIX3-xen"); + -1, true, TYPE_PIIX3_XEN_DEVICE); piix3 = PIIX3_PCI_DEVICE(pci_dev); pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq, piix3, XEN_PIIX_NUM_PIRQS); } else { PCIDevice *pci_dev = pci_create_simple_multifunction(b, - -1, true, "PIIX3"); + -1, true, TYPE_PIIX3_DEVICE); piix3 = PIIX3_PCI_DEVICE(pci_dev); pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, PIIX_NUM_PIRQS); @@ -741,7 +751,7 @@ static void piix3_class_init(ObjectClass *klass, void *data) } static const TypeInfo piix3_info = { - .name = "PIIX3", + .name = TYPE_PIIX3_DEVICE, .parent = TYPE_PIIX3_PCI_DEVICE, .class_init = piix3_class_init, }; @@ -754,7 +764,7 @@ static void piix3_xen_class_init(ObjectClass *klass, void *data) }; static const TypeInfo piix3_xen_info = { - .name = "PIIX3-xen", + .name = TYPE_PIIX3_XEN_DEVICE, .parent = TYPE_PIIX3_PCI_DEVICE, .class_init = piix3_xen_class_init, }; diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 966a7cf92d..0c38a8dfd3 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -113,9 +113,7 @@ static void q35_host_get_pci_hole_end(Object *obj, Visitor *v, * the 64bit PCI hole will start after "over 4G RAM" and the * reserved space for memory hotplug if any. */ -static void q35_host_get_pci_hole64_start(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) +static uint64_t q35_host_get_pci_hole64_start_value(Object *obj) { PCIHostState *h = PCI_HOST_BRIDGE(obj); Q35PCIHost *s = Q35_HOST_DEVICE(obj); @@ -127,7 +125,16 @@ static void q35_host_get_pci_hole64_start(Object *obj, Visitor *v, if (!value && s->pci_hole64_fix) { value = pc_pci_hole64_start(); } - visit_type_uint64(v, name, &value, errp); + return value; +} + +static void q35_host_get_pci_hole64_start(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + uint64_t hole64_start = q35_host_get_pci_hole64_start_value(obj); + + visit_type_uint64(v, name, &hole64_start, errp); } /* @@ -142,7 +149,7 @@ static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v, { PCIHostState *h = PCI_HOST_BRIDGE(obj); Q35PCIHost *s = Q35_HOST_DEVICE(obj); - uint64_t hole64_start = pc_pci_hole64_start(); + uint64_t hole64_start = q35_host_get_pci_hole64_start_value(obj); Range w64; uint64_t value, hole64_end; diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 08b7e44e2e..ee9dff2d3a 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -399,7 +399,7 @@ void pci_bridge_exitfn(PCIDevice *pci_dev) /* * before qdev initialization(qdev_init()), this function sets bus_name and - * map_irq callback which are necessry for pci_bridge_initfn() to + * map_irq callback which are necessary for pci_bridge_initfn() to * initialize bus. */ void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index becf550085..7f21b4f9d6 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -183,7 +183,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) } vsc->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; - vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs); + vsc->dev.vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs); vsc->dev.vq_index = 0; vsc->dev.backend_features = 0; diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index fbfedcb1c0..ed4e758273 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -66,8 +66,6 @@ typedef struct VTDIOTLBEntry VTDIOTLBEntry; typedef struct VTDBus VTDBus; typedef union VTD_IR_TableEntry VTD_IR_TableEntry; typedef union VTD_IR_MSIAddress VTD_IR_MSIAddress; -typedef struct VTDIrq VTDIrq; -typedef struct VTD_MSIMessage VTD_MSIMessage; /* Context-Entry */ struct VTDContextEntry { @@ -197,63 +195,6 @@ union VTD_IR_MSIAddress { uint32_t data; }; -/* Generic IRQ entry information */ -struct VTDIrq { - /* Used by both IOAPIC/MSI interrupt remapping */ - uint8_t trigger_mode; - uint8_t vector; - uint8_t delivery_mode; - uint32_t dest; - uint8_t dest_mode; - - /* only used by MSI interrupt remapping */ - uint8_t redir_hint; - uint8_t msi_addr_last_bits; -}; - -struct VTD_MSIMessage { - union { - struct { -#ifdef HOST_WORDS_BIGENDIAN - uint32_t __addr_head:12; /* 0xfee */ - uint32_t dest:8; - uint32_t __reserved:8; - uint32_t redir_hint:1; - uint32_t dest_mode:1; - uint32_t __not_used:2; -#else - uint32_t __not_used:2; - uint32_t dest_mode:1; - uint32_t redir_hint:1; - uint32_t __reserved:8; - uint32_t dest:8; - uint32_t __addr_head:12; /* 0xfee */ -#endif - uint32_t __addr_hi; - } QEMU_PACKED; - uint64_t msi_addr; - }; - union { - struct { -#ifdef HOST_WORDS_BIGENDIAN - uint16_t trigger_mode:1; - uint16_t level:1; - uint16_t __resved:3; - uint16_t delivery_mode:3; - uint16_t vector:8; -#else - uint16_t vector:8; - uint16_t delivery_mode:3; - uint16_t __resved:3; - uint16_t level:1; - uint16_t trigger_mode:1; -#endif - uint16_t __resved1; - } QEMU_PACKED; - uint32_t msi_data; - }; -}; - /* When IR is enabled, all MSI/MSI-X data bits should be zero */ #define VTD_IR_MSI_DATA (0) diff --git a/include/hw/i386/x86-iommu.h b/include/hw/i386/x86-iommu.h index 7c71fc7470..2b22a579a3 100644 --- a/include/hw/i386/x86-iommu.h +++ b/include/hw/i386/x86-iommu.h @@ -22,6 +22,7 @@ #include "hw/sysbus.h" #include "hw/pci/pci.h" +#include "hw/pci/msi.h" #define TYPE_X86_IOMMU_DEVICE ("x86-iommu") #define X86_IOMMU_DEVICE(obj) \ @@ -35,6 +36,8 @@ typedef struct X86IOMMUState X86IOMMUState; typedef struct X86IOMMUClass X86IOMMUClass; +typedef struct X86IOMMUIrq X86IOMMUIrq; +typedef struct X86IOMMU_MSIMessage X86IOMMU_MSIMessage; typedef enum IommuType { TYPE_INTEL, @@ -78,6 +81,63 @@ struct X86IOMMUState { QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */ }; +/* Generic IRQ entry information when interrupt remapping is enabled */ +struct X86IOMMUIrq { + /* Used by both IOAPIC/MSI interrupt remapping */ + uint8_t trigger_mode; + uint8_t vector; + uint8_t delivery_mode; + uint32_t dest; + uint8_t dest_mode; + + /* only used by MSI interrupt remapping */ + uint8_t redir_hint; + uint8_t msi_addr_last_bits; +}; + +struct X86IOMMU_MSIMessage { + union { + struct { +#ifdef HOST_WORDS_BIGENDIAN + uint32_t __addr_head:12; /* 0xfee */ + uint32_t dest:8; + uint32_t __reserved:8; + uint32_t redir_hint:1; + uint32_t dest_mode:1; + uint32_t __not_used:2; +#else + uint32_t __not_used:2; + uint32_t dest_mode:1; + uint32_t redir_hint:1; + uint32_t __reserved:8; + uint32_t dest:8; + uint32_t __addr_head:12; /* 0xfee */ +#endif + uint32_t __addr_hi; + } QEMU_PACKED; + uint64_t msi_addr; + }; + union { + struct { +#ifdef HOST_WORDS_BIGENDIAN + uint16_t trigger_mode:1; + uint16_t level:1; + uint16_t __resved:3; + uint16_t delivery_mode:3; + uint16_t vector:8; +#else + uint16_t vector:8; + uint16_t delivery_mode:3; + uint16_t __resved:3; + uint16_t level:1; + uint16_t trigger_mode:1; +#endif + uint16_t __resved1; + } QEMU_PACKED; + uint32_t msi_data; + }; +}; + /** * x86_iommu_get_default - get default IOMMU device * @return: pointer to default IOMMU device @@ -110,4 +170,10 @@ void x86_iommu_iec_register_notifier(X86IOMMUState *iommu, void x86_iommu_iec_notify_all(X86IOMMUState *iommu, bool global, uint32_t index, uint32_t mask); +/** + * x86_iommu_irq_to_msi_message - Populate one MSIMessage from X86IOMMUIrq + * @X86IOMMUIrq: The IRQ information + * @out: Output MSI message + */ +void x86_iommu_irq_to_msi_message(X86IOMMUIrq *irq, MSIMessage *out); #endif diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h index b7da8f555b..dfb75752cb 100644 --- a/include/hw/pci/pci_bus.h +++ b/include/hw/pci/pci_bus.h @@ -1,6 +1,8 @@ #ifndef QEMU_PCI_BUS_H #define QEMU_PCI_BUS_H +#include "hw/pci/pci.h" + /* * PCI Bus datastructures. * diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 02e77ec811..d661d9be62 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -42,7 +42,7 @@ typedef struct { } test_data; static char disk[] = "tests/acpi-test-disk-XXXXXX"; -static const char *data_dir = "tests/acpi-test-data"; +static const char *data_dir = "tests/data/acpi"; #ifdef CONFIG_IASL static const char *iasl = stringify(CONFIG_IASL); #else @@ -708,6 +708,21 @@ static void test_acpi_q35_tcg_bridge(void) free_test_data(&data); } +static void test_acpi_q35_tcg_mmio64(void) +{ + test_data data = { + .machine = MACHINE_Q35, + .variant = ".mmio64", + .required_struct_types = base_required_struct_types, + .required_struct_types_len = ARRAY_SIZE(base_required_struct_types) + }; + + test_acpi_one("-m 128M,slots=1,maxmem=2G " + "-device pci-testdev,membar=2G", + &data); + free_test_data(&data); +} + static void test_acpi_piix4_tcg_cphp(void) { test_data data; @@ -875,6 +890,7 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge); qtest_add_func("acpi/q35", test_acpi_q35_tcg); qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge); + qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64); qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi); qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi); qtest_add_func("acpi/piix4/cpuhp", test_acpi_piix4_tcg_cphp); diff --git a/tests/acpi-test-data/pc/APIC b/tests/data/acpi/pc/APIC Binary files differindex 84509e0ae4..84509e0ae4 100644 --- a/tests/acpi-test-data/pc/APIC +++ b/tests/data/acpi/pc/APIC diff --git a/tests/acpi-test-data/pc/APIC.cphp b/tests/data/acpi/pc/APIC.cphp Binary files differindex 1bf8a0a63b..1bf8a0a63b 100644 --- a/tests/acpi-test-data/pc/APIC.cphp +++ b/tests/data/acpi/pc/APIC.cphp diff --git a/tests/acpi-test-data/pc/APIC.dimmpxm b/tests/data/acpi/pc/APIC.dimmpxm Binary files differindex 427bb08248..427bb08248 100644 --- a/tests/acpi-test-data/pc/APIC.dimmpxm +++ b/tests/data/acpi/pc/APIC.dimmpxm diff --git a/tests/acpi-test-data/pc/DSDT b/tests/data/acpi/pc/DSDT Binary files differindex c6adfe32d5..c6adfe32d5 100644 --- a/tests/acpi-test-data/pc/DSDT +++ b/tests/data/acpi/pc/DSDT diff --git a/tests/acpi-test-data/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge Binary files differindex f01fa3ad4e..f01fa3ad4e 100644 --- a/tests/acpi-test-data/pc/DSDT.bridge +++ b/tests/data/acpi/pc/DSDT.bridge diff --git a/tests/acpi-test-data/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp Binary files differindex 3295d81c7f..3295d81c7f 100644 --- a/tests/acpi-test-data/pc/DSDT.cphp +++ b/tests/data/acpi/pc/DSDT.cphp diff --git a/tests/acpi-test-data/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm Binary files differindex f6ec911b11..f6ec911b11 100644 --- a/tests/acpi-test-data/pc/DSDT.dimmpxm +++ b/tests/data/acpi/pc/DSDT.dimmpxm diff --git a/tests/acpi-test-data/pc/DSDT.ipmikcs b/tests/data/acpi/pc/DSDT.ipmikcs Binary files differindex 2633a8cecf..2633a8cecf 100644 --- a/tests/acpi-test-data/pc/DSDT.ipmikcs +++ b/tests/data/acpi/pc/DSDT.ipmikcs diff --git a/tests/acpi-test-data/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp Binary files differindex e31ef50296..e31ef50296 100644 --- a/tests/acpi-test-data/pc/DSDT.memhp +++ b/tests/data/acpi/pc/DSDT.memhp diff --git a/tests/acpi-test-data/pc/DSDT.numamem b/tests/data/acpi/pc/DSDT.numamem Binary files differindex 71a975b3e2..71a975b3e2 100644 --- a/tests/acpi-test-data/pc/DSDT.numamem +++ b/tests/data/acpi/pc/DSDT.numamem diff --git a/tests/acpi-test-data/pc/FACP b/tests/data/acpi/pc/FACP Binary files differindex 261ebdc5d1..261ebdc5d1 100644 --- a/tests/acpi-test-data/pc/FACP +++ b/tests/data/acpi/pc/FACP diff --git a/tests/acpi-test-data/pc/FACS b/tests/data/acpi/pc/FACS Binary files differindex fc67ecc407..fc67ecc407 100644 --- a/tests/acpi-test-data/pc/FACS +++ b/tests/data/acpi/pc/FACS diff --git a/tests/acpi-test-data/pc/HPET b/tests/data/acpi/pc/HPET Binary files differindex df689b8f99..df689b8f99 100644 --- a/tests/acpi-test-data/pc/HPET +++ b/tests/data/acpi/pc/HPET diff --git a/tests/acpi-test-data/pc/NFIT.dimmpxm b/tests/data/acpi/pc/NFIT.dimmpxm Binary files differindex 598d331b75..598d331b75 100644 --- a/tests/acpi-test-data/pc/NFIT.dimmpxm +++ b/tests/data/acpi/pc/NFIT.dimmpxm diff --git a/tests/acpi-test-data/pc/SLIT.cphp b/tests/data/acpi/pc/SLIT.cphp Binary files differindex 74ec3b4b46..74ec3b4b46 100644 --- a/tests/acpi-test-data/pc/SLIT.cphp +++ b/tests/data/acpi/pc/SLIT.cphp diff --git a/tests/acpi-test-data/pc/SLIT.memhp b/tests/data/acpi/pc/SLIT.memhp Binary files differindex 74ec3b4b46..74ec3b4b46 100644 --- a/tests/acpi-test-data/pc/SLIT.memhp +++ b/tests/data/acpi/pc/SLIT.memhp diff --git a/tests/acpi-test-data/pc/SRAT.cphp b/tests/data/acpi/pc/SRAT.cphp Binary files differindex ff2137642f..ff2137642f 100644 --- a/tests/acpi-test-data/pc/SRAT.cphp +++ b/tests/data/acpi/pc/SRAT.cphp diff --git a/tests/acpi-test-data/pc/SRAT.dimmpxm b/tests/data/acpi/pc/SRAT.dimmpxm Binary files differindex f5c0267ea2..f5c0267ea2 100644 --- a/tests/acpi-test-data/pc/SRAT.dimmpxm +++ b/tests/data/acpi/pc/SRAT.dimmpxm diff --git a/tests/acpi-test-data/pc/SRAT.memhp b/tests/data/acpi/pc/SRAT.memhp Binary files differindex e508b4ae3c..e508b4ae3c 100644 --- a/tests/acpi-test-data/pc/SRAT.memhp +++ b/tests/data/acpi/pc/SRAT.memhp diff --git a/tests/acpi-test-data/pc/SRAT.numamem b/tests/data/acpi/pc/SRAT.numamem Binary files differindex 119922f497..119922f497 100644 --- a/tests/acpi-test-data/pc/SRAT.numamem +++ b/tests/data/acpi/pc/SRAT.numamem diff --git a/tests/acpi-test-data/pc/SSDT.dimmpxm b/tests/data/acpi/pc/SSDT.dimmpxm Binary files differindex 8ba0e67cb7..8ba0e67cb7 100644 --- a/tests/acpi-test-data/pc/SSDT.dimmpxm +++ b/tests/data/acpi/pc/SSDT.dimmpxm diff --git a/tests/acpi-test-data/q35/APIC b/tests/data/acpi/q35/APIC Binary files differindex 84509e0ae4..84509e0ae4 100644 --- a/tests/acpi-test-data/q35/APIC +++ b/tests/data/acpi/q35/APIC diff --git a/tests/acpi-test-data/q35/APIC.cphp b/tests/data/acpi/q35/APIC.cphp Binary files differindex 1bf8a0a63b..1bf8a0a63b 100644 --- a/tests/acpi-test-data/q35/APIC.cphp +++ b/tests/data/acpi/q35/APIC.cphp diff --git a/tests/acpi-test-data/q35/APIC.dimmpxm b/tests/data/acpi/q35/APIC.dimmpxm Binary files differindex 427bb08248..427bb08248 100644 --- a/tests/acpi-test-data/q35/APIC.dimmpxm +++ b/tests/data/acpi/q35/APIC.dimmpxm diff --git a/tests/acpi-test-data/q35/DSDT b/tests/data/acpi/q35/DSDT Binary files differindex 7576ffcd05..7576ffcd05 100644 --- a/tests/acpi-test-data/q35/DSDT +++ b/tests/data/acpi/q35/DSDT diff --git a/tests/acpi-test-data/q35/DSDT.bridge b/tests/data/acpi/q35/DSDT.bridge Binary files differindex c623cc5d72..c623cc5d72 100644 --- a/tests/acpi-test-data/q35/DSDT.bridge +++ b/tests/data/acpi/q35/DSDT.bridge diff --git a/tests/acpi-test-data/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp Binary files differindex 7ac526e466..7ac526e466 100644 --- a/tests/acpi-test-data/q35/DSDT.cphp +++ b/tests/data/acpi/q35/DSDT.cphp diff --git a/tests/acpi-test-data/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm Binary files differindex 3837792dec..3837792dec 100644 --- a/tests/acpi-test-data/q35/DSDT.dimmpxm +++ b/tests/data/acpi/q35/DSDT.dimmpxm diff --git a/tests/acpi-test-data/q35/DSDT.ipmibt b/tests/data/acpi/q35/DSDT.ipmibt Binary files differindex c7f431f058..c7f431f058 100644 --- a/tests/acpi-test-data/q35/DSDT.ipmibt +++ b/tests/data/acpi/q35/DSDT.ipmibt diff --git a/tests/acpi-test-data/q35/DSDT.memhp b/tests/data/acpi/q35/DSDT.memhp Binary files differindex 8fba0baf79..8fba0baf79 100644 --- a/tests/acpi-test-data/q35/DSDT.memhp +++ b/tests/data/acpi/q35/DSDT.memhp diff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64 Binary files differnew file mode 100644 index 0000000000..a058ff2ee3 --- /dev/null +++ b/tests/data/acpi/q35/DSDT.mmio64 diff --git a/tests/acpi-test-data/q35/DSDT.numamem b/tests/data/acpi/q35/DSDT.numamem Binary files differindex 6c0d4f2bcb..6c0d4f2bcb 100644 --- a/tests/acpi-test-data/q35/DSDT.numamem +++ b/tests/data/acpi/q35/DSDT.numamem diff --git a/tests/acpi-test-data/q35/FACP b/tests/data/acpi/q35/FACP Binary files differindex 72c9d97902..72c9d97902 100644 --- a/tests/acpi-test-data/q35/FACP +++ b/tests/data/acpi/q35/FACP diff --git a/tests/acpi-test-data/q35/FACS b/tests/data/acpi/q35/FACS Binary files differindex fc67ecc407..fc67ecc407 100644 --- a/tests/acpi-test-data/q35/FACS +++ b/tests/data/acpi/q35/FACS diff --git a/tests/acpi-test-data/q35/HPET b/tests/data/acpi/q35/HPET Binary files differindex df689b8f99..df689b8f99 100644 --- a/tests/acpi-test-data/q35/HPET +++ b/tests/data/acpi/q35/HPET diff --git a/tests/acpi-test-data/q35/MCFG b/tests/data/acpi/q35/MCFG Binary files differindex 79ceb27a03..79ceb27a03 100644 --- a/tests/acpi-test-data/q35/MCFG +++ b/tests/data/acpi/q35/MCFG diff --git a/tests/acpi-test-data/q35/NFIT.dimmpxm b/tests/data/acpi/q35/NFIT.dimmpxm Binary files differindex 598d331b75..598d331b75 100644 --- a/tests/acpi-test-data/q35/NFIT.dimmpxm +++ b/tests/data/acpi/q35/NFIT.dimmpxm diff --git a/tests/acpi-test-data/q35/SLIT.cphp b/tests/data/acpi/q35/SLIT.cphp Binary files differindex 74ec3b4b46..74ec3b4b46 100644 --- a/tests/acpi-test-data/q35/SLIT.cphp +++ b/tests/data/acpi/q35/SLIT.cphp diff --git a/tests/acpi-test-data/q35/SLIT.memhp b/tests/data/acpi/q35/SLIT.memhp Binary files differindex 74ec3b4b46..74ec3b4b46 100644 --- a/tests/acpi-test-data/q35/SLIT.memhp +++ b/tests/data/acpi/q35/SLIT.memhp diff --git a/tests/acpi-test-data/q35/SRAT.cphp b/tests/data/acpi/q35/SRAT.cphp Binary files differindex ff2137642f..ff2137642f 100644 --- a/tests/acpi-test-data/q35/SRAT.cphp +++ b/tests/data/acpi/q35/SRAT.cphp diff --git a/tests/acpi-test-data/q35/SRAT.dimmpxm b/tests/data/acpi/q35/SRAT.dimmpxm Binary files differindex f5c0267ea2..f5c0267ea2 100644 --- a/tests/acpi-test-data/q35/SRAT.dimmpxm +++ b/tests/data/acpi/q35/SRAT.dimmpxm diff --git a/tests/acpi-test-data/q35/SRAT.memhp b/tests/data/acpi/q35/SRAT.memhp Binary files differindex e508b4ae3c..e508b4ae3c 100644 --- a/tests/acpi-test-data/q35/SRAT.memhp +++ b/tests/data/acpi/q35/SRAT.memhp diff --git a/tests/data/acpi/q35/SRAT.mmio64 b/tests/data/acpi/q35/SRAT.mmio64 Binary files differnew file mode 100644 index 0000000000..ac35f3dac4 --- /dev/null +++ b/tests/data/acpi/q35/SRAT.mmio64 diff --git a/tests/acpi-test-data/q35/SRAT.numamem b/tests/data/acpi/q35/SRAT.numamem Binary files differindex 119922f497..119922f497 100644 --- a/tests/acpi-test-data/q35/SRAT.numamem +++ b/tests/data/acpi/q35/SRAT.numamem diff --git a/tests/acpi-test-data/q35/SSDT.dimmpxm b/tests/data/acpi/q35/SSDT.dimmpxm Binary files differindex 2d5b721bcf..2d5b721bcf 100644 --- a/tests/acpi-test-data/q35/SSDT.dimmpxm +++ b/tests/data/acpi/q35/SSDT.dimmpxm diff --git a/tests/acpi-test-data/rebuild-expected-aml.sh b/tests/data/acpi/rebuild-expected-aml.sh index 11bf743914..bf9ba242ad 100755 --- a/tests/acpi-test-data/rebuild-expected-aml.sh +++ b/tests/data/acpi/rebuild-expected-aml.sh @@ -32,5 +32,3 @@ fi TEST_ACPI_REBUILD_AML=y QTEST_QEMU_BINARY=$qemu tests/bios-tables-test echo "The files were rebuilt and can be added to git." -echo "However, if new files were created, please copy them manually" \ - "to tests/acpi-test-data/pc/ or tests/acpi-test-data/q35/ ." diff --git a/tests/hex-loader-check-data/test.hex b/tests/data/hex-loader/test.hex index 008a90bd4d..008a90bd4d 100644 --- a/tests/hex-loader-check-data/test.hex +++ b/tests/data/hex-loader/test.hex diff --git a/tests/hexloader-test.c b/tests/hexloader-test.c index b653d44ba1..834ed52c22 100644 --- a/tests/hexloader-test.c +++ b/tests/hexloader-test.c @@ -23,7 +23,7 @@ static void hex_loader_test(void) const unsigned int base_addr = 0x00010000; QTestState *s = qtest_initf( - "-M vexpress-a9 -nographic -device loader,file=tests/hex-loader-check-data/test.hex"); + "-M vexpress-a9 -nographic -device loader,file=tests/data/hex-loader/test.hex"); for (i = 0; i < 256; ++i) { uint8_t val = qtest_readb(s, base_addr + i); |