mirror of https://github.com/xemu-project/xemu.git
* Add virtio-net failover test
* Make qtests a little bit more flexible with regards to reduced configs * Move libssh setup from configure to meson.build * Run device-crash-test in CI * Add jobs for NetBSD and OpenBSD to the CI * Test compilation with MSYS2 in the gitlab-ci, too * Add new virtio-iommu test -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmG5lToRHHRodXRoQHJl ZGhhdC5jb20ACgkQLtnXdP5wLbWyeQ//SBWfwMBmkFlxW8dhsxaFIpuTDkgIrAZ0 UEV2DWMfFQIqKJ4g/BiFHpSeM4eyFV+mwBdM5zfcjjEsbBVb4A9tc+MVHLok/KYp Dwnhg/gDGt+E8TqzCvNYoHyjncP/kI9xhx4FVmgyJjtz4pt2cKckwxgizuwUgIht t1h+f09p467N4bCsaXbaRtKPVS5sfnL1PUlE2gHogvUqV3JZWpTbE+hYAIAr5TK6 7iGcueRvzl/lw7V1kNYe3wc47abjNfem0JJ2Gl3kBgZr70aB5GOHE+1Xd8eoC3w7 b3O3iIOvaAeSKKPp3hKF5/Q2/eAC7EcuZeBunOHXbjYdfB6r6r7fii+l6m9o//O3 /kI2PfaDJLMiuGmjJa8eVXfu1CCcz7SzyrRHMxz1UYZZRpCC54b6EEQPOXShsMjy hWtTobSwOgnSwVazKiiKquox59dqNkRQfbE9Zu1MViYpF5vXOzRpY8/LAY3qyxVi G/u7whAmpWLTr+dDSZiFhQwQD+7c23Bh6qM1iReZAudoj9cX6iY8A6broLgg5Dau UECqh53U7pqqzASsMC5oycustoQ0tpzqLA1GLJBZp7DdbpE306KZDgEFHXyZb0KX SdSdsvfQqYvMqkvh+omO82ZwwrzZ/NSBdgWePJ+6L0wZNC5BTexdTSTcbM0++a4l 3HacdnOR1zA= =+ds5 -----END PGP SIGNATURE----- Merge tag 'pull-request-2021-12-15' of https://gitlab.com/thuth/qemu into staging * Add virtio-net failover test * Make qtests a little bit more flexible with regards to reduced configs * Move libssh setup from configure to meson.build * Run device-crash-test in CI * Add jobs for NetBSD and OpenBSD to the CI * Test compilation with MSYS2 in the gitlab-ci, too * Add new virtio-iommu test # gpg: Signature made Tue 14 Dec 2021 11:11:54 PM PST # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "thuth@redhat.com" # gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full] # gpg: aka "Thomas Huth <thuth@redhat.com>" [full] # gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full] * tag 'pull-request-2021-12-15' of https://gitlab.com/thuth/qemu: gitlab-ci: Test compilation on Windows with MSYS2 tests: qtest: Add virtio-iommu test virtio-iommu: Fix the domain_range end virtio-iommu: Fix endianness in get_config virtio-iommu: Remove set_config callback gitlab-ci: Add cirrus-ci based tests for NetBSD and OpenBSD gitlab-ci.d/buildtest: Add jobs that run the device-crash-test Move the libssh setup from configure to meson.build tests/qtest: Add a function to check whether a machine is available tests/qtest: Add a function that gets a list with available machine types tests/qtest: Fence the tests that need xlnx-zcu102 with CONFIG_XLNX_ZYNQMP_ARM tests/qtest: Run the PPC 32-bit tests with the 64-bit target binary, too tests/libqtest: add a migration test with two couples of failover devices tests/libqtest: add some virtio-net failover migration cancelling tests tests/qtest: add some tests for virtio-net failover qtest/libqos: add a function to initialize secondary PCI buses Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
5d3da09e44
|
@ -100,6 +100,17 @@ avocado-system-debian:
|
|||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
crash-test-debian:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
script:
|
||||
- cd build
|
||||
- scripts/device-crash-test -q ./qemu-system-i386
|
||||
|
||||
build-system-fedora:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
|
@ -134,6 +145,18 @@ avocado-system-fedora:
|
|||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
crash-test-fedora:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-fedora
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
script:
|
||||
- cd build
|
||||
- scripts/device-crash-test -q ./qemu-system-ppc
|
||||
- scripts/device-crash-test -q ./qemu-system-riscv32
|
||||
|
||||
build-system-centos:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
|
|
|
@ -89,3 +89,38 @@ x64-macos-11-base-build:
|
|||
PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin
|
||||
PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig
|
||||
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
||||
|
||||
|
||||
# The following jobs run VM-based tests via KVM on a Linux-based Cirrus-CI job
|
||||
.cirrus_kvm_job:
|
||||
stage: build
|
||||
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
||||
needs: []
|
||||
timeout: 80m
|
||||
allow_failure: true
|
||||
script:
|
||||
- sed -e "s|[@]CI_REPOSITORY_URL@|$CI_REPOSITORY_URL|g"
|
||||
-e "s|[@]CI_COMMIT_REF_NAME@|$CI_COMMIT_REF_NAME|g"
|
||||
-e "s|[@]CI_COMMIT_SHA@|$CI_COMMIT_SHA|g"
|
||||
-e "s|[@]NAME@|$NAME|g"
|
||||
-e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g"
|
||||
-e "s|[@]TEST_TARGETS@|$TEST_TARGETS|g"
|
||||
<.gitlab-ci.d/cirrus/kvm-build.yml >.gitlab-ci.d/cirrus/$NAME.yml
|
||||
- cat .gitlab-ci.d/cirrus/$NAME.yml
|
||||
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
|
||||
rules:
|
||||
- when: manual
|
||||
|
||||
x86-netbsd:
|
||||
extends: .cirrus_kvm_job
|
||||
variables:
|
||||
NAME: netbsd
|
||||
CONFIGURE_ARGS: --target-list=x86_64-softmmu,ppc64-softmmu,aarch64-softmmu
|
||||
TEST_TARGETS: check
|
||||
|
||||
x86-openbsd:
|
||||
extends: .cirrus_kvm_job
|
||||
variables:
|
||||
NAME: openbsd
|
||||
CONFIGURE_ARGS: --target-list=i386-softmmu,riscv64-softmmu,mips64-softmmu
|
||||
TEST_TARGETS: check
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
container:
|
||||
image: fedora:35
|
||||
cpu: 4
|
||||
memory: 8Gb
|
||||
kvm: true
|
||||
|
||||
env:
|
||||
CIRRUS_CLONE_DEPTH: 1
|
||||
CI_REPOSITORY_URL: "@CI_REPOSITORY_URL@"
|
||||
CI_COMMIT_REF_NAME: "@CI_COMMIT_REF_NAME@"
|
||||
CI_COMMIT_SHA: "@CI_COMMIT_SHA@"
|
||||
|
||||
@NAME@_task:
|
||||
@NAME@_vm_cache:
|
||||
folder: $HOME/.cache/qemu-vm
|
||||
install_script:
|
||||
- dnf update -y
|
||||
- dnf install -y git make openssh-clients qemu-img qemu-system-x86 wget
|
||||
clone_script:
|
||||
- git clone --depth 100 "$CI_REPOSITORY_URL" .
|
||||
- git fetch origin "$CI_COMMIT_REF_NAME"
|
||||
- git reset --hard "$CI_COMMIT_SHA"
|
||||
build_script:
|
||||
- if [ -f $HOME/.cache/qemu-vm/images/@NAME@.img ]; then
|
||||
make vm-build-@NAME@ J=$(getconf _NPROCESSORS_ONLN)
|
||||
EXTRA_CONFIGURE_OPTS="@CONFIGURE_ARGS@"
|
||||
BUILD_TARGET="@TEST_TARGETS@" ;
|
||||
else
|
||||
make vm-build-@NAME@ J=$(getconf _NPROCESSORS_ONLN) BUILD_TARGET=help
|
||||
EXTRA_CONFIGURE_OPTS="--disable-system --disable-user --disable-tools" ;
|
||||
fi
|
|
@ -11,3 +11,4 @@ include:
|
|||
- local: '/.gitlab-ci.d/static_checks.yml'
|
||||
- local: '/.gitlab-ci.d/custom-runners.yml'
|
||||
- local: '/.gitlab-ci.d/cirrus.yml'
|
||||
- local: '/.gitlab-ci.d/windows.yml'
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
.shared_msys2_builder:
|
||||
tags:
|
||||
- shared-windows
|
||||
- windows
|
||||
- windows-1809
|
||||
cache:
|
||||
key: "${CI_JOB_NAME}-cache"
|
||||
paths:
|
||||
- ${CI_PROJECT_DIR}/msys64/var/cache
|
||||
needs: []
|
||||
stage: build
|
||||
timeout: 70m
|
||||
before_script:
|
||||
- If ( !(Test-Path -Path msys64\var\cache ) ) {
|
||||
mkdir msys64\var\cache
|
||||
}
|
||||
- If ( !(Test-Path -Path msys64\var\cache\msys2.exe ) ) {
|
||||
Invoke-WebRequest
|
||||
"https://github.com/msys2/msys2-installer/releases/download/2021-07-25/msys2-base-x86_64-20210725.sfx.exe"
|
||||
-outfile "msys64\var\cache\msys2.exe"
|
||||
}
|
||||
- msys64\var\cache\msys2.exe -y
|
||||
- ((Get-Content -path .\msys64\etc\\post-install\\07-pacman-key.post -Raw)
|
||||
-replace '--refresh-keys', '--version') |
|
||||
Set-Content -Path ${CI_PROJECT_DIR}\msys64\etc\\post-install\\07-pacman-key.post
|
||||
- .\msys64\usr\bin\bash -lc "sed -i 's/^CheckSpace/#CheckSpace/g' /etc/pacman.conf"
|
||||
- .\msys64\usr\bin\bash -lc 'pacman --noconfirm -Syuu' # Core update
|
||||
- .\msys64\usr\bin\bash -lc 'pacman --noconfirm -Syuu' # Normal update
|
||||
- taskkill /F /FI "MODULES eq msys-2.0.dll"
|
||||
|
||||
msys2-64bit:
|
||||
extends: .shared_msys2_builder
|
||||
script:
|
||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
||||
diffutils git grep make sed
|
||||
mingw-w64-x86_64-capstone
|
||||
mingw-w64-x86_64-curl
|
||||
mingw-w64-x86_64-cyrus-sasl
|
||||
mingw-w64-x86_64-gcc
|
||||
mingw-w64-x86_64-glib2
|
||||
mingw-w64-x86_64-gnutls
|
||||
mingw-w64-x86_64-libnfs
|
||||
mingw-w64-x86_64-libpng
|
||||
mingw-w64-x86_64-libssh
|
||||
mingw-w64-x86_64-libtasn1
|
||||
mingw-w64-x86_64-libusb
|
||||
mingw-w64-x86_64-libxml2
|
||||
mingw-w64-x86_64-nettle
|
||||
mingw-w64-x86_64-ninja
|
||||
mingw-w64-x86_64-pixman
|
||||
mingw-w64-x86_64-pkgconf
|
||||
mingw-w64-x86_64-python
|
||||
mingw-w64-x86_64-SDL2
|
||||
mingw-w64-x86_64-SDL2_image
|
||||
mingw-w64-x86_64-snappy
|
||||
mingw-w64-x86_64-usbredir
|
||||
mingw-w64-x86_64-zstd "
|
||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
||||
- $env:MSYSTEM = 'MINGW64' # Start a 64 bit Mingw environment
|
||||
- .\msys64\usr\bin\bash -lc './configure --target-list=x86_64-softmmu
|
||||
--enable-capstone=system'
|
||||
- .\msys64\usr\bin\bash -lc "sed -i '/^ROMS=/d' build/config-host.mak"
|
||||
- .\msys64\usr\bin\bash -lc 'make -j2'
|
||||
- .\msys64\usr\bin\bash -lc 'make check'
|
||||
|
||||
msys2-32bit:
|
||||
extends: .shared_msys2_builder
|
||||
script:
|
||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
||||
diffutils git grep make sed
|
||||
mingw-w64-i686-capstone
|
||||
mingw-w64-i686-curl
|
||||
mingw-w64-i686-cyrus-sasl
|
||||
mingw-w64-i686-gcc
|
||||
mingw-w64-i686-glib2
|
||||
mingw-w64-i686-gnutls
|
||||
mingw-w64-i686-gtk3
|
||||
mingw-w64-i686-libgcrypt
|
||||
mingw-w64-i686-libjpeg-turbo
|
||||
mingw-w64-i686-libssh
|
||||
mingw-w64-i686-libtasn1
|
||||
mingw-w64-i686-libusb
|
||||
mingw-w64-i686-libxml2
|
||||
mingw-w64-i686-lzo2
|
||||
mingw-w64-i686-ninja
|
||||
mingw-w64-i686-pixman
|
||||
mingw-w64-i686-pkgconf
|
||||
mingw-w64-i686-python
|
||||
mingw-w64-i686-snappy
|
||||
mingw-w64-i686-usbredir "
|
||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
||||
- $env:MSYSTEM = 'MINGW32' # Start a 32-bit MinG environment
|
||||
- mkdir output
|
||||
- cd output
|
||||
- ..\msys64\usr\bin\bash -lc "../configure --target-list=ppc64-softmmu
|
||||
--enable-capstone=system"
|
||||
- ..\msys64\usr\bin\bash -lc 'make -j2'
|
||||
- ..\msys64\usr\bin\bash -lc 'make check'
|
|
@ -344,7 +344,6 @@ debug_stack_usage="no"
|
|||
crypto_afalg="no"
|
||||
tls_priority="NORMAL"
|
||||
tpm="$default_feature"
|
||||
libssh="$default_feature"
|
||||
live_block_migration=${default_feature:-yes}
|
||||
numa="$default_feature"
|
||||
replication=${default_feature:-yes}
|
||||
|
@ -1078,10 +1077,6 @@ for opt do
|
|||
;;
|
||||
--enable-tpm) tpm="yes"
|
||||
;;
|
||||
--disable-libssh) libssh="no"
|
||||
;;
|
||||
--enable-libssh) libssh="yes"
|
||||
;;
|
||||
--disable-live-block-migration) live_block_migration="no"
|
||||
;;
|
||||
--enable-live-block-migration) live_block_migration="yes"
|
||||
|
@ -1448,7 +1443,6 @@ cat << EOF
|
|||
live-block-migration Block migration in the main migration stream
|
||||
coroutine-pool coroutine freelist (better performance)
|
||||
tpm TPM support
|
||||
libssh ssh block device support
|
||||
numa libnuma support
|
||||
avx2 AVX2 optimization support
|
||||
avx512f AVX512F optimization support
|
||||
|
@ -2561,21 +2555,6 @@ if test "$modules" = yes; then
|
|||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# libssh probe
|
||||
if test "$libssh" != "no" ; then
|
||||
if $pkg_config --exists "libssh >= 0.8.7"; then
|
||||
libssh_cflags=$($pkg_config libssh --cflags)
|
||||
libssh_libs=$($pkg_config libssh --libs)
|
||||
libssh=yes
|
||||
else
|
||||
if test "$libssh" = "yes" ; then
|
||||
error_exit "libssh required for --enable-libssh"
|
||||
fi
|
||||
libssh=no
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# TPM emulation is only on POSIX
|
||||
|
||||
|
@ -3636,12 +3615,6 @@ if test "$cmpxchg128" = "yes" ; then
|
|||
echo "CONFIG_CMPXCHG128=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$libssh" = "yes" ; then
|
||||
echo "CONFIG_LIBSSH=y" >> $config_host_mak
|
||||
echo "LIBSSH_CFLAGS=$libssh_cflags" >> $config_host_mak
|
||||
echo "LIBSSH_LIBS=$libssh_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$live_block_migration" = "yes" ; then
|
||||
echo "CONFIG_LIVE_BLOCK_MIGRATION=y" >> $config_host_mak
|
||||
fi
|
||||
|
|
|
@ -91,8 +91,7 @@ virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d"
|
|||
virtio_iommu_device_reset(void) "reset!"
|
||||
virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64
|
||||
virtio_iommu_device_status(uint8_t status) "driver status = %d"
|
||||
virtio_iommu_get_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_range, uint32_t probe_size) "page_size_mask=0x%"PRIx64" start=0x%"PRIx64" end=0x%"PRIx64" domain_range=%d probe_size=0x%x"
|
||||
virtio_iommu_set_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_range, uint32_t probe_size) "page_size_mask=0x%"PRIx64" start=0x%"PRIx64" end=0x%"PRIx64" domain_bits=%d probe_size=0x%x"
|
||||
virtio_iommu_get_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_start, uint32_t domain_end, uint32_t probe_size) "page_size_mask=0x%"PRIx64" input range start=0x%"PRIx64" input range end=0x%"PRIx64" domain range start=%d domain range end=%d probe_size=0x%x"
|
||||
virtio_iommu_attach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d"
|
||||
virtio_iommu_detach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d"
|
||||
virtio_iommu_map(uint32_t domain_id, uint64_t virt_start, uint64_t virt_end, uint64_t phys_start, uint32_t flags) "domain=%d virt_start=0x%"PRIx64" virt_end=0x%"PRIx64 " phys_start=0x%"PRIx64" flags=%d"
|
||||
|
|
|
@ -822,27 +822,22 @@ unlock:
|
|||
static void virtio_iommu_get_config(VirtIODevice *vdev, uint8_t *config_data)
|
||||
{
|
||||
VirtIOIOMMU *dev = VIRTIO_IOMMU(vdev);
|
||||
struct virtio_iommu_config *config = &dev->config;
|
||||
struct virtio_iommu_config *dev_config = &dev->config;
|
||||
struct virtio_iommu_config *out_config = (void *)config_data;
|
||||
|
||||
trace_virtio_iommu_get_config(config->page_size_mask,
|
||||
config->input_range.start,
|
||||
config->input_range.end,
|
||||
config->domain_range.end,
|
||||
config->probe_size);
|
||||
memcpy(config_data, &dev->config, sizeof(struct virtio_iommu_config));
|
||||
}
|
||||
out_config->page_size_mask = cpu_to_le64(dev_config->page_size_mask);
|
||||
out_config->input_range.start = cpu_to_le64(dev_config->input_range.start);
|
||||
out_config->input_range.end = cpu_to_le64(dev_config->input_range.end);
|
||||
out_config->domain_range.start = cpu_to_le32(dev_config->domain_range.start);
|
||||
out_config->domain_range.end = cpu_to_le32(dev_config->domain_range.end);
|
||||
out_config->probe_size = cpu_to_le32(dev_config->probe_size);
|
||||
|
||||
static void virtio_iommu_set_config(VirtIODevice *vdev,
|
||||
const uint8_t *config_data)
|
||||
{
|
||||
struct virtio_iommu_config config;
|
||||
|
||||
memcpy(&config, config_data, sizeof(struct virtio_iommu_config));
|
||||
trace_virtio_iommu_set_config(config.page_size_mask,
|
||||
config.input_range.start,
|
||||
config.input_range.end,
|
||||
config.domain_range.end,
|
||||
config.probe_size);
|
||||
trace_virtio_iommu_get_config(dev_config->page_size_mask,
|
||||
dev_config->input_range.start,
|
||||
dev_config->input_range.end,
|
||||
dev_config->domain_range.start,
|
||||
dev_config->domain_range.end,
|
||||
dev_config->probe_size);
|
||||
}
|
||||
|
||||
static uint64_t virtio_iommu_get_features(VirtIODevice *vdev, uint64_t f,
|
||||
|
@ -983,8 +978,8 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
|
|||
s->event_vq = virtio_add_queue(vdev, VIOMMU_DEFAULT_QUEUE_SIZE, NULL);
|
||||
|
||||
s->config.page_size_mask = TARGET_PAGE_MASK;
|
||||
s->config.input_range.end = -1UL;
|
||||
s->config.domain_range.end = 32;
|
||||
s->config.input_range.end = UINT64_MAX;
|
||||
s->config.domain_range.end = UINT32_MAX;
|
||||
s->config.probe_size = VIOMMU_PROBE_SIZE;
|
||||
|
||||
virtio_add_feature(&s->features, VIRTIO_RING_F_EVENT_IDX);
|
||||
|
@ -1185,7 +1180,6 @@ static void virtio_iommu_class_init(ObjectClass *klass, void *data)
|
|||
vdc->unrealize = virtio_iommu_device_unrealize;
|
||||
vdc->reset = virtio_iommu_device_reset;
|
||||
vdc->get_config = virtio_iommu_get_config;
|
||||
vdc->set_config = virtio_iommu_set_config;
|
||||
vdc->get_features = virtio_iommu_get_features;
|
||||
vdc->set_status = virtio_iommu_set_status;
|
||||
vdc->vmsd = &vmstate_virtio_iommu_device;
|
||||
|
|
|
@ -138,6 +138,7 @@ typedef struct PCIBridgeQemuCap {
|
|||
uint64_t mem_pref_64; /* Prefetchable memory to reserve (64-bit MMIO) */
|
||||
} PCIBridgeQemuCap;
|
||||
|
||||
#define REDHAT_PCI_CAP_TYPE_OFFSET 3
|
||||
#define REDHAT_PCI_CAP_RESOURCE_RESERVE 1
|
||||
|
||||
/*
|
||||
|
@ -152,6 +153,13 @@ typedef struct PCIResReserve {
|
|||
uint64_t mem_pref_64;
|
||||
} PCIResReserve;
|
||||
|
||||
#define REDHAT_PCI_CAP_RES_RESERVE_BUS_RES 4
|
||||
#define REDHAT_PCI_CAP_RES_RESERVE_IO 8
|
||||
#define REDHAT_PCI_CAP_RES_RESERVE_MEM 16
|
||||
#define REDHAT_PCI_CAP_RES_RESERVE_PREF_MEM_32 20
|
||||
#define REDHAT_PCI_CAP_RES_RESERVE_PREF_MEM_64 24
|
||||
#define REDHAT_PCI_CAP_RES_RESERVE_CAP_SIZE 32
|
||||
|
||||
int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset,
|
||||
PCIResReserve res_reserve, Error **errp);
|
||||
|
||||
|
|
13
meson.build
13
meson.build
|
@ -874,11 +874,15 @@ if not get_option('glusterfs').auto() or have_block
|
|||
''', dependencies: glusterfs)
|
||||
endif
|
||||
endif
|
||||
|
||||
libssh = not_found
|
||||
if 'CONFIG_LIBSSH' in config_host
|
||||
libssh = declare_dependency(compile_args: config_host['LIBSSH_CFLAGS'].split(),
|
||||
link_args: config_host['LIBSSH_LIBS'].split())
|
||||
if not get_option('libssh').auto() or have_block
|
||||
libssh = dependency('libssh', version: '>=0.8.7',
|
||||
method: 'pkg-config',
|
||||
required: get_option('libssh'),
|
||||
kwargs: static_kwargs)
|
||||
endif
|
||||
|
||||
libbzip2 = not_found
|
||||
if not get_option('bzip2').auto() or have_block
|
||||
libbzip2 = cc.find_library('bz2', has_headers: ['bzlib.h'],
|
||||
|
@ -1451,6 +1455,7 @@ config_host_data.set('CONFIG_EBPF', libbpf.found())
|
|||
config_host_data.set('CONFIG_LIBDAXCTL', libdaxctl.found())
|
||||
config_host_data.set('CONFIG_LIBISCSI', libiscsi.found())
|
||||
config_host_data.set('CONFIG_LIBNFS', libnfs.found())
|
||||
config_host_data.set('CONFIG_LIBSSH', libssh.found())
|
||||
config_host_data.set('CONFIG_LINUX_AIO', libaio.found())
|
||||
config_host_data.set('CONFIG_LINUX_IO_URING', linux_io_uring.found())
|
||||
config_host_data.set('CONFIG_LIBPMEM', libpmem.found())
|
||||
|
@ -3430,7 +3435,7 @@ endif
|
|||
summary_info += {'seccomp support': seccomp}
|
||||
summary_info += {'GlusterFS support': glusterfs}
|
||||
summary_info += {'TPM support': config_host.has_key('CONFIG_TPM')}
|
||||
summary_info += {'libssh support': config_host.has_key('CONFIG_LIBSSH')}
|
||||
summary_info += {'libssh support': libssh}
|
||||
summary_info += {'lzo support': lzo}
|
||||
summary_info += {'snappy support': snappy}
|
||||
summary_info += {'bzip2 support': libbzip2}
|
||||
|
|
|
@ -105,6 +105,8 @@ option('libdaxctl', type : 'feature', value : 'auto',
|
|||
description: 'libdaxctl support')
|
||||
option('libpmem', type : 'feature', value : 'auto',
|
||||
description: 'libpmem support')
|
||||
option('libssh', type : 'feature', value : 'auto',
|
||||
description: 'ssh block device support')
|
||||
option('libudev', type : 'feature', value : 'auto',
|
||||
description: 'Use libudev to enumerate host devices')
|
||||
option('libusb', type : 'feature', value : 'auto',
|
||||
|
|
|
@ -53,6 +53,7 @@ meson_options_help() {
|
|||
printf "%s\n" ' libiscsi libiscsi userspace initiator'
|
||||
printf "%s\n" ' libnfs libnfs block device driver'
|
||||
printf "%s\n" ' libpmem libpmem support'
|
||||
printf "%s\n" ' libssh ssh block device support'
|
||||
printf "%s\n" ' libudev Use libudev to enumerate host devices'
|
||||
printf "%s\n" ' libusb libusb support for USB passthrough'
|
||||
printf "%s\n" ' libxml2 libxml2 support for Parallels image format'
|
||||
|
@ -177,6 +178,8 @@ _meson_option_parse() {
|
|||
--disable-libnfs) printf "%s" -Dlibnfs=disabled ;;
|
||||
--enable-libpmem) printf "%s" -Dlibpmem=enabled ;;
|
||||
--disable-libpmem) printf "%s" -Dlibpmem=disabled ;;
|
||||
--enable-libssh) printf "%s" -Dlibssh=enabled ;;
|
||||
--disable-libssh) printf "%s" -Dlibssh=disabled ;;
|
||||
--enable-libudev) printf "%s" -Dlibudev=enabled ;;
|
||||
--disable-libudev) printf "%s" -Dlibudev=disabled ;;
|
||||
--enable-libusb) printf "%s" -Dlibusb=enabled ;;
|
||||
|
|
|
@ -285,7 +285,8 @@ int main(int argc, char *argv[])
|
|||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
for (i = 0; tests[i].arch != NULL; i++) {
|
||||
if (strcmp(arch, tests[i].arch) == 0) {
|
||||
if (g_str_equal(arch, tests[i].arch) &&
|
||||
qtest_has_machine(tests[i].machine)) {
|
||||
char *name = g_strdup_printf("boot-serial/%s", tests[i].machine);
|
||||
qtest_add_data_func(name, &tests[i], test_machine);
|
||||
g_free(name);
|
||||
|
|
|
@ -109,9 +109,11 @@ static void test_cdrom_param(gconstpointer data)
|
|||
static void add_cdrom_param_tests(const char **machines)
|
||||
{
|
||||
while (*machines) {
|
||||
char *testname = g_strdup_printf("cdrom/param/%s", *machines);
|
||||
qtest_add_data_func(testname, *machines, test_cdrom_param);
|
||||
g_free(testname);
|
||||
if (qtest_has_machine(*machines)) {
|
||||
char *testname = g_strdup_printf("cdrom/param/%s", *machines);
|
||||
qtest_add_data_func(testname, *machines, test_cdrom_param);
|
||||
g_free(testname);
|
||||
}
|
||||
machines++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -710,6 +710,14 @@ QDict *qmp_fd(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
|
|||
void qtest_cb_for_every_machine(void (*cb)(const char *machine),
|
||||
bool skip_old_versioned);
|
||||
|
||||
/**
|
||||
* qtest_has_machine:
|
||||
* @machine: The machine to look for
|
||||
*
|
||||
* Returns: true if the machine is available in the target binary.
|
||||
*/
|
||||
bool qtest_has_machine(const char *machine);
|
||||
|
||||
/**
|
||||
* qtest_qmp_device_add_qdict:
|
||||
* @qts: QTestState instance to operate on
|
||||
|
|
|
@ -41,6 +41,7 @@ libqos_srcs = files('../libqtest.c',
|
|||
'virtio-rng.c',
|
||||
'virtio-scsi.c',
|
||||
'virtio-serial.c',
|
||||
'virtio-iommu.c',
|
||||
|
||||
# qgraph machines:
|
||||
'aarch64-xlnx-zcu102-machine.c',
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "pci.h"
|
||||
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_bridge.h"
|
||||
#include "hw/pci/pci_regs.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "qgraph.h"
|
||||
|
@ -99,6 +101,123 @@ void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr)
|
|||
g_assert(!addr->device_id || device_id == addr->device_id);
|
||||
}
|
||||
|
||||
static uint8_t qpci_find_resource_reserve_capability(QPCIDevice *dev)
|
||||
{
|
||||
uint16_t device_id;
|
||||
uint8_t cap = 0;
|
||||
|
||||
if (qpci_config_readw(dev, PCI_VENDOR_ID) != PCI_VENDOR_ID_REDHAT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
|
||||
|
||||
if (device_id != PCI_DEVICE_ID_REDHAT_PCIE_RP &&
|
||||
device_id != PCI_DEVICE_ID_REDHAT_BRIDGE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
cap = qpci_find_capability(dev, PCI_CAP_ID_VNDR, cap);
|
||||
} while (cap &&
|
||||
qpci_config_readb(dev, cap + REDHAT_PCI_CAP_TYPE_OFFSET) !=
|
||||
REDHAT_PCI_CAP_RESOURCE_RESERVE);
|
||||
if (cap) {
|
||||
uint8_t cap_len = qpci_config_readb(dev, cap + PCI_CAP_FLAGS);
|
||||
if (cap_len < REDHAT_PCI_CAP_RES_RESERVE_CAP_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return cap;
|
||||
}
|
||||
|
||||
static void qpci_secondary_buses_rec(QPCIBus *qbus, int bus, int *pci_bus)
|
||||
{
|
||||
QPCIDevice *dev;
|
||||
uint16_t class;
|
||||
uint8_t pribus, secbus, subbus;
|
||||
int index;
|
||||
|
||||
for (index = 0; index < 32; index++) {
|
||||
dev = qpci_device_find(qbus, QPCI_DEVFN(bus + index, 0));
|
||||
if (dev == NULL) {
|
||||
continue;
|
||||
}
|
||||
class = qpci_config_readw(dev, PCI_CLASS_DEVICE);
|
||||
if (class == PCI_CLASS_BRIDGE_PCI) {
|
||||
qpci_config_writeb(dev, PCI_SECONDARY_BUS, 255);
|
||||
qpci_config_writeb(dev, PCI_SUBORDINATE_BUS, 0);
|
||||
}
|
||||
g_free(dev);
|
||||
}
|
||||
|
||||
for (index = 0; index < 32; index++) {
|
||||
dev = qpci_device_find(qbus, QPCI_DEVFN(bus + index, 0));
|
||||
if (dev == NULL) {
|
||||
continue;
|
||||
}
|
||||
class = qpci_config_readw(dev, PCI_CLASS_DEVICE);
|
||||
if (class != PCI_CLASS_BRIDGE_PCI) {
|
||||
g_free(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
pribus = qpci_config_readb(dev, PCI_PRIMARY_BUS);
|
||||
if (pribus != bus) {
|
||||
qpci_config_writeb(dev, PCI_PRIMARY_BUS, bus);
|
||||
}
|
||||
|
||||
secbus = qpci_config_readb(dev, PCI_SECONDARY_BUS);
|
||||
(*pci_bus)++;
|
||||
if (*pci_bus != secbus) {
|
||||
secbus = *pci_bus;
|
||||
qpci_config_writeb(dev, PCI_SECONDARY_BUS, secbus);
|
||||
}
|
||||
|
||||
subbus = qpci_config_readb(dev, PCI_SUBORDINATE_BUS);
|
||||
qpci_config_writeb(dev, PCI_SUBORDINATE_BUS, 255);
|
||||
|
||||
qpci_secondary_buses_rec(qbus, secbus << 5, pci_bus);
|
||||
|
||||
if (subbus != *pci_bus) {
|
||||
uint8_t res_bus = *pci_bus;
|
||||
uint8_t cap = qpci_find_resource_reserve_capability(dev);
|
||||
|
||||
if (cap) {
|
||||
uint32_t tmp_res_bus;
|
||||
|
||||
tmp_res_bus = qpci_config_readl(dev, cap +
|
||||
REDHAT_PCI_CAP_RES_RESERVE_BUS_RES);
|
||||
if (tmp_res_bus != (uint32_t)-1) {
|
||||
res_bus = tmp_res_bus & 0xFF;
|
||||
if ((uint8_t)(res_bus + secbus) < secbus ||
|
||||
(uint8_t)(res_bus + secbus) < res_bus) {
|
||||
res_bus = 0;
|
||||
}
|
||||
if (secbus + res_bus > *pci_bus) {
|
||||
res_bus = secbus + res_bus;
|
||||
}
|
||||
}
|
||||
}
|
||||
subbus = res_bus;
|
||||
*pci_bus = res_bus;
|
||||
}
|
||||
|
||||
qpci_config_writeb(dev, PCI_SUBORDINATE_BUS, subbus);
|
||||
g_free(dev);
|
||||
}
|
||||
}
|
||||
|
||||
int qpci_secondary_buses_init(QPCIBus *bus)
|
||||
{
|
||||
int last_bus = 0;
|
||||
|
||||
qpci_secondary_buses_rec(bus, 0, &last_bus);
|
||||
|
||||
return last_bus;
|
||||
}
|
||||
|
||||
|
||||
void qpci_device_enable(QPCIDevice *dev)
|
||||
{
|
||||
uint16_t cmd;
|
||||
|
|
|
@ -81,6 +81,7 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
|
|||
void *data);
|
||||
QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn);
|
||||
void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr);
|
||||
int qpci_secondary_buses_init(QPCIBus *bus);
|
||||
|
||||
bool qpci_has_buggy_msi(QPCIDevice *dev);
|
||||
bool qpci_check_buggy_msi(QPCIDevice *dev);
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* libqos driver virtio-iommu-pci framework
|
||||
*
|
||||
* Copyright (c) 2021 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Auger <eric.auger@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at your
|
||||
* option) any later version. See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "libqtest.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qgraph.h"
|
||||
#include "virtio-iommu.h"
|
||||
#include "hw/virtio/virtio-iommu.h"
|
||||
|
||||
static QGuestAllocator *alloc;
|
||||
|
||||
/* virtio-iommu-device */
|
||||
static void *qvirtio_iommu_get_driver(QVirtioIOMMU *v_iommu,
|
||||
const char *interface)
|
||||
{
|
||||
if (!g_strcmp0(interface, "virtio-iommu")) {
|
||||
return v_iommu;
|
||||
}
|
||||
if (!g_strcmp0(interface, "virtio")) {
|
||||
return v_iommu->vdev;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s not present in virtio-iommu-device\n", interface);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static void virtio_iommu_cleanup(QVirtioIOMMU *interface)
|
||||
{
|
||||
qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
|
||||
}
|
||||
|
||||
static void virtio_iommu_setup(QVirtioIOMMU *interface)
|
||||
{
|
||||
QVirtioDevice *vdev = interface->vdev;
|
||||
uint64_t features;
|
||||
|
||||
features = qvirtio_get_features(vdev);
|
||||
features &= ~(QVIRTIO_F_BAD_FEATURE |
|
||||
(1ull << VIRTIO_RING_F_INDIRECT_DESC) |
|
||||
(1ull << VIRTIO_RING_F_EVENT_IDX) |
|
||||
(1ull << VIRTIO_IOMMU_F_BYPASS));
|
||||
qvirtio_set_features(vdev, features);
|
||||
interface->vq = qvirtqueue_setup(interface->vdev, alloc, 0);
|
||||
qvirtio_set_driver_ok(interface->vdev);
|
||||
}
|
||||
|
||||
/* virtio-iommu-pci */
|
||||
static void *qvirtio_iommu_pci_get_driver(void *object, const char *interface)
|
||||
{
|
||||
QVirtioIOMMUPCI *v_iommu = object;
|
||||
if (!g_strcmp0(interface, "pci-device")) {
|
||||
return v_iommu->pci_vdev.pdev;
|
||||
}
|
||||
return qvirtio_iommu_get_driver(&v_iommu->iommu, interface);
|
||||
}
|
||||
|
||||
static void qvirtio_iommu_pci_destructor(QOSGraphObject *obj)
|
||||
{
|
||||
QVirtioIOMMUPCI *iommu_pci = (QVirtioIOMMUPCI *) obj;
|
||||
QVirtioIOMMU *interface = &iommu_pci->iommu;
|
||||
QOSGraphObject *pci_vobj = &iommu_pci->pci_vdev.obj;
|
||||
|
||||
virtio_iommu_cleanup(interface);
|
||||
qvirtio_pci_destructor(pci_vobj);
|
||||
}
|
||||
|
||||
static void qvirtio_iommu_pci_start_hw(QOSGraphObject *obj)
|
||||
{
|
||||
QVirtioIOMMUPCI *iommu_pci = (QVirtioIOMMUPCI *) obj;
|
||||
QVirtioIOMMU *interface = &iommu_pci->iommu;
|
||||
QOSGraphObject *pci_vobj = &iommu_pci->pci_vdev.obj;
|
||||
|
||||
qvirtio_pci_start_hw(pci_vobj);
|
||||
virtio_iommu_setup(interface);
|
||||
}
|
||||
|
||||
|
||||
static void *virtio_iommu_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
|
||||
void *addr)
|
||||
{
|
||||
QVirtioIOMMUPCI *virtio_rpci = g_new0(QVirtioIOMMUPCI, 1);
|
||||
QVirtioIOMMU *interface = &virtio_rpci->iommu;
|
||||
QOSGraphObject *obj = &virtio_rpci->pci_vdev.obj;
|
||||
|
||||
virtio_pci_init(&virtio_rpci->pci_vdev, pci_bus, addr);
|
||||
interface->vdev = &virtio_rpci->pci_vdev.vdev;
|
||||
alloc = t_alloc;
|
||||
|
||||
obj->get_driver = qvirtio_iommu_pci_get_driver;
|
||||
obj->start_hw = qvirtio_iommu_pci_start_hw;
|
||||
obj->destructor = qvirtio_iommu_pci_destructor;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void virtio_iommu_register_nodes(void)
|
||||
{
|
||||
QPCIAddress addr = {
|
||||
.devfn = QPCI_DEVFN(4, 0),
|
||||
};
|
||||
|
||||
QOSGraphEdgeOptions opts = {
|
||||
.extra_device_opts = "addr=04.0",
|
||||
};
|
||||
|
||||
/* virtio-iommu-pci */
|
||||
add_qpci_address(&opts, &addr);
|
||||
qos_node_create_driver("virtio-iommu-pci", virtio_iommu_pci_create);
|
||||
qos_node_consumes("virtio-iommu-pci", "pci-bus", &opts);
|
||||
qos_node_produces("virtio-iommu-pci", "pci-device");
|
||||
qos_node_produces("virtio-iommu-pci", "virtio");
|
||||
qos_node_produces("virtio-iommu-pci", "virtio-iommu");
|
||||
}
|
||||
|
||||
libqos_init(virtio_iommu_register_nodes);
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* libqos driver virtio-iommu-pci framework
|
||||
*
|
||||
* Copyright (c) 2021 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Auger <eric.auger@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at your
|
||||
* option) any later version. See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TESTS_LIBQOS_VIRTIO_IOMMU_H
|
||||
#define TESTS_LIBQOS_VIRTIO_IOMMU_H
|
||||
|
||||
#include "qgraph.h"
|
||||
#include "virtio.h"
|
||||
#include "virtio-pci.h"
|
||||
|
||||
typedef struct QVirtioIOMMU QVirtioIOMMU;
|
||||
typedef struct QVirtioIOMMUPCI QVirtioIOMMUPCI;
|
||||
typedef struct QVirtioIOMMUDevice QVirtioIOMMUDevice;
|
||||
|
||||
struct QVirtioIOMMU {
|
||||
QVirtioDevice *vdev;
|
||||
QVirtQueue *vq;
|
||||
};
|
||||
|
||||
struct QVirtioIOMMUPCI {
|
||||
QVirtioPCIDevice pci_vdev;
|
||||
QVirtioIOMMU iommu;
|
||||
};
|
||||
|
||||
struct QVirtioIOMMUDevice {
|
||||
QOSGraphObject obj;
|
||||
QVirtioIOMMU iommu;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1321,16 +1321,29 @@ static bool qtest_is_old_versioned_machine(const char *mname)
|
|||
return res;
|
||||
}
|
||||
|
||||
void qtest_cb_for_every_machine(void (*cb)(const char *machine),
|
||||
bool skip_old_versioned)
|
||||
struct MachInfo {
|
||||
char *name;
|
||||
char *alias;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns an array with pointers to the available machine names.
|
||||
* The terminating entry has the name set to NULL.
|
||||
*/
|
||||
static struct MachInfo *qtest_get_machines(void)
|
||||
{
|
||||
static struct MachInfo *machines;
|
||||
QDict *response, *minfo;
|
||||
QList *list;
|
||||
const QListEntry *p;
|
||||
QObject *qobj;
|
||||
QString *qstr;
|
||||
const char *mname;
|
||||
QTestState *qts;
|
||||
int idx;
|
||||
|
||||
if (machines) {
|
||||
return machines;
|
||||
}
|
||||
|
||||
qts = qtest_init("-machine none");
|
||||
response = qtest_qmp(qts, "{ 'execute': 'query-machines' }");
|
||||
|
@ -1338,25 +1351,71 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine),
|
|||
list = qdict_get_qlist(response, "return");
|
||||
g_assert(list);
|
||||
|
||||
for (p = qlist_first(list); p; p = qlist_next(p)) {
|
||||
machines = g_new(struct MachInfo, qlist_size(list) + 1);
|
||||
|
||||
for (p = qlist_first(list), idx = 0; p; p = qlist_next(p), idx++) {
|
||||
minfo = qobject_to(QDict, qlist_entry_obj(p));
|
||||
g_assert(minfo);
|
||||
|
||||
qobj = qdict_get(minfo, "name");
|
||||
g_assert(qobj);
|
||||
qstr = qobject_to(QString, qobj);
|
||||
g_assert(qstr);
|
||||
mname = qstring_get_str(qstr);
|
||||
/* Ignore machines that cannot be used for qtests */
|
||||
if (!strncmp("xenfv", mname, 5) || g_str_equal("xenpv", mname)) {
|
||||
continue;
|
||||
}
|
||||
if (!skip_old_versioned || !qtest_is_old_versioned_machine(mname)) {
|
||||
cb(mname);
|
||||
machines[idx].name = g_strdup(qstring_get_str(qstr));
|
||||
|
||||
qobj = qdict_get(minfo, "alias");
|
||||
if (qobj) { /* The alias is optional */
|
||||
qstr = qobject_to(QString, qobj);
|
||||
g_assert(qstr);
|
||||
machines[idx].alias = g_strdup(qstring_get_str(qstr));
|
||||
} else {
|
||||
machines[idx].alias = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
qtest_quit(qts);
|
||||
qobject_unref(response);
|
||||
|
||||
memset(&machines[idx], 0, sizeof(struct MachInfo)); /* Terminating entry */
|
||||
return machines;
|
||||
}
|
||||
|
||||
void qtest_cb_for_every_machine(void (*cb)(const char *machine),
|
||||
bool skip_old_versioned)
|
||||
{
|
||||
struct MachInfo *machines;
|
||||
int i;
|
||||
|
||||
machines = qtest_get_machines();
|
||||
|
||||
for (i = 0; machines[i].name != NULL; i++) {
|
||||
/* Ignore machines that cannot be used for qtests */
|
||||
if (!strncmp("xenfv", machines[i].name, 5) ||
|
||||
g_str_equal("xenpv", machines[i].name)) {
|
||||
continue;
|
||||
}
|
||||
if (!skip_old_versioned ||
|
||||
!qtest_is_old_versioned_machine(machines[i].name)) {
|
||||
cb(machines[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool qtest_has_machine(const char *machine)
|
||||
{
|
||||
struct MachInfo *machines;
|
||||
int i;
|
||||
|
||||
machines = qtest_get_machines();
|
||||
|
||||
for (i = 0; machines[i].name != NULL; i++) {
|
||||
if (g_str_equal(machine, machines[i].name) ||
|
||||
(machines[i].alias && g_str_equal(machine, machines[i].alias))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -68,6 +68,10 @@ qtests_i386 = \
|
|||
(config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_E1000E_PCI_EXPRESS') ? ['fuzz-e1000e-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_VIRTIO_NET') and \
|
||||
config_all_devices.has_key('CONFIG_Q35') and \
|
||||
config_all_devices.has_key('CONFIG_VIRTIO_PCI') and \
|
||||
slirp.found() ? ['virtio-net-failover'] : []) + \
|
||||
(unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
|
||||
qtests_pci + \
|
||||
['fdc-test',
|
||||
|
@ -134,6 +138,7 @@ qtests_ppc = \
|
|||
['boot-order-test', 'prom-env-test', 'boot-serial-test'] \
|
||||
|
||||
qtests_ppc64 = \
|
||||
qtests_ppc + \
|
||||
(config_all_devices.has_key('CONFIG_PSERIES') ? ['device-plug-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xscom-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + \
|
||||
|
@ -183,11 +188,10 @@ qtests_aarch64 = \
|
|||
(cpu != 'arm' and unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_XLNX_ZYNQMP_ARM') ? ['xlnx-can-test', 'fuzz-xlnx-dp-test'] : []) + \
|
||||
['arm-cpu-features',
|
||||
'numa-test',
|
||||
'boot-serial-test',
|
||||
'xlnx-can-test',
|
||||
'fuzz-xlnx-dp-test',
|
||||
'migration-test']
|
||||
|
||||
qtests_s390x = \
|
||||
|
@ -230,6 +234,7 @@ qos_test_ss.add(
|
|||
'virtio-rng-test.c',
|
||||
'virtio-scsi-test.c',
|
||||
'virtio-serial-test.c',
|
||||
'virtio-iommu-test.c',
|
||||
'vmxnet3-test.c',
|
||||
)
|
||||
if have_virtfs
|
||||
|
|
|
@ -71,9 +71,11 @@ static void add_tests(const char *machines[])
|
|||
char *name;
|
||||
|
||||
for (i = 0; machines[i] != NULL; i++) {
|
||||
name = g_strdup_printf("prom-env/%s", machines[i]);
|
||||
qtest_add_data_func(name, machines[i], test_machine);
|
||||
g_free(name);
|
||||
if (qtest_has_machine(machines[i])) {
|
||||
name = g_strdup_printf("prom-env/%s", machines[i]);
|
||||
qtest_add_data_func(name, machines[i], test_machine);
|
||||
g_free(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* QTest testcase for VirtIO IOMMU
|
||||
*
|
||||
* Copyright (c) 2021 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Auger <eric.auger@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at your
|
||||
* option) any later version. See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "libqtest-single.h"
|
||||
#include "qemu/module.h"
|
||||
#include "libqos/qgraph.h"
|
||||
#include "libqos/virtio-iommu.h"
|
||||
#include "hw/virtio/virtio-iommu.h"
|
||||
|
||||
#define PCI_SLOT_HP 0x06
|
||||
#define QVIRTIO_IOMMU_TIMEOUT_US (30 * 1000 * 1000)
|
||||
|
||||
static QGuestAllocator *alloc;
|
||||
|
||||
static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
|
||||
{
|
||||
QVirtioIOMMU *v_iommu = obj;
|
||||
QVirtioDevice *dev = v_iommu->vdev;
|
||||
uint64_t input_range_start = qvirtio_config_readq(dev, 8);
|
||||
uint64_t input_range_end = qvirtio_config_readq(dev, 16);
|
||||
uint32_t domain_range_start = qvirtio_config_readl(dev, 24);
|
||||
uint32_t domain_range_end = qvirtio_config_readl(dev, 28);
|
||||
|
||||
g_assert_cmpint(input_range_start, ==, 0);
|
||||
g_assert_cmphex(input_range_end, ==, UINT64_MAX);
|
||||
g_assert_cmpint(domain_range_start, ==, 0);
|
||||
g_assert_cmpint(domain_range_end, ==, UINT32_MAX);
|
||||
}
|
||||
|
||||
static int read_tail_status(struct virtio_iommu_req_tail *buffer)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
g_assert_cmpint(buffer->reserved[i], ==, 0);
|
||||
}
|
||||
return buffer->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* send_attach_detach - Send an attach/detach command to the device
|
||||
* @type: VIRTIO_IOMMU_T_ATTACH/VIRTIO_IOMMU_T_DETACH
|
||||
* @domain: domain the endpoint is attached to
|
||||
* @ep: endpoint
|
||||
*/
|
||||
static int send_attach_detach(QTestState *qts, QVirtioIOMMU *v_iommu,
|
||||
uint8_t type, uint32_t domain, uint32_t ep)
|
||||
{
|
||||
QVirtioDevice *dev = v_iommu->vdev;
|
||||
QVirtQueue *vq = v_iommu->vq;
|
||||
uint64_t ro_addr, wr_addr;
|
||||
uint32_t free_head;
|
||||
struct virtio_iommu_req_attach req = {}; /* same layout as detach */
|
||||
size_t ro_size = sizeof(req) - sizeof(struct virtio_iommu_req_tail);
|
||||
size_t wr_size = sizeof(struct virtio_iommu_req_tail);
|
||||
struct virtio_iommu_req_tail buffer;
|
||||
int ret;
|
||||
|
||||
req.head.type = type;
|
||||
req.domain = cpu_to_le32(domain);
|
||||
req.endpoint = cpu_to_le32(ep);
|
||||
|
||||
ro_addr = guest_alloc(alloc, ro_size);
|
||||
wr_addr = guest_alloc(alloc, wr_size);
|
||||
|
||||
qtest_memwrite(qts, ro_addr, &req, ro_size);
|
||||
free_head = qvirtqueue_add(qts, vq, ro_addr, ro_size, false, true);
|
||||
qvirtqueue_add(qts, vq, wr_addr, wr_size, true, false);
|
||||
qvirtqueue_kick(qts, dev, vq, free_head);
|
||||
qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
|
||||
QVIRTIO_IOMMU_TIMEOUT_US);
|
||||
qtest_memread(qts, wr_addr, &buffer, wr_size);
|
||||
ret = read_tail_status(&buffer);
|
||||
guest_free(alloc, ro_addr);
|
||||
guest_free(alloc, wr_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* send_map - Send a map command to the device
|
||||
* @domain: domain the new mapping is attached to
|
||||
* @virt_start: iova start
|
||||
* @virt_end: iova end
|
||||
* @phys_start: base physical address
|
||||
* @flags: mapping flags
|
||||
*/
|
||||
static int send_map(QTestState *qts, QVirtioIOMMU *v_iommu,
|
||||
uint32_t domain, uint64_t virt_start, uint64_t virt_end,
|
||||
uint64_t phys_start, uint32_t flags)
|
||||
{
|
||||
QVirtioDevice *dev = v_iommu->vdev;
|
||||
QVirtQueue *vq = v_iommu->vq;
|
||||
uint64_t ro_addr, wr_addr;
|
||||
uint32_t free_head;
|
||||
struct virtio_iommu_req_map req;
|
||||
size_t ro_size = sizeof(req) - sizeof(struct virtio_iommu_req_tail);
|
||||
size_t wr_size = sizeof(struct virtio_iommu_req_tail);
|
||||
struct virtio_iommu_req_tail buffer;
|
||||
int ret;
|
||||
|
||||
req.head.type = VIRTIO_IOMMU_T_MAP;
|
||||
req.domain = cpu_to_le32(domain);
|
||||
req.virt_start = cpu_to_le64(virt_start);
|
||||
req.virt_end = cpu_to_le64(virt_end);
|
||||
req.phys_start = cpu_to_le64(phys_start);
|
||||
req.flags = cpu_to_le32(flags);
|
||||
|
||||
ro_addr = guest_alloc(alloc, ro_size);
|
||||
wr_addr = guest_alloc(alloc, wr_size);
|
||||
|
||||
qtest_memwrite(qts, ro_addr, &req, ro_size);
|
||||
free_head = qvirtqueue_add(qts, vq, ro_addr, ro_size, false, true);
|
||||
qvirtqueue_add(qts, vq, wr_addr, wr_size, true, false);
|
||||
qvirtqueue_kick(qts, dev, vq, free_head);
|
||||
qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
|
||||
QVIRTIO_IOMMU_TIMEOUT_US);
|
||||
qtest_memread(qts, wr_addr, &buffer, wr_size);
|
||||
ret = read_tail_status(&buffer);
|
||||
guest_free(alloc, ro_addr);
|
||||
guest_free(alloc, wr_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* send_unmap - Send an unmap command to the device
|
||||
* @domain: domain the new binding is attached to
|
||||
* @virt_start: iova start
|
||||
* @virt_end: iova end
|
||||
*/
|
||||
static int send_unmap(QTestState *qts, QVirtioIOMMU *v_iommu,
|
||||
uint32_t domain, uint64_t virt_start, uint64_t virt_end)
|
||||
{
|
||||
QVirtioDevice *dev = v_iommu->vdev;
|
||||
QVirtQueue *vq = v_iommu->vq;
|
||||
uint64_t ro_addr, wr_addr;
|
||||
uint32_t free_head;
|
||||
struct virtio_iommu_req_unmap req;
|
||||
size_t ro_size = sizeof(req) - sizeof(struct virtio_iommu_req_tail);
|
||||
size_t wr_size = sizeof(struct virtio_iommu_req_tail);
|
||||
struct virtio_iommu_req_tail buffer;
|
||||
int ret;
|
||||
|
||||
req.head.type = VIRTIO_IOMMU_T_UNMAP;
|
||||
req.domain = cpu_to_le32(domain);
|
||||
req.virt_start = cpu_to_le64(virt_start);
|
||||
req.virt_end = cpu_to_le64(virt_end);
|
||||
|
||||
ro_addr = guest_alloc(alloc, ro_size);
|
||||
wr_addr = guest_alloc(alloc, wr_size);
|
||||
|
||||
qtest_memwrite(qts, ro_addr, &req, ro_size);
|
||||
free_head = qvirtqueue_add(qts, vq, ro_addr, ro_size, false, true);
|
||||
qvirtqueue_add(qts, vq, wr_addr, wr_size, true, false);
|
||||
qvirtqueue_kick(qts, dev, vq, free_head);
|
||||
qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
|
||||
QVIRTIO_IOMMU_TIMEOUT_US);
|
||||
qtest_memread(qts, wr_addr, &buffer, wr_size);
|
||||
ret = read_tail_status(&buffer);
|
||||
guest_free(alloc, ro_addr);
|
||||
guest_free(alloc, wr_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_attach_detach(void *obj, void *data, QGuestAllocator *t_alloc)
|
||||
{
|
||||
QVirtioIOMMU *v_iommu = obj;
|
||||
QTestState *qts = global_qtest;
|
||||
int ret;
|
||||
|
||||
alloc = t_alloc;
|
||||
|
||||
/* type, domain, ep */
|
||||
|
||||
/* attach ep0 to domain 0 */
|
||||
ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_ATTACH, 0, 0);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
/* attach a non existing device */
|
||||
ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_ATTACH, 0, 444);
|
||||
g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_NOENT);
|
||||
|
||||
/* detach a non existing device (1) */
|
||||
ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_DETACH, 0, 1);
|
||||
g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_NOENT);
|
||||
|
||||
/* move ep0 from domain 0 to domain 1 */
|
||||
ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_ATTACH, 1, 0);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
/* detach ep0 from domain 0 */
|
||||
ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_DETACH, 0, 0);
|
||||
g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_INVAL);
|
||||
|
||||
/* detach ep0 from domain 1 */
|
||||
ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_DETACH, 1, 0);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_ATTACH, 1, 0);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_map(qts, v_iommu, 1, 0x0, 0xFFF, 0xa1000,
|
||||
VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_map(qts, v_iommu, 1, 0x2000, 0x2FFF, 0xb1000,
|
||||
VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_DETACH, 1, 0);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
}
|
||||
|
||||
/* Test map/unmap scenari documented in the spec */
|
||||
static void test_map_unmap(void *obj, void *data, QGuestAllocator *t_alloc)
|
||||
{
|
||||
QVirtioIOMMU *v_iommu = obj;
|
||||
QTestState *qts = global_qtest;
|
||||
int ret;
|
||||
|
||||
alloc = t_alloc;
|
||||
|
||||
/* attach ep0 to domain 1 */
|
||||
ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_ATTACH, 1, 0);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
ret = send_map(qts, v_iommu, 0, 0, 0xFFF, 0xa1000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_NOENT);
|
||||
|
||||
/* domain, virt start, virt end, phys start, flags */
|
||||
ret = send_map(qts, v_iommu, 1, 0x0, 0xFFF, 0xa1000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
/* send a new mapping overlapping the previous one */
|
||||
ret = send_map(qts, v_iommu, 1, 0, 0xFFFF, 0xb1000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_INVAL);
|
||||
|
||||
ret = send_unmap(qts, v_iommu, 4, 0x10, 0xFFF);
|
||||
g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_NOENT);
|
||||
|
||||
ret = send_unmap(qts, v_iommu, 1, 0x10, 0xFFF);
|
||||
g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_RANGE);
|
||||
|
||||
ret = send_unmap(qts, v_iommu, 1, 0, 0x1000);
|
||||
g_assert_cmpint(ret, ==, 0); /* unmap everything */
|
||||
|
||||
/* Spec example sequence */
|
||||
|
||||
/* 1 */
|
||||
ret = send_unmap(qts, v_iommu, 1, 0, 4);
|
||||
g_assert_cmpint(ret, ==, 0); /* doesn't unmap anything */
|
||||
|
||||
/* 2 */
|
||||
ret = send_map(qts, v_iommu, 1, 0, 9, 0xa1000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_unmap(qts, v_iommu, 1, 0, 9);
|
||||
g_assert_cmpint(ret, ==, 0); /* unmaps [0,9] */
|
||||
|
||||
/* 3 */
|
||||
ret = send_map(qts, v_iommu, 1, 0, 4, 0xb1000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_map(qts, v_iommu, 1, 5, 9, 0xb2000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_unmap(qts, v_iommu, 1, 0, 9);
|
||||
g_assert_cmpint(ret, ==, 0); /* unmaps [0,4] and [5,9] */
|
||||
|
||||
/* 4 */
|
||||
ret = send_map(qts, v_iommu, 1, 0, 9, 0xc1000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
ret = send_unmap(qts, v_iommu, 1, 0, 4);
|
||||
g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_RANGE); /* doesn't unmap anything */
|
||||
|
||||
ret = send_unmap(qts, v_iommu, 1, 0, 10);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
/* 5 */
|
||||
ret = send_map(qts, v_iommu, 1, 0, 4, 0xd1000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_map(qts, v_iommu, 1, 5, 9, 0xd2000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_unmap(qts, v_iommu, 1, 0, 4);
|
||||
g_assert_cmpint(ret, ==, 0); /* unmaps [0,4] */
|
||||
|
||||
ret = send_unmap(qts, v_iommu, 1, 5, 9);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
/* 6 */
|
||||
ret = send_map(qts, v_iommu, 1, 0, 4, 0xe2000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_unmap(qts, v_iommu, 1, 0, 9);
|
||||
g_assert_cmpint(ret, ==, 0); /* unmaps [0,4] */
|
||||
|
||||
/* 7 */
|
||||
ret = send_map(qts, v_iommu, 1, 0, 4, 0xf2000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_map(qts, v_iommu, 1, 10, 14, 0xf3000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_unmap(qts, v_iommu, 1, 0, 14);
|
||||
g_assert_cmpint(ret, ==, 0); /* unmaps [0,4] and [10,14] */
|
||||
|
||||
ret = send_map(qts, v_iommu, 1, 10, 14, 0xf3000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_map(qts, v_iommu, 1, 0, 4, 0xf2000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, 0);
|
||||
ret = send_unmap(qts, v_iommu, 1, 0, 4);
|
||||
g_assert_cmpint(ret, ==, 0); /* only unmaps [0,4] */
|
||||
ret = send_map(qts, v_iommu, 1, 10, 14, 0xf3000, VIRTIO_IOMMU_MAP_F_READ);
|
||||
g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_INVAL); /* 10-14 still is mapped */
|
||||
}
|
||||
|
||||
static void register_virtio_iommu_test(void)
|
||||
{
|
||||
qos_add_test("config", "virtio-iommu", pci_config, NULL);
|
||||
qos_add_test("attach_detach", "virtio-iommu", test_attach_detach, NULL);
|
||||
qos_add_test("map_unmap", "virtio-iommu", test_map_unmap, NULL);
|
||||
}
|
||||
|
||||
libqos_init(register_virtio_iommu_test);
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue