diff options
83 files changed, 1234 insertions, 672 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 3dd9fcff7f..d58782ce67 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,38 +1,19 @@ env: CIRRUS_CLONE_DEPTH: 1 -freebsd_1st_task: +freebsd_12_task: freebsd_instance: image_family: freebsd-12-1 - cpu: 4 - memory: 4G - install_script: ASSUME_ALWAYS_YES=yes pkg bootstrap -f ; pkg install -y - bash curl cyrus-sasl git glib gmake gnutls gsed - nettle perl5 pixman pkgconf png usbredir + cpu: 8 + memory: 8G + install_script: + - ASSUME_ALWAYS_YES=yes pkg bootstrap -f ; + - pkg install -y bash curl cyrus-sasl git glib gmake gnutls gsed + nettle perl5 pixman pkgconf png usbredir script: - mkdir build - cd build - - ../configure --disable-user --target-list-exclude='alpha-softmmu - ppc64-softmmu ppc-softmmu riscv32-softmmu riscv64-softmmu s390x-softmmu - sparc64-softmmu sparc-softmmu x86_64-softmmu i386-softmmu' - --enable-werror || { cat config.log; exit 1; } - - gmake -j$(sysctl -n hw.ncpu) - - gmake -j$(sysctl -n hw.ncpu) check - -freebsd_2nd_task: - freebsd_instance: - image_family: freebsd-12-1 - cpu: 4 - memory: 4G - install_script: ASSUME_ALWAYS_YES=yes pkg bootstrap -f ; pkg install -y - bash curl cyrus-sasl git glib gmake gnutls gtk3 gsed libepoxy mesa-libs - nettle perl5 pixman pkgconf png SDL2 usbredir - script: - - ./configure --enable-werror --target-list='alpha-softmmu ppc64-softmmu - ppc-softmmu riscv32-softmmu riscv64-softmmu s390x-softmmu - sparc64-softmmu sparc-softmmu x86_64-softmmu i386-softmmu - sparc-bsd-user sparc64-bsd-user x86_64-bsd-user i386-bsd-user' - || { cat config.log; exit 1; } + - ../configure --enable-werror || { cat config.log; exit 1; } - gmake -j$(sysctl -n hw.ncpu) - gmake -j$(sysctl -n hw.ncpu) check @@ -63,3 +44,66 @@ macos_xcode_task: --enable-werror --cc=clang || { cat config.log; exit 1; } - gmake -j$(sysctl -n hw.ncpu) - gmake check + +windows_msys2_task: + windows_container: + image: cirrusci/windowsservercore:cmake + os_version: 2019 + cpu: 8 + memory: 8G + env: + MSYS: winsymlinks:nativestrict + MSYSTEM: MINGW64 + CHERE_INVOKING: 1 + printenv_script: + - C:\tools\msys64\usr\bin\bash.exe -lc 'printenv' + install_script: + - C:\tools\msys64\usr\bin\bash.exe -lc "cd /c/tools && + curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz" + - C:\tools\msys64\usr\bin\bash.exe -lc "cd /c/tools && + curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig" + - C:\tools\msys64\usr\bin\bash.exe -lc "cd /c/tools && + pacman -U --noconfirm msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz" + - C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -Sy" + - C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -S --needed + bash pacman pacman-mirrors msys2-runtime" + - taskkill /F /IM gpg-agent.exe + - C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -Su" + - C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -S --needed + base-devel + git + mingw-w64-x86_64-python + mingw-w64-x86_64-python-setuptools + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-capstone + mingw-w64-x86_64-SDL2 + mingw-w64-x86_64-SDL2_image + mingw-w64-x86_64-gtk3 + mingw-w64-x86_64-glib2 + mingw-w64-x86_64-ninja + mingw-w64-x86_64-make + mingw-w64-x86_64-lzo2 + mingw-w64-x86_64-zstd + mingw-w64-x86_64-libjpeg-turbo + mingw-w64-x86_64-pixman + mingw-w64-x86_64-libgcrypt + mingw-w64-x86_64-libpng + mingw-w64-x86_64-libssh + mingw-w64-x86_64-libxml2 + mingw-w64-x86_64-snappy + mingw-w64-x86_64-libusb + mingw-w64-x86_64-usbredir + mingw-w64-x86_64-libtasn1 + mingw-w64-x86_64-nettle + mingw-w64-x86_64-cyrus-sasl + mingw-w64-x86_64-curl + mingw-w64-x86_64-gnutls + mingw-w64-x86_64-zstd" + script: + - C:\tools\msys64\usr\bin\bash.exe -lc "mkdir build" + - C:\tools\msys64\usr\bin\bash.exe -lc "cd build && ../configure + --python=python3 --ninja=ninja + --target-list-exclude=i386-softmmu,arm-softmmu,ppc-softmmu,mips-softmmu" + - C:\tools\msys64\usr\bin\bash.exe -lc "cd build && make -j$NUMBER_OF_PROCESSORS" + test_script: + - C:\tools\msys64\usr\bin\bash.exe -lc "cd build && make V=1 check" diff --git a/.gitignore b/.gitignore index b6fdd34ddf..5515f595e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,163 +1,11 @@ /GNUmakefile /build/ -/.doctrees -/config-devices.* -/config-host.* -/config-target.* -/config.status -/config-temp -/tools/virtiofsd/50-qemu-virtiofsd.json -/elf2dmp -/trace-events-all -/trace/generated-events.h -/trace/generated-events.c -/trace/generated-helpers-wrappers.h -/trace/generated-helpers.h -/trace/generated-helpers.c -/trace/generated-tcg-tracers.h -/ui/shader/texture-blit-frag.h -/ui/shader/texture-blit-vert.h -/ui/shader/texture-blit-flip-vert.h -/ui/input-keymap-*.c.inc -*-timestamp -/*-softmmu -/*-darwin-user -/*-linux-user -/*-bsd-user -/ivshmem-client -/ivshmem-server -/libdis* -/libuser -/linux-headers/asm -/qga/qapi-generated -/qapi-gen-timestamp -/qapi/qapi-builtin-types.[ch] -/qapi/qapi-builtin-visit.[ch] -/qapi/qapi-commands-*.[ch] -**/qapi/qapi-commands.[ch] -**/qapi/qapi-emit-events.[ch] -/qapi/qapi-events-*.[ch] -**/qapi/qapi-events.[ch] -**/qapi/qapi-init-commands.[ch] -**/qapi/qapi-introspect.[ch] -/qapi/qapi-types-*.[ch] -**/qapi/qapi-types.[ch] -/qapi/qapi-visit-*.[ch] -!/qapi/qapi-visit-core.c -**/qapi/qapi-visit.[ch] -**/qapi/qapi-doc.texi -/qemu-edid -/qemu-img -/qemu-nbd -/qemu-options.def -/qemu-options.texi -/qemu-img-cmds.texi -/qemu-img-cmds.h -/qemu-io -/qemu-ga -/qemu-bridge-helper -/qemu-keymap -/qemu-monitor.texi -/qemu-monitor-info.texi -/qemu-storage-daemon -/qemu-version.h -/qemu-version.h.tmp -/module_block.h -/scsi/qemu-pr-helper -/vhost-user-scsi -/vhost-user-blk -/vhost-user-gpu -/vhost-user-input -/fsdev/virtfs-proxy-helper -*.tmp -*.[1-9] -*.a -*.aux -*.cp -*.exe -*.msi -*.dll -*.so -*.fn -*.ky -*.log -*.pdf -*.pod -*.cps -*.fns -*.kys -*.pg -*.pyc -*.toc -*.tp -*.vr -*.d -!/.gitlab-ci.d -!/scripts/qemu-guest-agent/fsfreeze-hook.d -*.o .sdk -*.gcda -*.gcno -*.gcov -/pc-bios/bios-pq/status -/pc-bios/edk2-*.fd -/pc-bios/vgabios-pq/status -/pc-bios/optionrom/linuxboot.asm -/pc-bios/optionrom/linuxboot.bin -/pc-bios/optionrom/linuxboot.raw -/pc-bios/optionrom/linuxboot.img -/pc-bios/optionrom/linuxboot_dma.asm -/pc-bios/optionrom/linuxboot_dma.bin -/pc-bios/optionrom/linuxboot_dma.raw -/pc-bios/optionrom/linuxboot_dma.img -/pc-bios/optionrom/pvh.asm -/pc-bios/optionrom/pvh.bin -/pc-bios/optionrom/pvh.raw -/pc-bios/optionrom/pvh.img -/pc-bios/optionrom/multiboot.asm -/pc-bios/optionrom/multiboot.bin -/pc-bios/optionrom/multiboot.raw -/pc-bios/optionrom/multiboot.img -/pc-bios/optionrom/kvmvapic.asm -/pc-bios/optionrom/kvmvapic.bin -/pc-bios/optionrom/kvmvapic.raw -/pc-bios/optionrom/kvmvapic.img -/pc-bios/s390-ccw/s390-ccw.elf -/pc-bios/s390-ccw/s390-ccw.img -/docs/built -/docs/interop/qemu-ga-qapi.texi -/docs/interop/qemu-ga-ref.html -/docs/interop/qemu-ga-ref.info* -/docs/interop/qemu-ga-ref.txt -/docs/interop/qemu-qmp-qapi.texi -/docs/interop/qemu-qmp-ref.html -/docs/interop/qemu-qmp-ref.info* -/docs/interop/qemu-qmp-ref.txt -/docs/version.texi -/contrib/vhost-user-gpu/50-qemu-gpu.json -*.tps .stgit-* .git-submodule-status cscope.* tags TAGS -docker-src.* *~ *.ast_raw *.depend_raw -trace.c -trace-ust.h -trace-ust.h -trace-dtrace.h -trace-dtrace.dtrace -trace-root.h -trace-root.c -trace-ust-root.h -trace-ust-root.h -trace-ust-all.h -trace-ust-all.c -trace-dtrace-root.h -trace-dtrace-root.dtrace -trace-ust-all.h -trace-ust-all.c -/target/arm/decode-sve.c.inc diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 72e8604579..a18e18b57e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -134,7 +134,7 @@ build-system-fedora: variables: IMAGE: fedora CONFIGURE_ARGS: --disable-gcrypt --enable-nettle - TARGETS: tricore-softmmu unicore32-softmmu microblaze-softmmu mips-softmmu + TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu MAKE_CHECK_ARGS: check-build artifacts: @@ -166,7 +166,7 @@ build-system-centos: variables: IMAGE: centos8 CONFIGURE_ARGS: --disable-nettle --enable-gcrypt - TARGETS: ppc64-softmmu lm32-softmmu or1k-softmmu s390x-softmmu + TARGETS: ppc64-softmmu or1k-softmmu s390x-softmmu x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu MAKE_CHECK_ARGS: check-build artifacts: @@ -254,6 +254,17 @@ build-clang: ppc-softmmu s390x-softmmu arm-linux-user MAKE_CHECK_ARGS: check +# These targets are on the way out +build-deprecated: + <<: *native_build_job_definition + variables: + IMAGE: debian-all-test-cross + CONFIGURE_ARGS: --disable-docs --disable-tools + MAKE_CHECK_ARGS: check-tcg + TARGETS: ppc64abi32-linux-user tilegx-linux-user lm32-softmmu + unicore32-softmmu + allow_failure: true + build-oss-fuzz: <<: *native_build_job_definition variables: diff --git a/.shippable.yml b/.shippable.yml index 89d8be4291..0b4fd6df1d 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -8,7 +8,7 @@ env: - IMAGE=debian-amd64 TARGET_LIST=x86_64-softmmu,x86_64-linux-user - IMAGE=debian-win32-cross - TARGET_LIST=arm-softmmu,i386-softmmu,lm32-softmmu + TARGET_LIST=arm-softmmu,i386-softmmu - IMAGE=debian-win64-cross TARGET_LIST=aarch64-softmmu,sparc64-softmmu,x86_64-softmmu - IMAGE=debian-armel-cross diff --git a/.travis.yml b/.travis.yml index 65341634d0..c75221dca3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -344,10 +344,9 @@ jobs: # Run check-tcg against linux-user (with plugins) # we skip sparc64-linux-user until it has been fixed somewhat # we skip cris-linux-user as it doesn't use the common run loop - # we skip ppc64abi32-linux-user as it seems to have a broken libc - name: "GCC plugins check-tcg (user)" env: - - CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user,ppc64abi32-linux-user" + - CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user" - TEST_BUILD_CMD="make build-tcg" - TEST_CMD="make check-tcg" - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg" diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 63ef6af9a1..ad8b315b35 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -2013,7 +2013,7 @@ static int kvm_init(MachineState *ms) #endif QLIST_INIT(&s->kvm_parked_vcpus); s->vmfd = -1; - s->fd = qemu_open("/dev/kvm", O_RDWR); + s->fd = qemu_open_old("/dev/kvm", O_RDWR); if (s->fd == -1) { fprintf(stderr, "Could not access KVM kernel module: %m\n"); ret = -errno; diff --git a/backends/rng-random.c b/backends/rng-random.c index 32998d8ee7..245b12ab24 100644 --- a/backends/rng-random.c +++ b/backends/rng-random.c @@ -75,7 +75,7 @@ static void rng_random_opened(RngBackend *b, Error **errp) error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "filename", "a valid filename"); } else { - s->fd = qemu_open(s->filename, O_RDONLY | O_NONBLOCK); + s->fd = qemu_open_old(s->filename, O_RDONLY | O_NONBLOCK); if (s->fd == -1) { error_setg_file_open(errp, errno, s->filename); } diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c index 10722e0a41..6d6294ef0a 100644 --- a/backends/tpm/tpm_passthrough.c +++ b/backends/tpm/tpm_passthrough.c @@ -218,7 +218,7 @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) char path[PATH_MAX]; if (tpm_pt->options->cancel_path) { - fd = qemu_open(tpm_pt->options->cancel_path, O_WRONLY); + fd = qemu_open_old(tpm_pt->options->cancel_path, O_WRONLY); if (fd < 0) { error_report("tpm_passthrough: Could not open TPM cancel path: %s", strerror(errno)); @@ -236,11 +236,11 @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) dev++; if (snprintf(path, sizeof(path), "/sys/class/tpm/%s/device/cancel", dev) < sizeof(path)) { - fd = qemu_open(path, O_WRONLY); + fd = qemu_open_old(path, O_WRONLY); if (fd < 0) { if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel", dev) < sizeof(path)) { - fd = qemu_open(path, O_WRONLY); + fd = qemu_open_old(path, O_WRONLY); } } } @@ -272,7 +272,7 @@ tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) } tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE; - tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR); + tpm_pt->tpm_fd = qemu_open_old(tpm_pt->tpm_dev, O_RDWR); if (tpm_pt->tpm_fd < 0) { error_report("Cannot access TPM device using '%s': %s", tpm_pt->tpm_dev, strerror(errno)); diff --git a/block/file-posix.c b/block/file-posix.c index 9a00d4190a..c63926d592 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -630,11 +630,10 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, raw_parse_flags(bdrv_flags, &s->open_flags, false); s->fd = -1; - fd = qemu_open(filename, s->open_flags, 0644); + fd = qemu_open(filename, s->open_flags, errp); ret = fd < 0 ? -errno : 0; if (ret < 0) { - error_setg_file_open(errp, -ret, filename); if (ret == -EROFS) { ret = -EACCES; } @@ -1037,10 +1036,8 @@ static int raw_reconfigure_getfd(BlockDriverState *bs, int flags, const char *normalized_filename = bs->filename; ret = raw_normalize_devicepath(&normalized_filename, errp); if (ret >= 0) { - assert(!(*open_flags & O_CREAT)); - fd = qemu_open(normalized_filename, *open_flags); + fd = qemu_open(normalized_filename, *open_flags, errp); if (fd == -1) { - error_setg_errno(errp, errno, "Could not reopen file"); return -1; } } @@ -2411,10 +2408,9 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) } /* Create file */ - fd = qemu_open(file_opts->filename, O_RDWR | O_CREAT | O_BINARY, 0644); + fd = qemu_create(file_opts->filename, O_RDWR | O_BINARY, 0644, errp); if (fd < 0) { result = -errno; - error_setg_errno(errp, -result, "Could not create file"); goto out; } @@ -3335,7 +3331,7 @@ static bool setup_cdrom(char *bsd_path, Error **errp) for (index = 0; index < num_of_test_partitions; index++) { snprintf(test_partition, sizeof(test_partition), "%ss%d", bsd_path, index); - fd = qemu_open(test_partition, O_RDONLY | O_BINARY | O_LARGEFILE); + fd = qemu_open(test_partition, O_RDONLY | O_BINARY | O_LARGEFILE, NULL); if (fd >= 0) { partition_found = true; qemu_close(fd); @@ -3653,7 +3649,7 @@ static int cdrom_probe_device(const char *filename) int prio = 0; struct stat st; - fd = qemu_open(filename, O_RDONLY | O_NONBLOCK); + fd = qemu_open(filename, O_RDONLY | O_NONBLOCK, NULL); if (fd < 0) { goto out; } @@ -3787,7 +3783,7 @@ static int cdrom_reopen(BlockDriverState *bs) */ if (s->fd >= 0) qemu_close(s->fd); - fd = qemu_open(bs->filename, s->open_flags, 0644); + fd = qemu_open(bs->filename, s->open_flags, NULL); if (fd < 0) { s->fd = -1; return -EIO; diff --git a/block/file-win32.c b/block/file-win32.c index e2900c3a51..2642088bd6 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -596,10 +596,9 @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) return -EINVAL; } - fd = qemu_open(file_opts->filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - 0644); + fd = qemu_create(file_opts->filename, O_WRONLY | O_TRUNC | O_BINARY, + 0644, errp); if (fd < 0) { - error_setg_errno(errp, errno, "Could not create file"); return -EIO; } set_sparse(fd); diff --git a/block/vvfat.c b/block/vvfat.c index 36b53c8757..5abb90e7c7 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -1352,7 +1352,8 @@ static int open_file(BDRVVVFATState* s,mapping_t* mapping) if(!s->current_mapping || strcmp(s->current_mapping->path,mapping->path)) { /* open file */ - int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE); + int fd = qemu_open_old(mapping->path, + O_RDONLY | O_BINARY | O_LARGEFILE); if(fd<0) return -1; vvfat_close_current_file(s); @@ -2513,7 +2514,7 @@ static int commit_one_file(BDRVVVFATState* s, for (i = s->cluster_size; i < offset; i += s->cluster_size) c = modified_fat_get(s, c); - fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666); + fd = qemu_open_old(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666); if (fd < 0) { fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path, strerror(errno), errno); diff --git a/chardev/char-fd.c b/chardev/char-fd.c index c2d8101106..1cd62f2779 100644 --- a/chardev/char-fd.c +++ b/chardev/char-fd.c @@ -119,7 +119,7 @@ int qmp_chardev_open_file_source(char *src, int flags, Error **errp) { int fd = -1; - TFR(fd = qemu_open(src, flags, 0666)); + TFR(fd = qemu_open_old(src, flags, 0666)); if (fd == -1) { error_setg_file_open(errp, errno, src); } diff --git a/chardev/char-pipe.c b/chardev/char-pipe.c index fd12c9e63b..7eca5d9a56 100644 --- a/chardev/char-pipe.c +++ b/chardev/char-pipe.c @@ -132,8 +132,8 @@ static void qemu_chr_open_pipe(Chardev *chr, filename_in = g_strdup_printf("%s.in", filename); filename_out = g_strdup_printf("%s.out", filename); - TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY)); - TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY)); + TFR(fd_in = qemu_open_old(filename_in, O_RDWR | O_BINARY)); + TFR(fd_out = qemu_open_old(filename_out, O_RDWR | O_BINARY)); g_free(filename_in); g_free(filename_out); if (fd_in < 0 || fd_out < 0) { @@ -143,7 +143,7 @@ static void qemu_chr_open_pipe(Chardev *chr, if (fd_out >= 0) { close(fd_out); } - TFR(fd_in = fd_out = qemu_open(filename, O_RDWR | O_BINARY)); + TFR(fd_in = fd_out = qemu_open_old(filename, O_RDWR | O_BINARY)); if (fd_in < 0) { error_setg_file_open(errp, errno, filename); return; diff --git a/chardev/char.c b/chardev/char.c index 77e7ec814f..6b85099c03 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -235,7 +235,7 @@ static void qemu_char_open(Chardev *chr, ChardevBackend *backend, } else { flags |= O_TRUNC; } - chr->logfd = qemu_open(common->logfile, flags, 0666); + chr->logfd = qemu_open_old(common->logfile, flags, 0666); if (chr->logfd < 0) { error_setg_errno(errp, errno, "Unable to open logfile %s", diff --git a/configure b/configure index ce27eafb0a..7564479008 100755 --- a/configure +++ b/configure @@ -280,6 +280,9 @@ supported_whpx_target() { return 1 } +deprecated_targets_list=ppc64abi32-linux-user,tilegx-linux-user,lm32-softmmu,unicore32-softmmu +deprecated_features="" + supported_target() { case "$1" in *-softmmu) @@ -301,6 +304,12 @@ supported_target() { return 1 ;; esac + + # if a deprecated target is enabled we note it here + if echo "$deprecated_targets_list" | grep -q "$1"; then + add_to deprecated_features $1 + fi + test "$tcg" = "yes" && return 0 supported_kvm_target "$1" && return 0 supported_xen_target "$1" && return 0 @@ -542,8 +551,6 @@ gettext="" bogus_os="no" malloc_trim="" -deprecated_features="" - # parse CC options first for opt do optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') @@ -1722,22 +1729,19 @@ if [ "$bsd_user" = "yes" ]; then mak_wilds="${mak_wilds} $source_path/default-configs/*-bsd-user.mak" fi -if test -z "$target_list_exclude" -a -z "$target_list"; then - # if the user doesn't specify anything lets skip deprecating stuff - target_list_exclude=ppc64abi32-linux-user +# If the user doesn't explicitly specify a deprecated target we will +# skip it. +if test -z "$target_list"; then + if test -z "$target_list_exclude"; then + target_list_exclude="$deprecated_targets_list" + else + target_list_exclude="$target_list_exclude,$deprecated_targets_list" + fi fi -exclude_list=$(echo "$target_list_exclude" | sed -e 's/,/ /g') for config in $mak_wilds; do target="$(basename "$config" .mak)" - exclude="no" - for excl in $exclude_list; do - if test "$excl" = "$target"; then - exclude="yes" - break; - fi - done - if test "$exclude" = "no"; then + if echo "$target_list_exclude" | grep -vq "$target"; then default_target_list="${default_target_list} $target" fi done @@ -7668,7 +7672,6 @@ case "$target_name" in TARGET_SYSTBL_ABI=common,nospu,32 echo "TARGET_ABI32=y" >> $config_target_mak gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml" - deprecated_features="ppc64abi32 ${deprecated_features}" ;; riscv32) TARGET_BASE_ARCH=riscv diff --git a/dump/dump.c b/dump/dump.c index 383bc7876b..13fda440a4 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -1994,7 +1994,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, #endif if (strstart(file, "file:", &p)) { - fd = qemu_open(p, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR); + fd = qemu_open_old(p, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR); if (fd < 0) { error_setg_file_open(errp, errno, p); return; diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index f2f7772c86..d51cec2f3b 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -64,6 +64,10 @@ typedef struct ExtendedOps { */ #define V9FS_REMAP_INODES 0x00000200 #define V9FS_FORBID_MULTIDEVS 0x00000400 +/* + * Disables certain performance warnings from being logged on host side. + */ +#define V9FS_NO_PERF_WARN 0x00000800 #define V9FS_SEC_MASK 0x0000003C diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index 7eb210ffa8..cec8c0eefc 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -541,6 +541,8 @@ static int synth_init(FsContext *ctx, Error **errp) QLIST_INIT(&synth_root.child); qemu_mutex_init(&synth_mutex); + ctx->export_flags |= V9FS_NO_PERF_WARN; + /* Add "." and ".." entries for root */ v9fs_add_dir_node(&synth_root, synth_root.attr->mode, "..", synth_root.attr, synth_root.attr->inode); diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 7bb994bbf2..741d222c3f 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1353,6 +1353,15 @@ static void coroutine_fn v9fs_version(void *opaque) goto out; } + /* 8192 is the default msize of Linux clients */ + if (s->msize <= 8192 && !(s->ctx.export_flags & V9FS_NO_PERF_WARN)) { + warn_report_once( + "9p: degraded performance: a reasonable high msize should be " + "chosen on client/guest side (chosen msize is <= 8192). See " + "https://wiki.qemu.org/Documentation/9psetup#msize for details." + ); + } + marshal: err = pdu_marshal(pdu, offset, "ds", s->msize, &version); if (err < 0) { diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index b8abdefa1c..6df400e1ee 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -20,6 +20,7 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qemu/error-report.h" +#include "sysemu/runstate.h" static const uint32_t ged_supported_events[] = { ACPI_GED_MEM_HOTPLUG_EVT, @@ -141,6 +142,14 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev, aml_append(table, dev); } +void acpi_dsdt_add_power_button(Aml *scope) +{ + Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE); + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + aml_append(scope, dev); +} + /* Memory read by the GED _EVT AML dynamic method */ static uint64_t ged_evt_read(void *opaque, hwaddr addr, unsigned size) { @@ -176,6 +185,45 @@ static const MemoryRegionOps ged_evt_ops = { }, }; +static uint64_t ged_regs_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + +static void ged_regs_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) +{ + bool slp_en; + int slp_typ; + + switch (addr) { + case ACPI_GED_REG_SLEEP_CTL: + slp_typ = (data >> 2) & 0x07; + slp_en = (data >> 5) & 0x01; + if (slp_en && slp_typ == 5) { + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } + return; + case ACPI_GED_REG_SLEEP_STS: + return; + case ACPI_GED_REG_RESET: + if (data == ACPI_GED_RESET_VALUE) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } + return; + } +} + +static const MemoryRegionOps ged_regs_ops = { + .read = ged_regs_read, + .write = ged_regs_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -332,6 +380,10 @@ static void acpi_ged_initfn(Object *obj) sysbus_init_mmio(sbd, &s->container_memhp); acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev), &s->memhp_state, 0); + + memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st, + TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT); + sysbus_init_mmio(sbd, &ged_st->regs); } static void acpi_ged_class_init(ObjectClass *class, void *data) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 9efd7a3881..6bff5e3738 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -357,14 +357,6 @@ static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap, aml_append(scope, dev); } -static void acpi_dsdt_add_power_button(Aml *scope) -{ - Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE); - aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C"))); - aml_append(dev, aml_name_decl("_UID", aml_int(0))); - aml_append(scope, dev); -} - static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms) { PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev); diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index 03e347b207..d0bd8b537d 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -103,6 +103,7 @@ config MICROVM select I8259 select MC146818RTC select VIRTIO_MMIO + select ACPI_HW_REDUCED config X86_IOMMU bool diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 7a5a8b3521..0e0535d2e3 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2431,7 +2431,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_add_table(table_offsets, tables_blob); acpi_build_madt(tables_blob, tables->linker, x86ms, - ACPI_DEVICE_IF(pcms->acpi_dev), true); + ACPI_DEVICE_IF(x86ms->acpi_dev), true); vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c new file mode 100644 index 0000000000..df39c5d3bd --- /dev/null +++ b/hw/i386/acpi-microvm.c @@ -0,0 +1,240 @@ +/* Support for generating ACPI tables and passing them to Guests + * + * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net> + * Copyright (C) 2006 Fabrice Bellard + * Copyright (C) 2013 Red Hat Inc + * + * Author: Michael S. Tsirkin <mst@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "qapi/error.h" + +#include "exec/memory.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/bios-linker-loader.h" +#include "hw/acpi/generic_event_device.h" +#include "hw/acpi/utils.h" +#include "hw/boards.h" +#include "hw/i386/fw_cfg.h" +#include "hw/i386/microvm.h" +#include "hw/virtio/virtio-mmio.h" + +#include "acpi-common.h" +#include "acpi-microvm.h" + +static void acpi_dsdt_add_virtio(Aml *scope, + MicrovmMachineState *mms) +{ + gchar *separator; + long int index; + BusState *bus; + BusChild *kid; + + bus = sysbus_get_default(); + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + Object *obj = object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MMIO); + + if (obj) { + VirtIOMMIOProxy *mmio = VIRTIO_MMIO(obj); + VirtioBusState *mmio_virtio_bus = &mmio->bus; + BusState *mmio_bus = &mmio_virtio_bus->parent_obj; + + if (QTAILQ_EMPTY(&mmio_bus->children)) { + continue; + } + separator = g_strrstr(mmio_bus->name, "."); + if (!separator) { + continue; + } + if (qemu_strtol(separator + 1, NULL, 10, &index) != 0) { + continue; + } + + uint32_t irq = mms->virtio_irq_base + index; + hwaddr base = VIRTIO_MMIO_BASE + index * 512; + hwaddr size = 512; + + Aml *dev = aml_device("VR%02u", (unsigned)index); + aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005"))); + aml_append(dev, aml_name_decl("_UID", aml_int(index))); + aml_append(dev, aml_name_decl("_CCA", aml_int(1))); + + Aml *crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); + aml_append(crs, + aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_EXCLUSIVE, &irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); + } + } +} + +static void +build_dsdt_microvm(GArray *table_data, BIOSLinker *linker, + MicrovmMachineState *mms) +{ + X86MachineState *x86ms = X86_MACHINE(mms); + Aml *dsdt, *sb_scope, *scope, *pkg; + bool ambiguous; + Object *isabus; + + isabus = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous); + assert(isabus); + assert(!ambiguous); + + dsdt = init_aml_allocator(); + + /* Reserve space for header */ + acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader)); + + sb_scope = aml_scope("_SB"); + fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg); + isa_build_aml(ISA_BUS(isabus), sb_scope); + build_ged_aml(sb_scope, GED_DEVICE, x86ms->acpi_dev, + GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE); + acpi_dsdt_add_power_button(sb_scope); + acpi_dsdt_add_virtio(sb_scope, mms); + aml_append(dsdt, sb_scope); + + /* ACPI 5.0: Table 7-209 System State Package */ + scope = aml_scope("\\"); + pkg = aml_package(4); + aml_append(pkg, aml_int(ACPI_GED_SLP_TYP_S5)); + aml_append(pkg, aml_int(0)); /* ignored */ + aml_append(pkg, aml_int(0)); /* reserved */ + aml_append(pkg, aml_int(0)); /* reserved */ + aml_append(scope, aml_name_decl("_S5", pkg)); + aml_append(dsdt, scope); + + /* copy AML table into ACPI tables blob and patch header there */ + g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); + build_header(linker, table_data, + (void *)(table_data->data + table_data->len - dsdt->buf->len), + "DSDT", dsdt->buf->len, 2, NULL, NULL); + free_aml_allocator(); +} + +static void acpi_build_microvm(AcpiBuildTables *tables, + MicrovmMachineState *mms) +{ + MachineState *machine = MACHINE(mms); + X86MachineState *x86ms = X86_MACHINE(mms); + GArray *table_offsets; + GArray *tables_blob = tables->table_data; + unsigned dsdt, xsdt; + AcpiFadtData pmfadt = { + /* ACPI 5.0: 4.1 Hardware-Reduced ACPI */ + .rev = 5, + .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) | + (1 << ACPI_FADT_F_RESET_REG_SUP)), + + /* ACPI 5.0: 4.8.3.7 Sleep Control and Status Registers */ + .sleep_ctl = { + .space_id = AML_AS_SYSTEM_MEMORY, + .bit_width = 8, + .address = GED_MMIO_BASE_REGS + ACPI_GED_REG_SLEEP_CTL, + }, + .sleep_sts = { + .space_id = AML_AS_SYSTEM_MEMORY, + .bit_width = 8, + .address = GED_MMIO_BASE_REGS + ACPI_GED_REG_SLEEP_STS, + }, + + /* ACPI 5.0: 4.8.3.6 Reset Register */ + .reset_reg = { + .space_id = AML_AS_SYSTEM_MEMORY, + .bit_width = 8, + .address = GED_MMIO_BASE_REGS + ACPI_GED_REG_RESET, + }, + .reset_val = ACPI_GED_RESET_VALUE, + }; + + table_offsets = g_array_new(false, true /* clear */, + sizeof(uint32_t)); + bios_linker_loader_alloc(tables->linker, + ACPI_BUILD_TABLE_FILE, tables_blob, + 64 /* Ensure FACS is aligned */, + false /* high memory */); + + dsdt = tables_blob->len; + build_dsdt_microvm(tables_blob, tables->linker, mms); + + pmfadt.dsdt_tbl_offset = &dsdt; + pmfadt.xdsdt_tbl_offset = &dsdt; + acpi_add_table(table_offsets, tables_blob); + build_fadt(tables_blob, tables->linker, &pmfadt, NULL, NULL); + + acpi_add_table(table_offsets, tables_blob); + acpi_build_madt(tables_blob, tables->linker, X86_MACHINE(machine), + ACPI_DEVICE_IF(x86ms->acpi_dev), false); + + xsdt = tables_blob->len; + build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL); + + /* RSDP is in FSEG memory, so allocate it separately */ + { + AcpiRsdpData rsdp_data = { + /* ACPI 2.0: 5.2.4.3 RSDP Structure */ + .revision = 2, /* xsdt needs v2 */ + .oem_id = ACPI_BUILD_APPNAME6, + .xsdt_tbl_offset = &xsdt, + .rsdt_tbl_offset = NULL, + }; + build_rsdp(tables->rsdp, tables->linker, &rsdp_data); + } + + /* Cleanup memory that's no longer used. */ + g_array_free(table_offsets, true); +} + +static void acpi_build_no_update(void *build_opaque) +{ + /* nothing, microvm tables don't change at runtime */ +} + +void acpi_setup_microvm(MicrovmMachineState *mms) +{ + X86MachineState *x86ms = X86_MACHINE(mms); + AcpiBuildTables tables; + + assert(x86ms->fw_cfg); + + if (!x86_machine_is_acpi_enabled(x86ms)) { + return; + } + + acpi_build_tables_init(&tables); + acpi_build_microvm(&tables, mms); + + /* Now expose it all to Guest */ + acpi_add_rom_blob(acpi_build_no_update, NULL, + tables.table_data, + ACPI_BUILD_TABLE_FILE, + ACPI_BUILD_TABLE_MAX_SIZE); + acpi_add_rom_blob(acpi_build_no_update, NULL, + tables.linker->cmd_blob, + "etc/table-loader", 0); + acpi_add_rom_blob(acpi_build_no_update, NULL, + tables.rsdp, + ACPI_BUILD_RSDP_FILE, 0); + + acpi_build_tables_cleanup(&tables, false); +} diff --git a/hw/i386/acpi-microvm.h b/hw/i386/acpi-microvm.h new file mode 100644 index 0000000000..dfe853690e --- /dev/null +++ b/hw/i386/acpi-microvm.h @@ -0,0 +1,8 @@ +#ifndef HW_I386_ACPI_MICROVM_H +#define HW_I386_ACPI_MICROVM_H + +#include "hw/i386/microvm.h" + +void acpi_setup_microvm(MicrovmMachineState *mms); + +#endif diff --git a/hw/i386/generic_event_device_x86.c b/hw/i386/generic_event_device_x86.c new file mode 100644 index 0000000000..e26fb02a2e --- /dev/null +++ b/hw/i386/generic_event_device_x86.c @@ -0,0 +1,36 @@ +/* + * x86 variant of the generic event device for hw reduced acpi + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + */ + +#include "qemu/osdep.h" +#include "hw/acpi/generic_event_device.h" +#include "hw/i386/pc.h" + +static void acpi_ged_x86_class_init(ObjectClass *class, void *data) +{ + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class); + + adevc->madt_cpu = pc_madt_cpu_entry; +} + +static const TypeInfo acpi_ged_x86_info = { + .name = TYPE_ACPI_GED_X86, + .parent = TYPE_ACPI_GED, + .class_init = acpi_ged_x86_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { TYPE_ACPI_DEVICE_IF }, + { } + } +}; + +static void acpi_ged_x86_register_types(void) +{ + type_register_static(&acpi_ged_x86_info); +} + +type_init(acpi_ged_x86_register_types) diff --git a/hw/i386/meson.build b/hw/i386/meson.build index 63918fbe22..e5d109f5c6 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -11,13 +11,14 @@ i386_ss.add(when: 'CONFIG_X86_IOMMU', if_true: files('x86-iommu.c'), if_false: files('x86-iommu-stub.c')) i386_ss.add(when: 'CONFIG_AMD_IOMMU', if_true: files('amd_iommu.c')) i386_ss.add(when: 'CONFIG_I440FX', if_true: files('pc_piix.c')) -i386_ss.add(when: 'CONFIG_MICROVM', if_true: files('microvm.c')) +i386_ss.add(when: 'CONFIG_MICROVM', if_true: files('microvm.c', 'acpi-microvm.c')) i386_ss.add(when: 'CONFIG_Q35', if_true: files('pc_q35.c')) i386_ss.add(when: 'CONFIG_VMMOUSE', if_true: files('vmmouse.c')) i386_ss.add(when: 'CONFIG_VMPORT', if_true: files('vmport.c')) i386_ss.add(when: 'CONFIG_VTD', if_true: files('intel_iommu.c')) i386_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-common.c')) +i386_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device_x86.c')) i386_ss.add(when: 'CONFIG_PC', if_true: files( 'pc.c', 'pc_sysfw.c', diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 81d0888930..60d3272230 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -26,6 +26,8 @@ #include "sysemu/cpus.h" #include "sysemu/numa.h" #include "sysemu/reset.h" +#include "sysemu/runstate.h" +#include "acpi-microvm.h" #include "hw/loader.h" #include "hw/irq.h" @@ -37,17 +39,21 @@ #include "hw/timer/i8254.h" #include "hw/rtc/mc146818rtc.h" #include "hw/char/serial.h" +#include "hw/display/ramfb.h" #include "hw/i386/topology.h" #include "hw/i386/e820_memory_layout.h" #include "hw/i386/fw_cfg.h" #include "hw/virtio/virtio-mmio.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/generic_event_device.h" #include "cpu.h" #include "elf.h" #include "kvm_i386.h" #include "hw/xen/start_info.h" -#define MICROVM_BIOS_FILENAME "bios-microvm.bin" +#define MICROVM_QBOOT_FILENAME "qboot.rom" +#define MICROVM_BIOS_FILENAME "bios-microvm.bin" static void microvm_set_rtc(MicrovmMachineState *mms, ISADevice *s) { @@ -121,13 +127,25 @@ static void microvm_devices_init(MicrovmMachineState *mms) kvmclock_create(); + mms->virtio_irq_base = x86_machine_is_acpi_enabled(x86ms) ? 16 : 5; for (i = 0; i < VIRTIO_NUM_TRANSPORTS; i++) { sysbus_create_simple("virtio-mmio", VIRTIO_MMIO_BASE + i * 512, - x86ms->gsi[VIRTIO_IRQ_BASE + i]); + x86ms->gsi[mms->virtio_irq_base + i]); } /* Optional and legacy devices */ + if (x86_machine_is_acpi_enabled(x86ms)) { + DeviceState *dev = qdev_new(TYPE_ACPI_GED_X86); + qdev_prop_set_uint32(dev, "ged-event", ACPI_GED_PWR_DOWN_EVT); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, GED_MMIO_BASE); + /* sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, GED_MMIO_BASE_MEMHP); */ + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, GED_MMIO_BASE_REGS); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, + x86ms->gsi[GED_MMIO_IRQ]); + sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal); + x86ms->acpi_dev = HOTPLUG_HANDLER(dev); + } if (mms->pic == ON_OFF_AUTO_ON || mms->pic == ON_OFF_AUTO_AUTO) { qemu_irq *i8259; @@ -158,7 +176,9 @@ static void microvm_devices_init(MicrovmMachineState *mms) } if (bios_name == NULL) { - bios_name = MICROVM_BIOS_FILENAME; + bios_name = x86_machine_is_acpi_enabled(x86ms) + ? MICROVM_BIOS_FILENAME + : MICROVM_QBOOT_FILENAME; } x86_bios_rom_init(get_system_memory(), true); } @@ -227,7 +247,7 @@ static void microvm_memory_init(MicrovmMachineState *mms) x86ms->ioapic_as = &address_space_memory; } -static gchar *microvm_get_mmio_cmdline(gchar *name) +static gchar *microvm_get_mmio_cmdline(gchar *name, uint32_t virtio_irq_base) { gchar *cmdline; gchar *separator; @@ -247,7 +267,7 @@ static gchar *microvm_get_mmio_cmdline(gchar *name) ret = g_snprintf(cmdline, VIRTIO_CMDLINE_MAXLEN, " virtio_mmio.device=512@0x%lx:%ld", VIRTIO_MMIO_BASE + index * 512, - VIRTIO_IRQ_BASE + index); + virtio_irq_base + index); if (ret < 0 || ret >= VIRTIO_CMDLINE_MAXLEN) { g_free(cmdline); return NULL; @@ -259,6 +279,7 @@ static gchar *microvm_get_mmio_cmdline(gchar *name) static void microvm_fix_kernel_cmdline(MachineState *machine) { X86MachineState *x86ms = X86_MACHINE(machine); + MicrovmMachineState *mms = MICROVM_MACHINE(machine); BusState *bus; BusChild *kid; char *cmdline; @@ -282,7 +303,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) BusState *mmio_bus = &mmio_virtio_bus->parent_obj; if (!QTAILQ_EMPTY(&mmio_bus->children)) { - gchar *mmio_cmdline = microvm_get_mmio_cmdline(mmio_bus->name); + gchar *mmio_cmdline = microvm_get_mmio_cmdline + (mmio_bus->name, mms->virtio_irq_base); if (mmio_cmdline) { char *newcmd = g_strjoin(NULL, cmdline, mmio_cmdline, NULL); g_free(mmio_cmdline); @@ -299,6 +321,39 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) g_free(cmdline); } +static void microvm_device_pre_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + x86_cpu_pre_plug(hotplug_dev, dev, errp); +} + +static void microvm_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + x86_cpu_plug(hotplug_dev, dev, errp); +} + +static void microvm_device_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + error_setg(errp, "unplug not supported by microvm"); +} + +static void microvm_device_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + error_setg(errp, "unplug not supported by microvm"); +} + +static HotplugHandler *microvm_get_hotplug_handler(MachineState *machine, + DeviceState *dev) +{ + if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + return HOTPLUG_HANDLER(machine); + } + return NULL; +} + static void microvm_machine_state_init(MachineState *machine) { MicrovmMachineState *mms = MICROVM_MACHINE(machine); @@ -322,7 +377,8 @@ static void microvm_machine_reset(MachineState *machine) CPUState *cs; X86CPU *cpu; - if (machine->kernel_filename != NULL && + if (!x86_machine_is_acpi_enabled(X86_MACHINE(machine)) && + machine->kernel_filename != NULL && mms->auto_kernel_cmdline && !mms->kernel_cmdline_fixed) { microvm_fix_kernel_cmdline(machine); mms->kernel_cmdline_fixed = true; @@ -435,6 +491,28 @@ static void microvm_machine_set_auto_kernel_cmdline(Object *obj, bool value, mms->auto_kernel_cmdline = value; } +static void microvm_machine_done(Notifier *notifier, void *data) +{ + MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState, + machine_done); + + acpi_setup_microvm(mms); +} + +static void microvm_powerdown_req(Notifier *notifier, void *data) +{ + MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState, + powerdown_req); + X86MachineState *x86ms = X86_MACHINE(mms); + + if (x86ms->acpi_dev) { + Object *obj = OBJECT(x86ms->acpi_dev); + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); + adevc->send_event(ACPI_DEVICE_IF(x86ms->acpi_dev), + ACPI_POWER_DOWN_STATUS); + } +} + static void microvm_machine_initfn(Object *obj) { MicrovmMachineState *mms = MICROVM_MACHINE(obj); @@ -449,11 +527,17 @@ static void microvm_machine_initfn(Object *obj) /* State */ mms->kernel_cmdline_fixed = false; + + mms->machine_done.notify = microvm_machine_done; + qemu_add_machine_init_done_notifier(&mms->machine_done); + mms->powerdown_req.notify = microvm_powerdown_req; + qemu_register_powerdown_notifier(&mms->powerdown_req); } static void microvm_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); mc->init = microvm_machine_state_init; @@ -475,6 +559,13 @@ static void microvm_class_init(ObjectClass *oc, void *data) /* Machine class handlers */ mc->reset = microvm_machine_reset; + /* hotplug (for cpu coldplug) */ + mc->get_hotplug_handler = microvm_get_hotplug_handler; + hc->pre_plug = microvm_device_pre_plug_cb; + hc->plug = microvm_device_plug_cb; + hc->unplug_request = microvm_device_unplug_request_cb; + hc->unplug = microvm_device_unplug_cb; + object_class_property_add(oc, MICROVM_MACHINE_PIC, "OnOffAuto", microvm_machine_get_pic, microvm_machine_set_pic, @@ -514,6 +605,8 @@ static void microvm_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, MICROVM_MACHINE_AUTO_KERNEL_CMDLINE, "Set off to disable adding virtio-mmio devices to the kernel cmdline"); + + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); } static const TypeInfo microvm_machine_info = { @@ -524,6 +617,7 @@ static const TypeInfo microvm_machine_info = { .class_size = sizeof(MicrovmMachineClass), .class_init = microvm_class_init, .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, { } }, }; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d11daacc23..b55369357e 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -803,19 +803,6 @@ void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp) } } -static void rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count) -{ - if (cpus_count > 0xff) { - /* If the number of CPUs can't be represented in 8 bits, the - * BIOS must use "FW_CFG_NB_CPUS". Set RTC field to 0 just - * to make old BIOSes fail more predictably. - */ - rtc_set_memory(rtc, 0x5f, 0); - } else { - rtc_set_memory(rtc, 0x5f, cpus_count - 1); - } -} - static void pc_machine_done(Notifier *notifier, void *data) { @@ -825,7 +812,7 @@ void pc_machine_done(Notifier *notifier, void *data) PCIBus *bus = pcms->bus; /* set the number of CPUs */ - rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); + x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); if (bus) { int extra_hosts = 0; @@ -1274,6 +1261,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { const PCMachineState *pcms = PC_MACHINE(hotplug_dev); + const X86MachineState *x86ms = X86_MACHINE(hotplug_dev); const PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); const MachineState *ms = MACHINE(hotplug_dev); const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM); @@ -1285,7 +1273,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, * but pcms->acpi_dev is still created. Check !acpi_enabled in * addition to cover this case. */ - if (!pcms->acpi_dev || !x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) { + if (!x86ms->acpi_dev || !x86_machine_is_acpi_enabled(x86ms)) { error_setg(errp, "memory hotplug is not enabled: missing acpi device or acpi disabled"); return; @@ -1296,7 +1284,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } - hotplug_handler_pre_plug(pcms->acpi_dev, dev, &local_err); + hotplug_handler_pre_plug(x86ms->acpi_dev, dev, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1311,6 +1299,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev, { Error *local_err = NULL; PCMachineState *pcms = PC_MACHINE(hotplug_dev); + X86MachineState *x86ms = X86_MACHINE(hotplug_dev); MachineState *ms = MACHINE(hotplug_dev); bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM); @@ -1323,7 +1312,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev, nvdimm_plug(ms->nvdimms_state); } - hotplug_handler_plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &error_abort); + hotplug_handler_plug(x86ms->acpi_dev, dev, &error_abort); out: error_propagate(errp, local_err); } @@ -1331,14 +1320,14 @@ out: static void pc_memory_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - PCMachineState *pcms = PC_MACHINE(hotplug_dev); + X86MachineState *x86ms = X86_MACHINE(hotplug_dev); /* * When -no-acpi is used with Q35 machine type, no ACPI is built, * but pcms->acpi_dev is still created. Check !acpi_enabled in * addition to cover this case. */ - if (!pcms->acpi_dev || !x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) { + if (!x86ms->acpi_dev || !x86_machine_is_acpi_enabled(x86ms)) { error_setg(errp, "memory hotplug is not enabled: missing acpi device or acpi disabled"); return; @@ -1349,7 +1338,7 @@ static void pc_memory_unplug_request(HotplugHandler *hotplug_dev, return; } - hotplug_handler_unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, + hotplug_handler_unplug_request(x86ms->acpi_dev, dev, errp); } @@ -1357,9 +1346,10 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { PCMachineState *pcms = PC_MACHINE(hotplug_dev); + X86MachineState *x86ms = X86_MACHINE(hotplug_dev); Error *local_err = NULL; - hotplug_handler_unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); + hotplug_handler_unplug(x86ms->acpi_dev, dev, &local_err); if (local_err) { goto out; } @@ -1370,263 +1360,6 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev, error_propagate(errp, local_err); } -static int pc_apic_cmp(const void *a, const void *b) -{ - CPUArchId *apic_a = (CPUArchId *)a; - CPUArchId *apic_b = (CPUArchId *)b; - - return apic_a->arch_id - apic_b->arch_id; -} - -/* returns pointer to CPUArchId descriptor that matches CPU's apic_id - * in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no - * entry corresponding to CPU's apic_id returns NULL. - */ -static CPUArchId *pc_find_cpu_slot(MachineState *ms, uint32_t id, int *idx) -{ - CPUArchId apic_id, *found_cpu; - - apic_id.arch_id = id; - found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus, - ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus), - pc_apic_cmp); - if (found_cpu && idx) { - *idx = found_cpu - ms->possible_cpus->cpus; - } - return found_cpu; -} - -static void pc_cpu_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - CPUArchId *found_cpu; - Error *local_err = NULL; - X86CPU *cpu = X86_CPU(dev); - PCMachineState *pcms = PC_MACHINE(hotplug_dev); - X86MachineState *x86ms = X86_MACHINE(pcms); - - if (pcms->acpi_dev) { - hotplug_handler_plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); - if (local_err) { - goto out; - } - } - - /* increment the number of CPUs */ - x86ms->boot_cpus++; - if (x86ms->rtc) { - rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); - } - if (x86ms->fw_cfg) { - fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); - } - - found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL); - found_cpu->cpu = OBJECT(dev); -out: - error_propagate(errp, local_err); -} -static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - int idx = -1; - X86CPU *cpu = X86_CPU(dev); - PCMachineState *pcms = PC_MACHINE(hotplug_dev); - - if (!pcms->acpi_dev) { - error_setg(errp, "CPU hot unplug not supported without ACPI"); - return; - } - - pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx); - assert(idx != -1); - if (idx == 0) { - error_setg(errp, "Boot CPU is unpluggable"); - return; - } - - hotplug_handler_unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, - errp); -} - -static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - CPUArchId *found_cpu; - Error *local_err = NULL; - X86CPU *cpu = X86_CPU(dev); - PCMachineState *pcms = PC_MACHINE(hotplug_dev); - X86MachineState *x86ms = X86_MACHINE(pcms); - - hotplug_handler_unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); - if (local_err) { - goto out; - } - - found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL); - found_cpu->cpu = NULL; - qdev_unrealize(dev); - - /* decrement the number of CPUs */ - x86ms->boot_cpus--; - /* Update the number of CPUs in CMOS */ - rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); - fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); - out: - error_propagate(errp, local_err); -} - -static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - int idx; - CPUState *cs; - CPUArchId *cpu_slot; - X86CPUTopoIDs topo_ids; - X86CPU *cpu = X86_CPU(dev); - CPUX86State *env = &cpu->env; - MachineState *ms = MACHINE(hotplug_dev); - PCMachineState *pcms = PC_MACHINE(hotplug_dev); - X86MachineState *x86ms = X86_MACHINE(pcms); - unsigned int smp_cores = ms->smp.cores; - unsigned int smp_threads = ms->smp.threads; - X86CPUTopoInfo topo_info; - - if(!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { - error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", - ms->cpu_type); - return; - } - - init_topo_info(&topo_info, x86ms); - - env->nr_dies = x86ms->smp_dies; - - /* - * If APIC ID is not set, - * set it based on socket/die/core/thread properties. - */ - if (cpu->apic_id == UNASSIGNED_APIC_ID) { - int max_socket = (ms->smp.max_cpus - 1) / - smp_threads / smp_cores / x86ms->smp_dies; - - /* - * die-id was optional in QEMU 4.0 and older, so keep it optional - * if there's only one die per socket. - */ - if (cpu->die_id < 0 && x86ms->smp_dies == 1) { - cpu->die_id = 0; - } - - if (cpu->socket_id < 0) { - error_setg(errp, "CPU socket-id is not set"); - return; - } else if (cpu->socket_id > max_socket) { - error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u", - cpu->socket_id, max_socket); - return; - } - if (cpu->die_id < 0) { - error_setg(errp, "CPU die-id is not set"); - return; - } else if (cpu->die_id > x86ms->smp_dies - 1) { - error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u", - cpu->die_id, x86ms->smp_dies - 1); - return; - } - if (cpu->core_id < 0) { - error_setg(errp, "CPU core-id is not set"); - return; - } else if (cpu->core_id > (smp_cores - 1)) { - error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", - cpu->core_id, smp_cores - 1); - return; - } - if (cpu->thread_id < 0) { - error_setg(errp, "CPU thread-id is not set"); - return; - } else if (cpu->thread_id > (smp_threads - 1)) { - error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u", - cpu->thread_id, smp_threads - 1); - return; - } - - topo_ids.pkg_id = cpu->socket_id; - topo_ids.die_id = cpu->die_id; - topo_ids.core_id = cpu->core_id; - topo_ids.smt_id = cpu->thread_id; - cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids); - } - - cpu_slot = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx); - if (!cpu_slot) { - MachineState *ms = MACHINE(pcms); - - x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); - error_setg(errp, - "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with" - " APIC ID %" PRIu32 ", valid index range 0:%d", - topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id, - cpu->apic_id, ms->possible_cpus->len - 1); - return; - } - - if (cpu_slot->cpu) { - error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists", - idx, cpu->apic_id); - return; - } - - /* if 'address' properties socket-id/core-id/thread-id are not set, set them - * so that machine_query_hotpluggable_cpus would show correct values - */ - /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn() - * once -smp refactoring is complete and there will be CPU private - * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */ - x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); - if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) { - error_setg(errp, "property socket-id: %u doesn't match set apic-id:" - " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id, - topo_ids.pkg_id); - return; - } - cpu->socket_id = topo_ids.pkg_id; - - if (cpu->die_id != -1 && cpu->die_id != topo_ids.die_id) { - error_setg(errp, "property die-id: %u doesn't match set apic-id:" - " 0x%x (die-id: %u)", cpu->die_id, cpu->apic_id, topo_ids.die_id); - return; - } - cpu->die_id = topo_ids.die_id; - - if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) { - error_setg(errp, "property core-id: %u doesn't match set apic-id:" - " 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id, - topo_ids.core_id); - return; - } - cpu->core_id = topo_ids.core_id; - - if (cpu->thread_id != -1 && cpu->thread_id != topo_ids.smt_id) { - error_setg(errp, "property thread-id: %u doesn't match set apic-id:" - " 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id, - topo_ids.smt_id); - return; - } - cpu->thread_id = topo_ids.smt_id; - - if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) && - !kvm_hv_vpindex_settable()) { - error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX"); - return; - } - - cs = CPU(cpu); - cs->cpu_index = idx; - - numa_cpu_pre_plug(cpu_slot, dev, errp); -} - static void pc_virtio_md_pci_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -1695,7 +1428,7 @@ static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { pc_memory_pre_plug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - pc_cpu_pre_plug(hotplug_dev, dev, errp); + x86_cpu_pre_plug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) || object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) { pc_virtio_md_pci_pre_plug(hotplug_dev, dev, errp); @@ -1708,7 +1441,7 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev, if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { pc_memory_plug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - pc_cpu_plug(hotplug_dev, dev, errp); + x86_cpu_plug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) || object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) { pc_virtio_md_pci_plug(hotplug_dev, dev, errp); @@ -1721,7 +1454,7 @@ static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev, if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { pc_memory_unplug_request(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - pc_cpu_unplug_request_cb(hotplug_dev, dev, errp); + x86_cpu_unplug_request_cb(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) || object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) { pc_virtio_md_pci_unplug_request(hotplug_dev, dev, errp); @@ -1737,7 +1470,7 @@ static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev, if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { pc_memory_unplug(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - pc_cpu_unplug_cb(hotplug_dev, dev, errp); + x86_cpu_unplug_cb(hotplug_dev, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) || object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) { pc_virtio_md_pci_unplug(hotplug_dev, dev, errp); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 33fa035fb7..6f3e78bb60 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -293,7 +293,7 @@ static void pc_init1(MachineState *machine, object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, TYPE_HOTPLUG_HANDLER, - (Object **)&pcms->acpi_dev, + (Object **)&x86ms->acpi_dev, object_property_allow_set_link, OBJ_PROP_LINK_STRONG); object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 0cb9c18cd4..622d039717 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -240,7 +240,7 @@ static void pc_q35_init(MachineState *machine) object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, TYPE_HOTPLUG_HANDLER, - (Object **)&pcms->acpi_dev, + (Object **)&x86ms->acpi_dev, object_property_allow_set_link, OBJ_PROP_LINK_STRONG); object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, diff --git a/hw/i386/x86.c b/hw/i386/x86.c index c1954db152..c2ea989579 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -41,6 +41,7 @@ #include "hw/i386/topology.h" #include "hw/i386/fw_cfg.h" #include "hw/intc/i8259.h" +#include "hw/rtc/mc146818rtc.h" #include "hw/acpi/cpu_hotplug.h" #include "hw/irq.h" @@ -137,6 +138,276 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version) } } +void x86_rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count) +{ + if (cpus_count > 0xff) { + /* + * If the number of CPUs can't be represented in 8 bits, the + * BIOS must use "FW_CFG_NB_CPUS". Set RTC field to 0 just + * to make old BIOSes fail more predictably. + */ + rtc_set_memory(rtc, 0x5f, 0); + } else { + rtc_set_memory(rtc, 0x5f, cpus_count - 1); + } +} + +static int x86_apic_cmp(const void *a, const void *b) +{ + CPUArchId *apic_a = (CPUArchId *)a; + CPUArchId *apic_b = (CPUArchId *)b; + + return apic_a->arch_id - apic_b->arch_id; +} + +/* + * returns pointer to CPUArchId descriptor that matches CPU's apic_id + * in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no + * entry corresponding to CPU's apic_id returns NULL. + */ +CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx) +{ + CPUArchId apic_id, *found_cpu; + + apic_id.arch_id = id; + found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus, + ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus), + x86_apic_cmp); + if (found_cpu && idx) { + *idx = found_cpu - ms->possible_cpus->cpus; + } + return found_cpu; +} + +void x86_cpu_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + CPUArchId *found_cpu; + Error *local_err = NULL; + X86CPU *cpu = X86_CPU(dev); + X86MachineState *x86ms = X86_MACHINE(hotplug_dev); + + if (x86ms->acpi_dev) { + hotplug_handler_plug(x86ms->acpi_dev, dev, &local_err); + if (local_err) { + goto out; + } + } + + /* increment the number of CPUs */ + x86ms->boot_cpus++; + if (x86ms->rtc) { + x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); + } + if (x86ms->fw_cfg) { + fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); + } + + found_cpu = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, NULL); + found_cpu->cpu = OBJECT(dev); +out: + error_propagate(errp, local_err); +} + +void x86_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + int idx = -1; + X86CPU *cpu = X86_CPU(dev); + X86MachineState *x86ms = X86_MACHINE(hotplug_dev); + + if (!x86ms->acpi_dev) { + error_setg(errp, "CPU hot unplug not supported without ACPI"); + return; + } + + x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx); + assert(idx != -1); + if (idx == 0) { + error_setg(errp, "Boot CPU is unpluggable"); + return; + } + + hotplug_handler_unplug_request(x86ms->acpi_dev, dev, + errp); +} + +void x86_cpu_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + CPUArchId *found_cpu; + Error *local_err = NULL; + X86CPU *cpu = X86_CPU(dev); + X86MachineState *x86ms = X86_MACHINE(hotplug_dev); + + hotplug_handler_unplug(x86ms->acpi_dev, dev, &local_err); + if (local_err) { + goto out; + } + + found_cpu = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, NULL); + found_cpu->cpu = NULL; + qdev_unrealize(dev); + + /* decrement the number of CPUs */ + x86ms->boot_cpus--; + /* Update the number of CPUs in CMOS */ + x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); + fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); + out: + error_propagate(errp, local_err); +} + +void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + int idx; + CPUState *cs; + CPUArchId *cpu_slot; + X86CPUTopoIDs topo_ids; + X86CPU *cpu = X86_CPU(dev); + CPUX86State *env = &cpu->env; + MachineState *ms = MACHINE(hotplug_dev); + X86MachineState *x86ms = X86_MACHINE(hotplug_dev); + unsigned int smp_cores = ms->smp.cores; + unsigned int smp_threads = ms->smp.threads; + X86CPUTopoInfo topo_info; + + if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { + error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", + ms->cpu_type); + return; + } + + init_topo_info(&topo_info, x86ms); + + env->nr_dies = x86ms->smp_dies; + + /* + * If APIC ID is not set, + * set it based on socket/die/core/thread properties. + */ + if (cpu->apic_id == UNASSIGNED_APIC_ID) { + int max_socket = (ms->smp.max_cpus - 1) / + smp_threads / smp_cores / x86ms->smp_dies; + + /* + * die-id was optional in QEMU 4.0 and older, so keep it optional + * if there's only one die per socket. + */ + if (cpu->die_id < 0 && x86ms->smp_dies == 1) { + cpu->die_id = 0; + } + + if (cpu->socket_id < 0) { + error_setg(errp, "CPU socket-id is not set"); + return; + } else if (cpu->socket_id > max_socket) { + error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u", + cpu->socket_id, max_socket); + return; + } + if (cpu->die_id < 0) { + error_setg(errp, "CPU die-id is not set"); + return; + } else if (cpu->die_id > x86ms->smp_dies - 1) { + error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u", + cpu->die_id, x86ms->smp_dies - 1); + return; + } + if (cpu->core_id < 0) { + error_setg(errp, "CPU core-id is not set"); + return; + } else if (cpu->core_id > (smp_cores - 1)) { + error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", + cpu->core_id, smp_cores - 1); + return; + } + if (cpu->thread_id < 0) { + error_setg(errp, "CPU thread-id is not set"); + return; + } else if (cpu->thread_id > (smp_threads - 1)) { + error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u", + cpu->thread_id, smp_threads - 1); + return; + } + + topo_ids.pkg_id = cpu->socket_id; + topo_ids.die_id = cpu->die_id; + topo_ids.core_id = cpu->core_id; + topo_ids.smt_id = cpu->thread_id; + cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids); + } + + cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx); + if (!cpu_slot) { + MachineState *ms = MACHINE(x86ms); + + x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); + error_setg(errp, + "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with" + " APIC ID %" PRIu32 ", valid index range 0:%d", + topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id, + cpu->apic_id, ms->possible_cpus->len - 1); + return; + } + + if (cpu_slot->cpu) { + error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists", + idx, cpu->apic_id); + return; + } + + /* if 'address' properties socket-id/core-id/thread-id are not set, set them + * so that machine_query_hotpluggable_cpus would show correct values + */ + /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn() + * once -smp refactoring is complete and there will be CPU private + * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */ + x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); + if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) { + error_setg(errp, "property socket-id: %u doesn't match set apic-id:" + " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id, + topo_ids.pkg_id); + return; + } + cpu->socket_id = topo_ids.pkg_id; + + if (cpu->die_id != -1 && cpu->die_id != topo_ids.die_id) { + error_setg(errp, "property die-id: %u doesn't match set apic-id:" + " 0x%x (die-id: %u)", cpu->die_id, cpu->apic_id, topo_ids.die_id); + return; + } + cpu->die_id = topo_ids.die_id; + + if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) { + error_setg(errp, "property core-id: %u doesn't match set apic-id:" + " 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id, + topo_ids.core_id); + return; + } + cpu->core_id = topo_ids.core_id; + + if (cpu->thread_id != -1 && cpu->thread_id != topo_ids.smt_id) { + error_setg(errp, "property thread-id: %u doesn't match set apic-id:" + " 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id, + topo_ids.smt_id); + return; + } + cpu->thread_id = topo_ids.smt_id; + + if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) && + !kvm_hv_vpindex_settable()) { + error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX"); + return; + } + + cs = CPU(cpu); + cs->cpu_index = idx; + + numa_cpu_pre_plug(cpu_slot, dev, errp); +} + CpuInstanceProperties x86_cpu_index_to_props(MachineState *ms, unsigned cpu_index) { @@ -821,7 +1092,7 @@ void x86_bios_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw) bios); } -bool x86_machine_is_smm_enabled(X86MachineState *x86ms) +bool x86_machine_is_smm_enabled(const X86MachineState *x86ms) { bool smm_available = false; @@ -863,7 +1134,7 @@ static void x86_machine_set_smm(Object *obj, Visitor *v, const char *name, visit_type_OnOffAuto(v, name, &x86ms->smm, errp); } -bool x86_machine_is_acpi_enabled(X86MachineState *x86ms) +bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms) { if (x86ms->acpi == ON_OFF_AUTO_OFF) { return false; diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index db2f49cb27..5cc559fe4c 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -125,7 +125,7 @@ void qmp_dump_skeys(const char *filename, Error **errp) return; } - fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + fd = qemu_open_old(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) { error_setg_file_open(errp, errno, filename); return; diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 43c93504a2..8b02bee547 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -1147,7 +1147,7 @@ static void usb_host_realize(USBDevice *udev, Error **errp) if (s->hostdevice) { int fd; s->needs_autoscan = false; - fd = qemu_open(s->hostdevice, O_RDWR); + fd = qemu_open_old(s->hostdevice, O_RDWR); if (fd < 0) { error_setg_errno(errp, errno, "failed to open %s", s->hostdevice); return; diff --git a/hw/usb/u2f-passthru.c b/hw/usb/u2f-passthru.c index e9c8aa4595..ae00e93f35 100644 --- a/hw/usb/u2f-passthru.c +++ b/hw/usb/u2f-passthru.c @@ -383,7 +383,7 @@ static int u2f_passthru_open_from_device(struct udev_device *device) { const char *devnode = udev_device_get_devnode(device); - int fd = qemu_open(devnode, O_RDWR); + int fd = qemu_open_old(devnode, O_RDWR); if (fd < 0) { return -1; } else if (!u2f_passthru_is_u2f_device(fd)) { @@ -482,7 +482,7 @@ static void u2f_passthru_realize(U2FKeyState *base, Error **errp) return; #endif } else { - fd = qemu_open(key->hidraw, O_RDWR); + fd = qemu_open_old(key->hidraw, O_RDWR); if (fd < 0) { error_setg(errp, "%s: Failed to open %s", TYPE_U2F_PASSTHRU, key->hidraw); diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 33357140b8..13471ae294 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1254,7 +1254,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, } } - fd = qemu_open("/dev/vfio/vfio", O_RDWR); + fd = qemu_open_old("/dev/vfio/vfio", O_RDWR); if (fd < 0) { error_setg_errno(errp, errno, "failed to open /dev/vfio/vfio"); ret = -errno; @@ -1479,7 +1479,7 @@ VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp) group = g_malloc0(sizeof(*group)); snprintf(path, sizeof(path), "/dev/vfio/%d", groupid); - group->fd = qemu_open(path, O_RDWR); + group->fd = qemu_open_old(path, O_RDWR); if (group->fd < 0) { error_setg_errno(errp, errno, "failed to open %s", path); goto free_group_exit; diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h index 1be05a3c0f..ac921e9f0c 100644 --- a/include/hw/acpi/generic_event_device.h +++ b/include/hw/acpi/generic_event_device.h @@ -71,9 +71,24 @@ typedef struct AcpiGedState AcpiGedState; DECLARE_INSTANCE_CHECKER(AcpiGedState, ACPI_GED, TYPE_ACPI_GED) +#define TYPE_ACPI_GED_X86 "acpi-ged-x86" +#define ACPI_GED_X86(obj) \ + OBJECT_CHECK(AcpiGedX86State, (obj), TYPE_ACPI_GED_X86) + #define ACPI_GED_EVT_SEL_OFFSET 0x0 #define ACPI_GED_EVT_SEL_LEN 0x4 +#define ACPI_GED_REG_SLEEP_CTL 0x00 +#define ACPI_GED_REG_SLEEP_STS 0x01 +#define ACPI_GED_REG_RESET 0x02 +#define ACPI_GED_REG_COUNT 0x03 + +/* ACPI_GED_REG_RESET value for reset*/ +#define ACPI_GED_RESET_VALUE 0x42 + +/* ACPI_GED_REG_SLEEP_CTL.SLP_TYP value for S5 (aka poweroff) */ +#define ACPI_GED_SLP_TYP_S5 0x05 + #define GED_DEVICE "GED" #define AML_GED_EVT_REG "EREG" #define AML_GED_EVT_SEL "ESEL" @@ -89,6 +104,7 @@ DECLARE_INSTANCE_CHECKER(AcpiGedState, ACPI_GED, typedef struct GEDState { MemoryRegion evt; + MemoryRegion regs; uint32_t sel; } GEDState; @@ -104,5 +120,6 @@ struct AcpiGedState { void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev, uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base); +void acpi_dsdt_add_power_button(Aml *scope); #endif diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h index 36dbcdd123..be2d95af4d 100644 --- a/include/hw/i386/microvm.h +++ b/include/hw/i386/microvm.h @@ -24,14 +24,19 @@ #include "hw/boards.h" #include "hw/i386/x86.h" +#include "hw/acpi/acpi_dev_interface.h" #include "qom/object.h" /* Platform virtio definitions */ #define VIRTIO_MMIO_BASE 0xfeb00000 -#define VIRTIO_IRQ_BASE 5 #define VIRTIO_NUM_TRANSPORTS 8 #define VIRTIO_CMDLINE_MAXLEN 64 +#define GED_MMIO_BASE 0xfea00000 +#define GED_MMIO_BASE_MEMHP (GED_MMIO_BASE + 0x100) +#define GED_MMIO_BASE_REGS (GED_MMIO_BASE + 0x200) +#define GED_MMIO_IRQ 9 + /* Machine type options */ #define MICROVM_MACHINE_PIT "pit" #define MICROVM_MACHINE_PIC "pic" @@ -59,7 +64,10 @@ struct MicrovmMachineState { bool auto_kernel_cmdline; /* Machine state */ + uint32_t virtio_irq_base; bool kernel_cmdline_fixed; + Notifier machine_done; + Notifier powerdown_req; }; typedef struct MicrovmMachineState MicrovmMachineState; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 421a77acc2..c14e14dfe0 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -30,7 +30,6 @@ struct PCMachineState { Notifier machine_done; /* Pointers to devices and objects: */ - HotplugHandler *acpi_dev; PCIBus *bus; I2CBus *smbus; PFlashCFI01 *flash[2]; diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index 1a188a7dea..0eef9fb0c0 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -52,6 +52,7 @@ struct X86MachineState { FWCfgState *fw_cfg; qemu_irq *gsi; GMappedFile *initrd_mapped_file; + HotplugHandler *acpi_dev; /* RAM information (sizes, addresses, configuration): */ ram_addr_t below_4g_mem_size, above_4g_mem_size; @@ -91,6 +92,16 @@ CpuInstanceProperties x86_cpu_index_to_props(MachineState *ms, unsigned cpu_index); int64_t x86_get_default_cpu_node_id(const MachineState *ms, int idx); const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms); +CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx); +void x86_rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count); +void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp); +void x86_cpu_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp); +void x86_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp); +void x86_cpu_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp); void x86_bios_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw); @@ -100,8 +111,8 @@ void x86_load_linux(X86MachineState *x86ms, bool pvh_enabled, bool linuxboot_dma_enabled); -bool x86_machine_is_smm_enabled(X86MachineState *x86ms); -bool x86_machine_is_acpi_enabled(X86MachineState *x86ms); +bool x86_machine_is_smm_enabled(const X86MachineState *x86ms); +bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms); /* Global System Interrupts */ diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 1018d754a6..c0170773d4 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -43,8 +43,7 @@ int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, bool has_opaque, const char *opaque, Error **errp); -int monitor_fdset_get_fd(int64_t fdset_id, int flags); -int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd); +int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags); void monitor_fdset_dup_fd_remove(int dup_fd); int64_t monitor_fdset_dup_fd_find(int dup_fd); diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 412962d91a..dad44be043 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -497,16 +497,23 @@ int qemu_madvise(void *addr, size_t len, int advice); int qemu_mprotect_rwx(void *addr, size_t size); int qemu_mprotect_none(void *addr, size_t size); -int qemu_open(const char *name, int flags, ...); +/* + * Don't introduce new usage of this function, prefer the following + * qemu_open/qemu_create that take an "Error **errp" + */ +int qemu_open_old(const char *name, int flags, ...); +int qemu_open(const char *name, int flags, Error **errp); +int qemu_create(const char *name, int flags, mode_t mode, Error **errp); int qemu_close(int fd); int qemu_unlink(const char *name); #ifndef _WIN32 +int qemu_dup_flags(int fd, int flags); int qemu_dup(int fd); -#endif int qemu_lock_fd(int fd, int64_t start, int64_t len, bool exclusive); int qemu_unlock_fd(int fd, int64_t start, int64_t len); int qemu_lock_fd_test(int fd, int64_t start, int64_t len, bool exclusive); bool qemu_has_ofd_lock(void); +#endif #if defined(__HAIKU__) && defined(__i386__) #define FMT_pid "%ld" diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h index 570aa603eb..0e375ebe13 100644 --- a/include/qemu/rcu.h +++ b/include/qemu/rcu.h @@ -133,6 +133,7 @@ struct rcu_head { }; extern void call_rcu1(struct rcu_head *head, RCUCBFunc *func); +extern void drain_call_rcu(void); /* The operands of the minus operator must have the same type, * which must be the one that we specify in the cast. diff --git a/io/channel-file.c b/io/channel-file.c index dac21f6012..2ed3b75e8b 100644 --- a/io/channel-file.c +++ b/io/channel-file.c @@ -51,7 +51,7 @@ qio_channel_file_new_path(const char *path, ioc = QIO_CHANNEL_FILE(object_new(TYPE_QIO_CHANNEL_FILE)); - ioc->fd = qemu_open(path, flags, mode); + ioc->fd = qemu_open_old(path, flags, mode); if (ioc->fd < 0) { object_unref(OBJECT(ioc)); error_setg_errno(errp, errno, diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 4961e6119e..f6022fd704 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2331,14 +2331,13 @@ static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr, assert(guest_base != 0); test = g2h(0); addr = mmap(test, reserved_va, PROT_NONE, flags, -1, 0); - if (addr == MAP_FAILED) { + if (addr == MAP_FAILED || addr != test) { error_report("Unable to reserve 0x%lx bytes of virtual address " - "space (%s) for use as guest address space (check your " - "virtual memory ulimit setting or reserve less " - "using -R option)", reserved_va, strerror(errno)); + "space at %p (%s) for use as guest address space (check your" + "virtual memory ulimit setting, min_mmap_addr or reserve less " + "using -R option)", reserved_va, test, strerror(errno)); exit(EXIT_FAILURE); } - assert(addr == test); } void probe_guest_base(const char *image_name, abi_ulong guest_loaddr, diff --git a/meson.build b/meson.build index bba766b4bc..f4d1ab1096 100644 --- a/meson.build +++ b/meson.build @@ -317,7 +317,6 @@ opengl = not_found if 'CONFIG_OPENGL' in config_host opengl = declare_dependency(compile_args: config_host['OPENGL_CFLAGS'].split(), link_args: config_host['OPENGL_LIBS'].split()) -else endif gtk = not_found if 'CONFIG_GTK' in config_host @@ -344,11 +343,6 @@ if 'CONFIG_ICONV' in config_host iconv = declare_dependency(compile_args: config_host['ICONV_CFLAGS'].split(), link_args: config_host['ICONV_LIBS'].split()) endif -gio = not_found -if 'CONFIG_GIO' in config_host - gio = declare_dependency(compile_args: config_host['GIO_CFLAGS'].split(), - link_args: config_host['GIO_LIBS'].split()) -endif vnc = not_found png = not_found jpeg = not_found diff --git a/monitor/misc.c b/monitor/misc.c index e847b58a8c..0b1b9b196c 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -1547,69 +1547,61 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, return fdinfo; } -int monitor_fdset_get_fd(int64_t fdset_id, int flags) +int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags) { #ifdef _WIN32 return -ENOENT; #else MonFdset *mon_fdset; - MonFdsetFd *mon_fdset_fd; - int mon_fd_flags; - int ret; qemu_mutex_lock(&mon_fdsets_lock); QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { + MonFdsetFd *mon_fdset_fd; + MonFdsetFd *mon_fdset_fd_dup; + int fd = -1; + int dup_fd; + int mon_fd_flags; + if (mon_fdset->id != fdset_id) { continue; } + QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL); if (mon_fd_flags == -1) { - ret = -errno; - goto out; + qemu_mutex_unlock(&mon_fdsets_lock); + return -1; } if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) { - ret = mon_fdset_fd->fd; - goto out; + fd = mon_fdset_fd->fd; + break; } } - ret = -EACCES; - goto out; - } - ret = -ENOENT; - -out: - qemu_mutex_unlock(&mon_fdsets_lock); - return ret; -#endif -} - -int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd) -{ - MonFdset *mon_fdset; - MonFdsetFd *mon_fdset_fd_dup; - qemu_mutex_lock(&mon_fdsets_lock); - QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { - if (mon_fdset->id != fdset_id) { - continue; + if (fd == -1) { + qemu_mutex_unlock(&mon_fdsets_lock); + errno = EACCES; + return -1; } - QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { - if (mon_fdset_fd_dup->fd == dup_fd) { - goto err; - } + + dup_fd = qemu_dup_flags(fd, flags); + if (dup_fd == -1) { + qemu_mutex_unlock(&mon_fdsets_lock); + return -1; } + mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup)); mon_fdset_fd_dup->fd = dup_fd; QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next); qemu_mutex_unlock(&mon_fdsets_lock); - return 0; + return dup_fd; } -err: qemu_mutex_unlock(&mon_fdsets_lock); + errno = ENOENT; return -1; +#endif } static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index bc0e0d2d35..e2b3ba85bf 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -184,7 +184,7 @@ static int net_vhost_vdpa_init(NetClientState *peer, const char *device, snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); nc->queue_index = 0; s = DO_UPCAST(VhostVDPAState, nc, nc); - vdpa_device_fd = qemu_open(vhostdev, O_RDWR); + vdpa_device_fd = qemu_open_old(vhostdev, O_RDWR); if (vdpa_device_fd == -1) { return -errno; } diff --git a/os-posix.c b/os-posix.c index bf98508b6d..0bfd8e2d3c 100644 --- a/os-posix.c +++ b/os-posix.c @@ -297,7 +297,7 @@ void os_setup_post(void) error_report("not able to chdir to /: %s", strerror(errno)); exit(1); } - TFR(fd = qemu_open("/dev/null", O_RDWR)); + TFR(fd = qemu_open_old("/dev/null", O_RDWR)); if (fd == -1) { exit(1); } diff --git a/pc-bios/bios-microvm.bin b/pc-bios/bios-microvm.bin index 45eabc5166..eefd32197e 100644 --- a/pc-bios/bios-microvm.bin +++ b/pc-bios/bios-microvm.bin Binary files differdiff --git a/pc-bios/meson.build b/pc-bios/meson.build index 182d5ebb35..a0d21be432 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -28,6 +28,7 @@ blobs = files( 'bios.bin', 'bios-256k.bin', 'bios-microvm.bin', + 'qboot.rom', 'sgabios.bin', 'vgabios.bin', 'vgabios-cirrus.bin', diff --git a/pc-bios/qboot.rom b/pc-bios/qboot.rom new file mode 100644 index 0000000000..45eabc5166 --- /dev/null +++ b/pc-bios/qboot.rom Binary files differdiff --git a/qga/channel-posix.c b/qga/channel-posix.c index 8fc205ad21..0373975360 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -127,7 +127,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, switch (c->method) { case GA_CHANNEL_VIRTIO_SERIAL: { assert(fd < 0); - fd = qemu_open(path, O_RDWR | O_NONBLOCK + fd = qemu_open_old(path, O_RDWR | O_NONBLOCK #ifndef CONFIG_SOLARIS | O_ASYNC #endif @@ -157,7 +157,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, struct termios tio; assert(fd < 0); - fd = qemu_open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); + fd = qemu_open_old(path, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd == -1) { g_critical("error opening channel: %s", strerror(errno)); return false; diff --git a/qga/commands-posix.c b/qga/commands-posix.c index af5a58a9fd..3bffee99d4 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -1365,7 +1365,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints, } } - fd = qemu_open(mount->dirname, O_RDONLY); + fd = qemu_open_old(mount->dirname, O_RDONLY); if (fd == -1) { error_setg_errno(errp, errno, "failed to open %s", mount->dirname); goto error; @@ -1432,7 +1432,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp) QTAILQ_FOREACH(mount, &mounts, next) { logged = false; - fd = qemu_open(mount->dirname, O_RDONLY); + fd = qemu_open_old(mount->dirname, O_RDONLY); if (fd == -1) { continue; } @@ -1522,7 +1522,7 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp) list->next = response->paths; response->paths = list; - fd = qemu_open(mount->dirname, O_RDONLY); + fd = qemu_open_old(mount->dirname, O_RDONLY); if (fd == -1) { result->error = g_strdup_printf("failed to open: %s", strerror(errno)); diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 48d8bbe649..0c3c05484f 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -57,8 +57,10 @@ DEFINE_DEVPROPKEY(qga_DEVPKEY_Device_DriverDate, 0xa8b865dd, 0x2e3d, DEFINE_DEVPROPKEY(qga_DEVPKEY_Device_DriverVersion, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3); /* DEVPROP_TYPE_STRING */ -/* The following shoud be in cfgmgr32.h, but it isn't */ +/* The CM_Get_DevNode_PropertyW prototype is only sometimes in cfgmgr32.h */ #ifndef CM_Get_DevNode_Property +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" CMAPI CONFIGRET WINAPI CM_Get_DevNode_PropertyW( DEVINST dnDevInst, CONST DEVPROPKEY * PropertyKey, @@ -68,6 +70,7 @@ CMAPI CONFIGRET WINAPI CM_Get_DevNode_PropertyW( ULONG ulFlags ); #define CM_Get_DevNode_Property CM_Get_DevNode_PropertyW +#pragma GCC diagnostic pop #endif #ifndef SHTDN_REASON_FLAG_PLANNED diff --git a/roms/Makefile b/roms/Makefile index 3726f06fe7..1489d47350 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -68,13 +68,16 @@ default help: @echo " efi -- update UEFI (edk2) platform firmware" @echo " opensbi32-generic -- update OpenSBI for 32-bit generic machine" @echo " opensbi64-generic -- update OpenSBI for 64-bit generic machine" - @echo " bios-microvm -- update bios-microvm.bin (qboot)" + @echo " qboot -- update qboot" @echo " clean -- delete the files generated by the previous" \ "build targets" -bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k +bios: build-seabios-config-seabios-128k \ + build-seabios-config-seabios-256k \ + build-seabios-config-seabios-microvm cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin cp seabios/builds/seabios-256k/bios.bin ../pc-bios/bios-256k.bin + cp seabios/builds/seabios-microvm/bios.bin ../pc-bios/bios-microvm.bin vgabios seavgabios: $(patsubst %,seavgabios-%,$(vgabios_variants)) @@ -183,9 +186,9 @@ opensbi64-generic: cp opensbi/build/platform/generic/firmware/fw_dynamic.bin ../pc-bios/opensbi-riscv64-generic-fw_dynamic.bin cp opensbi/build/platform/generic/firmware/fw_dynamic.elf ../pc-bios/opensbi-riscv64-generic-fw_dynamic.elf -bios-microvm: +qboot: $(MAKE) -C qboot - cp qboot/bios.bin ../pc-bios/bios-microvm.bin + cp qboot/bios.bin ../pc-bios/qboot.rom npcm7xx_bootrom: $(MAKE) -C vbootrom CROSS_COMPILE=$(arm_cross_prefix) diff --git a/roms/config.seabios-microvm b/roms/config.seabios-microvm new file mode 100644 index 0000000000..a253e2edc6 --- /dev/null +++ b/roms/config.seabios-microvm @@ -0,0 +1,26 @@ +CONFIG_QEMU=y +CONFIG_QEMU_HARDWARE=y +CONFIG_PERMIT_UNALIGNED_PCIROM=y +CONFIG_ROM_SIZE=128 +CONFIG_XEN=n +CONFIG_BOOTSPLASH=n +CONFIG_ATA=n +CONFIG_AHCI=n +CONFIG_SDCARD=n +CONFIG_PVSCSI=n +CONFIG_ESP_SCSI=n +CONFIG_LSI_SCSI=n +CONFIG_MEGASAS=n +CONFIG_MPT_SCSI=n +CONFIG_FLOPPY=n +CONFIG_FLASH_FLOPPY=n +CONFIG_NVME=n +CONFIG_PS2PORT=n +CONFIG_USB=n +CONFIG_LPT=n +CONFIG_RTC_TIMER=n +CONFIG_USE_SMM=n +CONFIG_PMTIMER=n +CONFIG_TCGBIOS=n +CONFIG_HARDWARE_IRQ=n +CONFIG_ACPI_PARSE=y diff --git a/stubs/fdset.c b/stubs/fdset.c index 67dd5e1d34..56b3663d58 100644 --- a/stubs/fdset.c +++ b/stubs/fdset.c @@ -1,8 +1,9 @@ #include "qemu/osdep.h" #include "monitor/monitor.h" -int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd) +int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags) { + errno = ENOSYS; return -1; } @@ -11,11 +12,6 @@ int64_t monitor_fdset_dup_fd_find(int dup_fd) return -1; } -int monitor_fdset_get_fd(int64_t fdset_id, int flags) -{ - return -ENOENT; -} - void monitor_fdset_dup_fd_remove(int dupfd) { } diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 2eae73315d..0dcb9bfe13 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -71,7 +71,7 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try, { int ret = 0, kvmfd = -1, vmfd = -1, cpufd = -1; - kvmfd = qemu_open("/dev/kvm", O_RDWR); + kvmfd = qemu_open_old("/dev/kvm", O_RDWR); if (kvmfd < 0) { goto err; } diff --git a/tests/data/acpi/microvm/APIC b/tests/data/acpi/microvm/APIC new file mode 100644 index 0000000000..7472c7e830 --- /dev/null +++ b/tests/data/acpi/microvm/APIC Binary files differdiff --git a/tests/data/acpi/microvm/DSDT b/tests/data/acpi/microvm/DSDT new file mode 100644 index 0000000000..b43f427a22 --- /dev/null +++ b/tests/data/acpi/microvm/DSDT Binary files differdiff --git a/tests/data/acpi/microvm/FACP b/tests/data/acpi/microvm/FACP new file mode 100644 index 0000000000..0ba5795d62 --- /dev/null +++ b/tests/data/acpi/microvm/FACP Binary files differdiff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 3daabaa2fd..75704268ff 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -243,7 +243,6 @@ docker-run: docker-qemu-src $(DOCKER_SCRIPT) run \ $(if $(NOUSER),,--run-as-current-user) \ --security-opt seccomp=unconfined \ - $(if $V,,--rm) \ $(if $(DEBUG),-ti,) \ $(if $(NETWORK),$(if $(subst $(NETWORK),,1),--net=$(NETWORK)),--net=none) \ -e TARGET_LIST=$(subst $(SPACE),$(COMMA),$(TARGET_LIST)) \ diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 356d7618f1..36b7868406 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -377,7 +377,7 @@ class Docker(object): if self._command[0] == "podman": cmd.insert(0, '--userns=keep-id') - ret = self._do_check(["run", "--label", + ret = self._do_check(["run", "--rm", "--label", "com.qemu.instance.uuid=" + label] + cmd, quiet=quiet) if not keep: @@ -616,7 +616,7 @@ class CcCommand(SubCommand): if argv and argv[0] == "--": argv = argv[1:] cwd = os.getcwd() - cmd = ["--rm", "-w", cwd, + cmd = ["-w", cwd, "-v", "%s:%s:rw" % (cwd, cwd)] if args.paths: for p in args.paths: diff --git a/tests/meson.build b/tests/meson.build index dae8a77df1..8c3e930687 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -145,7 +145,8 @@ if have_block 'test-crypto-block': [io], } if 'CONFIG_GNUTLS' in config_host and \ - 'CONFIG_TASN1' in config_host + 'CONFIG_TASN1' in config_host and \ + 'CONFIG_POSIX' in config_host tests += { 'test-crypto-tlscredsx509': ['crypto-tls-x509-helpers.c', 'pkix_asn1_tab.c', tasn1, crypto], @@ -195,8 +196,13 @@ if have_system # are not runnable under TSan due to a known issue. # https://github.com/google/sanitizers/issues/1116 if 'CONFIG_TSAN' not in config_host + if 'CONFIG_POSIX' in config_host + tests += { + 'test-char': ['socket-helpers.c', qom, io, chardev] + } + endif + tests += { - 'test-char': ['socket-helpers.c', qom, io, chardev], 'test-qdev-global-props': [qom, hwcore, testqapi] } endif diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index c87d141417..f1449298b0 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -220,6 +220,6 @@ qapi_doc = custom_target('QAPI doc', # "full_path()" needed here to work around # https://github.com/mesonbuild/meson/issues/7585 -test('QAPI doc', diff, args: ['-u', files('doc-good.texi'), qapi_doc[0].full_path()], +test('QAPI doc', diff, args: ['-b', '-u', files('doc-good.texi'), qapi_doc[0].full_path()], depends: qapi_doc, suite: ['qapi-schema', 'qapi-doc']) diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index e14a1f354d..678b6e4910 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -44,7 +44,7 @@ then _init_error "failed to obtain source tree name from check symlink" fi source_iotests=$(cd "$source_iotests"; pwd) || _init_error "failed to enter source tree" - build_iotests=$(readlink -f $(dirname "$0")) + build_iotests=$(cd "$(dirname "$0")"; pwd) else # called from the source tree source_iotests=$PWD diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 504b810af5..a9c8d478ae 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -72,6 +72,7 @@ typedef struct { const char *variant; const char *uefi_fl1; const char *uefi_fl2; + const char *blkdev; const char *cd; const uint64_t ram_start; const uint64_t scan_len; @@ -666,9 +667,10 @@ static void test_acpi_one(const char *params, test_data *data) args = g_strdup_printf("-machine %s,kernel-irqchip=off %s -accel tcg " "-net none -display none %s " "-drive id=hd0,if=none,file=%s,format=raw " - "-device ide-hd,drive=hd0 ", + "-device %s,drive=hd0 ", data->machine, data->tcg_only ? "" : "-accel kvm", - params ? params : "", disk); + params ? params : "", disk, + data->blkdev ?: "ide-hd"); } data->qts = qtest_init(args); @@ -1042,6 +1044,20 @@ static void test_acpi_virt_tcg_memhp(void) } +static void test_acpi_microvm_tcg(void) +{ + test_data data; + + memset(&data, 0, sizeof(data)); + data.machine = "microvm"; + data.required_struct_types = NULL; /* no smbios */ + data.required_struct_types_len = 0; + data.blkdev = "virtio-blk-device"; + test_acpi_one(" -machine microvm,acpi=on,rtc=off", + &data); + free_test_data(&data); +} + static void test_acpi_virt_tcg_numamem(void) { test_data data = { @@ -1159,6 +1175,7 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat); qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat); + qtest_add_func("acpi/microvm", test_acpi_microvm_tcg); } else if (strcmp(arch, "aarch64") == 0) { qtest_add_func("acpi/virt", test_acpi_virt_tcg); qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem); diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 1ceea84702..7f266ffc63 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -202,9 +202,8 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) /* Run QEMU's softmmu main with the fuzz-target dependent arguments */ GString *cmd_line = fuzz_target->get_init_cmdline(fuzz_target); - g_string_append_printf(cmd_line, - " -qtest /dev/null -qtest-log %s", - getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null"); + g_string_append_printf(cmd_line, " %s -qtest /dev/null ", + getenv("QTEST_LOG") ? "" : "-qtest-log none"); /* Split the runcmd into an argv and argc */ wordexp_t result; diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c index 3109a9fe96..8a4c570e83 100644 --- a/tests/qtest/qmp-cmd-test.c +++ b/tests/qtest/qmp-cmd-test.c @@ -82,9 +82,9 @@ static void test_query(const void *data) qtest_quit(qts); } -static bool query_is_blacklisted(const char *cmd) +static bool query_is_ignored(const char *cmd) { - const char *blacklist[] = { + const char *ignored[] = { /* Not actually queries: */ "add-fd", /* Success depends on target arch: */ @@ -101,8 +101,8 @@ static bool query_is_blacklisted(const char *cmd) }; int i; - for (i = 0; blacklist[i]; i++) { - if (!strcmp(cmd, blacklist[i])) { + for (i = 0; ignored[i]; i++) { + if (!strcmp(cmd, ignored[i])) { return true; } } @@ -179,7 +179,7 @@ static void add_query_tests(QmpSchema *schema) continue; } - if (query_is_blacklisted(si->name)) { + if (query_is_ignored(si->name)) { continue; } diff --git a/tests/socket-helpers.c b/tests/socket-helpers.c index 19a51e887e..f704fd1a69 100644 --- a/tests/socket-helpers.c +++ b/tests/socket-helpers.c @@ -59,8 +59,7 @@ static int socket_can_bind_connect(const char *hostname, int family) /* lookup */ rc = getaddrinfo(hostname, NULL, &ai, &res); if (rc != 0) { - if (rc == EAI_ADDRFAMILY || - rc == EAI_FAMILY) { + if (rc == EAI_ADDRFAMILY || rc == EAI_FAMILY || rc == EAI_NONAME) { errno = EADDRNOTAVAIL; } else { errno = EINVAL; diff --git a/tests/test-io-channel-file.c b/tests/test-io-channel-file.c index bac2b07562..0aa0477541 100644 --- a/tests/test-io-channel-file.c +++ b/tests/test-io-channel-file.c @@ -28,6 +28,16 @@ #define TEST_FILE "tests/test-io-channel-file.txt" #define TEST_MASK 0600 +/* + * On Windows the stat() function in the C library checks only + * the FAT-style READONLY attribute and does not look at the ACL at all. + */ +#ifdef _WIN32 +#define TEST_MASK_EXPECT 0700 +#else +#define TEST_MASK_EXPECT 0777 +#endif + static void test_io_channel_file_helper(int flags) { QIOChannel *src, *dst; @@ -56,7 +66,7 @@ static void test_io_channel_file_helper(int flags) umask(mask); ret = stat(TEST_FILE, &st); g_assert_cmpint(ret, >, -1); - g_assert_cmpuint(TEST_MASK & ~mask, ==, st.st_mode & 0777); + g_assert_cmpuint(TEST_MASK & ~mask, ==, st.st_mode & TEST_MASK_EXPECT); unlink(TEST_FILE); object_unref(OBJECT(src)); diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c index d43083a766..743577d744 100644 --- a/tests/test-io-channel-socket.c +++ b/tests/test-io-channel-socket.c @@ -25,6 +25,7 @@ #include "socket-helpers.h" #include "qapi/error.h" #include "qemu/module.h" +#include "qemu/main-loop.h" static void test_io_channel_set_socket_bufs(QIOChannel *src, @@ -556,6 +557,7 @@ int main(int argc, char **argv) bool has_ipv4, has_ipv6; module_call_init(MODULE_INIT_QOM); + qemu_init_main_loop(&error_abort); socket_init(); g_test_init(&argc, &argv, NULL); diff --git a/tests/test-logging.c b/tests/test-logging.c index 8a1161de1d..8b1522cfed 100644 --- a/tests/test-logging.c +++ b/tests/test-logging.c @@ -196,7 +196,7 @@ static void rmdir_full(gchar const *root) int main(int argc, char **argv) { - gchar *tmp_path = g_dir_make_tmp("qemu-test-logging.XXXXXX", NULL); + g_autofree gchar *tmp_path = g_dir_make_tmp("qemu-test-logging.XXXXXX", NULL); int rc; g_test_init(&argc, &argv, NULL); @@ -210,8 +210,9 @@ int main(int argc, char **argv) tmp_path, test_logfile_lock); rc = g_test_run(); + qemu_log_close(); + drain_call_rcu(); rmdir_full(tmp_path); - g_free(tmp_path); return rc; } diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c index 8a3c14d92c..c8862cac5f 100644 --- a/tests/test-qdev-global-props.c +++ b/tests/test-qdev-global-props.c @@ -251,10 +251,13 @@ static void test_dynamic_globalprop(void) g_test_trap_assert_passed(); g_test_trap_assert_stderr_unmatched("*prop1*"); g_test_trap_assert_stderr_unmatched("*prop2*"); - g_test_trap_assert_stderr("*warning: global dynamic-prop-type-bad.prop3 has invalid class name\n*"); + g_test_trap_assert_stderr( + "*warning: global dynamic-prop-type-bad.prop3 has invalid class name*"); g_test_trap_assert_stderr_unmatched("*prop4*"); - g_test_trap_assert_stderr("*warning: global nohotplug-type.prop5=105 not used\n*"); - g_test_trap_assert_stderr("*warning: global nondevice-type.prop6 has invalid class name\n*"); + g_test_trap_assert_stderr( + "*warning: global nohotplug-type.prop5=105 not used*"); + g_test_trap_assert_stderr( + "*warning: global nondevice-type.prop6 has invalid class name*"); g_test_trap_assert_stdout(""); } diff --git a/tests/test-replication.c b/tests/test-replication.c index 9ab3666a90..b067240add 100644 --- a/tests/test-replication.c +++ b/tests/test-replication.c @@ -23,14 +23,14 @@ /* primary */ #define P_ID "primary-id" -static char p_local_disk[] = "/tmp/p_local_disk.XXXXXX"; +static char *p_local_disk; /* secondary */ #define S_ID "secondary-id" #define S_LOCAL_DISK_ID "secondary-local-disk-id" -static char s_local_disk[] = "/tmp/s_local_disk.XXXXXX"; -static char s_active_disk[] = "/tmp/s_active_disk.XXXXXX"; -static char s_hidden_disk[] = "/tmp/s_hidden_disk.XXXXXX"; +static char *s_local_disk; +static char *s_active_disk; +static char *s_hidden_disk; /* FIXME: steal from blockdev.c */ QemuOptsList qemu_drive_opts = { @@ -392,6 +392,7 @@ static void test_secondary_write(void) teardown_secondary(); } +#ifndef _WIN32 static void test_secondary_start(void) { BlockBackend *top_blk, *local_blk; @@ -546,6 +547,7 @@ static void test_secondary_get_error_all(void) teardown_secondary(); } +#endif static void sigabrt_handler(int signo) { @@ -571,6 +573,11 @@ static void setup_sigabrt_handler(void) int main(int argc, char **argv) { int ret; + const char *tmpdir = g_get_tmp_dir(); + p_local_disk = g_strdup_printf("%s/p_local_disk.XXXXXX", tmpdir); + s_local_disk = g_strdup_printf("%s/s_local_disk.XXXXXX", tmpdir); + s_active_disk = g_strdup_printf("%s/s_active_disk.XXXXXX", tmpdir); + s_hidden_disk = g_strdup_printf("%s/s_hidden_disk.XXXXXX", tmpdir); qemu_init_main_loop(&error_fatal); bdrv_init(); @@ -592,6 +599,7 @@ int main(int argc, char **argv) /* Secondary */ g_test_add_func("/replication/secondary/read", test_secondary_read); g_test_add_func("/replication/secondary/write", test_secondary_write); +#ifndef _WIN32 g_test_add_func("/replication/secondary/start", test_secondary_start); g_test_add_func("/replication/secondary/stop", test_secondary_stop); g_test_add_func("/replication/secondary/continuous_replication", @@ -600,10 +608,16 @@ int main(int argc, char **argv) test_secondary_do_checkpoint); g_test_add_func("/replication/secondary/get_error_all", test_secondary_get_error_all); +#endif ret = g_test_run(); cleanup_imgs(); + g_free(p_local_disk); + g_free(s_local_disk); + g_free(s_active_disk); + g_free(s_hidden_disk); + return ret; } diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c index af9f5c0c70..1bbb16d9b1 100644 --- a/tests/test-util-sockets.c +++ b/tests/test-util-sockets.c @@ -75,7 +75,7 @@ int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) {} void monitor_init_hmp(Chardev *chr, bool use_readline, Error **errp) {} - +#ifndef _WIN32 static void test_socket_fd_pass_name_good(void) { SocketAddress addr; @@ -227,6 +227,7 @@ static void test_socket_fd_pass_num_nocli(void) g_free(addr.u.fd.str); } +#endif #ifdef __linux__ static gchar *abstract_sock_name; @@ -321,6 +322,7 @@ int main(int argc, char **argv) { bool has_ipv4, has_ipv6; + qemu_init_main_loop(&error_abort); socket_init(); g_test_init(&argc, &argv, NULL); @@ -340,6 +342,7 @@ int main(int argc, char **argv) test_fd_is_socket_bad); g_test_add_func("/util/socket/is-socket/good", test_fd_is_socket_good); +#ifndef _WIN32 g_test_add_func("/socket/fd-pass/name/good", test_socket_fd_pass_name_good); g_test_add_func("/socket/fd-pass/name/bad", @@ -352,6 +355,7 @@ int main(int argc, char **argv) test_socket_fd_pass_num_bad); g_test_add_func("/socket/fd-pass/num/nocli", test_socket_fd_pass_num_nocli); +#endif } #ifdef __linux__ diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c index 1c763015d0..a001879585 100644 --- a/tests/test-vmstate.c +++ b/tests/test-vmstate.c @@ -34,7 +34,6 @@ #include "qemu/module.h" #include "io/channel-file.h" -static char temp_file[] = "/tmp/vmst.test.XXXXXX"; static int temp_fd; @@ -1484,6 +1483,8 @@ static void test_tmp_struct(void) int main(int argc, char **argv) { + g_autofree char *temp_file = g_strdup_printf("%s/vmst.test.XXXXXX", + g_get_tmp_dir()); temp_fd = mkstemp(temp_file); module_call_init(MODULE_INIT_QOM); diff --git a/ui/console.c b/ui/console.c index f8d7643fe4..7592c3c324 100644 --- a/ui/console.c +++ b/ui/console.c @@ -373,7 +373,7 @@ void qmp_screendump(const char *filename, bool has_device, const char *device, return; } - fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + fd = qemu_open_old(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); if (fd == -1) { error_setg(errp, "failed to open file '%s': %s", filename, strerror(errno)); diff --git a/util/aio-win32.c b/util/aio-win32.c index 953c56ab48..49bd90e62e 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -37,6 +37,16 @@ struct AioHandler { static void aio_remove_fd_handler(AioContext *ctx, AioHandler *node) { + /* + * If the GSource is in the process of being destroyed then + * g_source_remove_poll() causes an assertion failure. Skip + * removal in that case, because glib cleans up its state during + * destruction anyway. + */ + if (!g_source_is_destroyed(&ctx->source)) { + g_source_remove_poll(&ctx->source, &node->pfd); + } + /* If aio_poll is in progress, just mark the node as deleted */ if (qemu_lockcnt_count(&ctx->list_lock)) { node->deleted = 1; @@ -139,8 +149,6 @@ void aio_set_event_notifier(AioContext *ctx, /* Are we deleting the fd handler? */ if (!io_notify) { if (node) { - g_source_remove_poll(&ctx->source, &node->pfd); - aio_remove_fd_handler(ctx, node); } } else { diff --git a/util/osdep.c b/util/osdep.c index 4829c07ff6..8ea7a807c1 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qapi/error.h" /* Needed early for CONFIG_BSD etc. */ @@ -122,7 +123,7 @@ static int fcntl_op_getlk = -1; /* * Dups an fd and sets the flags */ -static int qemu_dup_flags(int fd, int flags) +int qemu_dup_flags(int fd, int flags) { int ret; int serrno; @@ -279,13 +280,27 @@ int qemu_lock_fd_test(int fd, int64_t start, int64_t len, bool exclusive) } #endif +static int qemu_open_cloexec(const char *name, int flags, mode_t mode) +{ + int ret; +#ifdef O_CLOEXEC + ret = open(name, flags | O_CLOEXEC, mode); +#else + ret = open(name, flags, mode); + if (ret >= 0) { + qemu_set_cloexec(ret); + } +#endif + return ret; +} + /* * Opens a file with FD_CLOEXEC set */ -int qemu_open(const char *name, int flags, ...) +static int +qemu_open_internal(const char *name, int flags, mode_t mode, Error **errp) { int ret; - int mode = 0; #ifndef _WIN32 const char *fdset_id_str; @@ -293,29 +308,19 @@ int qemu_open(const char *name, int flags, ...) /* Attempt dup of fd from fd set */ if (strstart(name, "/dev/fdset/", &fdset_id_str)) { int64_t fdset_id; - int fd, dupfd; + int dupfd; fdset_id = qemu_parse_fdset(fdset_id_str); if (fdset_id == -1) { + error_setg(errp, "Could not parse fdset %s", name); errno = EINVAL; return -1; } - fd = monitor_fdset_get_fd(fdset_id, flags); - if (fd < 0) { - errno = -fd; - return -1; - } - - dupfd = qemu_dup_flags(fd, flags); + dupfd = monitor_fdset_dup_fd_add(fdset_id, flags); if (dupfd == -1) { - return -1; - } - - ret = monitor_fdset_dup_fd_add(fdset_id, dupfd); - if (ret == -1) { - close(dupfd); - errno = EINVAL; + error_setg_errno(errp, errno, "Could not dup FD for %s flags %x", + name, flags); return -1; } @@ -323,22 +328,61 @@ int qemu_open(const char *name, int flags, ...) } #endif - if (flags & O_CREAT) { - va_list ap; + ret = qemu_open_cloexec(name, flags, mode); - va_start(ap, flags); - mode = va_arg(ap, int); - va_end(ap); + if (ret == -1) { + const char *action = flags & O_CREAT ? "create" : "open"; +#ifdef O_DIRECT + /* Give more helpful error message for O_DIRECT */ + if (errno == EINVAL && (flags & O_DIRECT)) { + ret = open(name, flags & ~O_DIRECT, mode); + if (ret != -1) { + close(ret); + error_setg(errp, "Could not %s '%s': " + "filesystem does not support O_DIRECT", + action, name); + errno = EINVAL; /* restore first open()'s errno */ + return -1; + } + } +#endif /* O_DIRECT */ + error_setg_errno(errp, errno, "Could not %s '%s'", + action, name); } -#ifdef O_CLOEXEC - ret = open(name, flags | O_CLOEXEC, mode); -#else - ret = open(name, flags, mode); - if (ret >= 0) { - qemu_set_cloexec(ret); + return ret; +} + + +int qemu_open(const char *name, int flags, Error **errp) +{ + assert(!(flags & O_CREAT)); + + return qemu_open_internal(name, flags, 0, errp); +} + + +int qemu_create(const char *name, int flags, mode_t mode, Error **errp) +{ + assert(!(flags & O_CREAT)); + + return qemu_open_internal(name, flags | O_CREAT, mode, errp); +} + + +int qemu_open_old(const char *name, int flags, ...) +{ + va_list ap; + mode_t mode = 0; + int ret; + + va_start(ap, flags); + if (flags & O_CREAT) { + mode = va_arg(ap, int); } -#endif + va_end(ap); + + ret = qemu_open_internal(name, flags, mode, NULL); #ifdef O_DIRECT if (ret == -1 && errno == EINVAL && (flags & O_DIRECT)) { diff --git a/util/oslib-posix.c b/util/oslib-posix.c index ad8001a4ad..f5f676f079 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -125,7 +125,7 @@ bool qemu_write_pidfile(const char *path, Error **errp) .l_len = 0, }; - fd = qemu_open(path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + fd = qemu_open_old(path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); if (fd == -1) { error_setg_errno(errp, errno, "Cannot open pid file"); return false; diff --git a/util/rcu.c b/util/rcu.c index 60a37f72c3..c4fefa9333 100644 --- a/util/rcu.c +++ b/util/rcu.c @@ -293,6 +293,61 @@ void call_rcu1(struct rcu_head *node, void (*func)(struct rcu_head *node)) qemu_event_set(&rcu_call_ready_event); } + +struct rcu_drain { + struct rcu_head rcu; + QemuEvent drain_complete_event; +}; + +static void drain_rcu_callback(struct rcu_head *node) +{ + struct rcu_drain *event = (struct rcu_drain *)node; + qemu_event_set(&event->drain_complete_event); +} + +/* + * This function ensures that all pending RCU callbacks + * on the current thread are done executing + + * drops big qemu lock during the wait to allow RCU thread + * to process the callbacks + * + */ + +void drain_call_rcu(void) +{ + struct rcu_drain rcu_drain; + bool locked = qemu_mutex_iothread_locked(); + + memset(&rcu_drain, 0, sizeof(struct rcu_drain)); + qemu_event_init(&rcu_drain.drain_complete_event, false); + + if (locked) { + qemu_mutex_unlock_iothread(); + } + + + /* + * RCU callbacks are invoked in the same order as in which they + * are registered, thus we can be sure that when 'drain_rcu_callback' + * is called, all RCU callbacks that were registered on this thread + * prior to calling this function are completed. + * + * Note that since we have only one global queue of the RCU callbacks, + * we also end up waiting for most of RCU callbacks that were registered + * on the other threads, but this is a side effect that shoudn't be + * assumed. + */ + + call_rcu1(&rcu_drain.rcu, drain_rcu_callback); + qemu_event_wait(&rcu_drain.drain_complete_event); + + if (locked) { + qemu_mutex_lock_iothread(); + } + +} + void rcu_register_thread(void) { assert(rcu_reader.ctr == 0); |