* 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:
Richard Henderson 2021-12-15 07:23:50 -08:00
commit 5d3da09e44
25 changed files with 2289 additions and 75 deletions

View File

@ -100,6 +100,17 @@ avocado-system-debian:
IMAGE: debian-amd64 IMAGE: debian-amd64
MAKE_CHECK_ARGS: check-avocado 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: build-system-fedora:
extends: .native_build_job_template extends: .native_build_job_template
needs: needs:
@ -134,6 +145,18 @@ avocado-system-fedora:
IMAGE: fedora IMAGE: fedora
MAKE_CHECK_ARGS: check-avocado 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: build-system-centos:
extends: .native_build_job_template extends: .native_build_job_template
needs: needs:

View File

@ -89,3 +89,38 @@ x64-macos-11-base-build:
PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin 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 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 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

View File

@ -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

View File

@ -11,3 +11,4 @@ include:
- local: '/.gitlab-ci.d/static_checks.yml' - local: '/.gitlab-ci.d/static_checks.yml'
- local: '/.gitlab-ci.d/custom-runners.yml' - local: '/.gitlab-ci.d/custom-runners.yml'
- local: '/.gitlab-ci.d/cirrus.yml' - local: '/.gitlab-ci.d/cirrus.yml'
- local: '/.gitlab-ci.d/windows.yml'

98
.gitlab-ci.d/windows.yml Normal file
View File

@ -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'

27
configure vendored
View File

@ -344,7 +344,6 @@ debug_stack_usage="no"
crypto_afalg="no" crypto_afalg="no"
tls_priority="NORMAL" tls_priority="NORMAL"
tpm="$default_feature" tpm="$default_feature"
libssh="$default_feature"
live_block_migration=${default_feature:-yes} live_block_migration=${default_feature:-yes}
numa="$default_feature" numa="$default_feature"
replication=${default_feature:-yes} replication=${default_feature:-yes}
@ -1078,10 +1077,6 @@ for opt do
;; ;;
--enable-tpm) tpm="yes" --enable-tpm) tpm="yes"
;; ;;
--disable-libssh) libssh="no"
;;
--enable-libssh) libssh="yes"
;;
--disable-live-block-migration) live_block_migration="no" --disable-live-block-migration) live_block_migration="no"
;; ;;
--enable-live-block-migration) live_block_migration="yes" --enable-live-block-migration) live_block_migration="yes"
@ -1448,7 +1443,6 @@ cat << EOF
live-block-migration Block migration in the main migration stream live-block-migration Block migration in the main migration stream
coroutine-pool coroutine freelist (better performance) coroutine-pool coroutine freelist (better performance)
tpm TPM support tpm TPM support
libssh ssh block device support
numa libnuma support numa libnuma support
avx2 AVX2 optimization support avx2 AVX2 optimization support
avx512f AVX512F optimization support avx512f AVX512F optimization support
@ -2561,21 +2555,6 @@ if test "$modules" = yes; then
fi fi
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 # TPM emulation is only on POSIX
@ -3636,12 +3615,6 @@ if test "$cmpxchg128" = "yes" ; then
echo "CONFIG_CMPXCHG128=y" >> $config_host_mak echo "CONFIG_CMPXCHG128=y" >> $config_host_mak
fi 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 if test "$live_block_migration" = "yes" ; then
echo "CONFIG_LIVE_BLOCK_MIGRATION=y" >> $config_host_mak echo "CONFIG_LIVE_BLOCK_MIGRATION=y" >> $config_host_mak
fi fi

View File

@ -91,8 +91,7 @@ virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d"
virtio_iommu_device_reset(void) "reset!" virtio_iommu_device_reset(void) "reset!"
virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64 virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64
virtio_iommu_device_status(uint8_t status) "driver status = %d" 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_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_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_attach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d" 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_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" 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"

View File

@ -822,27 +822,22 @@ unlock:
static void virtio_iommu_get_config(VirtIODevice *vdev, uint8_t *config_data) static void virtio_iommu_get_config(VirtIODevice *vdev, uint8_t *config_data)
{ {
VirtIOIOMMU *dev = VIRTIO_IOMMU(vdev); 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, out_config->page_size_mask = cpu_to_le64(dev_config->page_size_mask);
config->input_range.start, out_config->input_range.start = cpu_to_le64(dev_config->input_range.start);
config->input_range.end, out_config->input_range.end = cpu_to_le64(dev_config->input_range.end);
config->domain_range.end, out_config->domain_range.start = cpu_to_le32(dev_config->domain_range.start);
config->probe_size); out_config->domain_range.end = cpu_to_le32(dev_config->domain_range.end);
memcpy(config_data, &dev->config, sizeof(struct virtio_iommu_config)); out_config->probe_size = cpu_to_le32(dev_config->probe_size);
}
static void virtio_iommu_set_config(VirtIODevice *vdev, trace_virtio_iommu_get_config(dev_config->page_size_mask,
const uint8_t *config_data) dev_config->input_range.start,
{ dev_config->input_range.end,
struct virtio_iommu_config config; dev_config->domain_range.start,
dev_config->domain_range.end,
memcpy(&config, config_data, sizeof(struct virtio_iommu_config)); dev_config->probe_size);
trace_virtio_iommu_set_config(config.page_size_mask,
config.input_range.start,
config.input_range.end,
config.domain_range.end,
config.probe_size);
} }
static uint64_t virtio_iommu_get_features(VirtIODevice *vdev, uint64_t f, 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->event_vq = virtio_add_queue(vdev, VIOMMU_DEFAULT_QUEUE_SIZE, NULL);
s->config.page_size_mask = TARGET_PAGE_MASK; s->config.page_size_mask = TARGET_PAGE_MASK;
s->config.input_range.end = -1UL; s->config.input_range.end = UINT64_MAX;
s->config.domain_range.end = 32; s->config.domain_range.end = UINT32_MAX;
s->config.probe_size = VIOMMU_PROBE_SIZE; s->config.probe_size = VIOMMU_PROBE_SIZE;
virtio_add_feature(&s->features, VIRTIO_RING_F_EVENT_IDX); 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->unrealize = virtio_iommu_device_unrealize;
vdc->reset = virtio_iommu_device_reset; vdc->reset = virtio_iommu_device_reset;
vdc->get_config = virtio_iommu_get_config; vdc->get_config = virtio_iommu_get_config;
vdc->set_config = virtio_iommu_set_config;
vdc->get_features = virtio_iommu_get_features; vdc->get_features = virtio_iommu_get_features;
vdc->set_status = virtio_iommu_set_status; vdc->set_status = virtio_iommu_set_status;
vdc->vmsd = &vmstate_virtio_iommu_device; vdc->vmsd = &vmstate_virtio_iommu_device;

View File

@ -138,6 +138,7 @@ typedef struct PCIBridgeQemuCap {
uint64_t mem_pref_64; /* Prefetchable memory to reserve (64-bit MMIO) */ uint64_t mem_pref_64; /* Prefetchable memory to reserve (64-bit MMIO) */
} PCIBridgeQemuCap; } PCIBridgeQemuCap;
#define REDHAT_PCI_CAP_TYPE_OFFSET 3
#define REDHAT_PCI_CAP_RESOURCE_RESERVE 1 #define REDHAT_PCI_CAP_RESOURCE_RESERVE 1
/* /*
@ -152,6 +153,13 @@ typedef struct PCIResReserve {
uint64_t mem_pref_64; uint64_t mem_pref_64;
} PCIResReserve; } 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, int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset,
PCIResReserve res_reserve, Error **errp); PCIResReserve res_reserve, Error **errp);

View File

@ -874,11 +874,15 @@ if not get_option('glusterfs').auto() or have_block
''', dependencies: glusterfs) ''', dependencies: glusterfs)
endif endif
endif endif
libssh = not_found libssh = not_found
if 'CONFIG_LIBSSH' in config_host if not get_option('libssh').auto() or have_block
libssh = declare_dependency(compile_args: config_host['LIBSSH_CFLAGS'].split(), libssh = dependency('libssh', version: '>=0.8.7',
link_args: config_host['LIBSSH_LIBS'].split()) method: 'pkg-config',
required: get_option('libssh'),
kwargs: static_kwargs)
endif endif
libbzip2 = not_found libbzip2 = not_found
if not get_option('bzip2').auto() or have_block if not get_option('bzip2').auto() or have_block
libbzip2 = cc.find_library('bz2', has_headers: ['bzlib.h'], 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_LIBDAXCTL', libdaxctl.found())
config_host_data.set('CONFIG_LIBISCSI', libiscsi.found()) config_host_data.set('CONFIG_LIBISCSI', libiscsi.found())
config_host_data.set('CONFIG_LIBNFS', libnfs.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_AIO', libaio.found())
config_host_data.set('CONFIG_LINUX_IO_URING', linux_io_uring.found()) config_host_data.set('CONFIG_LINUX_IO_URING', linux_io_uring.found())
config_host_data.set('CONFIG_LIBPMEM', libpmem.found()) config_host_data.set('CONFIG_LIBPMEM', libpmem.found())
@ -3430,7 +3435,7 @@ endif
summary_info += {'seccomp support': seccomp} summary_info += {'seccomp support': seccomp}
summary_info += {'GlusterFS support': glusterfs} summary_info += {'GlusterFS support': glusterfs}
summary_info += {'TPM support': config_host.has_key('CONFIG_TPM')} 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 += {'lzo support': lzo}
summary_info += {'snappy support': snappy} summary_info += {'snappy support': snappy}
summary_info += {'bzip2 support': libbzip2} summary_info += {'bzip2 support': libbzip2}

View File

@ -105,6 +105,8 @@ option('libdaxctl', type : 'feature', value : 'auto',
description: 'libdaxctl support') description: 'libdaxctl support')
option('libpmem', type : 'feature', value : 'auto', option('libpmem', type : 'feature', value : 'auto',
description: 'libpmem support') description: 'libpmem support')
option('libssh', type : 'feature', value : 'auto',
description: 'ssh block device support')
option('libudev', type : 'feature', value : 'auto', option('libudev', type : 'feature', value : 'auto',
description: 'Use libudev to enumerate host devices') description: 'Use libudev to enumerate host devices')
option('libusb', type : 'feature', value : 'auto', option('libusb', type : 'feature', value : 'auto',

View File

@ -53,6 +53,7 @@ meson_options_help() {
printf "%s\n" ' libiscsi libiscsi userspace initiator' printf "%s\n" ' libiscsi libiscsi userspace initiator'
printf "%s\n" ' libnfs libnfs block device driver' printf "%s\n" ' libnfs libnfs block device driver'
printf "%s\n" ' libpmem libpmem support' 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" ' libudev Use libudev to enumerate host devices'
printf "%s\n" ' libusb libusb support for USB passthrough' printf "%s\n" ' libusb libusb support for USB passthrough'
printf "%s\n" ' libxml2 libxml2 support for Parallels image format' printf "%s\n" ' libxml2 libxml2 support for Parallels image format'
@ -177,6 +178,8 @@ _meson_option_parse() {
--disable-libnfs) printf "%s" -Dlibnfs=disabled ;; --disable-libnfs) printf "%s" -Dlibnfs=disabled ;;
--enable-libpmem) printf "%s" -Dlibpmem=enabled ;; --enable-libpmem) printf "%s" -Dlibpmem=enabled ;;
--disable-libpmem) printf "%s" -Dlibpmem=disabled ;; --disable-libpmem) printf "%s" -Dlibpmem=disabled ;;
--enable-libssh) printf "%s" -Dlibssh=enabled ;;
--disable-libssh) printf "%s" -Dlibssh=disabled ;;
--enable-libudev) printf "%s" -Dlibudev=enabled ;; --enable-libudev) printf "%s" -Dlibudev=enabled ;;
--disable-libudev) printf "%s" -Dlibudev=disabled ;; --disable-libudev) printf "%s" -Dlibudev=disabled ;;
--enable-libusb) printf "%s" -Dlibusb=enabled ;; --enable-libusb) printf "%s" -Dlibusb=enabled ;;

View File

@ -285,7 +285,8 @@ int main(int argc, char *argv[])
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
for (i = 0; tests[i].arch != NULL; i++) { 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); char *name = g_strdup_printf("boot-serial/%s", tests[i].machine);
qtest_add_data_func(name, &tests[i], test_machine); qtest_add_data_func(name, &tests[i], test_machine);
g_free(name); g_free(name);

View File

@ -109,9 +109,11 @@ static void test_cdrom_param(gconstpointer data)
static void add_cdrom_param_tests(const char **machines) static void add_cdrom_param_tests(const char **machines)
{ {
while (*machines) { while (*machines) {
if (qtest_has_machine(*machines)) {
char *testname = g_strdup_printf("cdrom/param/%s", *machines); char *testname = g_strdup_printf("cdrom/param/%s", *machines);
qtest_add_data_func(testname, *machines, test_cdrom_param); qtest_add_data_func(testname, *machines, test_cdrom_param);
g_free(testname); g_free(testname);
}
machines++; machines++;
} }
} }

View File

@ -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), void qtest_cb_for_every_machine(void (*cb)(const char *machine),
bool skip_old_versioned); 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: * qtest_qmp_device_add_qdict:
* @qts: QTestState instance to operate on * @qts: QTestState instance to operate on

View File

@ -41,6 +41,7 @@ libqos_srcs = files('../libqtest.c',
'virtio-rng.c', 'virtio-rng.c',
'virtio-scsi.c', 'virtio-scsi.c',
'virtio-serial.c', 'virtio-serial.c',
'virtio-iommu.c',
# qgraph machines: # qgraph machines:
'aarch64-xlnx-zcu102-machine.c', 'aarch64-xlnx-zcu102-machine.c',

View File

@ -13,6 +13,8 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "pci.h" #include "pci.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_regs.h" #include "hw/pci/pci_regs.h"
#include "qemu/host-utils.h" #include "qemu/host-utils.h"
#include "qgraph.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); 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) void qpci_device_enable(QPCIDevice *dev)
{ {
uint16_t cmd; uint16_t cmd;

View File

@ -81,6 +81,7 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
void *data); void *data);
QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn); QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn);
void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr); 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_has_buggy_msi(QPCIDevice *dev);
bool qpci_check_buggy_msi(QPCIDevice *dev); bool qpci_check_buggy_msi(QPCIDevice *dev);

View File

@ -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);

View File

@ -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

View File

@ -1321,16 +1321,29 @@ static bool qtest_is_old_versioned_machine(const char *mname)
return res; return res;
} }
void qtest_cb_for_every_machine(void (*cb)(const char *machine), struct MachInfo {
bool skip_old_versioned) 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; QDict *response, *minfo;
QList *list; QList *list;
const QListEntry *p; const QListEntry *p;
QObject *qobj; QObject *qobj;
QString *qstr; QString *qstr;
const char *mname;
QTestState *qts; QTestState *qts;
int idx;
if (machines) {
return machines;
}
qts = qtest_init("-machine none"); qts = qtest_init("-machine none");
response = qtest_qmp(qts, "{ 'execute': 'query-machines' }"); 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"); list = qdict_get_qlist(response, "return");
g_assert(list); 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)); minfo = qobject_to(QDict, qlist_entry_obj(p));
g_assert(minfo); g_assert(minfo);
qobj = qdict_get(minfo, "name"); qobj = qdict_get(minfo, "name");
g_assert(qobj); g_assert(qobj);
qstr = qobject_to(QString, qobj); qstr = qobject_to(QString, qobj);
g_assert(qstr); g_assert(qstr);
mname = qstring_get_str(qstr); machines[idx].name = g_strdup(qstring_get_str(qstr));
/* Ignore machines that cannot be used for qtests */
if (!strncmp("xenfv", mname, 5) || g_str_equal("xenpv", mname)) { qobj = qdict_get(minfo, "alias");
continue; if (qobj) { /* The alias is optional */
} qstr = qobject_to(QString, qobj);
if (!skip_old_versioned || !qtest_is_old_versioned_machine(mname)) { g_assert(qstr);
cb(mname); machines[idx].alias = g_strdup(qstring_get_str(qstr));
} else {
machines[idx].alias = NULL;
} }
} }
qtest_quit(qts); qtest_quit(qts);
qobject_unref(response); 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;
} }
/* /*

View File

@ -68,6 +68,10 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) + \ (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_E1000E_PCI_EXPRESS') ? ['fuzz-e1000e-test'] : []) + \
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-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'] : []) + \ (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
qtests_pci + \ qtests_pci + \
['fdc-test', ['fdc-test',
@ -134,6 +138,7 @@ qtests_ppc = \
['boot-order-test', 'prom-env-test', 'boot-serial-test'] \ ['boot-order-test', 'prom-env-test', 'boot-serial-test'] \
qtests_ppc64 = \ qtests_ppc64 = \
qtests_ppc + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['device-plug-test'] : []) + \ (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_POWERNV') ? ['pnv-xscom-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-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'] : []) + \ (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-test'] : []) + \
(config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-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', ['arm-cpu-features',
'numa-test', 'numa-test',
'boot-serial-test', 'boot-serial-test',
'xlnx-can-test',
'fuzz-xlnx-dp-test',
'migration-test'] 'migration-test']
qtests_s390x = \ qtests_s390x = \
@ -230,6 +234,7 @@ qos_test_ss.add(
'virtio-rng-test.c', 'virtio-rng-test.c',
'virtio-scsi-test.c', 'virtio-scsi-test.c',
'virtio-serial-test.c', 'virtio-serial-test.c',
'virtio-iommu-test.c',
'vmxnet3-test.c', 'vmxnet3-test.c',
) )
if have_virtfs if have_virtfs

View File

@ -71,11 +71,13 @@ static void add_tests(const char *machines[])
char *name; char *name;
for (i = 0; machines[i] != NULL; i++) { for (i = 0; machines[i] != NULL; i++) {
if (qtest_has_machine(machines[i])) {
name = g_strdup_printf("prom-env/%s", machines[i]); name = g_strdup_printf("prom-env/%s", machines[i]);
qtest_add_data_func(name, machines[i], test_machine); qtest_add_data_func(name, machines[i], test_machine);
g_free(name); g_free(name);
} }
} }
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {

View File

@ -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