diff options
287 files changed, 2822 insertions, 1316 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 4f0cc1e448..38d1ac8803 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1819,7 +1819,6 @@ F: docs/specs/acpi_hw_reduced_hotplug.rst ACPI/VIOT M: Jean-Philippe Brucker <jean-philippe@linaro.org> -R: Ani Sinha <ani@anisinha.ca> S: Supported F: hw/acpi/viot.c F: hw/acpi/viot.h @@ -3611,7 +3610,8 @@ FreeBSD Hosted Continuous Integration M: Ed Maste <emaste@freebsd.org> M: Li-Wen Hsu <lwhsu@freebsd.org> S: Maintained -F: .cirrus.yml +F: .gitlab-ci.d/cirrus/freebsd* +F: tests/vm/freebsd W: https://cirrus-ci.com/github/qemu/qemu Windows Hosted Continuous Integration diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c index 7516c67a3f..c4244a23c6 100644 --- a/accel/kvm/kvm-accel-ops.c +++ b/accel/kvm/kvm-accel-ops.c @@ -74,11 +74,23 @@ static void kvm_start_vcpu_thread(CPUState *cpu) cpu, QEMU_THREAD_JOINABLE); } +static bool kvm_vcpu_thread_is_idle(CPUState *cpu) +{ + return !kvm_halt_in_kernel(); +} + +static bool kvm_cpus_are_resettable(void) +{ + return !kvm_enabled() || kvm_cpu_check_are_resettable(); +} + static void kvm_accel_ops_class_init(ObjectClass *oc, void *data) { AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); ops->create_vcpu_thread = kvm_start_vcpu_thread; + ops->cpu_thread_is_idle = kvm_vcpu_thread_is_idle; + ops->cpus_are_resettable = kvm_cpus_are_resettable; ops->synchronize_post_reset = kvm_cpu_synchronize_post_reset; ops->synchronize_post_init = kvm_cpu_synchronize_post_init; ops->synchronize_state = kvm_cpu_synchronize_state; diff --git a/accel/meson.build b/accel/meson.build index dfd808d2c8..b9a963cf80 100644 --- a/accel/meson.build +++ b/accel/meson.build @@ -2,12 +2,14 @@ specific_ss.add(files('accel-common.c')) softmmu_ss.add(files('accel-softmmu.c')) user_ss.add(files('accel-user.c')) -subdir('hvf') -subdir('qtest') -subdir('kvm') subdir('tcg') -subdir('xen') -subdir('stubs') +if have_system + subdir('hvf') + subdir('qtest') + subdir('kvm') + subdir('xen') + subdir('stubs') +endif dummy_ss = ss.source_set() dummy_ss.add(files( diff --git a/accel/qtest/qtest.c b/accel/qtest/qtest.c index 7e6b8110d5..f6056ac836 100644 --- a/accel/qtest/qtest.c +++ b/accel/qtest/qtest.c @@ -20,7 +20,6 @@ #include "qemu/accel.h" #include "sysemu/qtest.h" #include "sysemu/cpus.h" -#include "sysemu/cpu-timers.h" #include "qemu/guest-random.h" #include "qemu/main-loop.h" #include "hw/core/cpu.h" diff --git a/accel/stubs/hax-stub.c b/accel/stubs/hax-stub.c index 49077f88e3..2fe31aaa9a 100644 --- a/accel/stubs/hax-stub.c +++ b/accel/stubs/hax-stub.c @@ -16,6 +16,8 @@ #include "qemu/osdep.h" #include "sysemu/hax.h" +bool hax_allowed; + int hax_sync_vcpus(void) { return 0; diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c index 5319573e00..7e0fb884b9 100644 --- a/accel/stubs/kvm-stub.c +++ b/accel/stubs/kvm-stub.c @@ -12,10 +12,7 @@ #include "qemu/osdep.h" #include "sysemu/kvm.h" - -#ifndef CONFIG_USER_ONLY #include "hw/pci/msi.h" -#endif KVMState *kvm_state; bool kvm_kernel_irqchip; @@ -80,7 +77,6 @@ int kvm_on_sigbus(int code, void *addr) return 1; } -#ifndef CONFIG_USER_ONLY int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev) { return -ENOSYS; @@ -152,4 +148,3 @@ bool kvm_dirty_ring_enabled(void) { return false; } -#endif diff --git a/accel/stubs/meson.build b/accel/stubs/meson.build index 12dd1539af..0249b9258f 100644 --- a/accel/stubs/meson.build +++ b/accel/stubs/meson.build @@ -1,4 +1,7 @@ -specific_ss.add(when: 'CONFIG_HAX', if_false: files('hax-stub.c')) -specific_ss.add(when: 'CONFIG_XEN', if_false: files('xen-stub.c')) -specific_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) -specific_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c')) +sysemu_stubs_ss = ss.source_set() +sysemu_stubs_ss.add(when: 'CONFIG_HAX', if_false: files('hax-stub.c')) +sysemu_stubs_ss.add(when: 'CONFIG_XEN', if_false: files('xen-stub.c')) +sysemu_stubs_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) +sysemu_stubs_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c')) + +specific_ss.add_all(when: ['CONFIG_SOFTMMU'], if_true: sysemu_stubs_ss) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index c68270f794..c997c2e8e0 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -422,7 +422,7 @@ static void cpu_exec_exit(CPUState *cpu) void cpu_exec_step_atomic(CPUState *cpu) { - CPUArchState *env = (CPUArchState *)cpu->env_ptr; + CPUArchState *env = cpu->env_ptr; TranslationBlock *tb; target_ulong cs_base, pc; uint32_t flags, cflags; @@ -532,7 +532,7 @@ TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc, struct tb_desc desc; uint32_t h; - desc.env = (CPUArchState *)cpu->env_ptr; + desc.env = cpu->env_ptr; desc.cs_base = cs_base; desc.flags = flags; desc.cflags = cflags; diff --git a/accel/tcg/tcg-accel-ops-icount.c b/accel/tcg/tcg-accel-ops-icount.c index ea42d1d51b..bdaf2c943b 100644 --- a/accel/tcg/tcg-accel-ops-icount.c +++ b/accel/tcg/tcg-accel-ops-icount.c @@ -27,6 +27,7 @@ #include "qemu-common.h" #include "sysemu/tcg.h" #include "sysemu/replay.h" +#include "sysemu/cpu-timers.h" #include "qemu/main-loop.h" #include "qemu/guest-random.h" #include "exec/exec-all.h" diff --git a/accel/tcg/tcg-accel-ops-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c index 29632bd4c0..dc421c8fd7 100644 --- a/accel/tcg/tcg-accel-ops-mttcg.c +++ b/accel/tcg/tcg-accel-ops-mttcg.c @@ -27,6 +27,7 @@ #include "qemu-common.h" #include "sysemu/tcg.h" #include "sysemu/replay.h" +#include "sysemu/cpu-timers.h" #include "qemu/main-loop.h" #include "qemu/notify.h" #include "qemu/guest-random.h" diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index bf59f53dbc..a805fb6bdd 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -27,6 +27,7 @@ #include "qemu-common.h" #include "sysemu/tcg.h" #include "sysemu/replay.h" +#include "sysemu/cpu-timers.h" #include "qemu/main-loop.h" #include "qemu/notify.h" #include "qemu/guest-random.h" diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 1a8e8390bd..ea7dcad674 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -29,6 +29,7 @@ #include "qemu-common.h" #include "sysemu/tcg.h" #include "sysemu/replay.h" +#include "sysemu/cpu-timers.h" #include "qemu/main-loop.h" #include "qemu/guest-random.h" #include "exec/exec-all.h" diff --git a/block/blkverify.c b/block/blkverify.c index d1facf5ba9..53ba1c9195 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -16,6 +16,7 @@ #include "qemu/cutils.h" #include "qemu/module.h" #include "qemu/option.h" +#include "qemu/memalign.h" typedef struct { BdrvChild *test_file; diff --git a/block/block-copy.c b/block/block-copy.c index ef948dccec..ec46775ea5 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -23,6 +23,7 @@ #include "qemu/coroutine.h" #include "block/aio_task.h" #include "qemu/error-report.h" +#include "qemu/memalign.h" #define BLOCK_COPY_MAX_COPY_RANGE (16 * MiB) #define BLOCK_COPY_MAX_BUFFER (1 * MiB) diff --git a/block/commit.c b/block/commit.c index c76899f640..851d1c557a 100644 --- a/block/commit.c +++ b/block/commit.c @@ -20,6 +20,7 @@ #include "qapi/error.h" #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" +#include "qemu/memalign.h" #include "sysemu/block-backend.h" enum { diff --git a/block/crypto.c b/block/crypto.c index 9d5fecbef8..1ba82984ef 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -31,6 +31,7 @@ #include "qemu/module.h" #include "qemu/option.h" #include "qemu/cutils.h" +#include "qemu/memalign.h" #include "crypto.h" typedef struct BlockCrypto BlockCrypto; diff --git a/block/dmg.c b/block/dmg.c index 447901fbb8..c626587f9c 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -27,6 +27,7 @@ #include "qemu/bswap.h" #include "qemu/error-report.h" #include "qemu/module.h" +#include "qemu/memalign.h" #include "dmg.h" int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in, diff --git a/block/export/fuse.c b/block/export/fuse.c index 5029e70f84..e80b24a867 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -19,6 +19,7 @@ #define FUSE_USE_VERSION 31 #include "qemu/osdep.h" +#include "qemu/memalign.h" #include "block/aio.h" #include "block/block.h" #include "block/export.h" diff --git a/block/file-posix.c b/block/file-posix.c index 1f1756e192..c000a61db2 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -31,6 +31,7 @@ #include "qemu/module.h" #include "qemu/option.h" #include "qemu/units.h" +#include "qemu/memalign.h" #include "trace.h" #include "block/thread-pool.h" #include "qemu/iov.h" diff --git a/block/io.c b/block/io.c index f0c8da6b9f..3280144a17 100644 --- a/block/io.c +++ b/block/io.c @@ -32,6 +32,7 @@ #include "block/coroutines.h" #include "block/write-threshold.h" #include "qemu/cutils.h" +#include "qemu/memalign.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" diff --git a/block/mirror.c b/block/mirror.c index ce6bc58d1f..d8ecb9efa2 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -23,6 +23,7 @@ #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" #include "qemu/bitmap.h" +#include "qemu/memalign.h" #define MAX_IN_FLIGHT 16 #define MAX_IO_BYTES (1 << 20) /* 1 Mb */ diff --git a/block/nvme.c b/block/nvme.c index dd20de3865..552029931d 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -21,6 +21,7 @@ #include "qemu/module.h" #include "qemu/cutils.h" #include "qemu/option.h" +#include "qemu/memalign.h" #include "qemu/vfio-helpers.h" #include "block/block_int.h" #include "sysemu/replay.h" diff --git a/block/parallels-ext.c b/block/parallels-ext.c index e0dd0975c6..cb22a427d7 100644 --- a/block/parallels-ext.c +++ b/block/parallels-ext.c @@ -29,6 +29,7 @@ #include "parallels.h" #include "crypto/hash.h" #include "qemu/uuid.h" +#include "qemu/memalign.h" #define PARALLELS_FORMAT_EXTENSION_MAGIC 0xAB234CEF23DCEA87ULL diff --git a/block/parallels.c b/block/parallels.c index e58c828422..cd23e02d06 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -41,6 +41,7 @@ #include "qapi/qapi-visit-block-core.h" #include "qemu/bswap.h" #include "qemu/bitmap.h" +#include "qemu/memalign.h" #include "migration/blocker.h" #include "parallels.h" diff --git a/block/qcow.c b/block/qcow.c index c39940f33e..4fba1b9e36 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -32,6 +32,7 @@ #include "qemu/option.h" #include "qemu/bswap.h" #include "qemu/cutils.h" +#include "qemu/memalign.h" #include <zlib.h> #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index 7444b9c4ab..8a0105911f 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qemu/memalign.h" #include "qcow2.h" #include "trace.h" diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 21884a1ab9..20a16ba6ee 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -28,6 +28,7 @@ #include "qapi/error.h" #include "qcow2.h" #include "qemu/bswap.h" +#include "qemu/memalign.h" #include "trace.h" int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t exact_size) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 4614572252..94033972be 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -28,6 +28,7 @@ #include "qemu/range.h" #include "qemu/bswap.h" #include "qemu/cutils.h" +#include "qemu/memalign.h" #include "trace.h" static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size, diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 71ddb08c21..075269a023 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -29,6 +29,7 @@ #include "qemu/bswap.h" #include "qemu/error-report.h" #include "qemu/cutils.h" +#include "qemu/memalign.h" static void qcow2_free_single_snapshot(BlockDriverState *bs, int i) { diff --git a/block/qcow2.c b/block/qcow2.c index c8115e1cba..b5c47931ef 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -38,6 +38,7 @@ #include "qemu/option_int.h" #include "qemu/cutils.h" #include "qemu/bswap.h" +#include "qemu/memalign.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qapi-visit-block-core.h" #include "crypto.h" diff --git a/block/qed-l2-cache.c b/block/qed-l2-cache.c index b548362398..caf2c024c2 100644 --- a/block/qed-l2-cache.c +++ b/block/qed-l2-cache.c @@ -51,6 +51,7 @@ */ #include "qemu/osdep.h" +#include "qemu/memalign.h" #include "trace.h" #include "qed.h" diff --git a/block/qed-table.c b/block/qed-table.c index 405d446cbe..1cc844b1a5 100644 --- a/block/qed-table.c +++ b/block/qed-table.c @@ -17,6 +17,7 @@ #include "qemu/sockets.h" /* for EINPROGRESS on Windows */ #include "qed.h" #include "qemu/bswap.h" +#include "qemu/memalign.h" /* Called with table_lock held. */ static int coroutine_fn qed_read_table(BDRVQEDState *s, uint64_t offset, diff --git a/block/qed.c b/block/qed.c index 558d3646c4..f34d9a3ac1 100644 --- a/block/qed.c +++ b/block/qed.c @@ -20,6 +20,7 @@ #include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/option.h" +#include "qemu/memalign.h" #include "trace.h" #include "qed.h" #include "sysemu/block-backend.h" diff --git a/block/quorum.c b/block/quorum.c index c28dda7baa..f33f30d36b 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -17,6 +17,7 @@ #include "qemu/cutils.h" #include "qemu/module.h" #include "qemu/option.h" +#include "qemu/memalign.h" #include "block/block_int.h" #include "block/coroutines.h" #include "block/qdict.h" diff --git a/block/raw-format.c b/block/raw-format.c index bda757fd19..69fd650eaf 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -31,6 +31,7 @@ #include "qapi/error.h" #include "qemu/module.h" #include "qemu/option.h" +#include "qemu/memalign.h" typedef struct BDRVRawState { uint64_t offset; diff --git a/block/vdi.c b/block/vdi.c index bdc58d726e..cca3a3a356 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -64,6 +64,7 @@ #include "qemu/coroutine.h" #include "qemu/cutils.h" #include "qemu/uuid.h" +#include "qemu/memalign.h" /* Code configuration options. */ diff --git a/block/vhdx-log.c b/block/vhdx-log.c index 7672161d95..ff0d4e0da0 100644 --- a/block/vhdx-log.c +++ b/block/vhdx-log.c @@ -23,6 +23,7 @@ #include "block/block_int.h" #include "qemu/error-report.h" #include "qemu/bswap.h" +#include "qemu/memalign.h" #include "vhdx.h" diff --git a/block/vhdx.c b/block/vhdx.c index 356ec4c455..410c6f9610 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -25,6 +25,7 @@ #include "qemu/crc32c.h" #include "qemu/bswap.h" #include "qemu/error-report.h" +#include "qemu/memalign.h" #include "vhdx.h" #include "migration/blocker.h" #include "qemu/uuid.h" diff --git a/block/vmdk.c b/block/vmdk.c index 0dfab6e941..37c0946066 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -33,6 +33,7 @@ #include "qemu/module.h" #include "qemu/option.h" #include "qemu/bswap.h" +#include "qemu/memalign.h" #include "migration/blocker.h" #include "qemu/cutils.h" #include <zlib.h> diff --git a/block/vpc.c b/block/vpc.c index 297a26262a..4d8f16e199 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -33,6 +33,7 @@ #include "migration/blocker.h" #include "qemu/bswap.h" #include "qemu/uuid.h" +#include "qemu/memalign.h" #include "qapi/qmp/qdict.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qapi-visit-block-core.h" diff --git a/block/win32-aio.c b/block/win32-aio.c index c57e10c997..aadc7b1bc3 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -29,6 +29,7 @@ #include "block/raw-aio.h" #include "qemu/event_notifier.h" #include "qemu/iov.h" +#include "qemu/memalign.h" #include <windows.h> #include <winioctl.h> @@ -1659,8 +1659,8 @@ fi # vhost interdependencies and host support # vhost backends -if test "$vhost_user" = "yes" && test "$linux" != "yes"; then - error_exit "vhost-user is only available on Linux" +if test "$vhost_user" = "yes" && test "$mingw32" = "yes"; then + error_exit "vhost-user is not available on Windows" fi test "$vhost_vdpa" = "" && vhost_vdpa=$linux if test "$vhost_vdpa" = "yes" && test "$linux" != "yes"; then @@ -35,10 +35,12 @@ #include "sysemu/tcg.h" #include "sysemu/kvm.h" #include "sysemu/replay.h" +#include "exec/exec-all.h" #include "exec/translate-all.h" #include "exec/log.h" #include "hw/core/accel-cpu.h" #include "trace/trace-root.h" +#include "qemu/accel.h" uintptr_t qemu_host_page_size; intptr_t qemu_host_page_mask; @@ -415,11 +417,11 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...) /* physical memory access (slow version, mainly for debug) */ #if defined(CONFIG_USER_ONLY) -int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, - void *ptr, target_ulong len, bool is_write) +int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, + void *ptr, size_t len, bool is_write) { int flags; - target_ulong l, page; + vaddr l, page; void * p; uint8_t *buf = ptr; diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 85773db631..cf02ef6821 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -324,6 +324,14 @@ machine is hardly emulated at all (e.g. neither the LCD nor the USB part had been implemented), so there is not much value added by this board. Use the ``ref405ep`` machine instead. +``pc-i440fx-1.4`` up to ``pc-i440fx-1.7`` (since 7.0) +''''''''''''''''''''''''''''''''''''''''''''''''''''' + +These old machine types are quite neglected nowadays and thus might have +various pitfalls with regards to live migration. Use a newer machine type +instead. + + Backend options --------------- diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst index edc3ad84a3..4dbc84fd00 100644 --- a/docs/interop/vhost-user.rst +++ b/docs/interop/vhost-user.rst @@ -38,6 +38,26 @@ conventions <backend_conventions>`. *Master* and *slave* can be either a client (i.e. connecting) or server (listening) in the socket communication. +Support for platforms other than Linux +-------------------------------------- + +While vhost-user was initially developed targeting Linux, nowadays it +is supported on any platform that provides the following features: + +- A way for requesting shared memory represented by a file descriptor + so it can be passed over a UNIX domain socket and then mapped by the + other process. + +- AF_UNIX sockets with SCM_RIGHTS, so QEMU and the other process can + exchange messages through it, including ancillary data when needed. + +- Either eventfd or pipe/pipe2. On platforms where eventfd is not + available, QEMU will automatically fall back to pipe2 or, as a last + resort, pipe. Each file descriptor will be used for receiving or + sending events by reading or writing (respectively) an 8-byte value + to the corresponding it. The 8-value itself has no meaning and + should not be interpreted. + Message Specification ===================== diff --git a/docs/pcie_sriov.txt b/docs/pcie_sriov.txt new file mode 100644 index 0000000000..f5e891e1d4 --- /dev/null +++ b/docs/pcie_sriov.txt @@ -0,0 +1,115 @@ +PCI SR/IOV EMULATION SUPPORT +============================ + +Description +=========== +SR/IOV (Single Root I/O Virtualization) is an optional extended capability +of a PCI Express device. It allows a single physical function (PF) to appear as multiple +virtual functions (VFs) for the main purpose of eliminating software +overhead in I/O from virtual machines. + +Qemu now implements the basic common functionality to enable an emulated device +to support SR/IOV. Yet no fully implemented devices exists in Qemu, but a +proof-of-concept hack of the Intel igb can be found here: + +git://github.com/knuto/qemu.git sriov_patches_v5 + +Implementation +============== +Implementing emulation of an SR/IOV capable device typically consists of +implementing support for two types of device classes; the "normal" physical device +(PF) and the virtual device (VF). From Qemu's perspective, the VFs are just +like other devices, except that some of their properties are derived from +the PF. + +A virtual function is different from a physical function in that the BAR +space for all VFs are defined by the BAR registers in the PFs SR/IOV +capability. All VFs have the same BARs and BAR sizes. + +Accesses to these virtual BARs then is computed as + + <VF BAR start> + <VF number> * <BAR sz> + <offset> + +From our emulation perspective this means that there is a separate call for +setting up a BAR for a VF. + +1) To enable SR/IOV support in the PF, it must be a PCI Express device so + you would need to add a PCI Express capability in the normal PCI + capability list. You might also want to add an ARI (Alternative + Routing-ID Interpretation) capability to indicate that your device + supports functions beyond it's "own" function space (0-7), + which is necessary to support more than 7 functions, or + if functions extends beyond offset 7 because they are placed at an + offset > 1 or have stride > 1. + + ... + #include "hw/pci/pcie.h" + #include "hw/pci/pcie_sriov.h" + + pci_your_pf_dev_realize( ... ) + { + ... + int ret = pcie_endpoint_cap_init(d, 0x70); + ... + pcie_ari_init(d, 0x100, 1); + ... + + /* Add and initialize the SR/IOV capability */ + pcie_sriov_pf_init(d, 0x200, "your_virtual_dev", + vf_devid, initial_vfs, total_vfs, + fun_offset, stride); + + /* Set up individual VF BARs (parameters as for normal BARs) */ + pcie_sriov_pf_init_vf_bar( ... ) + ... + } + + For cleanup, you simply call: + + pcie_sriov_pf_exit(device); + + which will delete all the virtual functions and associated resources. + +2) Similarly in the implementation of the virtual function, you need to + make it a PCI Express device and add a similar set of capabilities + except for the SR/IOV capability. Then you need to set up the VF BARs as + subregions of the PFs SR/IOV VF BARs by calling + pcie_sriov_vf_register_bar() instead of the normal pci_register_bar() call: + + pci_your_vf_dev_realize( ... ) + { + ... + int ret = pcie_endpoint_cap_init(d, 0x60); + ... + pcie_ari_init(d, 0x100, 1); + ... + memory_region_init(mr, ... ) + pcie_sriov_vf_register_bar(d, bar_nr, mr); + ... + } + +Testing on Linux guest +====================== +The easiest is if your device driver supports sysfs based SR/IOV +enabling. Support for this was added in kernel v.3.8, so not all drivers +support it yet. + +To enable 4 VFs for a device at 01:00.0: + + modprobe yourdriver + echo 4 > /sys/bus/pci/devices/0000:01:00.0/sriov_numvfs + +You should now see 4 VFs with lspci. +To turn SR/IOV off again - the standard requires you to turn it off before you can enable +another VF count, and the emulation enforces this: + + echo 0 > /sys/bus/pci/devices/0000:01:00.0/sriov_numvfs + +Older drivers typically provide a max_vfs module parameter +to enable it at load time: + + modprobe yourdriver max_vfs=4 + +To disable the VFs again then, you simply have to unload the driver: + + rmmod yourdriver diff --git a/docs/specs/acpi_erst.rst b/docs/specs/acpi_erst.rst new file mode 100644 index 0000000000..a8a9d22d25 --- /dev/null +++ b/docs/specs/acpi_erst.rst @@ -0,0 +1,200 @@ +ACPI ERST DEVICE +================ + +The ACPI ERST device is utilized to support the ACPI Error Record +Serialization Table, ERST, functionality. This feature is designed for +storing error records in persistent storage for future reference +and/or debugging. + +The ACPI specification[1], in Chapter "ACPI Platform Error Interfaces +(APEI)", and specifically subsection "Error Serialization", outlines a +method for storing error records into persistent storage. + +The format of error records is described in the UEFI specification[2], +in Appendix N "Common Platform Error Record". + +While the ACPI specification allows for an NVRAM "mode" (see +GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES) where non-volatile RAM is +directly exposed for direct access by the OS/guest, this device +implements the non-NVRAM "mode". This non-NVRAM "mode" is what is +implemented by most BIOS (since flash memory requires programming +operations in order to update its contents). Furthermore, as of the +time of this writing, Linux only supports the non-NVRAM "mode". + + +Background/Motivation +--------------------- + +Linux uses the persistent storage filesystem, pstore, to record +information (eg. dmesg tail) upon panics and shutdowns. Pstore is +independent of, and runs before, kdump. In certain scenarios (ie. +hosts/guests with root filesystems on NFS/iSCSI where networking +software and/or hardware fails, and thus kdump fails), pstore may +contain information available for post-mortem debugging. + +Two common storage backends for the pstore filesystem are ACPI ERST +and UEFI. Most BIOS implement ACPI ERST. UEFI is not utilized in all +guests. With QEMU supporting ACPI ERST, it becomes a viable pstore +storage backend for virtual machines (as it is now for bare metal +machines). + +Enabling support for ACPI ERST facilitates a consistent method to +capture kernel panic information in a wide range of guests: from +resource-constrained microvms to very large guests, and in particular, +in direct-boot environments (which would lack UEFI run-time services). + +Note that Microsoft Windows also utilizes the ACPI ERST for certain +crash information, if available[3]. + + +Configuration|Usage +------------------- + +To use ACPI ERST, a memory-backend-file object and acpi-erst device +can be created, for example: + + qemu ... + -object memory-backend-file,id=erstnvram,mem-path=acpi-erst.backing,size=0x10000,share=on \ + -device acpi-erst,memdev=erstnvram + +For proper operation, the ACPI ERST device needs a memory-backend-file +object with the following parameters: + + - id: The id of the memory-backend-file object is used to associate + this memory with the acpi-erst device. + - size: The size of the ACPI ERST backing storage. This parameter is + required. + - mem-path: The location of the ACPI ERST backing storage file. This + parameter is also required. + - share: The share=on parameter is required so that updates to the + ERST backing store are written to the file. + +and ERST device: + + - memdev: Is the object id of the memory-backend-file. + - record_size: Specifies the size of the records (or slots) in the + backend storage. Must be a power of two value greater than or + equal to 4096 (PAGE_SIZE). + + +PCI Interface +------------- + +The ERST device is a PCI device with two BARs, one for accessing the +programming registers, and the other for accessing the record exchange +buffer. + +BAR0 contains the programming interface consisting of ACTION and VALUE +64-bit registers. All ERST actions/operations/side effects happen on +the write to the ACTION, by design. Any data needed by the action must +be placed into VALUE prior to writing ACTION. Reading the VALUE +simply returns the register contents, which can be updated by a +previous ACTION. + +BAR1 contains the 8KiB record exchange buffer, which is the +implemented maximum record size. + + +Backend Storage Format +---------------------- + +The backend storage is divided into fixed size "slots", 8KiB in +length, with each slot storing a single record. Not all slots need to +be occupied, and they need not be occupied in a contiguous fashion. +The ability to clear/erase specific records allows for the formation +of unoccupied slots. + +Slot 0 contains a backend storage header that identifies the contents +as ERST and also facilitates efficient access to the records. +Depending upon the size of the backend storage, additional slots will +be designated to be a part of the slot 0 header. For example, at 8KiB, +the slot 0 header can accomodate 1021 records. Thus a storage size +of 8MiB (8KiB * 1024) requires an additional slot for use by the +header. In this scenario, slot 0 and slot 1 form the backend storage +header, and records can be stored starting at slot 2. + +Below is an example layout of the backend storage format (for storage +size less than 8MiB). The size of the storage is a multiple of 8KiB, +and contains N number of slots to store records. The example below +shows two records (in CPER format) in the backend storage, while the +remaining slots are empty/available. + +:: + + Slot Record + <------------------ 8KiB --------------------> + +--------------------------------------------+ + 0 | storage header | + +--------------------------------------------+ + 1 | empty/available | + +--------------------------------------------+ + 2 | CPER | + +--------------------------------------------+ + 3 | CPER | + +--------------------------------------------+ + ... | | + +--------------------------------------------+ + N | empty/available | + +--------------------------------------------+ + +The storage header consists of some basic information and an array +of CPER record_id's to efficiently access records in the backend +storage. + +All fields in the header are stored in little endian format. + +:: + + +--------------------------------------------+ + | magic | 0x0000 + +--------------------------------------------+ + | record_offset | record_size | 0x0008 + +--------------------------------------------+ + | record_count | reserved | version | 0x0010 + +--------------------------------------------+ + | record_id[0] | 0x0018 + +--------------------------------------------+ + | record_id[1] | 0x0020 + +--------------------------------------------+ + | record_id[...] | + +--------------------------------------------+ + | record_id[N] | 0x1FF8 + +--------------------------------------------+ + +The 'magic' field contains the value 0x524F545354535245. + +The 'record_size' field contains the value 0x2000, 8KiB. + +The 'record_offset' field points to the first record_id in the array, +0x0018. + +The 'version' field contains 0x0100, the first version. + +The 'record_count' field contains the number of valid records in the +backend storage. + +The 'record_id' array fields are the 64-bit record identifiers of the +CPER record in the corresponding slot. Stated differently, the +location of a CPER record_id in the record_id[] array provides the +slot index for the corresponding record in the backend storage. + +Note that, for example, with a backend storage less than 8MiB, slot 0 +contains the header, so the record_id[0] will never contain a valid +CPER record_id. Instead slot 1 is the first available slot and thus +record_id_[1] may contain a CPER. + +A 'record_id' of all 0s or all 1s indicates an invalid record (ie. the +slot is available). + + +References +---------- + +[1] "Advanced Configuration and Power Interface Specification", + version 4.0, June 2009. + +[2] "Unified Extensible Firmware Interface Specification", + version 2.1, October 2008. + +[3] "Windows Hardware Error Architecture", specfically + "Error Record Persistence Mechanism". diff --git a/docs/specs/index.rst b/docs/specs/index.rst index 2a35700fb3..e10684bf53 100644 --- a/docs/specs/index.rst +++ b/docs/specs/index.rst @@ -18,4 +18,5 @@ guest hardware that is specific to QEMU. acpi_mem_hotplug acpi_pci_hotplug acpi_nvdimm + acpi_erst sev-guest-firmware diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt index 5e407a6f32..dd6859d039 100644 --- a/docs/specs/pci-ids.txt +++ b/docs/specs/pci-ids.txt @@ -65,6 +65,7 @@ PCI devices (other than virtio): 1b36:000f mdpy (mdev sample device), linux/samples/vfio-mdev/mdpy.c 1b36:0010 PCIe NVMe device (-device nvme) 1b36:0011 PCI PVPanic device (-device pvpanic-pci) +1b36:0012 PCI ACPI ERST device (-device acpi-erst) All these devices are documented in docs/specs. diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index 8fd89f0447..4997677460 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -16,10 +16,17 @@ #include <dirent.h> #include <utime.h> -#include <sys/vfs.h> #include "qemu-fsdev-throttle.h" #include "p9array.h" +#ifdef CONFIG_LINUX +# include <sys/vfs.h> +#endif +#ifdef CONFIG_DARWIN +# include <sys/param.h> +# include <sys/mount.h> +#endif + #define SM_LOCAL_MODE_BITS 0600 #define SM_LOCAL_DIR_MODE_BITS 0700 diff --git a/fsdev/meson.build b/fsdev/meson.build index adf57cc43e..b632b66348 100644 --- a/fsdev/meson.build +++ b/fsdev/meson.build @@ -7,6 +7,7 @@ fsdev_ss.add(when: ['CONFIG_FSDEV_9P'], if_true: files( 'qemu-fsdev.c', ), if_false: files('qemu-fsdev-dummy.c')) softmmu_ss.add_all(when: 'CONFIG_LINUX', if_true: fsdev_ss) +softmmu_ss.add_all(when: 'CONFIG_DARWIN', if_true: fsdev_ss) if have_virtfs_proxy_helper executable('virtfs-proxy-helper', diff --git a/fsdev/p9array.h b/fsdev/p9array.h index 6aa25327ca..90e83a7c7b 100644 --- a/fsdev/p9array.h +++ b/fsdev/p9array.h @@ -81,11 +81,11 @@ */ /** - * Declares an array type for the passed @a scalar_type. + * P9ARRAY_DECLARE_TYPE() - Declares an array type for the passed @scalar_type. * - * This is typically used from a shared header file. + * @scalar_type: type of the individual array elements * - * @param scalar_type - type of the individual array elements + * This is typically used from a shared header file. */ #define P9ARRAY_DECLARE_TYPE(scalar_type) \ typedef struct P9Array##scalar_type { \ @@ -97,14 +97,14 @@ void p9array_auto_free_##scalar_type(scalar_type **auto_var); \ /** - * Defines an array type for the passed @a scalar_type and appropriate - * @a scalar_cleanup_func. + * P9ARRAY_DEFINE_TYPE() - Defines an array type for the passed @scalar_type + * and appropriate @scalar_cleanup_func. * - * This is typically used from a C unit file. + * @scalar_type: type of the individual array elements + * @scalar_cleanup_func: appropriate function to free memory dynamically + * allocated by individual array elements before * - * @param scalar_type - type of the individual array elements - * @param scalar_cleanup_func - appropriate function to free memory dynamically - * allocated by individual array elements before + * This is typically used from a C unit file. */ #define P9ARRAY_DEFINE_TYPE(scalar_type, scalar_cleanup_func) \ void p9array_new_##scalar_type(scalar_type **auto_var, size_t len) \ @@ -132,23 +132,27 @@ } \ /** + * P9ARRAY_REF() - Declare a reference variable for an array. + * + * @scalar_type: type of the individual array elements + * * Used to declare a reference variable (unique pointer) for an array. After * leaving the scope of the reference variable, the associated array is * automatically freed. - * - * @param scalar_type - type of the individual array elements */ #define P9ARRAY_REF(scalar_type) \ __attribute((__cleanup__(p9array_auto_free_##scalar_type))) scalar_type* /** - * Allocates a new array of passed @a scalar_type with @a len number of array - * elements and assigns the created array to the reference variable - * @a auto_var. + * P9ARRAY_NEW() - Allocate a new array. * - * @param scalar_type - type of the individual array elements - * @param auto_var - destination reference variable - * @param len - amount of array elements to be allocated immediately + * @scalar_type: type of the individual array elements + * @auto_var: destination reference variable + * @len: amount of array elements to be allocated immediately + * + * Allocates a new array of passed @scalar_type with @len number of array + * elements and assigns the created array to the reference variable + * @auto_var. */ #define P9ARRAY_NEW(scalar_type, auto_var, len) \ QEMU_BUILD_BUG_MSG( \ diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 210d9e7705..d42ce6d8b8 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -32,10 +32,12 @@ #include "qemu/error-report.h" #include "qemu/option.h" #include <libgen.h> +#ifdef CONFIG_LINUX #include <linux/fs.h> #ifdef CONFIG_LINUX_MAGIC_H #include <linux/magic.h> #endif +#endif #include <sys/ioctl.h> #ifndef XFS_SUPER_MAGIC @@ -560,6 +562,15 @@ again: if (!entry) { return NULL; } +#ifdef CONFIG_DARWIN + int off; + off = telldir(fs->dir.stream); + /* If telldir fails, fail the entire readdir call */ + if (off < 0) { + return NULL; + } + entry->d_seekoff = off; +#endif if (ctx->export_flags & V9FS_SM_MAPPED) { entry->d_type = DT_UNKNOWN; @@ -671,7 +682,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, if (fs_ctx->export_flags & V9FS_SM_MAPPED || fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - err = mknodat(dirfd, name, fs_ctx->fmode | S_IFREG, 0); + err = qemu_mknodat(dirfd, name, fs_ctx->fmode | S_IFREG, 0); if (err == -1) { goto out; } @@ -686,7 +697,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, } } else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH || fs_ctx->export_flags & V9FS_SM_NONE) { - err = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev); + err = qemu_mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev); if (err == -1) { goto out; } @@ -779,16 +790,20 @@ static int local_fstat(FsContext *fs_ctx, int fid_type, mode_t tmp_mode; dev_t tmp_dev; - if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { + if (qemu_fgetxattr(fd, "user.virtfs.uid", + &tmp_uid, sizeof(uid_t)) > 0) { stbuf->st_uid = le32_to_cpu(tmp_uid); } - if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { + if (qemu_fgetxattr(fd, "user.virtfs.gid", + &tmp_gid, sizeof(gid_t)) > 0) { stbuf->st_gid = le32_to_cpu(tmp_gid); } - if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) { + if (qemu_fgetxattr(fd, "user.virtfs.mode", + &tmp_mode, sizeof(mode_t)) > 0) { stbuf->st_mode = le32_to_cpu(tmp_mode); } - if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { + if (qemu_fgetxattr(fd, "user.virtfs.rdev", + &tmp_dev, sizeof(dev_t)) > 0) { stbuf->st_rdev = le64_to_cpu(tmp_dev); } } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index 09bd9f1464..8b4b5cf7dc 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -123,10 +123,16 @@ static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs) stfs->f_bavail = prstfs->f_bavail; stfs->f_files = prstfs->f_files; stfs->f_ffree = prstfs->f_ffree; +#ifdef CONFIG_DARWIN + /* f_namelen and f_frsize do not exist on Darwin */ + stfs->f_fsid.val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU; + stfs->f_fsid.val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU; +#else stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU; stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU; stfs->f_namelen = prstfs->f_namelen; stfs->f_frsize = prstfs->f_frsize; +#endif } /* Converts proxy_stat structure to VFS stat structure */ @@ -143,12 +149,24 @@ static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat) stbuf->st_size = prstat->st_size; stbuf->st_blksize = prstat->st_blksize; stbuf->st_blocks = prstat->st_blocks; + stbuf->st_atime = prstat->st_atim_sec; + stbuf->st_mtime = prstat->st_mtim_sec; + stbuf->st_ctime = prstat->st_ctim_sec; +#ifdef CONFIG_DARWIN + stbuf->st_atimespec.tv_sec = prstat->st_atim_sec; + stbuf->st_mtimespec.tv_sec = prstat->st_mtim_sec; + stbuf->st_ctimespec.tv_sec = prstat->st_ctim_sec; + stbuf->st_atimespec.tv_nsec = prstat->st_atim_nsec; + stbuf->st_mtimespec.tv_nsec = prstat->st_mtim_nsec; + stbuf->st_ctimespec.tv_nsec = prstat->st_ctim_nsec; +#else stbuf->st_atim.tv_sec = prstat->st_atim_sec; + stbuf->st_mtim.tv_sec = prstat->st_mtim_sec; + stbuf->st_ctim.tv_sec = prstat->st_ctim_sec; stbuf->st_atim.tv_nsec = prstat->st_atim_nsec; - stbuf->st_mtime = prstat->st_mtim_sec; stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec; - stbuf->st_ctime = prstat->st_ctim_sec; stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec; +#endif } /* @@ -688,7 +706,21 @@ static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs) static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs) { - return readdir(fs->dir.stream); + struct dirent *entry; + entry = readdir(fs->dir.stream); +#ifdef CONFIG_DARWIN + if (!entry) { + return NULL; + } + int td; + td = telldir(fs->dir.stream); + /* If telldir fails, fail the entire readdir call */ + if (td < 0) { + return NULL; + } + entry->d_seekoff = td; +#endif + return entry; } static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index 7a7cd5c5ba..b3080e415b 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -234,7 +234,11 @@ static void synth_direntry(V9fsSynthNode *node, offsetof(struct dirent, d_name) + sz); memcpy(entry->d_name, node->name, sz); entry->d_ino = node->attr->inode; +#ifdef CONFIG_DARWIN + entry->d_seekoff = off + 1; +#else entry->d_off = off + 1; +#endif } static struct dirent *synth_get_dentry(V9fsSynthNode *dir, @@ -439,7 +443,9 @@ static int synth_statfs(FsContext *s, V9fsPath *fs_path, stbuf->f_bsize = 512; stbuf->f_blocks = 0; stbuf->f_files = synth_node_count; +#ifndef CONFIG_DARWIN stbuf->f_namelen = NAME_MAX; +#endif return 0; } diff --git a/hw/9pfs/9p-util-darwin.c b/hw/9pfs/9p-util-darwin.c new file mode 100644 index 0000000000..bec0253474 --- /dev/null +++ b/hw/9pfs/9p-util-darwin.c @@ -0,0 +1,97 @@ +/* + * 9p utilities (Darwin Implementation) + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/xattr.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "9p-util.h" + +ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name, + void *value, size_t size) +{ + int ret; + int fd = openat_file(dirfd, filename, + O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0); + if (fd == -1) { + return -1; + } + ret = fgetxattr(fd, name, value, size, 0, 0); + close_preserve_errno(fd); + return ret; +} + +ssize_t flistxattrat_nofollow(int dirfd, const char *filename, + char *list, size_t size) +{ + int ret; + int fd = openat_file(dirfd, filename, + O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0); + if (fd == -1) { + return -1; + } + ret = flistxattr(fd, list, size, 0); + close_preserve_errno(fd); + return ret; +} + +ssize_t fremovexattrat_nofollow(int dirfd, const char *filename, + const char *name) +{ + int ret; + int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0); + if (fd == -1) { + return -1; + } + ret = fremovexattr(fd, name, 0); + close_preserve_errno(fd); + return ret; +} + +int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name, + void *value, size_t size, int flags) +{ + int ret; + int fd = openat_file(dirfd, filename, O_PATH_9P_UTIL | O_NOFOLLOW, 0); + if (fd == -1) { + return -1; + } + ret = fsetxattr(fd, name, value, size, 0, flags); + close_preserve_errno(fd); + return ret; +} + +/* + * As long as mknodat is not available on macOS, this workaround + * using pthread_fchdir_np is needed. + * + * Radar filed with Apple for implementing mknodat: + * rdar://FB9862426 (https://openradar.appspot.com/FB9862426) + */ +#if defined CONFIG_PTHREAD_FCHDIR_NP + +int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev) +{ + int preserved_errno, err; + if (!pthread_fchdir_np) { + error_report_once("pthread_fchdir_np() not available on this version of macOS"); + return -ENOTSUP; + } + if (pthread_fchdir_np(dirfd) < 0) { + return -1; + } + err = mknod(filename, mode, dev); + preserved_errno = errno; + /* Stop using the thread-local cwd */ + pthread_fchdir_np(-1); + if (err < 0) { + errno = preserved_errno; + } + return err; +} + +#endif diff --git a/hw/9pfs/9p-util.c b/hw/9pfs/9p-util-linux.c index 3221d9b498..db451b0784 100644 --- a/hw/9pfs/9p-util.c +++ b/hw/9pfs/9p-util-linux.c @@ -1,5 +1,5 @@ /* - * 9p utilities + * 9p utilities (Linux Implementation) * * Copyright IBM, Corp. 2017 * @@ -61,4 +61,10 @@ int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name, ret = lsetxattr(proc_path, name, value, size, flags); g_free(proc_path); return ret; + +} + +int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev) +{ + return mknodat(dirfd, filename, mode, dev); } diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index 546f46dc7d..97e681e167 100644 --- a/hw/9pfs/9p-util.h +++ b/hw/9pfs/9p-util.h @@ -19,6 +19,23 @@ #define O_PATH_9P_UTIL 0 #endif +#ifdef CONFIG_DARWIN +#define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0) +#define qemu_lgetxattr(...) getxattr(__VA_ARGS__, 0, XATTR_NOFOLLOW) +#define qemu_llistxattr(...) listxattr(__VA_ARGS__, XATTR_NOFOLLOW) +#define qemu_lremovexattr(...) removexattr(__VA_ARGS__, XATTR_NOFOLLOW) +static inline int qemu_lsetxattr(const char *path, const char *name, + const void *value, size_t size, int flags) { + return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW); +} +#else +#define qemu_fgetxattr fgetxattr +#define qemu_lgetxattr lgetxattr +#define qemu_llistxattr llistxattr +#define qemu_lremovexattr lremovexattr +#define qemu_lsetxattr lsetxattr +#endif + static inline void close_preserve_errno(int fd) { int serrno = errno; @@ -37,10 +54,13 @@ static inline int openat_file(int dirfd, const char *name, int flags, { int fd, serrno, ret; +#ifndef CONFIG_DARWIN again: +#endif fd = openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK, mode); if (fd == -1) { +#ifndef CONFIG_DARWIN if (errno == EPERM && (flags & O_NOATIME)) { /* * The client passed O_NOATIME but we lack permissions to honor it. @@ -53,6 +73,7 @@ again: flags &= ~O_NOATIME; goto again; } +#endif return -1; } @@ -78,4 +99,61 @@ ssize_t flistxattrat_nofollow(int dirfd, const char *filename, ssize_t fremovexattrat_nofollow(int dirfd, const char *filename, const char *name); +/* + * Darwin has d_seekoff, which appears to function similarly to d_off. + * However, it does not appear to be supported on all file systems, + * so ensure it is manually injected earlier and call here when + * needed. + */ +static inline off_t qemu_dirent_off(struct dirent *dent) +{ +#ifdef CONFIG_DARWIN + return dent->d_seekoff; +#else + return dent->d_off; +#endif +} + +/** + * qemu_dirent_dup() - Duplicate directory entry @dent. + * + * @dent: original directory entry to be duplicated + * Return: duplicated directory entry which should be freed with g_free() + * + * It is highly recommended to use this function instead of open coding + * duplication of dirent objects, because the actual struct dirent + * size may be bigger or shorter than sizeof(struct dirent) and correct + * handling is platform specific (see gitlab issue #841). + */ +static inline struct dirent *qemu_dirent_dup(struct dirent *dent) +{ + size_t sz = 0; +#if defined _DIRENT_HAVE_D_RECLEN + /* Avoid use of strlen() if platform supports d_reclen. */ + sz = dent->d_reclen; +#endif + /* + * Test sz for zero even if d_reclen is available + * because some drivers may set d_reclen to zero. + */ + if (sz == 0) { + /* Fallback to the most portable way. */ + sz = offsetof(struct dirent, d_name) + + strlen(dent->d_name) + 1; + } + return g_memdup(dent, sz); +} + +/* + * As long as mknodat is not available on macOS, this workaround + * using pthread_fchdir_np is needed. qemu_mknodat is defined in + * os-posix.c. pthread_fchdir_np is weakly linked here as a guard + * in case it disappears in future macOS versions, because it is + * is a private API. + */ +#if defined CONFIG_DARWIN && defined CONFIG_PTHREAD_FCHDIR_NP +int pthread_fchdir_np(int fd) __attribute__((weak_import)); +#endif +int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev); + #endif diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 15b3f4d385..a6d6b3f835 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -27,12 +27,17 @@ #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" #include "9p-xattr.h" +#include "9p-util.h" #include "coth.h" #include "trace.h" #include "migration/blocker.h" #include "qemu/xxhash.h" #include <math.h> +#ifdef CONFIG_LINUX #include <linux/limits.h> +#else +#include <limits.h> +#endif int open_fd_hw; int total_open_fd; @@ -133,11 +138,20 @@ static int dotl_to_open_flags(int flags) { P9_DOTL_NONBLOCK, O_NONBLOCK } , { P9_DOTL_DSYNC, O_DSYNC }, { P9_DOTL_FASYNC, FASYNC }, +#ifndef CONFIG_DARWIN + { P9_DOTL_NOATIME, O_NOATIME }, + /* + * On Darwin, we could map to F_NOCACHE, which is + * similar, but doesn't quite have the same + * semantics. However, we don't support O_DIRECT + * even on linux at the moment, so we just ignore + * it here. + */ { P9_DOTL_DIRECT, O_DIRECT }, +#endif { P9_DOTL_LARGEFILE, O_LARGEFILE }, { P9_DOTL_DIRECTORY, O_DIRECTORY }, { P9_DOTL_NOFOLLOW, O_NOFOLLOW }, - { P9_DOTL_NOATIME, O_NOATIME }, { P9_DOTL_SYNC, O_SYNC }, }; @@ -166,10 +180,12 @@ static int get_dotl_openflags(V9fsState *s, int oflags) */ flags = dotl_to_open_flags(oflags); flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT); +#ifndef CONFIG_DARWIN /* * Ignore direct disk access hint until the server supports it. */ flags &= ~O_DIRECT; +#endif return flags; } @@ -612,8 +628,8 @@ static inline uint64_t mirror64bit(uint64_t value) ((uint64_t)mirror8bit((value >> 56) & 0xff)); } -/** - * @brief Parameter k for the Exponential Golomb algorihm to be used. +/* + * Parameter k for the Exponential Golomb algorihm to be used. * * The smaller this value, the smaller the minimum bit count for the Exp. * Golomb generated affixes will be (at lowest index) however for the @@ -626,28 +642,30 @@ static inline uint64_t mirror64bit(uint64_t value) * should be small, for a large amount of devices k might be increased * instead. The default of k=0 should be fine for most users though. * - * @b IMPORTANT: In case this ever becomes a runtime parameter; the value of + * IMPORTANT: In case this ever becomes a runtime parameter; the value of * k should not change as long as guest is still running! Because that would * cause completely different inode numbers to be generated on guest. */ #define EXP_GOLOMB_K 0 /** - * @brief Exponential Golomb algorithm for arbitrary k (including k=0). + * expGolombEncode() - Exponential Golomb algorithm for arbitrary k + * (including k=0). + * + * @n: natural number (or index) of the prefix to be generated + * (1, 2, 3, ...) + * @k: parameter k of Exp. Golomb algorithm to be used + * (see comment on EXP_GOLOMB_K macro for details about k) + * Return: prefix for given @n and @k * - * The Exponential Golomb algorithm generates @b prefixes (@b not suffixes!) + * The Exponential Golomb algorithm generates prefixes (NOT suffixes!) * with growing length and with the mathematical property of being * "prefix-free". The latter means the generated prefixes can be prepended * in front of arbitrary numbers and the resulting concatenated numbers are * guaranteed to be always unique. * * This is a minor adjustment to the original Exp. Golomb algorithm in the - * sense that lowest allowed index (@param n) starts with 1, not with zero. - * - * @param n - natural number (or index) of the prefix to be generated - * (1, 2, 3, ...) - * @param k - parameter k of Exp. Golomb algorithm to be used - * (see comment on EXP_GOLOMB_K macro for details about k) + * sense that lowest allowed index (@n) starts with 1, not with zero. */ static VariLenAffix expGolombEncode(uint64_t n, int k) { @@ -661,7 +679,9 @@ static VariLenAffix expGolombEncode(uint64_t n, int k) } /** - * @brief Converts a suffix into a prefix, or a prefix into a suffix. + * invertAffix() - Converts a suffix into a prefix, or a prefix into a suffix. + * @affix: either suffix or prefix to be inverted + * Return: inversion of passed @affix * * Simply mirror all bits of the affix value, for the purpose to preserve * respectively the mathematical "prefix-free" or "suffix-free" property @@ -685,16 +705,16 @@ static VariLenAffix invertAffix(const VariLenAffix *affix) } /** - * @brief Generates suffix numbers with "suffix-free" property. + * affixForIndex() - Generates suffix numbers with "suffix-free" property. + * @index: natural number (or index) of the suffix to be generated + * (1, 2, 3, ...) + * Return: Suffix suitable to assemble unique number. * * This is just a wrapper function on top of the Exp. Golomb algorithm. * * Since the Exp. Golomb algorithm generates prefixes, but we need suffixes, * this function converts the Exp. Golomb prefixes into appropriate suffixes * which are still suitable for generating unique numbers. - * - * @param n - natural number (or index) of the suffix to be generated - * (1, 2, 3, ...) */ static VariLenAffix affixForIndex(uint64_t index) { @@ -794,8 +814,8 @@ static int qid_inode_prefix_hash_bits(V9fsPDU *pdu, dev_t dev) return val->prefix_bits; } -/** - * @brief Slow / full mapping host inode nr -> guest inode nr. +/* + * Slow / full mapping host inode nr -> guest inode nr. * * This function performs a slower and much more costly remapping of an * original file inode number on host to an appropriate different inode @@ -807,7 +827,7 @@ static int qid_inode_prefix_hash_bits(V9fsPDU *pdu, dev_t dev) * qid_path_suffixmap() failed. In practice this slow / full mapping is not * expected ever to be used at all though. * - * @see qid_path_suffixmap() for details + * See qid_path_suffixmap() for details * */ static int qid_path_fullmap(V9fsPDU *pdu, const struct stat *stbuf, @@ -848,8 +868,8 @@ static int qid_path_fullmap(V9fsPDU *pdu, const struct stat *stbuf, return 0; } -/** - * @brief Quick mapping host inode nr -> guest inode nr. +/* + * Quick mapping host inode nr -> guest inode nr. * * This function performs quick remapping of an original file inode number * on host to an appropriate different inode number on guest. This remapping @@ -1265,12 +1285,15 @@ static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *path, /** - * Convert host filesystem's block size into an appropriate block size for - * 9p client (guest OS side). The value returned suggests an "optimum" block - * size for 9p I/O, i.e. to maximize performance. + * blksize_to_iounit() - Block size exposed to 9p client. + * Return: block size * * @pdu: 9p client request * @blksize: host filesystem's block size + * + * Convert host filesystem's block size into an appropriate block size for + * 9p client (guest OS side). The value returned suggests an "optimum" block + * size for 9p I/O, i.e. to maximize performance. */ static int32_t blksize_to_iounit(const V9fsPDU *pdu, int32_t blksize) { @@ -1309,11 +1332,17 @@ static int stat_to_v9stat_dotl(V9fsPDU *pdu, const struct stat *stbuf, v9lstat->st_blksize = stat_to_iounit(pdu, stbuf); v9lstat->st_blocks = stbuf->st_blocks; v9lstat->st_atime_sec = stbuf->st_atime; - v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec; v9lstat->st_mtime_sec = stbuf->st_mtime; - v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec; v9lstat->st_ctime_sec = stbuf->st_ctime; +#ifdef CONFIG_DARWIN + v9lstat->st_atime_nsec = stbuf->st_atimespec.tv_nsec; + v9lstat->st_mtime_nsec = stbuf->st_mtimespec.tv_nsec; + v9lstat->st_ctime_nsec = stbuf->st_ctimespec.tv_nsec; +#else + v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec; + v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec; v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec; +#endif /* Currently we only support BASIC fields in stat */ v9lstat->st_result_mask = P9_STATS_BASIC; @@ -2271,7 +2300,7 @@ static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu, count += len; v9fs_stat_free(&v9stat); v9fs_path_free(&path); - saved_dir_pos = dent->d_off; + saved_dir_pos = qemu_dirent_off(dent); } v9fs_readdir_unlock(&fidp->fs.dir); @@ -2376,10 +2405,11 @@ out_nofid: } /** - * Returns size required in Rreaddir response for the passed dirent @p name. + * v9fs_readdir_response_size() - Returns size required in Rreaddir response + * for the passed dirent @name. * - * @param name - directory entry's name (i.e. file name, directory name) - * @returns required size in bytes + * @name: directory entry's name (i.e. file name, directory name) + * Return: required size in bytes */ size_t v9fs_readdir_response_size(V9fsString *name) { @@ -2410,6 +2440,7 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString name; int len, err = 0; int32_t count = 0; + off_t off; struct dirent *dent; struct stat *st; struct V9fsDirEnt *entries = NULL; @@ -2470,12 +2501,13 @@ static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp, qid.version = 0; } + off = qemu_dirent_off(dent); v9fs_string_init(&name); v9fs_string_sprintf(&name, "%s", dent->d_name); /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */ len = pdu_marshal(pdu, 11 + count, "Qqbs", - &qid, dent->d_off, + &qid, off, dent->d_type, &name); v9fs_string_free(&name); @@ -3515,9 +3547,15 @@ static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf) f_bavail = stbuf->f_bavail / bsize_factor; f_files = stbuf->f_files; f_ffree = stbuf->f_ffree; +#ifdef CONFIG_DARWIN + fsid_val = (unsigned int)stbuf->f_fsid.val[0] | + (unsigned long long)stbuf->f_fsid.val[1] << 32; + f_namelen = NAME_MAX; +#else fsid_val = (unsigned int) stbuf->f_fsid.__val[0] | (unsigned long long)stbuf->f_fsid.__val[1] << 32; f_namelen = stbuf->f_namelen; +#endif return pdu_marshal(pdu, offset, "ddqqqqqqd", f_type, f_bsize, f_blocks, f_bfree, @@ -3919,7 +3957,7 @@ static void coroutine_fn v9fs_xattrcreate(void *opaque) rflags |= XATTR_REPLACE; } - if (size > XATTR_SIZE_MAX) { + if (size > P9_XATTR_SIZE_MAX) { err = -E2BIG; goto out_nofid; } diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 1567b67841..af2635fae9 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -100,8 +100,8 @@ typedef enum P9ProtoVersion { V9FS_PROTO_2000L = 0x02, } P9ProtoVersion; -/** - * @brief Minimum message size supported by this 9pfs server. +/* + * Minimum message size supported by this 9pfs server. * * A client establishes a session by sending a Tversion request along with a * 'msize' parameter which suggests the server a maximum message size ever to be @@ -231,7 +231,7 @@ static inline void v9fs_readdir_init(P9ProtoVersion proto_version, V9fsDir *dir) } } -/** +/* * Type for 9p fs drivers' (a.k.a. 9p backends) result of readdir requests, * which is a chained list of directory entries. */ @@ -289,8 +289,8 @@ typedef enum AffixType_t { AffixType_Suffix, /* A.k.a. postfix. */ } AffixType_t; -/** - * @brief Unique affix of variable length. +/* + * Unique affix of variable length. * * An affix is (currently) either a suffix or a prefix, which is either * going to be prepended (prefix) or appended (suffix) with some other @@ -304,7 +304,7 @@ typedef struct VariLenAffix { AffixType_t type; /* Whether this affix is a suffix or a prefix. */ uint64_t value; /* Actual numerical value of this affix. */ /* - * Lenght of the affix, that is how many (of the lowest) bits of @c value + * Lenght of the affix, that is how many (of the lowest) bits of ``value`` * must be used for appending/prepending this affix to its final resulting, * unique number. */ @@ -479,4 +479,22 @@ struct V9fsTransport { void (*push_and_notify)(V9fsPDU *pdu); }; +#if defined(XATTR_SIZE_MAX) +/* Linux */ +#define P9_XATTR_SIZE_MAX XATTR_SIZE_MAX +#elif defined(CONFIG_DARWIN) +/* + * Darwin doesn't seem to define a maximum xattr size in its user + * space header, so manually configure it across platforms as 64k. + * + * Having no limit at all can lead to QEMU crashing during large g_malloc() + * calls. Because QEMU does not currently support macOS guests, the below + * preliminary solution only works due to its being a reflection of the limit of + * Linux guests. + */ +#define P9_XATTR_SIZE_MAX 65536 +#else +#error Missing definition for P9_XATTR_SIZE_MAX for this host system +#endif + #endif diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index c0873bde16..75148bc985 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -22,6 +22,8 @@ #include "qemu/coroutine.h" #include "qemu/main-loop.h" #include "coth.h" +#include "9p-xattr.h" +#include "9p-util.h" /* * Intended to be called from bottom-half (e.g. background I/O thread) @@ -166,7 +168,7 @@ static int do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, } size += len; - saved_dir_pos = dent->d_off; + saved_dir_pos = qemu_dirent_off(dent); } /* restore (last) saved position */ @@ -182,14 +184,25 @@ out: } /** - * @brief Reads multiple directory entries in one rush. + * v9fs_co_readdir_many() - Reads multiple directory entries in one rush. + * + * @pdu: the causing 9p (T_readdir) client request + * @fidp: already opened directory where readdir shall be performed on + * @entries: output for directory entries (must not be NULL) + * @offset: initial position inside the directory the function shall + * seek to before retrieving the directory entries + * @maxsize: maximum result message body size (in bytes) + * @dostat: whether a stat() should be performed and returned for + * each directory entry + * Return: resulting response message body size (in bytes) on success, + * negative error code otherwise * * Retrieves the requested (max. amount of) directory entries from the fs * driver. This function must only be called by the main IO thread (top half). * Internally this function call will be dispatched to a background IO thread * (bottom half) where it is eventually executed by the fs driver. * - * @discussion Acquiring multiple directory entries in one rush from the fs + * Acquiring multiple directory entries in one rush from the fs * driver, instead of retrieving each directory entry individually, is very * beneficial from performance point of view. Because for every fs driver * request latency is added, which in practice could lead to overall @@ -197,20 +210,9 @@ out: * directory) if every directory entry was individually requested from fs * driver. * - * @note You must @b ALWAYS call @c v9fs_free_dirents(entries) after calling + * NOTE: You must ALWAYS call v9fs_free_dirents(entries) after calling * v9fs_co_readdir_many(), both on success and on error cases of this - * function, to avoid memory leaks once @p entries are no longer needed. - * - * @param pdu - the causing 9p (T_readdir) client request - * @param fidp - already opened directory where readdir shall be performed on - * @param entries - output for directory entries (must not be NULL) - * @param offset - initial position inside the directory the function shall - * seek to before retrieving the directory entries - * @param maxsize - maximum result message body size (in bytes) - * @param dostat - whether a stat() should be performed and returned for - * each directory entry - * @returns resulting response message body size (in bytes) on success, - * negative error code otherwise + * function, to avoid memory leaks once @entries are no longer needed. */ int coroutine_fn v9fs_co_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, struct V9fsDirEnt **entries, diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h index f83c7dda7b..1a1edbdc2a 100644 --- a/hw/9pfs/coth.h +++ b/hw/9pfs/coth.h @@ -19,7 +19,7 @@ #include "qemu/coroutine.h" #include "9p.h" -/** +/* * we want to use bottom half because we want to make sure the below * sequence of events. * @@ -29,7 +29,7 @@ * we cannot swap step 1 and 2, because that would imply worker thread * can enter coroutine while step1 is still running * - * @b PERFORMANCE @b CONSIDERATIONS: As a rule of thumb, keep in mind + * PERFORMANCE CONSIDERATIONS: As a rule of thumb, keep in mind * that hopping between threads adds @b latency! So when handling a * 9pfs request, avoid calling v9fs_co_run_in_worker() too often, because * this might otherwise sum up to a significant, huge overall latency for diff --git a/hw/9pfs/meson.build b/hw/9pfs/meson.build index 99be5d9119..12443b6ad5 100644 --- a/hw/9pfs/meson.build +++ b/hw/9pfs/meson.build @@ -4,7 +4,6 @@ fs_ss.add(files( '9p-posix-acl.c', '9p-proxy.c', '9p-synth.c', - '9p-util.c', '9p-xattr-user.c', '9p-xattr.c', '9p.c', @@ -14,6 +13,8 @@ fs_ss.add(files( 'coth.c', 'coxattr.c', )) +fs_ss.add(when: 'CONFIG_LINUX', if_true: files('9p-util-linux.c')) +fs_ss.add(when: 'CONFIG_DARWIN', if_true: files('9p-util-darwin.c')) fs_ss.add(when: 'CONFIG_XEN', if_true: files('xen-9p-backend.c')) softmmu_ss.add_all(when: 'CONFIG_FSDEV_9P', if_true: fs_ss) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 8966e16320..1773cf55f1 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -2152,7 +2152,13 @@ void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, build_append_int_noprefix(tbl, 0, 1); /* DAY_ALRM */ build_append_int_noprefix(tbl, 0, 1); /* MON_ALRM */ build_append_int_noprefix(tbl, f->rtc_century, 1); /* CENTURY */ - build_append_int_noprefix(tbl, 0, 2); /* IAPC_BOOT_ARCH */ + /* IAPC_BOOT_ARCH */ + if (f->rev == 1) { + build_append_int_noprefix(tbl, 0, 2); + } else { + /* since ACPI v2.0 */ + build_append_int_noprefix(tbl, f->iapc_boot_arch, 2); + } build_append_int_noprefix(tbl, 0, 1); /* Reserved */ build_append_int_noprefix(tbl, f->flags, 4); /* Flags */ diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index c0a23cf467..de509c2b48 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -80,11 +80,6 @@ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U #define UEFI_CPER_RECORD_ID_OFFSET 96U -#define IS_UEFI_CPER_RECORD(ptr) \ - (((ptr)[0] == 'C') && \ - ((ptr)[1] == 'P') && \ - ((ptr)[2] == 'E') && \ - ((ptr)[3] == 'R')) /* * NOTE that when accessing CPER fields within a record, memcpy() diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 6befd23e16..6351bd3424 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -32,6 +32,7 @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_host.h" #include "hw/pci/pcie_port.h" +#include "hw/pci-bridge/xio3130_downstream.h" #include "hw/i386/acpi-build.h" #include "hw/acpi/acpi.h" #include "hw/pci/pci_bus.h" @@ -336,6 +337,8 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, { PCIDevice *pdev = PCI_DEVICE(dev); int slot = PCI_SLOT(pdev->devfn); + PCIDevice *bridge; + PCIBus *bus; int bsel; /* Don't send event when device is enabled during qemu machine creation: @@ -365,7 +368,14 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, return; } - bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev)); + bus = pci_get_bus(pdev); + bridge = pci_bridge_get_device(bus); + if (object_dynamic_cast(OBJECT(bridge), TYPE_PCIE_ROOT_PORT) || + object_dynamic_cast(OBJECT(bridge), TYPE_XIO3130_DOWNSTREAM)) { + pcie_cap_slot_enable_power(bridge); + } + + bsel = acpi_pcihp_get_bsel(bus); g_assert(bsel >= 0); s->acpi_pcihp_pci_status[bsel].up |= (1U << slot); acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 46bf7ceddf..46a42502bc 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2102,6 +2102,10 @@ static void machvirt_init(MachineState *machine) object_property_set_bool(cpuobj, "pmu", false, NULL); } + if (vmc->no_tcg_lpa2 && object_property_find(cpuobj, "lpa2")) { + object_property_set_bool(cpuobj, "lpa2", false, NULL); + } + if (object_property_find(cpuobj, "reset-cbar")) { object_property_set_int(cpuobj, "reset-cbar", vms->memmap[VIRT_CPUPERIPHS].base, @@ -3020,8 +3024,11 @@ DEFINE_VIRT_MACHINE_AS_LATEST(7, 0) static void virt_machine_6_2_options(MachineClass *mc) { + VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); + virt_machine_7_0_options(mc); compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len); + vmc->no_tcg_lpa2 = true; } DEFINE_VIRT_MACHINE(6, 2) diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c index 7d60ce6f0e..0723e39430 100644 --- a/hw/audio/cs4231a.c +++ b/hw/audio/cs4231a.c @@ -677,7 +677,7 @@ static void cs4231a_realizefn (DeviceState *dev, Error **errp) return; } - isa_init_irq(d, &s->pic, s->irq); + s->pic = isa_get_irq(d, s->irq); k = ISADMA_GET_CLASS(s->isa_dma); k->register_channel(s->isa_dma, s->dma, cs_dma_read, s); diff --git a/hw/audio/gus.c b/hw/audio/gus.c index e8719ee117..42f010b671 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -282,7 +282,7 @@ static void gus_realizefn (DeviceState *dev, Error **errp) s->emu.himemaddr = s->himem; s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32; s->emu.opaque = s; - isa_init_irq (d, &s->pic, s->emu.gusirq); + s->pic = isa_get_irq(d, s->emu.gusirq); AUD_set_active_out (s->voice, 1); } diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index 60f1f75e3a..2215386ddb 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -1408,7 +1408,7 @@ static void sb16_realizefn (DeviceState *dev, Error **errp) return; } - isa_init_irq (isadev, &s->pic, s->irq); + s->pic = isa_get_irq(isadev, s->irq); s->mixer_regs[0x80] = magic_of_irq (s->irq); s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma); diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 860787580a..2785b9e849 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" +#include "qemu/memalign.h" #include "qapi/error.h" #include "hw/xen/xen_common.h" #include "hw/block/xen_blkif.h" diff --git a/hw/block/fdc-isa.c b/hw/block/fdc-isa.c index ab663dce93..fa20450747 100644 --- a/hw/block/fdc-isa.c +++ b/hw/block/fdc-isa.c @@ -94,7 +94,7 @@ static void isabus_fdc_realize(DeviceState *dev, Error **errp) isa->iobase, fdc_portio_list, fdctrl, "fdc"); - isa_init_irq(isadev, &fdctrl->irq, isa->irq); + fdctrl->irq = isa_get_irq(isadev, isa->irq); fdctrl->dma_chann = isa->dma; if (fdctrl->dma_chann != -1) { IsaDmaClass *k; diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 21d18ac2e3..347875a0cd 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -32,6 +32,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/timer.h" +#include "qemu/memalign.h" #include "hw/irq.h" #include "hw/isa/isa.h" #include "hw/qdev-properties.h" diff --git a/hw/char/parallel.c b/hw/char/parallel.c index b45e67bfbb..adb9bd9be3 100644 --- a/hw/char/parallel.c +++ b/hw/char/parallel.c @@ -553,7 +553,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp) index++; base = isa->iobase; - isa_init_irq(isadev, &s->irq, isa->isairq); + s->irq = isa_get_irq(isadev, isa->isairq); qemu_register_reset(parallel_reset, s); qemu_chr_fe_set_handlers(&s->chr, parallel_can_receive, NULL, diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index 1b8b303079..7a7ed239cd 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -75,7 +75,7 @@ static void serial_isa_realizefn(DeviceState *dev, Error **errp) } index++; - isa_init_irq(isadev, &s->irq, isa->isairq); + s->irq = isa_get_irq(isadev, isa->isairq); qdev_realize(DEVICE(s), NULL, errp); qdev_set_legacy_instance_id(dev, isa->iobase, 3); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index ebd47aa26f..4ad4d7286c 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -38,6 +38,7 @@ #include "hw/nvram/fw_cfg.h" #include "hw/acpi/bios-linker-loader.h" #include "hw/isa/isa.h" +#include "hw/input/i8042.h" #include "hw/block/fdc.h" #include "hw/acpi/memory_hotplug.h" #include "sysemu/tpm.h" @@ -192,6 +193,13 @@ static void init_common_fadt_data(MachineState *ms, Object *o, .address = object_property_get_uint(o, ACPI_PM_PROP_GPE0_BLK, NULL) }, }; + + /* + * ACPI v2, Table 5-10 - Fixed ACPI Description Table Boot Architecture + * Flags, bit offset 1 - 8042. + */ + fadt.iapc_boot_arch = iapc_boot_arch_8042(); + *data = fadt; } diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index 68ca7e7fc2..fb09185cbd 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -37,6 +37,7 @@ #include "hw/pci/pcie_host.h" #include "hw/usb/xhci.h" #include "hw/virtio/virtio-mmio.h" +#include "hw/input/i8042.h" #include "acpi-common.h" #include "acpi-microvm.h" @@ -187,6 +188,11 @@ static void acpi_build_microvm(AcpiBuildTables *tables, .address = GED_MMIO_BASE_REGS + ACPI_GED_REG_RESET, }, .reset_val = ACPI_GED_RESET_VALUE, + /* + * ACPI v2, Table 5-10 - Fixed ACPI Description Table Boot Architecture + * Flags, bit offset 1 - 8042. + */ + .iapc_boot_arch = iapc_boot_arch_8042(), }; table_offsets = g_array_new(false, true /* clear */, diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 4c6c016388..32471a44cb 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3030,6 +3030,13 @@ static int vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); IntelIOMMUState *s = vtd_as->iommu_state; + /* TODO: add support for VFIO and vhost users */ + if (s->snoop_control) { + error_setg_errno(errp, -ENOTSUP, + "Snoop Control with vhost or VFIO is not supported"); + return -ENOTSUP; + } + /* Update per-address-space notifier flags */ vtd_as->notifier_flags = new; @@ -3113,6 +3120,7 @@ static Property vtd_properties[] = { VTD_HOST_ADDRESS_WIDTH), DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE), DEFINE_PROP_BOOL("x-scalable-mode", IntelIOMMUState, scalable_mode, FALSE), + DEFINE_PROP_BOOL("snoop-control", IntelIOMMUState, snoop_control, false), DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true), DEFINE_PROP_END_OF_LIST(), }; @@ -3643,7 +3651,7 @@ static void vtd_init(IntelIOMMUState *s) vtd_spte_rsvd_large[3] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits, x86_iommu->dt_supported); - if (s->scalable_mode) { + if (s->scalable_mode || s->snoop_control) { vtd_spte_rsvd[1] &= ~VTD_SPTE_SNP; vtd_spte_rsvd_large[2] &= ~VTD_SPTE_SNP; vtd_spte_rsvd_large[3] &= ~VTD_SPTE_SNP; @@ -3674,6 +3682,10 @@ static void vtd_init(IntelIOMMUState *s) s->ecap |= VTD_ECAP_SMTS | VTD_ECAP_SRS | VTD_ECAP_SLTS; } + if (s->snoop_control) { + s->ecap |= VTD_ECAP_SC; + } + vtd_reset_caches(s); /* Define registers with default values and bit semantics */ diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index a6c788049b..1ff13b40f9 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -188,6 +188,7 @@ #define VTD_ECAP_IR (1ULL << 3) #define VTD_ECAP_EIM (1ULL << 4) #define VTD_ECAP_PT (1ULL << 6) +#define VTD_ECAP_SC (1ULL << 7) #define VTD_ECAP_MHMV (15ULL << 20) #define VTD_ECAP_SRS (1ULL << 31) #define VTD_ECAP_SMTS (1ULL << 43) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index c8696ac01e..fd55fc725c 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -318,8 +318,6 @@ GlobalProperty pc_compat_2_0[] = { { "pci-serial-4x", "prog_if", "0" }, { "virtio-net-pci", "guest_announce", "off" }, { "ICH9-LPC", "memory-hotplug-support", "off" }, - { "xio3130-downstream", COMPAT_PROP_PCP, "off" }, - { "ioh3420", COMPAT_PROP_PCP, "off" }, }; const size_t pc_compat_2_0_len = G_N_ELEMENTS(pc_compat_2_0); @@ -1014,7 +1012,8 @@ static const MemoryRegionOps ioportF0_io_ops = { }, }; -static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport) +static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, + bool create_i8042, bool no_vmport) { int i; DriveInfo *fd[MAX_FD]; @@ -1036,6 +1035,10 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl, bool no_vmport) } } + if (!create_i8042) { + return; + } + i8042 = isa_create_simple(isa_bus, "i8042"); if (!no_vmport) { isa_create_simple(isa_bus, TYPE_VMPORT); @@ -1131,7 +1134,8 @@ void pc_basic_device_init(struct PCMachineState *pcms, i8257_dma_init(isa_bus, 0); /* Super I/O */ - pc_superio_init(isa_bus, create_fdctrl, pcms->vmport != ON_OFF_AUTO_ON); + pc_superio_init(isa_bus, create_fdctrl, pcms->i8042_enabled, + pcms->vmport != ON_OFF_AUTO_ON); } void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus) @@ -1512,6 +1516,20 @@ static void pc_machine_set_hpet(Object *obj, bool value, Error **errp) pcms->hpet_enabled = value; } +static bool pc_machine_get_i8042(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->i8042_enabled; +} + +static void pc_machine_set_i8042(Object *obj, bool value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->i8042_enabled = value; +} + static bool pc_machine_get_default_bus_bypass_iommu(Object *obj, Error **errp) { PCMachineState *pcms = PC_MACHINE(obj); @@ -1641,6 +1659,7 @@ static void pc_machine_initfn(Object *obj) pcms->smbus_enabled = true; pcms->sata_enabled = true; pcms->pit_enabled = true; + pcms->i8042_enabled = true; pcms->max_fw_size = 8 * MiB; #ifdef CONFIG_HPET pcms->hpet_enabled = true; @@ -1777,6 +1796,9 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "hpet", "Enable/disable high precision event timer emulation"); + object_class_property_add_bool(oc, PC_MACHINE_I8042, + pc_machine_get_i8042, pc_machine_set_i8042); + object_class_property_add_bool(oc, "default-bus-bypass-iommu", pc_machine_get_default_bus_bypass_iommu, pc_machine_set_default_bus_bypass_iommu); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 8d33cf689d..b72c03d0a6 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -757,6 +757,7 @@ static void pc_i440fx_1_7_machine_options(MachineClass *m) m->hw_version = "1.7.0"; m->default_machine_opts = NULL; m->option_rom_has_mr = true; + m->deprecation_reason = "old and unattended - use a newer version instead"; compat_props_add(m->compat_props, pc_compat_1_7, pc_compat_1_7_len); pcmc->smbios_defaults = false; pcmc->gigabyte_align = false; diff --git a/hw/i386/x86.c b/hw/i386/x86.c index b84840a1bb..4cf107baea 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -83,24 +83,11 @@ inline void init_topo_info(X86CPUTopoInfo *topo_info, uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms, unsigned int cpu_index) { - X86MachineClass *x86mc = X86_MACHINE_GET_CLASS(x86ms); X86CPUTopoInfo topo_info; - uint32_t correct_id; - static bool warned; init_topo_info(&topo_info, x86ms); - correct_id = x86_apicid_from_cpu_idx(&topo_info, cpu_index); - if (x86mc->compat_apic_id_mode) { - if (cpu_index != correct_id && !warned && !qtest_enabled()) { - error_report("APIC IDs set in compatibility mode, " - "CPU topology won't match the configuration"); - warned = true; - } - return cpu_index; - } else { - return correct_id; - } + return x86_apicid_from_cpu_idx(&topo_info, cpu_index); } @@ -1330,7 +1317,6 @@ static void x86_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_instance_props = x86_cpu_index_to_props; mc->get_default_cpu_node_id = x86_get_default_cpu_node_id; mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids; - x86mc->compat_apic_id_mode = false; x86mc->save_tsc_khz = true; x86mc->fwcfg_dma_enabled = true; nc->nmi_monitor_handler = x86_nmi; diff --git a/hw/ide/core.c b/hw/ide/core.c index d667d0b55e..3a5afff5d7 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -30,6 +30,7 @@ #include "qemu/main-loop.h" #include "qemu/timer.h" #include "qemu/hw-version.h" +#include "qemu/memalign.h" #include "sysemu/sysemu.h" #include "sysemu/blockdev.h" #include "sysemu/dma.h" diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 24bbde24c2..8bedbd13f1 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -75,7 +75,7 @@ static void isa_ide_realizefn(DeviceState *dev, Error **errp) ide_bus_init(&s->bus, sizeof(s->bus), dev, 0, 2); ide_init_ioport(&s->bus, isadev, s->iobase, s->iobase2); - isa_init_irq(isadev, &s->irq, s->isairq); + s->irq = isa_get_irq(isadev, s->isairq); ide_init2(&s->bus, s->irq); vmstate_register(VMSTATE_IF(dev), 0, &vmstate_ide_isa, s); ide_register_restart_cb(&s->bus); diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index baba62f357..1773db0d25 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -26,6 +26,7 @@ #include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/timer.h" +#include "qapi/error.h" #include "hw/isa/isa.h" #include "migration/vmstate.h" #include "hw/acpi/aml-build.h" @@ -671,6 +672,8 @@ struct ISAKBDState { KBDState kbd; bool kbd_throttle; MemoryRegion io[2]; + uint8_t kbd_irq; + uint8_t mouse_irq; }; void i8042_isa_mouse_fake_event(ISAKBDState *isa) @@ -734,8 +737,20 @@ static void i8042_realizefn(DeviceState *dev, Error **errp) ISAKBDState *isa_s = I8042(dev); KBDState *s = &isa_s->kbd; - isa_init_irq(isadev, &s->irq_kbd, 1); - isa_init_irq(isadev, &s->irq_mouse, 12); + if (isa_s->kbd_irq >= ISA_NUM_IRQS) { + error_setg(errp, "Maximum value for \"kbd-irq\" is: %u", + ISA_NUM_IRQS - 1); + return; + } + + if (isa_s->mouse_irq >= ISA_NUM_IRQS) { + error_setg(errp, "Maximum value for \"mouse-irq\" is: %u", + ISA_NUM_IRQS - 1); + return; + } + + s->irq_kbd = isa_get_irq(isadev, isa_s->kbd_irq); + s->irq_mouse = isa_get_irq(isadev, isa_s->mouse_irq); isa_register_ioport(isadev, isa_s->io + 0, 0x60); isa_register_ioport(isadev, isa_s->io + 1, 0x64); @@ -754,6 +769,7 @@ static void i8042_realizefn(DeviceState *dev, Error **errp) static void i8042_build_aml(ISADevice *isadev, Aml *scope) { + ISAKBDState *isa_s = I8042(isadev); Aml *kbd; Aml *mou; Aml *crs; @@ -761,7 +777,7 @@ static void i8042_build_aml(ISADevice *isadev, Aml *scope) crs = aml_resource_template(); aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01)); aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01)); - aml_append(crs, aml_irq_no_flags(1)); + aml_append(crs, aml_irq_no_flags(isa_s->kbd_irq)); kbd = aml_device("KBD"); aml_append(kbd, aml_name_decl("_HID", aml_eisaid("PNP0303"))); @@ -769,7 +785,7 @@ static void i8042_build_aml(ISADevice *isadev, Aml *scope) aml_append(kbd, aml_name_decl("_CRS", crs)); crs = aml_resource_template(); - aml_append(crs, aml_irq_no_flags(12)); + aml_append(crs, aml_irq_no_flags(isa_s->mouse_irq)); mou = aml_device("MOU"); aml_append(mou, aml_name_decl("_HID", aml_eisaid("PNP0F13"))); @@ -783,6 +799,8 @@ static void i8042_build_aml(ISADevice *isadev, Aml *scope) static Property i8042_properties[] = { DEFINE_PROP_BOOL("extended-state", ISAKBDState, kbd.extended_state, true), DEFINE_PROP_BOOL("kbd-throttle", ISAKBDState, kbd_throttle, false), + DEFINE_PROP_UINT8("kbd-irq", ISAKBDState, kbd_irq, 1), + DEFINE_PROP_UINT8("mouse-irq", ISAKBDState, mouse_irq, 12), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c index 6d3c8ee231..0b8f79a122 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c @@ -369,11 +369,19 @@ static const MemoryRegionOps gic_ops[] = { .read_with_attrs = gicv3_dist_read, .write_with_attrs = gicv3_dist_write, .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .impl.min_access_size = 1, + .impl.max_access_size = 8, }, { .read_with_attrs = gicv3_redist_read, .write_with_attrs = gicv3_redist_write, .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .impl.min_access_size = 1, + .impl.max_access_size = 8, } }; diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index d7e03d0cab..1a3d440a54 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -612,7 +612,8 @@ static uint64_t icv_hppir_read(CPUARMState *env, const ARMCPRegInfo *ri) } } - trace_gicv3_icv_hppir_read(grp, gicv3_redist_affid(cs), value); + trace_gicv3_icv_hppir_read(ri->crm == 8 ? 0 : 1, + gicv3_redist_affid(cs), value); return value; } diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c index 4164500ea9..28d913b211 100644 --- a/hw/intc/arm_gicv3_dist.c +++ b/hw/intc/arm_gicv3_dist.c @@ -838,7 +838,7 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, if (!r) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest read at offset " TARGET_FMT_plx - "size %u\n", __func__, offset, size); + " size %u\n", __func__, offset, size); trace_gicv3_dist_badread(offset, size, attrs.secure); /* The spec requires that reserved registers are RAZ/WI; * so use MEMTX_ERROR returns from leaf functions as a way to @@ -879,7 +879,7 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data, if (!r) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write at offset " TARGET_FMT_plx - "size %u\n", __func__, offset, size); + " size %u\n", __func__, offset, size); trace_gicv3_dist_badwrite(offset, data, size, attrs.secure); /* The spec requires that reserved registers are RAZ/WI; * so use MEMTX_ERROR returns from leaf functions as a way to diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index 4f598d3c14..b96b874afd 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -161,16 +161,22 @@ static MemTxResult get_cte(GICv3ITSState *s, uint16_t icid, CTEntry *cte) if (entry_addr == -1) { /* No L2 table entry, i.e. no valid CTE, or a memory error */ cte->valid = false; - return res; + goto out; } cteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res); if (res != MEMTX_OK) { - return res; + goto out; } cte->valid = FIELD_EX64(cteval, CTE, VALID); cte->rdbase = FIELD_EX64(cteval, CTE, RDBASE); - return MEMTX_OK; +out: + if (res != MEMTX_OK) { + trace_gicv3_its_cte_read_fault(icid); + } else { + trace_gicv3_its_cte_read(icid, cte->valid, cte->rdbase); + } + return res; } /* @@ -187,6 +193,10 @@ static bool update_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte, uint64_t itel = 0; uint32_t iteh = 0; + trace_gicv3_its_ite_write(dte->ittaddr, eventid, ite->valid, + ite->inttype, ite->intid, ite->icid, + ite->vpeid, ite->doorbell); + if (ite->valid) { itel = FIELD_DP64(itel, ITE_L, VALID, 1); itel = FIELD_DP64(itel, ITE_L, INTTYPE, ite->inttype); @@ -221,11 +231,13 @@ static MemTxResult get_ite(GICv3ITSState *s, uint32_t eventid, itel = address_space_ldq_le(as, iteaddr, MEMTXATTRS_UNSPECIFIED, &res); if (res != MEMTX_OK) { + trace_gicv3_its_ite_read_fault(dte->ittaddr, eventid); return res; } iteh = address_space_ldl_le(as, iteaddr + 8, MEMTXATTRS_UNSPECIFIED, &res); if (res != MEMTX_OK) { + trace_gicv3_its_ite_read_fault(dte->ittaddr, eventid); return res; } @@ -235,6 +247,9 @@ static MemTxResult get_ite(GICv3ITSState *s, uint32_t eventid, ite->icid = FIELD_EX64(itel, ITE_L, ICID); ite->vpeid = FIELD_EX64(itel, ITE_L, VPEID); ite->doorbell = FIELD_EX64(iteh, ITE_H, DOORBELL); + trace_gicv3_its_ite_read(dte->ittaddr, eventid, ite->valid, + ite->inttype, ite->intid, ite->icid, + ite->vpeid, ite->doorbell); return MEMTX_OK; } @@ -254,17 +269,23 @@ static MemTxResult get_dte(GICv3ITSState *s, uint32_t devid, DTEntry *dte) if (entry_addr == -1) { /* No L2 table entry, i.e. no valid DTE, or a memory error */ dte->valid = false; - return res; + goto out; } dteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res); if (res != MEMTX_OK) { - return res; + goto out; } dte->valid = FIELD_EX64(dteval, DTE, VALID); dte->size = FIELD_EX64(dteval, DTE, SIZE); /* DTE word field stores bits [51:8] of the ITT address */ dte->ittaddr = FIELD_EX64(dteval, DTE, ITTADDR) << ITTADDR_SHIFT; - return MEMTX_OK; +out: + if (res != MEMTX_OK) { + trace_gicv3_its_dte_read_fault(devid); + } else { + trace_gicv3_its_dte_read(devid, dte->valid, dte->size, dte->ittaddr); + } + return res; } /* @@ -366,6 +387,19 @@ static ItsCmdResult process_its_cmd(GICv3ITSState *s, const uint64_t *cmdpkt, devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT; eventid = cmdpkt[1] & EVENTID_MASK; + switch (cmd) { + case INTERRUPT: + trace_gicv3_its_cmd_int(devid, eventid); + break; + case CLEAR: + trace_gicv3_its_cmd_clear(devid, eventid); + break; + case DISCARD: + trace_gicv3_its_cmd_discard(devid, eventid); + break; + default: + g_assert_not_reached(); + } return do_process_its_cmd(s, devid, eventid, cmd); } @@ -382,15 +416,16 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt, devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT; eventid = cmdpkt[1] & EVENTID_MASK; + icid = cmdpkt[2] & ICID_MASK; if (ignore_pInt) { pIntid = eventid; + trace_gicv3_its_cmd_mapi(devid, eventid, icid); } else { pIntid = (cmdpkt[1] & pINTID_MASK) >> pINTID_SHIFT; + trace_gicv3_its_cmd_mapti(devid, eventid, icid, pIntid); } - icid = cmdpkt[2] & ICID_MASK; - if (devid >= s->dt.num_entries) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid command attributes: devid %d>=%d", @@ -451,6 +486,8 @@ static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte) uint64_t cteval = 0; MemTxResult res = MEMTX_OK; + trace_gicv3_its_cte_write(icid, cte->valid, cte->rdbase); + if (cte->valid) { /* add mapping entry to collection table */ cteval = FIELD_DP64(cteval, CTE, VALID, 1); @@ -484,6 +521,7 @@ static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt) } else { cte.rdbase = 0; } + trace_gicv3_its_cmd_mapc(icid, cte.rdbase, cte.valid); if (icid >= s->ct.num_entries) { qemu_log_mask(LOG_GUEST_ERROR, "ITS MAPC: invalid ICID 0x%d", icid); @@ -509,6 +547,8 @@ static bool update_dte(GICv3ITSState *s, uint32_t devid, const DTEntry *dte) uint64_t dteval = 0; MemTxResult res = MEMTX_OK; + trace_gicv3_its_dte_write(devid, dte->valid, dte->size, dte->ittaddr); + if (dte->valid) { /* add mapping entry to device table */ dteval = FIELD_DP64(dteval, DTE, VALID, 1); @@ -539,6 +579,8 @@ static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt) dte.ittaddr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT; dte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK; + trace_gicv3_its_cmd_mapd(devid, dte.size, dte.ittaddr, dte.valid); + if (devid >= s->dt.num_entries) { qemu_log_mask(LOG_GUEST_ERROR, "ITS MAPD: invalid device ID field 0x%x >= 0x%x\n", @@ -562,6 +604,8 @@ static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt) rd1 = FIELD_EX64(cmdpkt[2], MOVALL_2, RDBASE1); rd2 = FIELD_EX64(cmdpkt[3], MOVALL_3, RDBASE2); + trace_gicv3_its_cmd_movall(rd1, rd2); + if (rd1 >= s->gicv3->num_cpu) { qemu_log_mask(LOG_GUEST_ERROR, "%s: RDBASE1 %" PRId64 @@ -601,6 +645,8 @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt) eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID); new_icid = FIELD_EX64(cmdpkt[2], MOVI_2, ICID); + trace_gicv3_its_cmd_movi(devid, eventid, new_icid); + if (devid >= s->dt.num_entries) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid command attributes: devid %d>=%d", @@ -779,6 +825,7 @@ static void process_cmdq(GICv3ITSState *s) * is already consistent by the time SYNC command is executed. * Hence no further processing is required for SYNC command. */ + trace_gicv3_its_cmd_sync(); break; case GITS_CMD_MAPD: result = process_mapd(s, cmdpkt); @@ -803,6 +850,7 @@ static void process_cmdq(GICv3ITSState *s) * need to trigger lpi priority re-calculation to be in * sync with LPI config table or pending table changes. */ + trace_gicv3_its_cmd_inv(); for (i = 0; i < s->gicv3->num_cpu; i++) { gicv3_redist_update_lpi(&s->gicv3->cpu[i]); } @@ -814,6 +862,7 @@ static void process_cmdq(GICv3ITSState *s) result = process_movall(s, cmdpkt); break; default: + trace_gicv3_its_cmd_unknown(cmd); break; } if (result == CMD_CONTINUE) { @@ -1264,7 +1313,7 @@ static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data, if (!result) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest read at offset " TARGET_FMT_plx - "size %u\n", __func__, offset, size); + " size %u\n", __func__, offset, size); trace_gicv3_its_badread(offset, size); /* * The spec requires that reserved registers are RAZ/WI; @@ -1300,7 +1349,7 @@ static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data, if (!result) { qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write at offset " TARGET_FMT_plx - "size %u\n", __func__, offset, size); + " size %u\n", __func__, offset, size); trace_gicv3_its_badwrite(offset, data, size); /* * The spec requires that reserved registers are RAZ/WI; diff --git a/hw/intc/trace-events b/hw/intc/trace-events index b28cda4e08..53414aa197 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -176,6 +176,27 @@ gicv3_its_write(uint64_t offset, uint64_t data, unsigned size) "GICv3 ITS write: gicv3_its_badwrite(uint64_t offset, uint64_t data, unsigned size) "GICv3 ITS write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u: error" gicv3_its_translation_write(uint64_t offset, uint64_t data, unsigned size, uint32_t requester_id) "GICv3 ITS TRANSLATER write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u requester_id 0x%x" gicv3_its_process_command(uint32_t rd_offset, uint8_t cmd) "GICv3 ITS: processing command at offset 0x%x: 0x%x" +gicv3_its_cmd_int(uint32_t devid, uint32_t eventid) "GICv3 ITS: command INT DeviceID 0x%x EventID 0x%x" +gicv3_its_cmd_clear(uint32_t devid, uint32_t eventid) "GICv3 ITS: command CLEAR DeviceID 0x%x EventID 0x%x" +gicv3_its_cmd_discard(uint32_t devid, uint32_t eventid) "GICv3 ITS: command DISCARD DeviceID 0x%x EventID 0x%x" +gicv3_its_cmd_sync(void) "GICv3 ITS: command SYNC" +gicv3_its_cmd_mapd(uint32_t devid, uint32_t size, uint64_t ittaddr, int valid) "GICv3 ITS: command MAPD DeviceID 0x%x Size 0x%x ITT_addr 0x%" PRIx64 " V %d" +gicv3_its_cmd_mapc(uint32_t icid, uint64_t rdbase, int valid) "GICv3 ITS: command MAPC ICID 0x%x RDbase 0x%" PRIx64 " V %d" +gicv3_its_cmd_mapi(uint32_t devid, uint32_t eventid, uint32_t icid) "GICv3 ITS: command MAPI DeviceID 0x%x EventID 0x%x ICID 0x%x" +gicv3_its_cmd_mapti(uint32_t devid, uint32_t eventid, uint32_t icid, uint32_t intid) "GICv3 ITS: command MAPTI DeviceID 0x%x EventID 0x%x ICID 0x%x pINTID 0x%x" +gicv3_its_cmd_inv(void) "GICv3 ITS: command INV or INVALL" +gicv3_its_cmd_movall(uint64_t rd1, uint64_t rd2) "GICv3 ITS: command MOVALL RDbase1 0x%" PRIx64 " RDbase2 0x%" PRIx64 +gicv3_its_cmd_movi(uint32_t devid, uint32_t eventid, uint32_t icid) "GICv3 ITS: command MOVI DeviceID 0x%x EventID 0x%x ICID 0x%x" +gicv3_its_cmd_unknown(unsigned cmd) "GICv3 ITS: unknown command 0x%x" +gicv3_its_cte_read(uint32_t icid, int valid, uint32_t rdbase) "GICv3 ITS: Collection Table read for ICID 0x%x: valid %d RDBase 0x%x" +gicv3_its_cte_write(uint32_t icid, int valid, uint32_t rdbase) "GICv3 ITS: Collection Table write for ICID 0x%x: valid %d RDBase 0x%x" +gicv3_its_cte_read_fault(uint32_t icid) "GICv3 ITS: Collection Table read for ICID 0x%x: faulted" +gicv3_its_ite_read(uint64_t ittaddr, uint32_t eventid, int valid, int inttype, uint32_t intid, uint32_t icid, uint32_t vpeid, uint32_t doorbell) "GICv3 ITS: Interrupt Table read for ITTaddr 0x%" PRIx64 " EventID 0x%x: valid %d inttype %d intid 0x%x ICID 0x%x vPEID 0x%x doorbell 0x%x" +gicv3_its_ite_read_fault(uint64_t ittaddr, uint32_t eventid) "GICv3 ITS: Interrupt Table read for ITTaddr 0x%" PRIx64 " EventID 0x%x: faulted" +gicv3_its_ite_write(uint64_t ittaddr, uint32_t eventid, int valid, int inttype, uint32_t intid, uint32_t icid, uint32_t vpeid, uint32_t doorbell) "GICv3 ITS: Interrupt Table write for ITTaddr 0x%" PRIx64 " EventID 0x%x: valid %d inttype %d intid 0x%x ICID 0x%x vPEID 0x%x doorbell 0x%x" +gicv3_its_dte_read(uint32_t devid, int valid, uint32_t size, uint64_t ittaddr) "GICv3 ITS: Device Table read for DeviceID 0x%x: valid %d size 0x%x ITTaddr 0x%" PRIx64 +gicv3_its_dte_write(uint32_t devid, int valid, uint32_t size, uint64_t ittaddr) "GICv3 ITS: Device Table write for DeviceID 0x%x: valid %d size 0x%x ITTaddr 0x%" PRIx64 +gicv3_its_dte_read_fault(uint32_t devid) "GICv3 ITS: Device Table read for DeviceID 0x%x: faulted" # armv7m_nvic.c nvic_recompute_state(int vectpending, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d vectpending_prio %d exception_prio %d" diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c index 02625eb94e..88aa734e9e 100644 --- a/hw/ipmi/isa_ipmi_bt.c +++ b/hw/ipmi/isa_ipmi_bt.c @@ -92,7 +92,7 @@ static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp) } if (iib->isairq > 0) { - isa_init_irq(isadev, &iib->irq, iib->isairq); + iib->irq = isa_get_irq(isadev, iib->isairq); iib->bt.use_irq = 1; iib->bt.raise_irq = isa_ipmi_bt_raise_irq; iib->bt.lower_irq = isa_ipmi_bt_lower_irq; diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c index 3b23ad08b3..afabb95ebe 100644 --- a/hw/ipmi/isa_ipmi_kcs.c +++ b/hw/ipmi/isa_ipmi_kcs.c @@ -91,7 +91,7 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp) } if (iik->isairq > 0) { - isa_init_irq(isadev, &iik->irq, iik->isairq); + iik->irq = isa_get_irq(isadev, iik->isairq); iik->kcs.use_irq = 1; iik->kcs.raise_irq = isa_ipmi_kcs_raise_irq; iik->kcs.lower_irq = isa_ipmi_kcs_lower_irq; diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 6c31398dda..0ad1c5fd65 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -21,21 +21,18 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qapi/error.h" -#include "monitor/monitor.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "hw/isa/isa.h" static ISABus *isabus; -static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *isabus_get_fw_dev_path(DeviceState *dev); static void isa_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); - k->print_dev = isabus_dev_print; k->get_fw_dev_path = isabus_get_fw_dev_path; } @@ -88,19 +85,9 @@ qemu_irq isa_get_irq(ISADevice *dev, unsigned isairq) return isabus->irqs[isairq]; } -void isa_init_irq(ISADevice *dev, qemu_irq *p, unsigned isairq) -{ - assert(dev->nirqs < ARRAY_SIZE(dev->isairq)); - assert(isairq < ISA_NUM_IRQS); - dev->isairq[dev->nirqs] = isairq; - *p = isa_get_irq(dev, isairq); - dev->nirqs++; -} - void isa_connect_gpio_out(ISADevice *isadev, int gpioirq, unsigned isairq) { - qemu_irq irq; - isa_init_irq(isadev, &irq, isairq); + qemu_irq irq = isa_get_irq(isadev, isairq); qdev_connect_gpio_out(DEVICE(isadev), gpioirq, irq); } @@ -153,14 +140,6 @@ int isa_register_portio_list(ISADevice *dev, return 0; } -static void isa_device_init(Object *obj) -{ - ISADevice *dev = ISA_DEVICE(obj); - - dev->isairq[0] = -1; - dev->isairq[1] = -1; -} - ISADevice *isa_new(const char *name) { return ISA_DEVICE(qdev_new(name)); @@ -222,19 +201,6 @@ void isa_build_aml(ISABus *bus, Aml *scope) } } -static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent) -{ - ISADevice *d = ISA_DEVICE(dev); - - if (d->isairq[1] != -1) { - monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "", - d->isairq[0], d->isairq[1]); - } else if (d->isairq[0] != -1) { - monitor_printf(mon, "%*sisa irq %d\n", indent, "", - d->isairq[0]); - } -} - static void isabus_bridge_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -260,7 +226,6 @@ static const TypeInfo isa_device_type_info = { .name = TYPE_ISA_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(ISADevice), - .instance_init = isa_device_init, .abstract = true, .class_size = sizeof(ISADeviceClass), .class_init = isa_device_class_init, diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 0fe7b69bc4..8607e0ac36 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -39,8 +39,6 @@ #include "sysemu/runstate.h" #include "qom/object.h" -PCIDevice *piix4_dev; - struct PIIX4State { PCIDevice dev; qemu_irq cpu_intr; @@ -54,6 +52,27 @@ struct PIIX4State { OBJECT_DECLARE_SIMPLE_TYPE(PIIX4State, PIIX4_PCI_DEVICE) +static void piix4_set_irq(void *opaque, int irq_num, int level) +{ + int i, pic_irq, pic_level; + PIIX4State *s = opaque; + PCIBus *bus = pci_get_bus(&s->dev); + + /* now we change the pic irq level according to the piix irq mappings */ + /* XXX: optimize */ + pic_irq = s->dev.config[PIIX_PIRQCA + irq_num]; + if (pic_irq < ISA_NUM_IRQS) { + /* The pic level is the logical OR of all the PCI irqs mapped to it. */ + pic_level = 0; + for (i = 0; i < PIIX_NUM_PIRQS; i++) { + if (pic_irq == s->dev.config[PIIX_PIRQCA + i]) { + pic_level |= pci_bus_get_irq_level(bus, i); + } + } + qemu_set_irq(s->isa[pic_irq], pic_level); + } +} + static void piix4_isa_reset(DeviceState *dev) { PIIX4State *d = PIIX4_PCI_DEVICE(dev); @@ -197,9 +216,7 @@ static void piix4_realize(PCIDevice *dev, Error **errp) if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), errp)) { return; } - isa_init_irq(ISA_DEVICE(&s->rtc), &s->rtc.irq, RTC_ISA_IRQ); - - piix4_dev = dev; + s->rtc.irq = isa_get_irq(ISA_DEVICE(&s->rtc), s->rtc.isairq); } static void piix4_init(Object *obj) @@ -248,8 +265,34 @@ static void piix4_register_types(void) type_init(piix4_register_types) +static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +{ + int slot; + + slot = PCI_SLOT(pci_dev->devfn); + + switch (slot) { + /* PIIX4 USB */ + case 10: + return 3; + /* AMD 79C973 Ethernet */ + case 11: + return 1; + /* Crystal 4281 Sound */ + case 12: + return 2; + /* PCI slot 1 to 4 */ + case 18 ... 21: + return ((slot - 18) + irq_num) & 0x03; + /* Unknown device, don't do any translation */ + default: + return irq_num; + } +} + DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus) { + PIIX4State *s; PCIDevice *pci; DeviceState *dev; int devfn = PCI_DEVFN(10, 0); @@ -257,6 +300,7 @@ DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus) pci = pci_create_simple_multifunction(pci_bus, devfn, true, TYPE_PIIX4_PCI_DEVICE); dev = DEVICE(pci); + s = PIIX4_PCI_DEVICE(pci); if (isa_bus) { *isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0")); } @@ -271,5 +315,7 @@ DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus) NULL, 0, NULL); } + pci_bus_irqs(pci_bus, piix4_set_irq, pci_slot_get_pirq, s, PIIX_NUM_PIRQS); + return dev; } diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index c7480bd019..e0ff1b5566 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -26,10 +26,8 @@ #include "qapi/error.h" #include "qemu/units.h" #include "qemu/log.h" -#include "hw/mips/mips.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" -#include "hw/southbridge/piix.h" #include "migration/vmstate.h" #include "hw/intc/i8259.h" #include "hw/irq.h" @@ -981,56 +979,6 @@ static const MemoryRegionOps isd_mem_ops = { }, }; -static int gt64120_pci_map_irq(PCIDevice *pci_dev, int irq_num) -{ - int slot; - - slot = PCI_SLOT(pci_dev->devfn); - - switch (slot) { - /* PIIX4 USB */ - case 10: - return 3; - /* AMD 79C973 Ethernet */ - case 11: - return 1; - /* Crystal 4281 Sound */ - case 12: - return 2; - /* PCI slot 1 to 4 */ - case 18 ... 21: - return ((slot - 18) + irq_num) & 0x03; - /* Unknown device, don't do any translation */ - default: - return irq_num; - } -} - -static int pci_irq_levels[4]; - -static void gt64120_pci_set_irq(void *opaque, int irq_num, int level) -{ - int i, pic_irq, pic_level; - qemu_irq *pic = opaque; - - pci_irq_levels[irq_num] = level; - - /* now we change the pic irq level according to the piix irq mappings */ - /* XXX: optimize */ - pic_irq = piix4_dev->config[PIIX_PIRQCA + irq_num]; - if (pic_irq < 16) { - /* The pic level is the logical OR of all the PCI irqs mapped to it. */ - pic_level = 0; - for (i = 0; i < 4; i++) { - if (pic_irq == piix4_dev->config[PIIX_PIRQCA + i]) { - pic_level |= pci_irq_levels[i]; - } - } - qemu_set_irq(pic[pic_irq], pic_level); - } -} - - static void gt64120_reset(DeviceState *dev) { GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev); @@ -1202,32 +1150,18 @@ static void gt64120_reset(DeviceState *dev) static void gt64120_realize(DeviceState *dev, Error **errp) { GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev); + PCIHostState *phb = PCI_HOST_BRIDGE(dev); memory_region_init_io(&s->ISD_mem, OBJECT(dev), &isd_mem_ops, s, "gt64120-isd", 0x1000); -} - -PCIBus *gt64120_register(qemu_irq *pic) -{ - GT64120State *d; - PCIHostState *phb; - DeviceState *dev; - - dev = qdev_new(TYPE_GT64120_PCI_HOST_BRIDGE); - d = GT64120_PCI_HOST_BRIDGE(dev); - phb = PCI_HOST_BRIDGE(dev); - memory_region_init(&d->pci0_mem, OBJECT(dev), "pci0-mem", 4 * GiB); - address_space_init(&d->pci0_mem_as, &d->pci0_mem, "pci0-mem"); - phb->bus = pci_register_root_bus(dev, "pci", - gt64120_pci_set_irq, gt64120_pci_map_irq, - pic, - &d->pci0_mem, - get_system_io(), - PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + memory_region_init(&s->pci0_mem, OBJECT(dev), "pci0-mem", 4 * GiB); + address_space_init(&s->pci0_mem_as, &s->pci0_mem, "pci0-mem"); + phb->bus = pci_root_bus_new(dev, "pci", + &s->pci0_mem, + get_system_io(), + PCI_DEVFN(18, 0), TYPE_PCI_BUS); pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci"); - return phb->bus; } static void gt64120_pci_realize(PCIDevice *d, Error **errp) diff --git a/hw/mips/malta.c b/hw/mips/malta.c index b770b8d367..55037eb90f 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -97,7 +97,6 @@ struct MaltaState { Clock *cpuclk; MIPSCPSState cps; - qemu_irq i8259[ISA_NUM_IRQS]; }; static struct _loaderparams { @@ -1391,7 +1390,8 @@ void mips_malta_init(MachineState *machine) stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420); /* Northbridge */ - pci_bus = gt64120_register(s->i8259); + dev = sysbus_create_simple("gt64120", -1, NULL); + pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci")); /* * The whole address space decoded by the GT-64120A doesn't generate * exception when accessing invalid memory. Create an empty slot to @@ -1404,9 +1404,6 @@ void mips_malta_init(MachineState *machine) /* Interrupt controller */ qdev_connect_gpio_out_named(dev, "intr", 0, i8259_irq); - for (int i = 0; i < ISA_NUM_IRQS; i++) { - s->i8259[i] = qdev_get_gpio_in_named(dev, "isa", i); - } /* generate SPD EEPROM data */ generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size); diff --git a/hw/misc/pvpanic-isa.c b/hw/misc/pvpanic-isa.c index a39fcdd1fc..b84d4d458d 100644 --- a/hw/misc/pvpanic-isa.c +++ b/hw/misc/pvpanic-isa.c @@ -21,6 +21,7 @@ #include "hw/misc/pvpanic.h" #include "qom/object.h" #include "hw/isa/isa.h" +#include "standard-headers/linux/pvpanic.h" OBJECT_DECLARE_SIMPLE_TYPE(PVPanicISAState, PVPANIC_ISA_DEVICE) @@ -64,7 +65,8 @@ static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp) static Property pvpanic_isa_properties[] = { DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicISAState, ioport, 0x505), - DEFINE_PROP_UINT8("events", PVPanicISAState, pvpanic.events, PVPANIC_PANICKED | PVPANIC_CRASHLOADED), + DEFINE_PROP_UINT8("events", PVPanicISAState, pvpanic.events, + PVPANIC_PANICKED | PVPANIC_CRASH_LOADED), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/misc/pvpanic-pci.c b/hw/misc/pvpanic-pci.c index 62e1be68c1..99cf7e2041 100644 --- a/hw/misc/pvpanic-pci.c +++ b/hw/misc/pvpanic-pci.c @@ -21,6 +21,7 @@ #include "hw/misc/pvpanic.h" #include "qom/object.h" #include "hw/pci/pci.h" +#include "standard-headers/linux/pvpanic.h" OBJECT_DECLARE_SIMPLE_TYPE(PVPanicPCIState, PVPANIC_PCI_DEVICE) @@ -53,7 +54,8 @@ static void pvpanic_pci_realizefn(PCIDevice *dev, Error **errp) } static Property pvpanic_pci_properties[] = { - DEFINE_PROP_UINT8("events", PVPanicPCIState, pvpanic.events, PVPANIC_PANICKED | PVPANIC_CRASHLOADED), + DEFINE_PROP_UINT8("events", PVPanicPCIState, pvpanic.events, + PVPANIC_PANICKED | PVPANIC_CRASH_LOADED), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c index e2cb4a5d28..1540e9091a 100644 --- a/hw/misc/pvpanic.c +++ b/hw/misc/pvpanic.c @@ -21,12 +21,13 @@ #include "hw/qdev-properties.h" #include "hw/misc/pvpanic.h" #include "qom/object.h" +#include "standard-headers/linux/pvpanic.h" static void handle_event(int event) { static bool logged; - if (event & ~(PVPANIC_PANICKED | PVPANIC_CRASHLOADED) && !logged) { + if (event & ~(PVPANIC_PANICKED | PVPANIC_CRASH_LOADED) && !logged) { qemu_log_mask(LOG_GUEST_ERROR, "pvpanic: unknown event %#x.\n", event); logged = true; } @@ -36,7 +37,7 @@ static void handle_event(int event) return; } - if (event & PVPANIC_CRASHLOADED) { + if (event & PVPANIC_CRASH_LOADED) { qemu_system_guest_crashloaded(NULL); return; } diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index dd6f6e34d3..6ced6775ff 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -68,7 +68,7 @@ static void isa_ne2000_realizefn(DeviceState *dev, Error **errp) ne2000_setup_io(s, DEVICE(isadev), 0x20); isa_register_ioport(isadev, &s->io, isa->iobase); - isa_init_irq(isadev, &s->irq, isa->isairq); + s->irq = isa_get_irq(isadev, isa->isairq); qemu_macaddr_default_if_unset(&s->c.macaddr); ne2000_reset(s); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index cf8ab0f8af..b02a0632df 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -628,17 +628,20 @@ static int virtio_net_max_tx_queue_size(VirtIONet *n) NetClientState *peer = n->nic_conf.peers.ncs[0]; /* - * Backends other than vhost-user don't support max queue size. + * Backends other than vhost-user or vhost-vdpa don't support max queue + * size. */ if (!peer) { return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; } - if (peer->info->type != NET_CLIENT_DRIVER_VHOST_USER) { + switch(peer->info->type) { + case NET_CLIENT_DRIVER_VHOST_USER: + case NET_CLIENT_DRIVER_VHOST_VDPA: + return VIRTQUEUE_MAX_SIZE; + default: return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; - } - - return VIRTQUEUE_MAX_SIZE; + }; } static int peer_attach(VirtIONet *n, int index) diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 10e6e7c2ab..de932286b5 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -193,6 +193,12 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin) PCIDevice *pxb = pci_get_bus(pci_dev)->parent_dev; /* + * First carry out normal swizzle to handle + * multple root ports on a pxb instance. + */ + pin = pci_swizzle_map_irq_fn(pci_dev, pin); + + /* * The bios does not index the pxb slot number when * it computes the IRQ because it resides on bus 0 * and not on the current bus. diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index 04aae72cd6..05e2b06c0c 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -28,6 +28,7 @@ #include "migration/vmstate.h" #include "qapi/error.h" #include "qemu/module.h" +#include "hw/pci-bridge/xio3130_downstream.h" #define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */ #define XIO3130_REVISION 0x1 @@ -84,7 +85,7 @@ static void xio3130_downstream_realize(PCIDevice *d, Error **errp) XIO3130_SSVID_SVID, XIO3130_SSVID_SSID, errp); if (rc < 0) { - goto err_bridge; + goto err_msi; } rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM, @@ -173,7 +174,7 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data) } static const TypeInfo xio3130_downstream_info = { - .name = "xio3130-downstream", + .name = TYPE_XIO3130_DOWNSTREAM, .parent = TYPE_PCIE_SLOT, .class_init = xio3130_downstream_class_init, .interfaces = (InterfaceInfo[]) { diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index 5cd3af4fbc..5ff46ef050 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -75,7 +75,7 @@ static void xio3130_upstream_realize(PCIDevice *d, Error **errp) XIO3130_SSVID_SVID, XIO3130_SSVID_SSID, errp); if (rc < 0) { - goto err_bridge; + goto err_msi; } rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM, diff --git a/hw/pci/meson.build b/hw/pci/meson.build index 5c4bbac817..bcc9c75919 100644 --- a/hw/pci/meson.build +++ b/hw/pci/meson.build @@ -5,6 +5,7 @@ pci_ss.add(files( 'pci.c', 'pci_bridge.c', 'pci_host.c', + 'pcie_sriov.c', 'shpc.c', 'slotid_cap.c' )) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 5d30f9ca60..5cb1232e27 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -239,6 +239,9 @@ int pci_bar(PCIDevice *d, int reg) { uint8_t type; + /* PCIe virtual functions do not have their own BARs */ + assert(!pci_is_vf(d)); + if (reg != PCI_ROM_SLOT) return PCI_BASE_ADDRESS_0 + reg * 4; @@ -304,10 +307,30 @@ void pci_device_deassert_intx(PCIDevice *dev) } } -static void pci_do_device_reset(PCIDevice *dev) +static void pci_reset_regions(PCIDevice *dev) { int r; + if (pci_is_vf(dev)) { + return; + } + + for (r = 0; r < PCI_NUM_REGIONS; ++r) { + PCIIORegion *region = &dev->io_regions[r]; + if (!region->size) { + continue; + } + if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) && + region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_set_quad(dev->config + pci_bar(dev, r), region->type); + } else { + pci_set_long(dev->config + pci_bar(dev, r), region->type); + } + } +} + +static void pci_do_device_reset(PCIDevice *dev) +{ pci_device_deassert_intx(dev); assert(dev->irq_state == 0); @@ -323,19 +346,7 @@ static void pci_do_device_reset(PCIDevice *dev) pci_get_word(dev->wmask + PCI_INTERRUPT_LINE) | pci_get_word(dev->w1cmask + PCI_INTERRUPT_LINE)); dev->config[PCI_CACHE_LINE_SIZE] = 0x0; - for (r = 0; r < PCI_NUM_REGIONS; ++r) { - PCIIORegion *region = &dev->io_regions[r]; - if (!region->size) { - continue; - } - - if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) && - region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_set_quad(dev->config + pci_bar(dev, r), region->type); - } else { - pci_set_long(dev->config + pci_bar(dev, r), region->type); - } - } + pci_reset_regions(dev); pci_update_mappings(dev); msi_reset(dev); @@ -885,6 +896,16 @@ static void pci_init_multifunction(PCIBus *bus, PCIDevice *dev, Error **errp) } /* + * With SR/IOV and ARI, a device at function 0 need not be a multifunction + * device, as it may just be a VF that ended up with function 0 in + * the legacy PCI interpretation. Avoid failing in such cases: + */ + if (pci_is_vf(dev) && + dev->exp.sriov_vf.pf->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { + return; + } + + /* * multifunction bit is interpreted in two ways as follows. * - all functions must set the bit to 1. * Example: Intel X53 @@ -1078,11 +1099,12 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, return NULL; } else if (!pci_bus_devfn_available(bus, devfn)) { error_setg(errp, "PCI: slot %d function %d not available for %s," - " in use by %s", + " in use by %s,id=%s", PCI_SLOT(devfn), PCI_FUNC(devfn), name, - bus->devices[devfn]->name); + bus->devices[devfn]->name, bus->devices[devfn]->qdev.id); return NULL; } else if (dev->hotplugged && + !pci_is_vf(pci_dev) && pci_get_function_0(pci_dev)) { error_setg(errp, "PCI: slot %d function 0 already occupied by %s," " new func %s cannot be exposed to guest.", @@ -1191,6 +1213,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, pcibus_t size = memory_region_size(memory); uint8_t hdr_type; + assert(!pci_is_vf(pci_dev)); /* VFs must use pcie_sriov_vf_register_bar */ assert(region_num >= 0); assert(region_num < PCI_NUM_REGIONS); assert(is_power_of_2(size)); @@ -1294,11 +1317,45 @@ pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num) return pci_dev->io_regions[region_num].addr; } -static pcibus_t pci_bar_address(PCIDevice *d, - int reg, uint8_t type, pcibus_t size) +static pcibus_t pci_config_get_bar_addr(PCIDevice *d, int reg, + uint8_t type, pcibus_t size) +{ + pcibus_t new_addr; + if (!pci_is_vf(d)) { + int bar = pci_bar(d, reg); + if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + new_addr = pci_get_quad(d->config + bar); + } else { + new_addr = pci_get_long(d->config + bar); + } + } else { + PCIDevice *pf = d->exp.sriov_vf.pf; + uint16_t sriov_cap = pf->exp.sriov_cap; + int bar = sriov_cap + PCI_SRIOV_BAR + reg * 4; + uint16_t vf_offset = + pci_get_word(pf->config + sriov_cap + PCI_SRIOV_VF_OFFSET); + uint16_t vf_stride = + pci_get_word(pf->config + sriov_cap + PCI_SRIOV_VF_STRIDE); + uint32_t vf_num = (d->devfn - (pf->devfn + vf_offset)) / vf_stride; + + if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + new_addr = pci_get_quad(pf->config + bar); + } else { + new_addr = pci_get_long(pf->config + bar); + } + new_addr += vf_num * size; + } + /* The ROM slot has a specific enable bit, keep it intact */ + if (reg != PCI_ROM_SLOT) { + new_addr &= ~(size - 1); + } + return new_addr; +} + +pcibus_t pci_bar_address(PCIDevice *d, + int reg, uint8_t type, pcibus_t size) { pcibus_t new_addr, last_addr; - int bar = pci_bar(d, reg); uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); Object *machine = qdev_get_machine(); ObjectClass *oc = object_get_class(machine); @@ -1309,7 +1366,7 @@ static pcibus_t pci_bar_address(PCIDevice *d, if (!(cmd & PCI_COMMAND_IO)) { return PCI_BAR_UNMAPPED; } - new_addr = pci_get_long(d->config + bar) & ~(size - 1); + new_addr = pci_config_get_bar_addr(d, reg, type, size); last_addr = new_addr + size - 1; /* Check if 32 bit BAR wraps around explicitly. * TODO: make priorities correct and remove this work around. @@ -1324,11 +1381,7 @@ static pcibus_t pci_bar_address(PCIDevice *d, if (!(cmd & PCI_COMMAND_MEMORY)) { return PCI_BAR_UNMAPPED; } - if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { - new_addr = pci_get_quad(d->config + bar); - } else { - new_addr = pci_get_long(d->config + bar); - } + new_addr = pci_config_get_bar_addr(d, reg, type, size); /* the ROM slot has a specific enable bit */ if (reg == PCI_ROM_SLOT && !(new_addr & PCI_ROM_ADDRESS_ENABLE)) { return PCI_BAR_UNMAPPED; @@ -1473,6 +1526,7 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int msi_write_config(d, addr, val_in, l); msix_write_config(d, addr, val_in, l); + pcie_sriov_config_write(d, addr, val_in, l); } /***********************************************************/ diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index d7d73a31e4..67a5d67372 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -366,6 +366,17 @@ static void hotplug_event_clear(PCIDevice *dev) } } +void pcie_cap_slot_enable_power(PCIDevice *dev) +{ + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; + uint32_t sltcap = pci_get_long(exp_cap + PCI_EXP_SLTCAP); + + if (sltcap & PCI_EXP_SLTCAP_PCP) { + pci_set_word_by_mask(exp_cap + PCI_EXP_SLTCTL, + PCI_EXP_SLTCTL_PCC, PCI_EXP_SLTCTL_PWR_ON); + } +} + static void pcie_set_power_device(PCIBus *bus, PCIDevice *dev, void *opaque) { bool *power = opaque; @@ -446,6 +457,11 @@ void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, PCIDevice *pci_dev = PCI_DEVICE(dev); uint32_t lnkcap = pci_get_long(exp_cap + PCI_EXP_LNKCAP); + if (pci_is_vf(pci_dev)) { + /* Virtual function cannot be physically disconnected */ + return; + } + /* Don't send event when device is enabled during qemu machine creation: * it is present on boot, no hotplug event is necessary. We do send an * event when the device is disabled later. */ diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c new file mode 100644 index 0000000000..87abad6ac8 --- /dev/null +++ b/hw/pci/pcie_sriov.c @@ -0,0 +1,302 @@ +/* + * pcie_sriov.c: + * + * Implementation of SR/IOV emulation support. + * + * Copyright (c) 2015-2017 Knut Omang <knut.omang@oracle.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie.h" +#include "hw/pci/pci_bus.h" +#include "hw/qdev-properties.h" +#include "qemu/error-report.h" +#include "qemu/range.h" +#include "qapi/error.h" +#include "trace.h" + +static PCIDevice *register_vf(PCIDevice *pf, int devfn, + const char *name, uint16_t vf_num); +static void unregister_vfs(PCIDevice *dev); + +void pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, + const char *vfname, uint16_t vf_dev_id, + uint16_t init_vfs, uint16_t total_vfs, + uint16_t vf_offset, uint16_t vf_stride) +{ + uint8_t *cfg = dev->config + offset; + uint8_t *wmask; + + pcie_add_capability(dev, PCI_EXT_CAP_ID_SRIOV, 1, + offset, PCI_EXT_CAP_SRIOV_SIZEOF); + dev->exp.sriov_cap = offset; + dev->exp.sriov_pf.num_vfs = 0; + dev->exp.sriov_pf.vfname = g_strdup(vfname); + dev->exp.sriov_pf.vf = NULL; + + pci_set_word(cfg + PCI_SRIOV_VF_OFFSET, vf_offset); + pci_set_word(cfg + PCI_SRIOV_VF_STRIDE, vf_stride); + + /* + * Mandatory page sizes to support. + * Device implementations can call pcie_sriov_pf_add_sup_pgsize() + * to set more bits: + */ + pci_set_word(cfg + PCI_SRIOV_SUP_PGSIZE, SRIOV_SUP_PGSIZE_MINREQ); + + /* + * Default is to use 4K pages, software can modify it + * to any of the supported bits + */ + pci_set_word(cfg + PCI_SRIOV_SYS_PGSIZE, 0x1); + + /* Set up device ID and initial/total number of VFs available */ + pci_set_word(cfg + PCI_SRIOV_VF_DID, vf_dev_id); + pci_set_word(cfg + PCI_SRIOV_INITIAL_VF, init_vfs); + pci_set_word(cfg + PCI_SRIOV_TOTAL_VF, total_vfs); + pci_set_word(cfg + PCI_SRIOV_NUM_VF, 0); + + /* Write enable control bits */ + wmask = dev->wmask + offset; + pci_set_word(wmask + PCI_SRIOV_CTRL, + PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE | PCI_SRIOV_CTRL_ARI); + pci_set_word(wmask + PCI_SRIOV_NUM_VF, 0xffff); + pci_set_word(wmask + PCI_SRIOV_SYS_PGSIZE, 0x553); + + qdev_prop_set_bit(&dev->qdev, "multifunction", true); +} + +void pcie_sriov_pf_exit(PCIDevice *dev) +{ + unregister_vfs(dev); + g_free((char *)dev->exp.sriov_pf.vfname); + dev->exp.sriov_pf.vfname = NULL; +} + +void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num, + uint8_t type, dma_addr_t size) +{ + uint32_t addr; + uint64_t wmask; + uint16_t sriov_cap = dev->exp.sriov_cap; + + assert(sriov_cap > 0); + assert(region_num >= 0); + assert(region_num < PCI_NUM_REGIONS); + assert(region_num != PCI_ROM_SLOT); + + wmask = ~(size - 1); + addr = sriov_cap + PCI_SRIOV_BAR + region_num * 4; + + pci_set_long(dev->config + addr, type); + if (!(type & PCI_BASE_ADDRESS_SPACE_IO) && + type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_set_quad(dev->wmask + addr, wmask); + pci_set_quad(dev->cmask + addr, ~0ULL); + } else { + pci_set_long(dev->wmask + addr, wmask & 0xffffffff); + pci_set_long(dev->cmask + addr, 0xffffffff); + } + dev->exp.sriov_pf.vf_bar_type[region_num] = type; +} + +void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num, + MemoryRegion *memory) +{ + PCIIORegion *r; + PCIBus *bus = pci_get_bus(dev); + uint8_t type; + pcibus_t size = memory_region_size(memory); + + assert(pci_is_vf(dev)); /* PFs must use pci_register_bar */ + assert(region_num >= 0); + assert(region_num < PCI_NUM_REGIONS); + type = dev->exp.sriov_vf.pf->exp.sriov_pf.vf_bar_type[region_num]; + + if (!is_power_of_2(size)) { + error_report("%s: PCI region size must be a power" + " of two - type=0x%x, size=0x%"FMT_PCIBUS, + __func__, type, size); + exit(1); + } + + r = &dev->io_regions[region_num]; + r->memory = memory; + r->address_space = + type & PCI_BASE_ADDRESS_SPACE_IO + ? bus->address_space_io + : bus->address_space_mem; + r->size = size; + r->type = type; + + r->addr = pci_bar_address(dev, region_num, r->type, r->size); + if (r->addr != PCI_BAR_UNMAPPED) { + memory_region_add_subregion_overlap(r->address_space, + r->addr, r->memory, 1); + } +} + +static PCIDevice *register_vf(PCIDevice *pf, int devfn, const char *name, + uint16_t vf_num) +{ + PCIDevice *dev = pci_new(devfn, name); + dev->exp.sriov_vf.pf = pf; + dev->exp.sriov_vf.vf_number = vf_num; + PCIBus *bus = pci_get_bus(pf); + Error *local_err = NULL; + + qdev_realize(&dev->qdev, &bus->qbus, &local_err); + if (local_err) { + error_report_err(local_err); + return NULL; + } + + /* set vid/did according to sr/iov spec - they are not used */ + pci_config_set_vendor_id(dev->config, 0xffff); + pci_config_set_device_id(dev->config, 0xffff); + + return dev; +} + +static void register_vfs(PCIDevice *dev) +{ + uint16_t num_vfs; + uint16_t i; + uint16_t sriov_cap = dev->exp.sriov_cap; + uint16_t vf_offset = + pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_OFFSET); + uint16_t vf_stride = + pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_STRIDE); + int32_t devfn = dev->devfn + vf_offset; + + assert(sriov_cap > 0); + num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF); + + dev->exp.sriov_pf.vf = g_malloc(sizeof(PCIDevice *) * num_vfs); + assert(dev->exp.sriov_pf.vf); + + trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), num_vfs); + for (i = 0; i < num_vfs; i++) { + dev->exp.sriov_pf.vf[i] = register_vf(dev, devfn, + dev->exp.sriov_pf.vfname, i); + if (!dev->exp.sriov_pf.vf[i]) { + num_vfs = i; + break; + } + devfn += vf_stride; + } + dev->exp.sriov_pf.num_vfs = num_vfs; +} + +static void unregister_vfs(PCIDevice *dev) +{ + Error *local_err = NULL; + uint16_t num_vfs = dev->exp.sriov_pf.num_vfs; + uint16_t i; + + trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), num_vfs); + for (i = 0; i < num_vfs; i++) { + PCIDevice *vf = dev->exp.sriov_pf.vf[i]; + object_property_set_bool(OBJECT(vf), "realized", false, &local_err); + if (local_err) { + fprintf(stderr, "Failed to unplug: %s\n", + error_get_pretty(local_err)); + error_free(local_err); + } + object_unparent(OBJECT(vf)); + } + g_free(dev->exp.sriov_pf.vf); + dev->exp.sriov_pf.vf = NULL; + dev->exp.sriov_pf.num_vfs = 0; + pci_set_word(dev->config + dev->exp.sriov_cap + PCI_SRIOV_NUM_VF, 0); +} + +void pcie_sriov_config_write(PCIDevice *dev, uint32_t address, + uint32_t val, int len) +{ + uint32_t off; + uint16_t sriov_cap = dev->exp.sriov_cap; + + if (!sriov_cap || address < sriov_cap) { + return; + } + off = address - sriov_cap; + if (off >= PCI_EXT_CAP_SRIOV_SIZEOF) { + return; + } + + trace_sriov_config_write(dev->name, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), off, val, len); + + if (range_covers_byte(off, len, PCI_SRIOV_CTRL)) { + if (dev->exp.sriov_pf.num_vfs) { + if (!(val & PCI_SRIOV_CTRL_VFE)) { + unregister_vfs(dev); + } + } else { + if (val & PCI_SRIOV_CTRL_VFE) { + register_vfs(dev); + } + } + } +} + + +/* Reset SR/IOV VF Enable bit to trigger an unregister of all VFs */ +void pcie_sriov_pf_disable_vfs(PCIDevice *dev) +{ + uint16_t sriov_cap = dev->exp.sriov_cap; + if (sriov_cap) { + uint32_t val = pci_get_byte(dev->config + sriov_cap + PCI_SRIOV_CTRL); + if (val & PCI_SRIOV_CTRL_VFE) { + val &= ~PCI_SRIOV_CTRL_VFE; + pcie_sriov_config_write(dev, sriov_cap + PCI_SRIOV_CTRL, val, 1); + } + } +} + +/* Add optional supported page sizes to the mask of supported page sizes */ +void pcie_sriov_pf_add_sup_pgsize(PCIDevice *dev, uint16_t opt_sup_pgsize) +{ + uint8_t *cfg = dev->config + dev->exp.sriov_cap; + uint8_t *wmask = dev->wmask + dev->exp.sriov_cap; + + uint16_t sup_pgsize = pci_get_word(cfg + PCI_SRIOV_SUP_PGSIZE); + + sup_pgsize |= opt_sup_pgsize; + + /* + * Make sure the new bits are set, and that system page size + * also can be set to any of the new values according to spec: + */ + pci_set_word(cfg + PCI_SRIOV_SUP_PGSIZE, sup_pgsize); + pci_set_word(wmask + PCI_SRIOV_SYS_PGSIZE, sup_pgsize); +} + + +uint16_t pcie_sriov_vf_number(PCIDevice *dev) +{ + assert(pci_is_vf(dev)); + return dev->exp.sriov_vf.vf_number; +} + +PCIDevice *pcie_sriov_get_pf(PCIDevice *dev) +{ + return dev->exp.sriov_vf.pf; +} + +PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n) +{ + assert(!pci_is_vf(dev)); + if (n < dev->exp.sriov_pf.num_vfs) { + return dev->exp.sriov_pf.vf[n]; + } + return NULL; +} diff --git a/hw/pci/trace-events b/hw/pci/trace-events index 7570752c40..aaf46bc92d 100644 --- a/hw/pci/trace-events +++ b/hw/pci/trace-events @@ -10,3 +10,8 @@ pci_cfg_write(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, unsig # msix.c msix_write_config(char *name, bool enabled, bool masked) "dev %s enabled %d masked %d" + +# hw/pci/pcie_sriov.c +sriov_register_vfs(const char *name, int slot, int function, int num_vfs) "%s %02x:%x: creating %d vf devs" +sriov_unregister_vfs(const char *name, int slot, int function, int num_vfs) "%s %02x:%x: Unregistering %d vf devs" +sriov_config_write(const char *name, int slot, int fun, uint32_t offset, uint32_t val, uint32_t len) "%s %02x:%x: sriov offset 0x%x val 0x%x len %d" diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 4cc204f90d..953fc65fa8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -27,6 +27,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/datadir.h" +#include "qemu/memalign.h" #include "qapi/error.h" #include "qapi/qapi-events-machine.h" #include "qapi/qapi-events-qdev.h" diff --git a/hw/ppc/spapr_softmmu.c b/hw/ppc/spapr_softmmu.c index 4ee03c83e4..5170a33369 100644 --- a/hw/ppc/spapr_softmmu.c +++ b/hw/ppc/spapr_softmmu.c @@ -1,5 +1,6 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" +#include "qemu/memalign.h" #include "cpu.h" #include "helper_regs.h" #include "hw/ppc/spapr.h" diff --git a/hw/rtc/m48t59-isa.c b/hw/rtc/m48t59-isa.c index dc21fb10a5..e61f7ec370 100644 --- a/hw/rtc/m48t59-isa.c +++ b/hw/rtc/m48t59-isa.c @@ -42,6 +42,7 @@ struct M48txxISAState { ISADevice parent_obj; M48t59State state; uint32_t io_base; + uint8_t isairq; MemoryRegion io; }; @@ -79,6 +80,7 @@ static void m48txx_isa_toggle_lock(Nvram *obj, int lock) static Property m48t59_isa_properties[] = { DEFINE_PROP_INT32("base-year", M48txxISAState, state.base_year, 0), DEFINE_PROP_UINT32("iobase", M48txxISAState, io_base, 0x74), + DEFINE_PROP_UINT8("irq", M48txxISAState, isairq, 8), DEFINE_PROP_END_OF_LIST(), }; @@ -97,9 +99,14 @@ static void m48t59_isa_realize(DeviceState *dev, Error **errp) M48txxISAState *d = M48TXX_ISA(dev); M48t59State *s = &d->state; + if (d->isairq >= ISA_NUM_IRQS) { + error_setg(errp, "Maximum value for \"irq\" is: %u", ISA_NUM_IRQS - 1); + return; + } + s->model = u->info.model; s->size = u->info.size; - isa_init_irq(isadev, &s->IRQ, 8); + s->IRQ = isa_get_irq(isadev, d->isairq); m48t59_realize_common(s, errp); memory_region_init_io(&d->io, OBJECT(dev), &m48t59_io_ops, s, "m48t59", 4); if (d->io_base != 0) { diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index ac9a60c90e..f235c2ddbe 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -912,6 +912,11 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) s->base_year = 0; } + if (s->isairq >= ISA_NUM_IRQS) { + error_setg(errp, "Maximum value for \"irq\" is: %u", ISA_NUM_IRQS - 1); + return; + } + rtc_set_date_from_host(isadev); switch (s->lost_tick_policy) { @@ -957,15 +962,17 @@ ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) { DeviceState *dev; ISADevice *isadev; + RTCState *s; isadev = isa_new(TYPE_MC146818_RTC); dev = DEVICE(isadev); + s = MC146818_RTC(isadev); qdev_prop_set_int32(dev, "base_year", base_year); isa_realize_and_unref(isadev, bus, &error_fatal); if (intercept_irq) { qdev_connect_gpio_out(dev, 0, intercept_irq); } else { - isa_connect_gpio_out(isadev, 0, RTC_ISA_IRQ); + isa_connect_gpio_out(isadev, 0, s->isairq); } object_property_add_alias(qdev_get_machine(), "rtc-time", OBJECT(isadev), @@ -976,6 +983,7 @@ ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) static Property mc146818rtc_properties[] = { DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980), + DEFINE_PROP_UINT8("irq", RTCState, isairq, RTC_ISA_IRQ), DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState, lost_tick_policy, LOST_TICK_POLICY_DISCARD), DEFINE_PROP_END_OF_LIST(), @@ -1011,6 +1019,7 @@ static void rtc_reset_hold(Object *obj) static void rtc_build_aml(ISADevice *isadev, Aml *scope) { + RTCState *s = MC146818_RTC(isadev); Aml *dev; Aml *crs; @@ -1021,7 +1030,7 @@ static void rtc_build_aml(ISADevice *isadev, Aml *scope) crs = aml_resource_template(); aml_append(crs, aml_io(AML_DECODE16, RTC_ISA_BASE, RTC_ISA_BASE, 0x01, 0x08)); - aml_append(crs, aml_irq_no_flags(RTC_ISA_IRQ)); + aml_append(crs, aml_irq_no_flags(s->isairq)); dev = aml_device("RTC"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0B00"))); diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 3666b8d946..072686ed58 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -26,6 +26,7 @@ #include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/hw-version.h" +#include "qemu/memalign.h" #include "hw/scsi/scsi.h" #include "migration/qemu-file-types.h" #include "migration/vmstate.h" diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 6013df1698..60349ee402 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -104,9 +104,11 @@ static struct { const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part; uint64_t max_speed; uint64_t current_speed; + uint64_t processor_id; } type4 = { .max_speed = DEFAULT_CPU_SPEED, - .current_speed = DEFAULT_CPU_SPEED + .current_speed = DEFAULT_CPU_SPEED, + .processor_id = 0, }; static struct { @@ -327,6 +329,10 @@ static const QemuOptDesc qemu_smbios_type4_opts[] = { .name = "part", .type = QEMU_OPT_STRING, .help = "part number", + }, { + .name = "processor-id", + .type = QEMU_OPT_NUMBER, + .help = "processor id", }, { /* end of list */ } }; @@ -549,9 +555,23 @@ bool smbios_skip_table(uint8_t type, bool required_table) return true; } +#define T0_BASE 0x000 +#define T1_BASE 0x100 +#define T2_BASE 0x200 +#define T3_BASE 0x300 +#define T4_BASE 0x400 +#define T11_BASE 0xe00 + +#define T16_BASE 0x1000 +#define T17_BASE 0x1100 +#define T19_BASE 0x1300 +#define T32_BASE 0x2000 +#define T41_BASE 0x2900 +#define T127_BASE 0x7F00 + static void smbios_build_type_0_table(void) { - SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */ + SMBIOS_BUILD_TABLE_PRE(0, T0_BASE, false); /* optional, leave up to BIOS */ SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor); SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version); @@ -599,7 +619,7 @@ static void smbios_encode_uuid(struct smbios_uuid *uuid, QemuUUID *in) static void smbios_build_type_1_table(void) { - SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */ + SMBIOS_BUILD_TABLE_PRE(1, T1_BASE, true); /* required */ SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer); SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product); @@ -619,7 +639,7 @@ static void smbios_build_type_1_table(void) static void smbios_build_type_2_table(void) { - SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */ + SMBIOS_BUILD_TABLE_PRE(2, T2_BASE, false); /* optional */ SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer); SMBIOS_TABLE_SET_STR(2, product_str, type2.product); @@ -637,7 +657,7 @@ static void smbios_build_type_2_table(void) static void smbios_build_type_3_table(void) { - SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */ + SMBIOS_BUILD_TABLE_PRE(3, T3_BASE, true); /* required */ SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer); t->type = 0x01; /* Other */ @@ -662,15 +682,20 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance) { char sock_str[128]; - SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */ + SMBIOS_BUILD_TABLE_PRE(4, T4_BASE + instance, true); /* required */ snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance); SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str); t->processor_type = 0x03; /* CPU */ t->processor_family = 0x01; /* Other */ SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer); - t->processor_id[0] = cpu_to_le32(smbios_cpuid_version); - t->processor_id[1] = cpu_to_le32(smbios_cpuid_features); + if (type4.processor_id == 0) { + t->processor_id[0] = cpu_to_le32(smbios_cpuid_version); + t->processor_id[1] = cpu_to_le32(smbios_cpuid_features); + } else { + t->processor_id[0] = cpu_to_le32((uint32_t)type4.processor_id); + t->processor_id[1] = cpu_to_le32(type4.processor_id >> 32); + } SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version); t->voltage = 0; t->external_clock = cpu_to_le16(0); /* Unknown */ @@ -702,7 +727,7 @@ static void smbios_build_type_11_table(void) return; } - SMBIOS_BUILD_TABLE_PRE(11, 0xe00, true); /* required */ + SMBIOS_BUILD_TABLE_PRE(11, T11_BASE, true); /* required */ snprintf(count_str, sizeof(count_str), "%zu", type11.nvalues); t->count = type11.nvalues; @@ -722,7 +747,7 @@ static void smbios_build_type_16_table(unsigned dimm_cnt) { uint64_t size_kb; - SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */ + SMBIOS_BUILD_TABLE_PRE(16, T16_BASE, true); /* required */ t->location = 0x01; /* Other */ t->use = 0x03; /* System memory */ @@ -749,7 +774,7 @@ static void smbios_build_type_17_table(unsigned instance, uint64_t size) char loc_str[128]; uint64_t size_mb; - SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */ + SMBIOS_BUILD_TABLE_PRE(17, T17_BASE + instance, true); /* required */ t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */ t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */ @@ -785,12 +810,13 @@ static void smbios_build_type_17_table(unsigned instance, uint64_t size) SMBIOS_BUILD_TABLE_POST; } -static void smbios_build_type_19_table(unsigned instance, +static void smbios_build_type_19_table(unsigned instance, unsigned offset, uint64_t start, uint64_t size) { uint64_t end, start_kb, end_kb; - SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */ + SMBIOS_BUILD_TABLE_PRE(19, T19_BASE + offset + instance, + true); /* required */ end = start + size - 1; assert(end > start); @@ -814,7 +840,7 @@ static void smbios_build_type_19_table(unsigned instance, static void smbios_build_type_32_table(void) { - SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */ + SMBIOS_BUILD_TABLE_PRE(32, T32_BASE, true); /* required */ memset(t->reserved, 0, 6); t->boot_status = 0; /* No errors detected */ @@ -828,7 +854,7 @@ static void smbios_build_type_41_table(Error **errp) struct type41_instance *t41; QTAILQ_FOREACH(t41, &type41, next) { - SMBIOS_BUILD_TABLE_PRE(41, 0x2900 + instance, true); + SMBIOS_BUILD_TABLE_PRE(41, T41_BASE + instance, true); SMBIOS_TABLE_SET_STR(41, reference_designation_str, t41->designation); t->device_type = t41->kind; @@ -871,7 +897,7 @@ static void smbios_build_type_41_table(Error **errp) static void smbios_build_type_127_table(void) { - SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */ + SMBIOS_BUILD_TABLE_PRE(127, T127_BASE, true); /* required */ SMBIOS_BUILD_TABLE_POST; } @@ -982,7 +1008,7 @@ void smbios_get_tables(MachineState *ms, uint8_t **anchor, size_t *anchor_len, Error **errp) { - unsigned i, dimm_cnt; + unsigned i, dimm_cnt, offset; if (smbios_legacy) { *tables = *anchor = NULL; @@ -1012,6 +1038,16 @@ void smbios_get_tables(MachineState *ms, dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ; + /* + * The offset determines if we need to keep additional space betweeen + * table 17 and table 19 header handle numbers so that they do + * not overlap. For example, for a VM with larger than 8 TB guest + * memory and DIMM like chunks of 16 GiB, the default space between + * the two tables (T19_BASE - T17_BASE = 512) is not enough. + */ + offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \ + dimm_cnt - (T19_BASE - T17_BASE) : 0; + smbios_build_type_16_table(dimm_cnt); for (i = 0; i < dimm_cnt; i++) { @@ -1019,10 +1055,16 @@ void smbios_get_tables(MachineState *ms, } for (i = 0; i < mem_array_size; i++) { - smbios_build_type_19_table(i, mem_array[i].address, + smbios_build_type_19_table(i, offset, mem_array[i].address, mem_array[i].length); } + /* + * make sure 16 bit handle numbers in the headers of tables 19 + * and 32 do not overlap. + */ + assert((mem_array_size + offset) < (T32_BASE - T19_BASE)); + smbios_build_type_32_table(); smbios_build_type_38_table(); smbios_build_type_41_table(errp); @@ -1292,6 +1334,8 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type4.serial, opts, "serial"); save_opt(&type4.asset, opts, "asset"); save_opt(&type4.part, opts, "part"); + /* If the value is 0, it will take the value from the CPU model. */ + type4.processor_id = qemu_opt_get_number(opts, "processor-id", 0); type4.max_speed = qemu_opt_get_number(opts, "max-speed", DEFAULT_CPU_SPEED); type4.current_speed = qemu_opt_get_number(opts, "current-speed", diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c index 6dbb9f41e4..c89ac53e65 100644 --- a/hw/tpm/tpm_ppi.c +++ b/hw/tpm/tpm_ppi.c @@ -12,7 +12,7 @@ */ #include "qemu/osdep.h" - +#include "qemu/memalign.h" #include "qapi/error.h" #include "sysemu/memory_mapping.h" #include "migration/vmstate.h" diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c index 10d8a14f19..3477afd735 100644 --- a/hw/tpm/tpm_tis_isa.c +++ b/hw/tpm/tpm_tis_isa.c @@ -127,7 +127,7 @@ static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) return; } - isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); + s->irq = isa_get_irq(ISA_DEVICE(dev), s->irq_num); memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), TPM_TIS_ADDR_BASE, &s->mmio); diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index f7ad6be5fb..a5102eac9e 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -89,9 +89,11 @@ virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d" # virtio-iommu.c virtio_iommu_device_reset(void) "reset!" +virtio_iommu_system_reset(void) "system reset!" virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64 virtio_iommu_device_status(uint8_t status) "driver status = %d" -virtio_iommu_get_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_start, uint32_t domain_end, uint32_t probe_size) "page_size_mask=0x%"PRIx64" input range start=0x%"PRIx64" input range end=0x%"PRIx64" domain range start=%d domain range end=%d probe_size=0x%x" +virtio_iommu_get_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_start, uint32_t domain_end, uint32_t probe_size, uint8_t bypass) "page_size_mask=0x%"PRIx64" input range start=0x%"PRIx64" input range end=0x%"PRIx64" domain range start=%d domain range end=%d probe_size=0x%x bypass=0x%x" +virtio_iommu_set_config(uint8_t bypass) "bypass=0x%x" virtio_iommu_attach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d" virtio_iommu_detach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d" virtio_iommu_map(uint32_t domain_id, uint64_t virt_start, uint64_t virt_end, uint64_t phys_start, uint32_t flags) "domain=%d virt_start=0x%"PRIx64" virt_end=0x%"PRIx64 " phys_start=0x%"PRIx64" flags=%d" diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c index d172632bb0..42c7f6d9e5 100644 --- a/hw/virtio/vhost-user-i2c.c +++ b/hw/virtio/vhost-user-i2c.c @@ -19,6 +19,11 @@ #define VIRTIO_ID_I2C_ADAPTER 34 #endif +static const int feature_bits[] = { + VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, + VHOST_INVALID_FEATURE_BIT +}; + static void vu_i2c_start(VirtIODevice *vdev) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); @@ -113,8 +118,10 @@ static void vu_i2c_set_status(VirtIODevice *vdev, uint8_t status) static uint64_t vu_i2c_get_features(VirtIODevice *vdev, uint64_t requested_features, Error **errp) { - /* No feature bits used yet */ - return requested_features; + VHostUserI2C *i2c = VHOST_USER_I2C(vdev); + + virtio_add_feature(&requested_features, VIRTIO_I2C_F_ZERO_LENGTH_REQUEST); + return vhost_get_features(&i2c->vhost_dev, feature_bits, requested_features); } static void vu_i2c_handle_output(VirtIODevice *vdev, VirtQueue *vq) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 662853513e..6abbc9da32 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -25,6 +25,7 @@ #include "migration/migration.h" #include "migration/postcopy-ram.h" #include "trace.h" +#include "exec/ramblock.h" #include <sys/ioctl.h> #include <sys/socket.h> @@ -1162,37 +1163,32 @@ static int vhost_user_set_vring_num(struct vhost_dev *dev, return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring); } -static void vhost_user_host_notifier_restore(struct vhost_dev *dev, - int queue_idx) +static void vhost_user_host_notifier_free(VhostUserHostNotifier *n) { - struct vhost_user *u = dev->opaque; - VhostUserHostNotifier *n = &u->user->notifier[queue_idx]; - VirtIODevice *vdev = dev->vdev; - - if (n->addr && !n->set) { - virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true); - n->set = true; - } + assert(n && n->unmap_addr); + munmap(n->unmap_addr, qemu_real_host_page_size); + n->unmap_addr = NULL; } -static void vhost_user_host_notifier_remove(struct vhost_dev *dev, - int queue_idx) +static void vhost_user_host_notifier_remove(VhostUserState *user, + VirtIODevice *vdev, int queue_idx) { - struct vhost_user *u = dev->opaque; - VhostUserHostNotifier *n = &u->user->notifier[queue_idx]; - VirtIODevice *vdev = dev->vdev; + VhostUserHostNotifier *n = &user->notifier[queue_idx]; - if (n->addr && n->set) { - virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); - n->set = false; + if (n->addr) { + if (vdev) { + virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); + } + assert(!n->unmap_addr); + n->unmap_addr = n->addr; + n->addr = NULL; + call_rcu(n, vhost_user_host_notifier_free, rcu); } } static int vhost_user_set_vring_base(struct vhost_dev *dev, struct vhost_vring_state *ring) { - vhost_user_host_notifier_restore(dev, ring->index); - return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring); } @@ -1235,8 +1231,9 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev, .payload.state = *ring, .hdr.size = sizeof(msg.payload.state), }; + struct vhost_user *u = dev->opaque; - vhost_user_host_notifier_remove(dev, ring->index); + vhost_user_host_notifier_remove(u->user, dev->vdev, ring->index); ret = vhost_user_write(dev, &msg, NULL, 0); if (ret < 0) { @@ -1522,12 +1519,7 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, n = &user->notifier[queue_idx]; - if (n->addr) { - virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false); - object_unparent(OBJECT(&n->mr)); - munmap(n->addr, page_size); - n->addr = NULL; - } + vhost_user_host_notifier_remove(user, vdev, queue_idx); if (area->u64 & VHOST_USER_VRING_NOFD_MASK) { return 0; @@ -1546,9 +1538,12 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]", user, queue_idx); - if (!n->mr.ram) /* Don't init again after suspend. */ + if (!n->mr.ram) { /* Don't init again after suspend. */ memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name, page_size, addr); + } else { + n->mr.ram_block->host = addr; + } g_free(name); if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) { @@ -1558,7 +1553,6 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, } n->addr = addr; - n->set = true; return 0; } @@ -2522,17 +2516,16 @@ bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) void vhost_user_cleanup(VhostUserState *user) { int i; + VhostUserHostNotifier *n; if (!user->chr) { return; } memory_region_transaction_begin(); for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { - if (user->notifier[i].addr) { - object_unparent(OBJECT(&user->notifier[i].mr)); - munmap(user->notifier[i].addr, qemu_real_host_page_size); - user->notifier[i].addr = NULL; - } + n = &user->notifier[i]; + vhost_user_host_notifier_remove(user, NULL, i); + object_unparent(OBJECT(&n->mr)); } memory_region_transaction_commit(); user->chr = NULL; diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 04ea43704f..6c67d5f034 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -395,15 +395,6 @@ static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev, } } -static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n) -{ - int i; - - for (i = 0; i < n; i++) { - vhost_vdpa_host_notifier_uninit(dev, i); - } -} - static int vhost_vdpa_host_notifier_init(struct vhost_dev *dev, int queue_index) { size_t page_size = qemu_real_host_page_size; @@ -431,6 +422,7 @@ static int vhost_vdpa_host_notifier_init(struct vhost_dev *dev, int queue_index) g_free(name); if (virtio_queue_set_host_notifier_mr(vdev, queue_index, &n->mr, true)) { + object_unparent(OBJECT(&n->mr)); munmap(addr, page_size); goto err; } @@ -442,6 +434,15 @@ err: return -1; } +static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n) +{ + int i; + + for (i = dev->vq_index; i < dev->vq_index + n; i++) { + vhost_vdpa_host_notifier_uninit(dev, i); + } +} + static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) { int i; @@ -455,7 +456,7 @@ static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev) return; err: - vhost_vdpa_host_notifiers_uninit(dev, i); + vhost_vdpa_host_notifiers_uninit(dev, i - dev->vq_index); return; } diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index 3f3771274e..ed706681ac 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -153,19 +153,23 @@ static void vhost_vsock_common_send_transport_reset(VHostVSockCommon *vvc) if (elem->out_num) { error_report("invalid vhost-vsock event virtqueue element with " "out buffers"); - goto out; + goto err; } if (iov_from_buf(elem->in_sg, elem->in_num, 0, &event, sizeof(event)) != sizeof(event)) { error_report("vhost-vsock event virtqueue element is too short"); - goto out; + goto err; } virtqueue_push(vq, elem, sizeof(event)); virtio_notify(VIRTIO_DEVICE(vvc), vq); -out: + g_free(elem); + return; + +err: + virtqueue_detach_element(vq, elem, 0); g_free(elem); } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 7b03efccec..b643f42ea4 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1287,7 +1287,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev, return r; } - file.fd = event_notifier_get_fd(&vq->masked_notifier); + file.fd = event_notifier_get_wfd(&vq->masked_notifier); r = dev->vhost_ops->vhost_set_vring_call(dev, &file); if (r) { VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed"); @@ -1542,9 +1542,9 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, if (mask) { assert(vdev->use_guest_notifier_mask); - file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier); + file.fd = event_notifier_get_wfd(&hdev->vqs[index].masked_notifier); } else { - file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq)); + file.fd = event_notifier_get_wfd(virtio_queue_get_guest_notifier(vvq)); } file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n); diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index d23db98c56..0f69d1c742 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -48,6 +48,7 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp) VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus); VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); bool has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); + bool vdev_has_iommu; Error *local_err = NULL; DPRINTF("%s: plug device.\n", qbus->name); @@ -69,11 +70,6 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp) return; } - if (has_iommu && !virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { - error_setg(errp, "iommu_platform=true is not supported by the device"); - return; - } - if (klass->device_plugged != NULL) { klass->device_plugged(qbus->parent, &local_err); } @@ -82,9 +78,15 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp) return; } + vdev_has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); if (klass->get_dma_as != NULL && has_iommu) { virtio_add_feature(&vdev->host_features, VIRTIO_F_IOMMU_PLATFORM); vdev->dma_as = klass->get_dma_as(qbus->parent); + if (!vdev_has_iommu && vdev->dma_as != &address_space_memory) { + error_setg(errp, + "iommu_platform=true is not supported by the device"); + return; + } } else { vdev->dma_as = &address_space_memory; } diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index aa9c16a17b..239fe97b12 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -24,6 +24,7 @@ #include "hw/qdev-properties.h" #include "hw/virtio/virtio.h" #include "sysemu/kvm.h" +#include "sysemu/reset.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "trace.h" @@ -42,6 +43,7 @@ typedef struct VirtIOIOMMUDomain { uint32_t id; + bool bypass; GTree *mappings; QLIST_HEAD(, VirtIOIOMMUEndpoint) endpoint_list; } VirtIOIOMMUDomain; @@ -257,12 +259,16 @@ static void virtio_iommu_put_endpoint(gpointer data) } static VirtIOIOMMUDomain *virtio_iommu_get_domain(VirtIOIOMMU *s, - uint32_t domain_id) + uint32_t domain_id, + bool bypass) { VirtIOIOMMUDomain *domain; domain = g_tree_lookup(s->domains, GUINT_TO_POINTER(domain_id)); if (domain) { + if (domain->bypass != bypass) { + return NULL; + } return domain; } domain = g_malloc0(sizeof(*domain)); @@ -270,6 +276,7 @@ static VirtIOIOMMUDomain *virtio_iommu_get_domain(VirtIOIOMMU *s, domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, NULL, (GDestroyNotify)g_free, (GDestroyNotify)g_free); + domain->bypass = bypass; g_tree_insert(s->domains, GUINT_TO_POINTER(domain_id), domain); QLIST_INIT(&domain->endpoint_list); trace_virtio_iommu_get_domain(domain_id); @@ -333,11 +340,16 @@ static int virtio_iommu_attach(VirtIOIOMMU *s, { uint32_t domain_id = le32_to_cpu(req->domain); uint32_t ep_id = le32_to_cpu(req->endpoint); + uint32_t flags = le32_to_cpu(req->flags); VirtIOIOMMUDomain *domain; VirtIOIOMMUEndpoint *ep; trace_virtio_iommu_attach(domain_id, ep_id); + if (flags & ~VIRTIO_IOMMU_ATTACH_F_BYPASS) { + return VIRTIO_IOMMU_S_INVAL; + } + ep = virtio_iommu_get_endpoint(s, ep_id); if (!ep) { return VIRTIO_IOMMU_S_NOENT; @@ -355,7 +367,12 @@ static int virtio_iommu_attach(VirtIOIOMMU *s, } } - domain = virtio_iommu_get_domain(s, domain_id); + domain = virtio_iommu_get_domain(s, domain_id, + flags & VIRTIO_IOMMU_ATTACH_F_BYPASS); + if (!domain) { + /* Incompatible bypass flag */ + return VIRTIO_IOMMU_S_INVAL; + } QLIST_INSERT_HEAD(&domain->endpoint_list, ep, next); ep->domain = domain; @@ -418,6 +435,10 @@ static int virtio_iommu_map(VirtIOIOMMU *s, return VIRTIO_IOMMU_S_NOENT; } + if (domain->bypass) { + return VIRTIO_IOMMU_S_INVAL; + } + interval = g_malloc0(sizeof(*interval)); interval->low = virt_start; @@ -463,6 +484,11 @@ static int virtio_iommu_unmap(VirtIOIOMMU *s, if (!domain) { return VIRTIO_IOMMU_S_NOENT; } + + if (domain->bypass) { + return VIRTIO_IOMMU_S_INVAL; + } + interval.low = virt_start; interval.high = virt_end; @@ -728,8 +754,7 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr, .perm = IOMMU_NONE, }; - bypass_allowed = virtio_vdev_has_feature(&s->parent_obj, - VIRTIO_IOMMU_F_BYPASS); + bypass_allowed = s->config.bypass; sid = virtio_iommu_get_bdf(sdev); @@ -780,6 +805,9 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr, entry.perm = flag; } goto unlock; + } else if (ep->domain->bypass) { + entry.perm = flag; + goto unlock; } found = g_tree_lookup_extended(ep->domain->mappings, (gpointer)(&interval), @@ -831,13 +859,37 @@ static void virtio_iommu_get_config(VirtIODevice *vdev, uint8_t *config_data) out_config->domain_range.start = cpu_to_le32(dev_config->domain_range.start); out_config->domain_range.end = cpu_to_le32(dev_config->domain_range.end); out_config->probe_size = cpu_to_le32(dev_config->probe_size); + out_config->bypass = dev_config->bypass; trace_virtio_iommu_get_config(dev_config->page_size_mask, dev_config->input_range.start, dev_config->input_range.end, dev_config->domain_range.start, dev_config->domain_range.end, - dev_config->probe_size); + dev_config->probe_size, + dev_config->bypass); +} + +static void virtio_iommu_set_config(VirtIODevice *vdev, + const uint8_t *config_data) +{ + VirtIOIOMMU *dev = VIRTIO_IOMMU(vdev); + struct virtio_iommu_config *dev_config = &dev->config; + const struct virtio_iommu_config *in_config = (void *)config_data; + + if (in_config->bypass != dev_config->bypass) { + if (!virtio_vdev_has_feature(vdev, VIRTIO_IOMMU_F_BYPASS_CONFIG)) { + virtio_error(vdev, "cannot set config.bypass"); + return; + } else if (in_config->bypass != 0 && in_config->bypass != 1) { + virtio_error(vdev, "invalid config.bypass value '%u'", + in_config->bypass); + return; + } + dev_config->bypass = in_config->bypass; + } + + trace_virtio_iommu_set_config(in_config->bypass); } static uint64_t virtio_iommu_get_features(VirtIODevice *vdev, uint64_t f, @@ -963,6 +1015,19 @@ static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr, return 0; } +static void virtio_iommu_system_reset(void *opaque) +{ + VirtIOIOMMU *s = opaque; + + trace_virtio_iommu_system_reset(); + + /* + * config.bypass is sticky across device reset, but should be restored on + * system reset + */ + s->config.bypass = s->boot_bypass; +} + static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -988,9 +1053,9 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) virtio_add_feature(&s->features, VIRTIO_IOMMU_F_INPUT_RANGE); virtio_add_feature(&s->features, VIRTIO_IOMMU_F_DOMAIN_RANGE); virtio_add_feature(&s->features, VIRTIO_IOMMU_F_MAP_UNMAP); - virtio_add_feature(&s->features, VIRTIO_IOMMU_F_BYPASS); virtio_add_feature(&s->features, VIRTIO_IOMMU_F_MMIO); virtio_add_feature(&s->features, VIRTIO_IOMMU_F_PROBE); + virtio_add_feature(&s->features, VIRTIO_IOMMU_F_BYPASS_CONFIG); qemu_mutex_init(&s->mutex); @@ -1001,6 +1066,8 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) } else { error_setg(errp, "VIRTIO-IOMMU is not attached to any PCI bus!"); } + + qemu_register_reset(virtio_iommu_system_reset, s); } static void virtio_iommu_device_unrealize(DeviceState *dev) @@ -1008,6 +1075,8 @@ static void virtio_iommu_device_unrealize(DeviceState *dev) VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOIOMMU *s = VIRTIO_IOMMU(dev); + qemu_unregister_reset(virtio_iommu_system_reset, s); + g_hash_table_destroy(s->as_by_busptr); if (s->domains) { g_tree_destroy(s->domains); @@ -1098,8 +1167,8 @@ static const VMStateDescription vmstate_endpoint = { static const VMStateDescription vmstate_domain = { .name = "domain", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .pre_load = domain_preload, .fields = (VMStateField[]) { VMSTATE_UINT32(id, VirtIOIOMMUDomain), @@ -1108,6 +1177,7 @@ static const VMStateDescription vmstate_domain = { VirtIOIOMMUInterval, VirtIOIOMMUMapping), VMSTATE_QLIST_V(endpoint_list, VirtIOIOMMUDomain, 1, vmstate_endpoint, VirtIOIOMMUEndpoint, next), + VMSTATE_BOOL_V(bypass, VirtIOIOMMUDomain, 2), VMSTATE_END_OF_LIST() } }; @@ -1141,21 +1211,22 @@ static int iommu_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_virtio_iommu_device = { .name = "virtio-iommu-device", - .minimum_version_id = 1, - .version_id = 1, + .minimum_version_id = 2, + .version_id = 2, .post_load = iommu_post_load, .fields = (VMStateField[]) { - VMSTATE_GTREE_DIRECT_KEY_V(domains, VirtIOIOMMU, 1, + VMSTATE_GTREE_DIRECT_KEY_V(domains, VirtIOIOMMU, 2, &vmstate_domain, VirtIOIOMMUDomain), + VMSTATE_UINT8_V(config.bypass, VirtIOIOMMU, 2), VMSTATE_END_OF_LIST() }, }; static const VMStateDescription vmstate_virtio_iommu = { .name = "virtio-iommu", - .minimum_version_id = 1, + .minimum_version_id = 2, .priority = MIG_PRI_IOMMU, - .version_id = 1, + .version_id = 2, .fields = (VMStateField[]) { VMSTATE_VIRTIO_DEVICE, VMSTATE_END_OF_LIST() @@ -1164,6 +1235,7 @@ static const VMStateDescription vmstate_virtio_iommu = { static Property virtio_iommu_properties[] = { DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, "PCI", PCIBus *), + DEFINE_PROP_BOOL("boot-bypass", VirtIOIOMMU, boot_bypass, true), DEFINE_PROP_END_OF_LIST(), }; @@ -1180,6 +1252,7 @@ static void virtio_iommu_class_init(ObjectClass *klass, void *data) vdc->unrealize = virtio_iommu_device_unrealize; vdc->reset = virtio_iommu_device_reset; vdc->get_config = virtio_iommu_get_config; + vdc->set_config = virtio_iommu_set_config; vdc->get_features = virtio_iommu_get_features; vdc->set_status = virtio_iommu_set_status; vdc->vmsd = &vmstate_virtio_iommu_device; diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 84caf5c3d9..c0f0fab28a 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -433,10 +433,6 @@ int cpu_exec(CPUState *cpu); void tcg_exec_realizefn(CPUState *cpu, Error **errp); void tcg_exec_unrealizefn(CPUState *cpu); -/* Returns: 0 on success, -1 on error */ -int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, - void *ptr, target_ulong len, bool is_write); - /** * cpu_set_cpustate_pointers(cpu) * @cpu: The cpu object diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index de5f444b19..7f7b5943c7 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -7,6 +7,18 @@ #include "exec/hwaddr.h" #endif +/** + * vaddr: + * Type wide enough to contain any #target_ulong virtual address. + */ +typedef uint64_t vaddr; +#define VADDR_PRId PRId64 +#define VADDR_PRIu PRIu64 +#define VADDR_PRIo PRIo64 +#define VADDR_PRIx PRIx64 +#define VADDR_PRIX PRIX64 +#define VADDR_MAX UINT64_MAX + /* Using intptr_t ensures that qemu_*_page_mask is sign-extended even * when intptr_t is 32-bit and we are aligning a long long. */ @@ -78,6 +90,28 @@ void qemu_ram_unset_migratable(RAMBlock *rb); size_t qemu_ram_pagesize(RAMBlock *block); size_t qemu_ram_pagesize_largest(void); +/** + * cpu_address_space_init: + * @cpu: CPU to add this address space to + * @asidx: integer index of this address space + * @prefix: prefix to be used as name of address space + * @mr: the root memory region of address space + * + * Add the specified address space to the CPU's cpu_ases list. + * The address space added with @asidx 0 is the one used for the + * convenience pointer cpu->as. + * The target-specific code which registers ASes is responsible + * for defining what semantics address space 0, 1, 2, etc have. + * + * Before the first call to this function, the caller must set + * cpu->num_ases to the total number of address spaces it needs + * to support. + * + * Note that with KVM only one address space is supported. + */ +void cpu_address_space_init(CPUState *cpu, int asidx, + const char *prefix, MemoryRegion *mr); + void cpu_physical_memory_rw(hwaddr addr, void *buf, hwaddr len, bool is_write); static inline void cpu_physical_memory_read(hwaddr addr, @@ -90,6 +124,7 @@ static inline void cpu_physical_memory_write(hwaddr addr, { cpu_physical_memory_rw(addr, (void *)buf, len, true); } +void cpu_reloading_memory_map(void); void *cpu_physical_memory_map(hwaddr addr, hwaddr *plen, bool is_write); @@ -116,6 +151,10 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length); #endif +/* Returns: 0 on success, -1 on error */ +int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, + void *ptr, size_t len, bool is_write); + /* vl.c */ extern int singlestep; diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index da987fe8ad..6adacf8928 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -64,6 +64,7 @@ #include "exec/memopidx.h" #include "qemu/int128.h" +#include "cpu.h" #if defined(CONFIG_USER_ONLY) /* sparc32plus has 64bit long but 32bit space address diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 227e10ba56..d2cb0981f4 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -24,7 +24,6 @@ #ifdef CONFIG_TCG #include "exec/cpu_ldst.h" #endif -#include "sysemu/cpu-timers.h" /* allow to see translation results - the slowdown should be negligible, so we leave it */ #define DEBUG_DISAS @@ -81,31 +80,6 @@ static inline bool cpu_loop_exit_requested(CPUState *cpu) return (int32_t)qatomic_read(&cpu_neg(cpu)->icount_decr.u32) < 0; } -#if !defined(CONFIG_USER_ONLY) -void cpu_reloading_memory_map(void); -/** - * cpu_address_space_init: - * @cpu: CPU to add this address space to - * @asidx: integer index of this address space - * @prefix: prefix to be used as name of address space - * @mr: the root memory region of address space - * - * Add the specified address space to the CPU's cpu_ases list. - * The address space added with @asidx 0 is the one used for the - * convenience pointer cpu->as. - * The target-specific code which registers ASes is responsible - * for defining what semantics address space 0, 1, 2, etc have. - * - * Before the first call to this function, the caller must set - * cpu->num_ases to the total number of address spaces it needs - * to support. - * - * Note that with KVM only one address space is supported. - */ -void cpu_address_space_init(CPUState *cpu, int asidx, - const char *prefix, MemoryRegion *mr); -#endif - #if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG) /* cputlb.c */ /** diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index a024a0350d..89edf94d28 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -45,17 +45,6 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...); */ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va); int use_gdb_syscalls(void); -void gdb_set_stop_cpu(CPUState *cpu); - -/** - * gdb_exit: exit gdb session, reporting inferior status - * @code: exit code reported - * - * This closes the session and sends a final packet to GDB reporting - * the exit status of the program. It also cleans up any connections - * detritus before returning. - */ -void gdb_exit(int code); #ifdef CONFIG_USER_ONLY /** @@ -165,7 +154,7 @@ static inline uint8_t * gdb_get_reg_ptr(GByteArray *buf, int len) #define ldtul_p(addr) ldl_p(addr) #endif -#endif +#endif /* NEED_CPU_H */ /** * gdbserver_start: start the gdb server @@ -178,6 +167,18 @@ static inline uint8_t * gdb_get_reg_ptr(GByteArray *buf, int len) int gdbserver_start(const char *port_or_device); /** + * gdb_exit: exit gdb session, reporting inferior status + * @code: exit code reported + * + * This closes the session and sends a final packet to GDB reporting + * the exit status of the program. It also cleans up any connections + * detritus before returning. + */ +void gdb_exit(int code); + +void gdb_set_stop_cpu(CPUState *cpu); + +/** * gdb_has_xml: * This is an ugly hack to cope with both new and old gdb. * If gdb sends qXfer:features:read then assume we're talking to a newish diff --git a/include/exec/poison.h b/include/exec/poison.h index 7ad4ad18e8..7c5c02f03f 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -51,8 +51,6 @@ #pragma GCC poison TARGET_PAGE_BITS #pragma GCC poison TARGET_PAGE_ALIGN -#pragma GCC poison CPUArchState - #pragma GCC poison CPU_INTERRUPT_HARD #pragma GCC poison CPU_INTERRUPT_EXITTB #pragma GCC poison CPU_INTERRUPT_HALT diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index c97e8633ad..2b42e4192b 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -77,6 +77,7 @@ typedef struct AcpiFadtData { uint16_t plvl2_lat; /* P_LVL2_LAT */ uint16_t plvl3_lat; /* P_LVL3_LAT */ uint16_t arm_boot_arch; /* ARM_BOOT_ARCH */ + uint16_t iapc_boot_arch; /* IAPC_BOOT_ARCH */ uint8_t minor_ver; /* FADT Minor Version */ /* diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index c1ea17d0de..7e76ee2619 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -132,6 +132,7 @@ struct VirtMachineClass { bool no_secure_gpio; /* Machines < 6.2 have no support for describing cpu topology to guest */ bool no_cpu_topology; + bool no_tcg_lpa2; }; struct VirtMachineState { diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 76ab3b851c..0efc6153ed 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -22,6 +22,7 @@ #include "hw/qdev-core.h" #include "disas/dis-asm.h" +#include "exec/cpu-common.h" #include "exec/hwaddr.h" #include "exec/memattrs.h" #include "qapi/qapi-types-run-state.h" @@ -36,18 +37,6 @@ typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size, void *opaque); /** - * vaddr: - * Type wide enough to contain any #target_ulong virtual address. - */ -typedef uint64_t vaddr; -#define VADDR_PRId PRId64 -#define VADDR_PRIu PRIu64 -#define VADDR_PRIo PRIo64 -#define VADDR_PRIx PRIx64 -#define VADDR_PRIX PRIX64 -#define VADDR_MAX UINT64_MAX - -/** * SECTION:cpu * @section_id: QEMU-cpu * @title: CPU Class @@ -66,6 +55,24 @@ typedef struct CPUClass CPUClass; DECLARE_CLASS_CHECKERS(CPUClass, CPU, TYPE_CPU) +/** + * OBJECT_DECLARE_CPU_TYPE: + * @CpuInstanceType: instance struct name + * @CpuClassType: class struct name + * @CPU_MODULE_OBJ_NAME: the CPU name in uppercase with underscore separators + * + * This macro is typically used in "cpu-qom.h" header file, and will: + * + * - create the typedefs for the CPU object and class structs + * - register the type for use with g_autoptr + * - provide three standard type cast functions + * + * The object struct and class struct need to be declared manually. + */ +#define OBJECT_DECLARE_CPU_TYPE(CpuInstanceType, CpuClassType, CPU_MODULE_OBJ_NAME) \ + typedef struct ArchCPU CpuInstanceType; \ + OBJECT_DECLARE_TYPE(ArchCPU, CpuClassType, CPU_MODULE_OBJ_NAME); + typedef enum MMUAccessType { MMU_DATA_LOAD = 0, MMU_DATA_STORE = 1, @@ -351,7 +358,7 @@ struct CPUState { AddressSpace *as; MemoryRegion *memory; - void *env_ptr; /* CPUArchState */ + CPUArchState *env_ptr; IcountDecr *icount_decr_ptr; /* Accessed in parallel; all accesses must be atomic */ diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 41783ee46d..3b5ac869db 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -228,6 +228,7 @@ struct IntelIOMMUState { bool caching_mode; /* RO - is cap CM enabled? */ bool scalable_mode; /* RO - is Scalable Mode supported? */ + bool snoop_control; /* RO - is SNP filed supported? */ dma_addr_t root; /* Current root table pointer */ bool root_scalable; /* Type of root table (scalable or not) */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 9c9f4ac748..1a27de9c8b 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -48,6 +48,7 @@ typedef struct PCMachineState { bool sata_enabled; bool pit_enabled; bool hpet_enabled; + bool i8042_enabled; bool default_bus_bypass_iommu; uint64_t max_fw_size; @@ -64,6 +65,7 @@ typedef struct PCMachineState { #define PC_MACHINE_SMBUS "smbus" #define PC_MACHINE_SATA "sata" #define PC_MACHINE_PIT "pit" +#define PC_MACHINE_I8042 "i8042" #define PC_MACHINE_MAX_FW_SIZE "max-fw-size" #define PC_MACHINE_SMBIOS_EP "smbios-entry-point-type" diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index a145a30370..916cc325ee 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -35,8 +35,6 @@ struct X86MachineClass { /* TSC rate migration: */ bool save_tsc_khz; - /* Enables contiguous-apic-ID mode */ - bool compat_apic_id_mode; /* use DMA capable linuxboot option rom */ bool fwcfg_dma_enabled; }; diff --git a/include/hw/input/i8042.h b/include/hw/input/i8042.h index 1d90432dae..e070f546e4 100644 --- a/include/hw/input/i8042.h +++ b/include/hw/input/i8042.h @@ -23,4 +23,19 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, void i8042_isa_mouse_fake_event(ISAKBDState *isa); void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out); +static inline bool i8042_present(void) +{ + bool amb = false; + return object_resolve_path_type("", TYPE_I8042, &amb) || amb; +} + +/* + * ACPI v2, Table 5-10 - Fixed ACPI Description Table Boot Architecture + * Flags, bit offset 1 - 8042. + */ +static inline uint16_t iapc_boot_arch_8042(void) +{ + return i8042_present() ? 0x1 << 1 : 0x0 ; +} + #endif /* HW_INPUT_I8042_H */ diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index d4417b34b6..034d706ba1 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -83,8 +83,6 @@ struct ISADevice { DeviceState parent_obj; /*< public >*/ - int8_t isairq[2]; /* -1 = unassigned */ - int nirqs; int ioport_id; }; @@ -92,7 +90,6 @@ ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space, MemoryRegion *address_space_io, Error **errp); void isa_bus_irqs(ISABus *bus, qemu_irq *irqs); qemu_irq isa_get_irq(ISADevice *dev, unsigned isairq); -void isa_init_irq(ISADevice *dev, qemu_irq *p, unsigned isairq); void isa_connect_gpio_out(ISADevice *isadev, int gpioirq, unsigned isairq); void isa_bus_dma(ISABus *bus, IsaDma *dma8, IsaDma *dma16); IsaDma *isa_get_dma(ISABus *bus, int nchan); diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h index 6c9c8805f3..101799f7d3 100644 --- a/include/hw/mips/mips.h +++ b/include/hw/mips/mips.h @@ -9,9 +9,6 @@ #include "exec/memory.h" -/* gt64xxx.c */ -PCIBus *gt64120_register(qemu_irq *pic); - /* bonito.c */ PCIBus *bonito_init(qemu_irq *pic); diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h index ca3c5bb533..7f16cc9b16 100644 --- a/include/hw/misc/pvpanic.h +++ b/include/hw/misc/pvpanic.h @@ -22,14 +22,6 @@ #define PVPANIC_IOPORT_PROP "ioport" -/* The bit of supported pv event, TODO: include uapi header and remove this */ -#define PVPANIC_F_PANICKED 0 -#define PVPANIC_F_CRASHLOADED 1 - -/* The pv event value */ -#define PVPANIC_PANICKED (1 << PVPANIC_F_PANICKED) -#define PVPANIC_CRASHLOADED (1 << PVPANIC_F_CRASHLOADED) - /* * PVPanicState for any device type */ diff --git a/include/hw/pci-bridge/xio3130_downstream.h b/include/hw/pci-bridge/xio3130_downstream.h new file mode 100644 index 0000000000..1d10139aea --- /dev/null +++ b/include/hw/pci-bridge/xio3130_downstream.h @@ -0,0 +1,15 @@ +/* + * TI X3130 pci express downstream port switch + * + * Copyright (C) 2022 Igor Mammedov <imammedo@redhat.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_PCI_BRIDGE_XIO3130_DOWNSTREAM_H +#define HW_PCI_BRIDGE_XIO3130_DOWNSTREAM_H + +#define TYPE_XIO3130_DOWNSTREAM "xio3130-downstream" + +#endif + diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index c3f3c90473..3a32b8dd40 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -7,9 +7,6 @@ /* PCI includes legacy ISA access. */ #include "hw/isa/isa.h" -#include "hw/pci/pcie.h" -#include "qom/object.h" - extern bool pci_available; /* PCI bus */ @@ -157,6 +154,7 @@ enum { #define QEMU_PCI_VGA_IO_HI_SIZE 0x20 #include "hw/pci/pci_regs.h" +#include "hw/pci/pcie.h" /* PCI HEADER_TYPE */ #define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 @@ -499,6 +497,9 @@ typedef AddressSpace *(*PCIIOMMUFunc)(PCIBus *, void *, int); AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque); +pcibus_t pci_bar_address(PCIDevice *d, + int reg, uint8_t type, pcibus_t size); + static inline void pci_set_byte(uint8_t *config, uint8_t val) { @@ -779,6 +780,11 @@ static inline int pci_is_express_downstream_port(const PCIDevice *d) return type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ROOT_PORT; } +static inline int pci_is_vf(const PCIDevice *d) +{ + return d->exp.sriov_vf.pf != NULL; +} + static inline uint32_t pci_config_size(const PCIDevice *d) { return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; diff --git a/include/hw/pci/pci_regs.h b/include/hw/pci/pci_regs.h index 77ba64b931..a590140962 100644 --- a/include/hw/pci/pci_regs.h +++ b/include/hw/pci/pci_regs.h @@ -4,5 +4,6 @@ #include "standard-headers/linux/pci_regs.h" #define PCI_PM_CAP_VER_1_1 0x0002 /* PCI PM spec ver. 1.1 */ +#define PCI_PM_CAP_VER_1_2 0x0003 /* PCI PM spec ver. 1.2 */ #endif diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index 6063bee0ec..798a262a0a 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -24,6 +24,7 @@ #include "hw/pci/pci_regs.h" #include "hw/pci/pcie_regs.h" #include "hw/pci/pcie_aer.h" +#include "hw/pci/pcie_sriov.h" #include "hw/hotplug.h" typedef enum { @@ -81,6 +82,11 @@ struct PCIExpressDevice { /* ACS */ uint16_t acs_cap; + + /* SR/IOV */ + uint16_t sriov_cap; + PCIESriovPF sriov_pf; + PCIESriovVF sriov_vf; }; #define COMPAT_PROP_PCP "power_controller_present" @@ -112,6 +118,7 @@ void pcie_cap_slot_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); int pcie_cap_slot_post_load(void *opaque, int version_id); void pcie_cap_slot_push_attention_button(PCIDevice *dev); +void pcie_cap_slot_enable_power(PCIDevice *dev); void pcie_cap_root_init(PCIDevice *dev); void pcie_cap_root_reset(PCIDevice *dev); diff --git a/include/hw/pci/pcie_sriov.h b/include/hw/pci/pcie_sriov.h new file mode 100644 index 0000000000..80f5c84e75 --- /dev/null +++ b/include/hw/pci/pcie_sriov.h @@ -0,0 +1,77 @@ +/* + * pcie_sriov.h: + * + * Implementation of SR/IOV emulation support. + * + * Copyright (c) 2015 Knut Omang <knut.omang@oracle.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_PCIE_SRIOV_H +#define QEMU_PCIE_SRIOV_H + +struct PCIESriovPF { + uint16_t num_vfs; /* Number of virtual functions created */ + uint8_t vf_bar_type[PCI_NUM_REGIONS]; /* Store type for each VF bar */ + const char *vfname; /* Reference to the device type used for the VFs */ + PCIDevice **vf; /* Pointer to an array of num_vfs VF devices */ +}; + +struct PCIESriovVF { + PCIDevice *pf; /* Pointer back to owner physical function */ + uint16_t vf_number; /* Logical VF number of this function */ +}; + +void pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, + const char *vfname, uint16_t vf_dev_id, + uint16_t init_vfs, uint16_t total_vfs, + uint16_t vf_offset, uint16_t vf_stride); +void pcie_sriov_pf_exit(PCIDevice *dev); + +/* Set up a VF bar in the SR/IOV bar area */ +void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num, + uint8_t type, dma_addr_t size); + +/* Instantiate a bar for a VF */ +void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num, + MemoryRegion *memory); + +/* + * Default (minimal) page size support values + * as required by the SR/IOV standard: + * 0x553 << 12 = 0x553000 = 4K + 8K + 64K + 256K + 1M + 4M + */ +#define SRIOV_SUP_PGSIZE_MINREQ 0x553 + +/* + * Optionally add supported page sizes to the mask of supported page sizes + * Page size values are interpreted as opt_sup_pgsize << 12. + */ +void pcie_sriov_pf_add_sup_pgsize(PCIDevice *dev, uint16_t opt_sup_pgsize); + +/* SR/IOV capability config write handler */ +void pcie_sriov_config_write(PCIDevice *dev, uint32_t address, + uint32_t val, int len); + +/* Reset SR/IOV VF Enable bit to unregister all VFs */ +void pcie_sriov_pf_disable_vfs(PCIDevice *dev); + +/* Get logical VF number of a VF - only valid for VFs */ +uint16_t pcie_sriov_vf_number(PCIDevice *dev); + +/* + * Get the physical function that owns this VF. + * Returns NULL if dev is not a virtual function + */ +PCIDevice *pcie_sriov_get_pf(PCIDevice *dev); + +/* + * Get the n-th VF of this physical function - only valid for PF. + * Returns NULL if index is invalid + */ +PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n); + +#endif /* QEMU_PCIE_SRIOV_H */ diff --git a/include/hw/rtc/mc146818rtc.h b/include/hw/rtc/mc146818rtc.h index 5b45b22924..deef93f89a 100644 --- a/include/hw/rtc/mc146818rtc.h +++ b/include/hw/rtc/mc146818rtc.h @@ -25,6 +25,7 @@ struct RTCState { MemoryRegion coalesced_io; uint8_t cmos_data[128]; uint8_t cmos_index; + uint8_t isairq; int32_t base_year; uint64_t base_rtc; uint64_t last_update; diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h index 6387f2b612..f63f83e5c6 100644 --- a/include/hw/southbridge/piix.h +++ b/include/hw/southbridge/piix.h @@ -70,8 +70,6 @@ typedef struct PIIXState PIIX3State; DECLARE_INSTANCE_CHECKER(PIIX3State, PIIX3_PCI_DEVICE, TYPE_PIIX3_PCI_DEVICE) -extern PCIDevice *piix4_dev; - PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus); DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus); diff --git a/include/hw/virtio/vhost-user-i2c.h b/include/hw/virtio/vhost-user-i2c.h index deae47a76d..d8372f3b43 100644 --- a/include/hw/virtio/vhost-user-i2c.h +++ b/include/hw/virtio/vhost-user-i2c.h @@ -25,4 +25,7 @@ struct VHostUserI2C { bool connected; }; +/* Virtio Feature bits */ +#define VIRTIO_I2C_F_ZERO_LENGTH_REQUEST 0 + #endif /* _QEMU_VHOST_USER_I2C_H */ diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index a9abca3288..e44a41bb70 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -12,9 +12,10 @@ #include "hw/virtio/virtio.h" typedef struct VhostUserHostNotifier { + struct rcu_head rcu; MemoryRegion mr; void *addr; - bool set; + void *unmap_addr; } VhostUserHostNotifier; typedef struct VhostUserState { diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-iommu.h index e2339e5b72..84391f8448 100644 --- a/include/hw/virtio/virtio-iommu.h +++ b/include/hw/virtio/virtio-iommu.h @@ -58,6 +58,7 @@ struct VirtIOIOMMU { GTree *domains; QemuMutex mutex; GTree *endpoints; + bool boot_bypass; }; #endif diff --git a/include/qemu-common.h b/include/qemu-common.h index 68b2e3bc10..8c0d9ab0f7 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -26,8 +26,6 @@ int qemu_main(int argc, char **argv, char **envp); #endif -void *qemu_oom_check(void *ptr); - ssize_t qemu_write_full(int fd, const void *buf, size_t count) QEMU_WARN_UNUSED_RESULT; diff --git a/include/qemu/event_notifier.h b/include/qemu/event_notifier.h index b79add035d..8a4ff308e1 100644 --- a/include/qemu/event_notifier.h +++ b/include/qemu/event_notifier.h @@ -38,6 +38,7 @@ int event_notifier_test_and_clear(EventNotifier *); #ifdef CONFIG_POSIX void event_notifier_init_fd(EventNotifier *, int fd); int event_notifier_get_fd(const EventNotifier *); +int event_notifier_get_wfd(const EventNotifier *); #else HANDLE event_notifier_get_handle(EventNotifier *); #endif diff --git a/include/qemu/memalign.h b/include/qemu/memalign.h new file mode 100644 index 0000000000..fa299f3bf6 --- /dev/null +++ b/include/qemu/memalign.h @@ -0,0 +1,61 @@ +/* + * Allocation and free functions for aligned memory + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_MEMALIGN_H +#define QEMU_MEMALIGN_H + +/** + * qemu_try_memalign: Allocate aligned memory + * @alignment: required alignment, in bytes + * @size: size of allocation, in bytes + * + * Allocate memory on an aligned boundary (i.e. the returned + * address will be an exact multiple of @alignment). + * @alignment must be a power of 2, or the function will assert(). + * On success, returns allocated memory; on failure, returns NULL. + * + * The memory allocated through this function must be freed via + * qemu_vfree() (and not via free()). + */ +void *qemu_try_memalign(size_t alignment, size_t size); +/** + * qemu_memalign: Allocate aligned memory, without failing + * @alignment: required alignment, in bytes + * @size: size of allocation, in bytes + * + * Allocate memory in the same way as qemu_try_memalign(), but + * abort() with an error message if the memory allocation fails. + * + * The memory allocated through this function must be freed via + * qemu_vfree() (and not via free()). + */ +void *qemu_memalign(size_t alignment, size_t size); +/** + * qemu_vfree: Free memory allocated through qemu_memalign + * @ptr: memory to free + * + * This function must be used to free memory allocated via qemu_memalign() + * or qemu_try_memalign(). (Using the wrong free function will cause + * subtle bugs on Windows hosts.) + */ +void qemu_vfree(void *ptr); +/* + * It's an analog of GLIB's g_autoptr_cleanup_generic_gfree(), used to define + * g_autofree macro. + */ +static inline void qemu_cleanup_generic_vfree(void *p) +{ + void **pp = (void **)p; + qemu_vfree(*pp); +} + +/* + * Analog of g_autofree, but qemu_vfree is called on cleanup instead of g_free. + */ +#define QEMU_AUTO_VFREE __attribute__((cleanup(qemu_cleanup_generic_vfree))) + +#endif diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 7bcce3bceb..c9ec7830c9 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -379,28 +379,10 @@ extern "C" { #endif int qemu_daemon(int nochdir, int noclose); -void *qemu_try_memalign(size_t alignment, size_t size); -void *qemu_memalign(size_t alignment, size_t size); void *qemu_anon_ram_alloc(size_t size, uint64_t *align, bool shared, bool noreserve); -void qemu_vfree(void *ptr); void qemu_anon_ram_free(void *ptr, size_t size); -/* - * It's an analog of GLIB's g_autoptr_cleanup_generic_gfree(), used to define - * g_autofree macro. - */ -static inline void qemu_cleanup_generic_vfree(void *p) -{ - void **pp = (void **)p; - qemu_vfree(*pp); -} - -/* - * Analog of g_autofree, but qemu_vfree is called on cleanup instead of g_free. - */ -#define QEMU_AUTO_VFREE __attribute__((cleanup(qemu_cleanup_generic_vfree))) - #ifdef _WIN32 #define HAVE_CHARDEV_SERIAL 1 #elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ @@ -673,19 +655,6 @@ static inline int platform_does_not_support_system(const char *command) } #endif /* !HAVE_SYSTEM_FUNCTION */ -/** - * Duplicate directory entry @dent. - * - * It is highly recommended to use this function instead of open coding - * duplication of @c dirent objects, because the actual @c struct @c dirent - * size may be bigger or shorter than @c sizeof(struct dirent) and correct - * handling is platform specific (see gitlab issue #841). - * - * @dent - original directory entry to be duplicated - * @returns duplicated directory entry which should be freed with g_free() - */ -struct dirent *qemu_dirent_dup(struct dirent *dent); - #ifdef __cplusplus } #endif diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index ee60eb3de4..42f4ceb701 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -26,6 +26,7 @@ typedef struct AddressSpace AddressSpace; typedef struct AioContext AioContext; typedef struct Aml Aml; typedef struct AnnounceTimer AnnounceTimer; +typedef struct ArchCPU ArchCPU; typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter; typedef struct BlockBackend BlockBackend; @@ -39,6 +40,7 @@ typedef struct CompatProperty CompatProperty; typedef struct CoMutex CoMutex; typedef struct ConfidentialGuestSupport ConfidentialGuestSupport; typedef struct CPUAddressSpace CPUAddressSpace; +typedef struct CPUArchState CPUArchState; typedef struct CPUState CPUState; typedef struct DeviceListener DeviceListener; typedef struct DeviceState DeviceState; @@ -86,6 +88,8 @@ typedef struct PCIDevice PCIDevice; typedef struct PCIEAERErr PCIEAERErr; typedef struct PCIEAERLog PCIEAERLog; typedef struct PCIEAERMsg PCIEAERMsg; +typedef struct PCIESriovPF PCIESriovPF; +typedef struct PCIESriovVF PCIESriovVF; typedef struct PCIEPort PCIEPort; typedef struct PCIESlot PCIESlot; typedef struct PCIExpressDevice PCIExpressDevice; diff --git a/include/qemu/xattr.h b/include/qemu/xattr.h index a83fe8e749..f1d0f7be74 100644 --- a/include/qemu/xattr.h +++ b/include/qemu/xattr.h @@ -22,7 +22,9 @@ #ifdef CONFIG_LIBATTR # include <attr/xattr.h> #else -# define ENOATTR ENODATA +# if !defined(ENOATTR) +# define ENOATTR ENODATA +# endif # include <sys/xattr.h> #endif diff --git a/include/standard-headers/linux/pvpanic.h b/include/standard-headers/linux/pvpanic.h new file mode 100644 index 0000000000..54b7485390 --- /dev/null +++ b/include/standard-headers/linux/pvpanic.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#ifndef __PVPANIC_H__ +#define __PVPANIC_H__ + +#define PVPANIC_PANICKED (1 << 0) +#define PVPANIC_CRASH_LOADED (1 << 1) + +#endif /* __PVPANIC_H__ */ diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h index 032f6979d7..6013c9444c 100644 --- a/include/sysemu/accel-ops.h +++ b/include/sysemu/accel-ops.h @@ -28,8 +28,11 @@ struct AccelOpsClass { /* initialization function called when accel is chosen */ void (*ops_init)(AccelOpsClass *ops); + bool (*cpus_are_resettable)(void); + void (*create_vcpu_thread)(CPUState *cpu); /* MANDATORY NON-NULL */ void (*kick_vcpu_thread)(CPUState *cpu); + bool (*cpu_thread_is_idle)(CPUState *cpu); void (*synchronize_post_reset)(CPUState *cpu); void (*synchronize_post_init)(CPUState *cpu); diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 70c579560a..79c2591425 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -28,4 +28,6 @@ enum { extern const uint32_t arch_type; +void qemu_init_arch_modules(void); + #endif diff --git a/include/sysemu/hax.h b/include/sysemu/hax.h index 247f0661d1..bf8f99a824 100644 --- a/include/sysemu/hax.h +++ b/include/sysemu/hax.h @@ -25,17 +25,23 @@ int hax_sync_vcpus(void); #ifdef NEED_CPU_H +# ifdef CONFIG_HAX +# define CONFIG_HAX_IS_POSSIBLE +# endif +#else /* !NEED_CPU_H */ +# define CONFIG_HAX_IS_POSSIBLE +#endif -#ifdef CONFIG_HAX +#ifdef CONFIG_HAX_IS_POSSIBLE -int hax_enabled(void); +extern bool hax_allowed; -#else /* CONFIG_HAX */ +#define hax_enabled() (hax_allowed) -#define hax_enabled() (0) +#else /* !CONFIG_HAX_IS_POSSIBLE */ -#endif /* CONFIG_HAX */ +#define hax_enabled() (0) -#endif /* NEED_CPU_H */ +#endif /* CONFIG_HAX_IS_POSSIBLE */ #endif /* QEMU_HAX_H */ diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h index 01b5ebf442..22903a55f7 100644 --- a/include/sysemu/hw_accel.h +++ b/include/sysemu/hw_accel.h @@ -23,9 +23,4 @@ void cpu_synchronize_post_reset(CPUState *cpu); void cpu_synchronize_post_init(CPUState *cpu); void cpu_synchronize_pre_loadvm(CPUState *cpu); -static inline bool cpu_check_are_resettable(void) -{ - return kvm_enabled() ? kvm_cpu_check_are_resettable() : true; -} - #endif /* QEMU_HW_ACCEL_H */ diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 6eb39a088b..a5bec96fb0 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -249,6 +249,9 @@ int kvm_has_intx_set_mask(void); bool kvm_arm_supports_user_irq(void); +int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); +int kvm_on_sigbus(int code, void *addr); + #ifdef NEED_CPU_H #include "cpu.h" @@ -261,9 +264,6 @@ int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr, void kvm_remove_all_breakpoints(CPUState *cpu); int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap); -int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); -int kvm_on_sigbus(int code, void *addr); - /* internal API */ int kvm_ioctl(KVMState *s, int type, ...); diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h index 4b20f1a639..3bbeb1bcb4 100644 --- a/include/sysemu/memory_mapping.h +++ b/include/sysemu/memory_mapping.h @@ -15,8 +15,7 @@ #define MEMORY_MAPPING_H #include "qemu/queue.h" -#include "exec/cpu-defs.h" -#include "exec/memory.h" +#include "exec/cpu-common.h" typedef struct GuestPhysBlock { /* visible to guest, reflects PCI hole, etc */ @@ -43,7 +42,7 @@ typedef struct GuestPhysBlockList { /* The physical and virtual address in the memory mapping are contiguous. */ typedef struct MemoryMapping { hwaddr phys_addr; - target_ulong virt_addr; + vaddr virt_addr; ram_addr_t length; QTAILQ_ENTRY(MemoryMapping) next; } MemoryMapping; diff --git a/meson.build b/meson.build index 038502714a..2d6601467f 100644 --- a/meson.build +++ b/meson.build @@ -1462,14 +1462,16 @@ dbus_display = get_option('dbus_display') \ .allowed() have_virtfs = get_option('virtfs') \ - .require(targetos == 'linux', - error_message: 'virtio-9p (virtfs) requires Linux') \ - .require(libattr.found() and libcap_ng.found(), - error_message: 'virtio-9p (virtfs) requires libcap-ng-devel and libattr-devel') \ + .require(targetos == 'linux' or targetos == 'darwin', + error_message: 'virtio-9p (virtfs) requires Linux or macOS') \ + .require(targetos == 'linux' or cc.has_function('pthread_fchdir_np'), + error_message: 'virtio-9p (virtfs) on macOS requires the presence of pthread_fchdir_np') \ + .require(targetos == 'darwin' or (libattr.found() and libcap_ng.found()), + error_message: 'virtio-9p (virtfs) on Linux requires libcap-ng-devel and libattr-devel') \ .disable_auto_if(not have_tools and not have_system) \ .allowed() -have_virtfs_proxy_helper = have_virtfs and have_tools +have_virtfs_proxy_helper = targetos != 'darwin' and have_virtfs and have_tools foreach k : get_option('trace_backends') config_host_data.set('CONFIG_TRACE_' + k.to_upper(), true) @@ -1619,9 +1621,15 @@ config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime')) config_host_data.set('CONFIG_DUP3', cc.has_function('dup3')) config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate')) config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate')) -config_host_data.set('CONFIG_POSIX_MEMALIGN', cc.has_function('posix_memalign')) +# Note that we need to specify prefix: here to avoid incorrectly +# thinking that Windows has posix_memalign() +config_host_data.set('CONFIG_POSIX_MEMALIGN', cc.has_function('posix_memalign', prefix: '#include <stdlib.h>')) +config_host_data.set('CONFIG_ALIGNED_MALLOC', cc.has_function('_aligned_malloc')) +config_host_data.set('CONFIG_VALLOC', cc.has_function('valloc')) +config_host_data.set('CONFIG_MEMALIGN', cc.has_function('memalign')) config_host_data.set('CONFIG_PPOLL', cc.has_function('ppoll')) config_host_data.set('CONFIG_PREADV', cc.has_function('preadv', prefix: '#include <sys/uio.h>')) +config_host_data.set('CONFIG_PTHREAD_FCHDIR_NP', cc.has_function('pthread_fchdir_np')) config_host_data.set('CONFIG_SEM_TIMEDWAIT', cc.has_function('sem_timedwait', dependencies: threads)) config_host_data.set('CONFIG_SENDFILE', cc.has_function('sendfile')) config_host_data.set('CONFIG_SETNS', cc.has_function('setns') and cc.has_function('unshare')) @@ -2432,8 +2440,8 @@ if get_option('cfi') and slirp_opt == 'system' endif fdt = not_found -fdt_opt = get_option('fdt') if have_system + fdt_opt = get_option('fdt') if fdt_opt in ['enabled', 'auto', 'system'] have_internal = fs.exists(meson.current_source_dir() / 'dtc/libfdt/Makefile.libfdt') fdt = cc.find_library('fdt', kwargs: static_kwargs, @@ -2476,6 +2484,8 @@ if have_system fdt = declare_dependency(link_with: libfdt, include_directories: fdt_inc) endif +else + fdt_opt = 'disabled' endif if not fdt.found() and fdt_required.length() > 0 error('fdt not available but required by targets ' + ', '.join(fdt_required)) @@ -2715,7 +2725,7 @@ if have_system or have_user endif vhost_user = not_found -if 'CONFIG_VHOST_USER' in config_host +if targetos == 'linux' and 'CONFIG_VHOST_USER' in config_host libvhost_user = subproject('libvhost-user') vhost_user = libvhost_user.get_variable('vhost_user_dep') endif diff --git a/nbd/server.c b/nbd/server.c index ba6f71e15d..5da884c2fc 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -25,6 +25,7 @@ #include "trace.h" #include "nbd-internal.h" #include "qemu/units.h" +#include "qemu/memalign.h" #define NBD_META_ID_BASE_ALLOCATION 0 #define NBD_META_ID_ALLOCATION_DEPTH 1 diff --git a/net/l2tpv3.c b/net/l2tpv3.c index e4d4218db6..b8faa8796c 100644 --- a/net/l2tpv3.c +++ b/net/l2tpv3.c @@ -34,7 +34,7 @@ #include "qemu/sockets.h" #include "qemu/iov.h" #include "qemu/main-loop.h" - +#include "qemu/memalign.h" /* The buffer size needs to be investigated for optimum numbers and * optimum means of paging in on different systems. This size is diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin Binary files differindex e0796344df..6163fb8149 100644 --- a/pc-bios/bios-256k.bin +++ b/pc-bios/bios-256k.bin diff --git a/pc-bios/bios-microvm.bin b/pc-bios/bios-microvm.bin Binary files differindex f0215521b0..97fbd3192a 100644 --- a/pc-bios/bios-microvm.bin +++ b/pc-bios/bios-microvm.bin diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin Binary files differindex bcf8b484c9..68f65ff2fd 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/pc-bios/vgabios-ati.bin b/pc-bios/vgabios-ati.bin Binary files differindex 7171a56f9d..4533d0d063 100644 --- a/pc-bios/vgabios-ati.bin +++ b/pc-bios/vgabios-ati.bin diff --git a/pc-bios/vgabios-bochs-display.bin b/pc-bios/vgabios-bochs-display.bin Binary files differindex afea4c930d..3ecf92de01 100644 --- a/pc-bios/vgabios-bochs-display.bin +++ b/pc-bios/vgabios-bochs-display.bin diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin Binary files differindex 194c8139a7..9b4ffdf45f 100644 --- a/pc-bios/vgabios-cirrus.bin +++ b/pc-bios/vgabios-cirrus.bin diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin Binary files differindex 056b6657b3..8a27dac557 100644 --- a/pc-bios/vgabios-qxl.bin +++ b/pc-bios/vgabios-qxl.bin diff --git a/pc-bios/vgabios-ramfb.bin b/pc-bios/vgabios-ramfb.bin Binary files differindex 02662006f2..ec9541cfb4 100644 --- a/pc-bios/vgabios-ramfb.bin +++ b/pc-bios/vgabios-ramfb.bin diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin Binary files differindex cf81ce2876..55390c45c9 100644 --- a/pc-bios/vgabios-stdvga.bin +++ b/pc-bios/vgabios-stdvga.bin diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin Binary files differindex f4178f70de..2334733a75 100644 --- a/pc-bios/vgabios-virtio.bin +++ b/pc-bios/vgabios-virtio.bin diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin Binary files differindex 8fae88af28..b668ac04a6 100644 --- a/pc-bios/vgabios-vmware.bin +++ b/pc-bios/vgabios-vmware.bin diff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin Binary files differindex e5f45f0c9e..a924891ea5 100644 --- a/pc-bios/vgabios.bin +++ b/pc-bios/vgabios.bin diff --git a/plugins/loader.c b/plugins/loader.c index 4883b0a1cb..88c30bde2d 100644 --- a/plugins/loader.c +++ b/plugins/loader.c @@ -27,6 +27,7 @@ #include "qemu/cacheinfo.h" #include "qemu/xxhash.h" #include "qemu/plugin.h" +#include "qemu/memalign.h" #include "hw/core/cpu.h" #include "exec/exec-all.h" #ifndef CONFIG_USER_ONLY diff --git a/python/qemu/aqmp/legacy.py b/python/qemu/aqmp/legacy.py index 6baa5f3409..46026e9fdc 100644 --- a/python/qemu/aqmp/legacy.py +++ b/python/qemu/aqmp/legacy.py @@ -57,7 +57,7 @@ class QEMUMonitorProtocol(qemu.qmp.QEMUMonitorProtocol): self._timeout: Optional[float] = None if server: - self._aqmp._bind_hack(address) # pylint: disable=protected-access + self._sync(self._aqmp.start_server(self._address)) _T = TypeVar('_T') @@ -90,10 +90,7 @@ class QEMUMonitorProtocol(qemu.qmp.QEMUMonitorProtocol): self._aqmp.await_greeting = True self._aqmp.negotiate = True - self._sync( - self._aqmp.accept(self._address), - timeout - ) + self._sync(self._aqmp.accept(), timeout) ret = self._get_greeting() assert ret is not None diff --git a/python/qemu/aqmp/protocol.py b/python/qemu/aqmp/protocol.py index 33358f5cd7..36fae57f27 100644 --- a/python/qemu/aqmp/protocol.py +++ b/python/qemu/aqmp/protocol.py @@ -10,12 +10,14 @@ In this package, it is used as the implementation for the `QMPClient` class. """ +# It's all the docstrings ... ! It's long for a good reason ^_^; +# pylint: disable=too-many-lines + import asyncio from asyncio import StreamReader, StreamWriter from enum import Enum from functools import wraps import logging -import socket from ssl import SSLContext from typing import ( Any, @@ -239,8 +241,9 @@ class AsyncProtocol(Generic[T]): self._runstate = Runstate.IDLE self._runstate_changed: Optional[asyncio.Event] = None - # Workaround for bind() - self._sock: Optional[socket.socket] = None + # Server state for start_server() and _incoming() + self._server: Optional[asyncio.AbstractServer] = None + self._accepted: Optional[asyncio.Event] = None def __repr__(self) -> str: cls_name = type(self).__name__ @@ -265,21 +268,90 @@ class AsyncProtocol(Generic[T]): @upper_half @require(Runstate.IDLE) - async def accept(self, address: SocketAddrT, - ssl: Optional[SSLContext] = None) -> None: + async def start_server_and_accept( + self, address: SocketAddrT, + ssl: Optional[SSLContext] = None + ) -> None: """ Accept a connection and begin processing message queues. If this call fails, `runstate` is guaranteed to be set back to `IDLE`. + This method is precisely equivalent to calling `start_server()` + followed by `accept()`. + + :param address: + Address to listen on; UNIX socket path or TCP address/port. + :param ssl: SSL context to use, if any. + + :raise StateError: When the `Runstate` is not `IDLE`. + :raise ConnectError: + When a connection or session cannot be established. + + This exception will wrap a more concrete one. In most cases, + the wrapped exception will be `OSError` or `EOFError`. If a + protocol-level failure occurs while establishing a new + session, the wrapped error may also be an `QMPError`. + """ + await self.start_server(address, ssl) + await self.accept() + assert self.runstate == Runstate.RUNNING + + @upper_half + @require(Runstate.IDLE) + async def start_server(self, address: SocketAddrT, + ssl: Optional[SSLContext] = None) -> None: + """ + Start listening for an incoming connection, but do not wait for a peer. + + This method starts listening for an incoming connection, but + does not block waiting for a peer. This call will return + immediately after binding and listening on a socket. A later + call to `accept()` must be made in order to finalize the + incoming connection. :param address: - Address to listen to; UNIX socket path or TCP address/port. + Address to listen on; UNIX socket path or TCP address/port. :param ssl: SSL context to use, if any. :raise StateError: When the `Runstate` is not `IDLE`. - :raise ConnectError: If a connection could not be accepted. + :raise ConnectError: + When the server could not start listening on this address. + + This exception will wrap a more concrete one. In most cases, + the wrapped exception will be `OSError`. + """ + await self._session_guard( + self._do_start_server(address, ssl), + 'Failed to establish connection') + assert self.runstate == Runstate.CONNECTING + + @upper_half + @require(Runstate.CONNECTING) + async def accept(self) -> None: + """ + Accept an incoming connection and begin processing message queues. + + If this call fails, `runstate` is guaranteed to be set back to `IDLE`. + + :raise StateError: When the `Runstate` is not `CONNECTING`. + :raise QMPError: When `start_server()` was not called yet. + :raise ConnectError: + When a connection or session cannot be established. + + This exception will wrap a more concrete one. In most cases, + the wrapped exception will be `OSError` or `EOFError`. If a + protocol-level failure occurs while establishing a new + session, the wrapped error may also be an `QMPError`. """ - await self._new_session(address, ssl, accept=True) + if self._accepted is None: + raise QMPError("Cannot call accept() before start_server().") + await self._session_guard( + self._do_accept(), + 'Failed to establish connection') + await self._session_guard( + self._establish_session(), + 'Failed to establish session') + assert self.runstate == Runstate.RUNNING @upper_half @require(Runstate.IDLE) @@ -295,9 +367,21 @@ class AsyncProtocol(Generic[T]): :param ssl: SSL context to use, if any. :raise StateError: When the `Runstate` is not `IDLE`. - :raise ConnectError: If a connection cannot be made to the server. + :raise ConnectError: + When a connection or session cannot be established. + + This exception will wrap a more concrete one. In most cases, + the wrapped exception will be `OSError` or `EOFError`. If a + protocol-level failure occurs while establishing a new + session, the wrapped error may also be an `QMPError`. """ - await self._new_session(address, ssl) + await self._session_guard( + self._do_connect(address, ssl), + 'Failed to establish connection') + await self._session_guard( + self._establish_session(), + 'Failed to establish session') + assert self.runstate == Runstate.RUNNING @upper_half async def disconnect(self) -> None: @@ -317,153 +401,146 @@ class AsyncProtocol(Generic[T]): # Section: Session machinery # -------------------------- - @property - def _runstate_event(self) -> asyncio.Event: - # asyncio.Event() objects should not be created prior to entrance into - # an event loop, so we can ensure we create it in the correct context. - # Create it on-demand *only* at the behest of an 'async def' method. - if not self._runstate_changed: - self._runstate_changed = asyncio.Event() - return self._runstate_changed - - @upper_half - @bottom_half - def _set_state(self, state: Runstate) -> None: - """ - Change the `Runstate` of the protocol connection. - - Signals the `runstate_changed` event. - """ - if state == self._runstate: - return - - self.logger.debug("Transitioning from '%s' to '%s'.", - str(self._runstate), str(state)) - self._runstate = state - self._runstate_event.set() - self._runstate_event.clear() - - @upper_half - async def _new_session(self, - address: SocketAddrT, - ssl: Optional[SSLContext] = None, - accept: bool = False) -> None: + async def _session_guard(self, coro: Awaitable[None], emsg: str) -> None: """ - Establish a new connection and initialize the session. + Async guard function used to roll back to `IDLE` on any error. - Connect or accept a new connection, then begin the protocol - session machinery. If this call fails, `runstate` is guaranteed - to be set back to `IDLE`. + On any Exception, the state machine will be reset back to + `IDLE`. Most Exceptions will be wrapped with `ConnectError`, but + `BaseException` events will be left alone (This includes + asyncio.CancelledError, even prior to Python 3.8). - :param address: - Address to connect to/listen on; - UNIX socket path or TCP address/port. - :param ssl: SSL context to use, if any. - :param accept: Accept a connection instead of connecting when `True`. + :param error_message: + Human-readable string describing what connection phase failed. + :raise BaseException: + When `BaseException` occurs in the guarded block. :raise ConnectError: - When a connection or session cannot be established. - - This exception will wrap a more concrete one. In most cases, - the wrapped exception will be `OSError` or `EOFError`. If a - protocol-level failure occurs while establishing a new - session, the wrapped error may also be an `QMPError`. + When any other error is encountered in the guarded block. """ - assert self.runstate == Runstate.IDLE - + # Note: After Python 3.6 support is removed, this should be an + # @asynccontextmanager instead of accepting a callback. try: - phase = "connection" - await self._establish_connection(address, ssl, accept) - - phase = "session" - await self._establish_session() - + await coro except BaseException as err: - emsg = f"Failed to establish {phase}" self.logger.error("%s: %s", emsg, exception_summary(err)) self.logger.debug("%s:\n%s\n", emsg, pretty_traceback()) try: - # Reset from CONNECTING back to IDLE. + # Reset the runstate back to IDLE. await self.disconnect() except: - emsg = "Unexpected bottom half exception" + # We don't expect any Exceptions from the disconnect function + # here, because we failed to connect in the first place. + # The disconnect() function is intended to perform + # only cannot-fail cleanup here, but you never know. + emsg = ( + "Unexpected bottom half exception. " + "This is a bug in the QMP library. " + "Please report it to <qemu-devel@nongnu.org> and " + "CC: John Snow <jsnow@redhat.com>." + ) self.logger.critical("%s:\n%s\n", emsg, pretty_traceback()) raise + # CancelledError is an Exception with special semantic meaning; + # We do NOT want to wrap it up under ConnectError. # NB: CancelledError is not a BaseException before Python 3.8 if isinstance(err, asyncio.CancelledError): raise + # Any other kind of error can be treated as some kind of connection + # failure broadly. Inspect the 'exc' field to explore the root + # cause in greater detail. if isinstance(err, Exception): raise ConnectError(emsg, err) from err # Raise BaseExceptions un-wrapped, they're more important. raise - assert self.runstate == Runstate.RUNNING + @property + def _runstate_event(self) -> asyncio.Event: + # asyncio.Event() objects should not be created prior to entrance into + # an event loop, so we can ensure we create it in the correct context. + # Create it on-demand *only* at the behest of an 'async def' method. + if not self._runstate_changed: + self._runstate_changed = asyncio.Event() + return self._runstate_changed @upper_half - async def _establish_connection( - self, - address: SocketAddrT, - ssl: Optional[SSLContext] = None, - accept: bool = False - ) -> None: + @bottom_half + def _set_state(self, state: Runstate) -> None: """ - Establish a new connection. + Change the `Runstate` of the protocol connection. - :param address: - Address to connect to/listen on; - UNIX socket path or TCP address/port. - :param ssl: SSL context to use, if any. - :param accept: Accept a connection instead of connecting when `True`. + Signals the `runstate_changed` event. """ - assert self.runstate == Runstate.IDLE - self._set_state(Runstate.CONNECTING) - - # Allow runstate watchers to witness 'CONNECTING' state; some - # failures in the streaming layer are synchronous and will not - # otherwise yield. - await asyncio.sleep(0) + if state == self._runstate: + return - if accept: - await self._do_accept(address, ssl) - else: - await self._do_connect(address, ssl) + self.logger.debug("Transitioning from '%s' to '%s'.", + str(self._runstate), str(state)) + self._runstate = state + self._runstate_event.set() + self._runstate_event.clear() - def _bind_hack(self, address: Union[str, Tuple[str, int]]) -> None: + @bottom_half + async def _stop_server(self) -> None: + """ + Stop listening for / accepting new incoming connections. """ - Used to create a socket in advance of accept(). + if self._server is None: + return - This is a workaround to ensure that we can guarantee timing of - precisely when a socket exists to avoid a connection attempt - bouncing off of nothing. + try: + self.logger.debug("Stopping server.") + self._server.close() + await self._server.wait_closed() + self.logger.debug("Server stopped.") + finally: + self._server = None - Python 3.7+ adds a feature to separate the server creation and - listening phases instead, and should be used instead of this - hack. + @bottom_half # However, it does not run from the R/W tasks. + async def _incoming(self, + reader: asyncio.StreamReader, + writer: asyncio.StreamWriter) -> None: """ - if isinstance(address, tuple): - family = socket.AF_INET - else: - family = socket.AF_UNIX + Accept an incoming connection and signal the upper_half. - sock = socket.socket(family, socket.SOCK_STREAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + This method does the minimum necessary to accept a single + incoming connection. It signals back to the upper_half ASAP so + that any errors during session initialization can occur + naturally in the caller's stack. - try: - sock.bind(address) - except: - sock.close() - raise + :param reader: Incoming `asyncio.StreamReader` + :param writer: Incoming `asyncio.StreamWriter` + """ + peer = writer.get_extra_info('peername', 'Unknown peer') + self.logger.debug("Incoming connection from %s", peer) + + if self._reader or self._writer: + # Sadly, we can have more than one pending connection + # because of https://bugs.python.org/issue46715 + # Close any extra connections we don't actually want. + self.logger.warning("Extraneous connection inadvertently accepted") + writer.close() + return - self._sock = sock + # A connection has been accepted; stop listening for new ones. + assert self._accepted is not None + await self._stop_server() + self._reader, self._writer = (reader, writer) + self._accepted.set() @upper_half - async def _do_accept(self, address: SocketAddrT, - ssl: Optional[SSLContext] = None) -> None: + async def _do_start_server(self, address: SocketAddrT, + ssl: Optional[SSLContext] = None) -> None: """ - Acting as the transport server, accept a single connection. + Start listening for an incoming connection, but do not wait for a peer. + + This method starts listening for an incoming connection, but does not + block waiting for a peer. This call will return immediately after + binding and listening to a socket. A later call to accept() must be + made in order to finalize the incoming connection. :param address: Address to listen on; UNIX socket path or TCP address/port. @@ -471,52 +548,54 @@ class AsyncProtocol(Generic[T]): :raise OSError: For stream-related errors. """ - self.logger.debug("Awaiting connection on %s ...", address) - connected = asyncio.Event() - server: Optional[asyncio.AbstractServer] = None - - async def _client_connected_cb(reader: asyncio.StreamReader, - writer: asyncio.StreamWriter) -> None: - """Used to accept a single incoming connection, see below.""" - nonlocal server - nonlocal connected - - # A connection has been accepted; stop listening for new ones. - assert server is not None - server.close() - await server.wait_closed() - server = None - - # Register this client as being connected - self._reader, self._writer = (reader, writer) + assert self.runstate == Runstate.IDLE + self._set_state(Runstate.CONNECTING) - # Signal back: We've accepted a client! - connected.set() + self.logger.debug("Awaiting connection on %s ...", address) + self._accepted = asyncio.Event() if isinstance(address, tuple): coro = asyncio.start_server( - _client_connected_cb, - host=None if self._sock else address[0], - port=None if self._sock else address[1], + self._incoming, + host=address[0], + port=address[1], ssl=ssl, backlog=1, limit=self._limit, - sock=self._sock, ) else: coro = asyncio.start_unix_server( - _client_connected_cb, - path=None if self._sock else address, + self._incoming, + path=address, ssl=ssl, backlog=1, limit=self._limit, - sock=self._sock, ) - server = await coro # Starts listening - await connected.wait() # Waits for the callback to fire (and finish) - assert server is None - self._sock = None + # Allow runstate watchers to witness 'CONNECTING' state; some + # failures in the streaming layer are synchronous and will not + # otherwise yield. + await asyncio.sleep(0) + + # This will start the server (bind(2), listen(2)). It will also + # call accept(2) if we yield, but we don't block on that here. + self._server = await coro + self.logger.debug("Server listening on %s", address) + + @upper_half + async def _do_accept(self) -> None: + """ + Wait for and accept an incoming connection. + + Requires that we have not yet accepted an incoming connection + from the upper_half, but it's OK if the server is no longer + running because the bottom_half has already accepted the + connection. + """ + assert self._accepted is not None + await self._accepted.wait() + assert self._server is None + self._accepted = None self.logger.debug("Connection accepted.") @@ -532,6 +611,14 @@ class AsyncProtocol(Generic[T]): :raise OSError: For stream-related errors. """ + assert self.runstate == Runstate.IDLE + self._set_state(Runstate.CONNECTING) + + # Allow runstate watchers to witness 'CONNECTING' state; some + # failures in the streaming layer are synchronous and will not + # otherwise yield. + await asyncio.sleep(0) + self.logger.debug("Connecting to %s ...", address) if isinstance(address, tuple): @@ -644,6 +731,7 @@ class AsyncProtocol(Generic[T]): self._reader = None self._writer = None + self._accepted = None # NB: _runstate_changed cannot be cleared because we still need it to # send the final runstate changed event ...! @@ -667,6 +755,9 @@ class AsyncProtocol(Generic[T]): def _done(task: Optional['asyncio.Future[Any]']) -> bool: return task is not None and task.done() + # If the server is running, stop it. + await self._stop_server() + # Are we already in an error pathway? If either of the tasks are # already done, or if we have no tasks but a reader/writer; we # must be. diff --git a/python/tests/protocol.py b/python/tests/protocol.py index 5cd7938be3..d6849ad306 100644 --- a/python/tests/protocol.py +++ b/python/tests/protocol.py @@ -41,12 +41,25 @@ class NullProtocol(AsyncProtocol[None]): self.trigger_input = asyncio.Event() await super()._establish_session() - async def _do_accept(self, address, ssl=None): - if not self.fake_session: - await super()._do_accept(address, ssl) + async def _do_start_server(self, address, ssl=None): + if self.fake_session: + self._accepted = asyncio.Event() + self._set_state(Runstate.CONNECTING) + await asyncio.sleep(0) + else: + await super()._do_start_server(address, ssl) + + async def _do_accept(self): + if self.fake_session: + self._accepted = None + else: + await super()._do_accept() async def _do_connect(self, address, ssl=None): - if not self.fake_session: + if self.fake_session: + self._set_state(Runstate.CONNECTING) + await asyncio.sleep(0) + else: await super()._do_connect(address, ssl) async def _do_recv(self) -> None: @@ -413,14 +426,14 @@ class Accept(Connect): assert family in ('INET', 'UNIX') if family == 'INET': - await self.proto.accept(('example.com', 1)) + await self.proto.start_server_and_accept(('example.com', 1)) elif family == 'UNIX': - await self.proto.accept('/dev/null') + await self.proto.start_server_and_accept('/dev/null') async def _hanging_connection(self): with TemporaryDirectory(suffix='.aqmp') as tmpdir: sock = os.path.join(tmpdir, type(self.proto).__name__ + ".sock") - await self.proto.accept(sock) + await self.proto.start_server_and_accept(sock) class FakeSession(TestBase): @@ -449,13 +462,13 @@ class FakeSession(TestBase): @TestBase.async_test async def testFakeAccept(self): """Test the full state lifecycle (via accept) with a no-op session.""" - await self.proto.accept('/not/a/real/path') + await self.proto.start_server_and_accept('/not/a/real/path') self.assertEqual(self.proto.runstate, Runstate.RUNNING) @TestBase.async_test async def testFakeRecv(self): """Test receiving a fake/null message.""" - await self.proto.accept('/not/a/real/path') + await self.proto.start_server_and_accept('/not/a/real/path') logname = self.proto.logger.name with self.assertLogs(logname, level='DEBUG') as context: @@ -471,7 +484,7 @@ class FakeSession(TestBase): @TestBase.async_test async def testFakeSend(self): """Test sending a fake/null message.""" - await self.proto.accept('/not/a/real/path') + await self.proto.start_server_and_accept('/not/a/real/path') logname = self.proto.logger.name with self.assertLogs(logname, level='DEBUG') as context: @@ -493,7 +506,7 @@ class FakeSession(TestBase): ): with self.assertRaises(StateError) as context: if accept: - await self.proto.accept('/not/a/real/path') + await self.proto.start_server_and_accept('/not/a/real/path') else: await self.proto.connect('/not/a/real/path') @@ -504,7 +517,7 @@ class FakeSession(TestBase): @TestBase.async_test async def testAcceptRequireRunning(self): """Test that accept() cannot be called when Runstate=RUNNING""" - await self.proto.accept('/not/a/real/path') + await self.proto.start_server_and_accept('/not/a/real/path') await self._prod_session_api( Runstate.RUNNING, @@ -515,7 +528,7 @@ class FakeSession(TestBase): @TestBase.async_test async def testConnectRequireRunning(self): """Test that connect() cannot be called when Runstate=RUNNING""" - await self.proto.accept('/not/a/real/path') + await self.proto.start_server_and_accept('/not/a/real/path') await self._prod_session_api( Runstate.RUNNING, @@ -526,7 +539,7 @@ class FakeSession(TestBase): @TestBase.async_test async def testAcceptRequireDisconnecting(self): """Test that accept() cannot be called when Runstate=DISCONNECTING""" - await self.proto.accept('/not/a/real/path') + await self.proto.start_server_and_accept('/not/a/real/path') # Cheat: force a disconnect. await self.proto.simulate_disconnect() @@ -541,7 +554,7 @@ class FakeSession(TestBase): @TestBase.async_test async def testConnectRequireDisconnecting(self): """Test that connect() cannot be called when Runstate=DISCONNECTING""" - await self.proto.accept('/not/a/real/path') + await self.proto.start_server_and_accept('/not/a/real/path') # Cheat: force a disconnect. await self.proto.simulate_disconnect() @@ -576,7 +589,7 @@ class SimpleSession(TestBase): async def testSmoke(self): with TemporaryDirectory(suffix='.aqmp') as tmpdir: sock = os.path.join(tmpdir, type(self.proto).__name__ + ".sock") - server_task = create_task(self.server.accept(sock)) + server_task = create_task(self.server.start_server_and_accept(sock)) # give the server a chance to start listening [...] await asyncio.sleep(0) diff --git a/qemu-img.c b/qemu-img.c index 6fe2466032..5dffb3e616 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -42,6 +42,7 @@ #include "qemu/module.h" #include "qemu/sockets.h" #include "qemu/units.h" +#include "qemu/memalign.h" #include "qom/object_interfaces.h" #include "sysemu/block-backend.h" #include "block/block_int.h" diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 45a9570933..2f0d8ac25a 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -21,6 +21,7 @@ #include "qemu/option.h" #include "qemu/timer.h" #include "qemu/cutils.h" +#include "qemu/memalign.h" #define CMD_NOFILE_OK 0x01 diff --git a/qemu-options.hx b/qemu-options.hx index 094a6c1d7c..5ce0ada75e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2537,6 +2537,7 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, " specify SMBIOS type 3 fields\n" "-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str]\n" " [,asset=str][,part=str][,max-speed=%d][,current-speed=%d]\n" + " [,processor-id=%d]\n" " specify SMBIOS type 4 fields\n" "-smbios type=11[,value=str][,path=filename]\n" " specify SMBIOS type 11 fields\n" @@ -2562,7 +2563,7 @@ SRST ``-smbios type=3[,manufacturer=str][,version=str][,serial=str][,asset=str][,sku=str]`` Specify SMBIOS type 3 fields -``-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str][,asset=str][,part=str]`` +``-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str][,asset=str][,part=str][,processor-id=%d]`` Specify SMBIOS type 4 fields ``-smbios type=11[,value=str][,path=filename]`` diff --git a/qom/object.c b/qom/object.c index 9f7a33139d..d34608558e 100644 --- a/qom/object.c +++ b/qom/object.c @@ -16,6 +16,7 @@ #include "qom/object.h" #include "qom/object_interfaces.h" #include "qemu/cutils.h" +#include "qemu/memalign.h" #include "qapi/visitor.h" #include "qapi/string-input-visitor.h" #include "qapi/string-output-visitor.h" @@ -1167,10 +1168,14 @@ GSList *object_class_get_list_sorted(const char *implements_type, Object *object_ref(void *objptr) { Object *obj = OBJECT(objptr); + uint32_t ref; + if (!obj) { return NULL; } - qatomic_inc(&obj->ref); + ref = qatomic_fetch_inc(&obj->ref); + /* Assert waaay before the integer overflows */ + g_assert(ref < INT_MAX); return obj; } diff --git a/roms/seabios b/roms/seabios -Subproject 6a62e0cb0dfe9cd28b70547dbea5caf76847c3a +Subproject d239552ce7220e448ae81f41515138f7b9e3c4d diff --git a/scripts/qmp/qmp-shell-wrap b/scripts/qmp/qmp-shell-wrap index 9e94da114f..66846e36d1 100755 --- a/scripts/qmp/qmp-shell-wrap +++ b/scripts/qmp/qmp-shell-wrap @@ -4,7 +4,7 @@ import os import sys sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) -from qemu.qmp import qmp_shell +from qemu.aqmp import qmp_shell if __name__ == '__main__': diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index fe850763c5..839a5ec614 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -214,7 +214,8 @@ for i in "$tmpdir"/include/linux/*virtio*.h \ "$tmpdir/include/linux/const.h" \ "$tmpdir/include/linux/kernel.h" \ "$tmpdir/include/linux/vhost_types.h" \ - "$tmpdir/include/linux/sysinfo.h"; do + "$tmpdir/include/linux/sysinfo.h" \ + "$tmpdir/include/misc/pvpanic.h"; do cp_portable "$i" "$output/include/standard-headers/linux" done mkdir -p "$output/include/standard-headers/drm" diff --git a/softmmu/arch_init.c b/softmmu/arch_init.c index 8919405c7b..79716f959b 100644 --- a/softmmu/arch_init.c +++ b/softmmu/arch_init.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu/module.h" #include "sysemu/arch_init.h" #ifdef TARGET_SPARC @@ -39,3 +40,11 @@ int graphic_depth = 32; #endif const uint32_t arch_type = QEMU_ARCH; + +void qemu_init_arch_modules(void) +{ +#ifdef CONFIG_MODULES + module_init_info(qemu_modinfo); + module_allow_arch(TARGET_NAME); +#endif +} diff --git a/softmmu/cpu-timers.c b/softmmu/cpu-timers.c index 34ddfa02f1..204d946a17 100644 --- a/softmmu/cpu-timers.c +++ b/softmmu/cpu-timers.c @@ -28,7 +28,6 @@ #include "migration/vmstate.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "exec/exec-all.h" #include "sysemu/cpus.h" #include "qemu/main-loop.h" #include "qemu/option.h" diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 1681844b61..e1d84c8ccb 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -33,7 +33,7 @@ #include "qapi/qmp/qerror.h" #include "exec/gdbstub.h" #include "sysemu/hw_accel.h" -#include "exec/exec-all.h" +#include "exec/cpu-common.h" #include "qemu/thread.h" #include "qemu/plugin.h" #include "sysemu/cpus.h" @@ -67,6 +67,11 @@ static QemuMutex qemu_global_mutex; +/* + * The chosen accelerator is supposed to register this. + */ +static const AccelOpsClass *cpus_accel; + bool cpu_is_stopped(CPUState *cpu) { return cpu->stopped || !runstate_is_running(); @@ -85,10 +90,12 @@ bool cpu_thread_is_idle(CPUState *cpu) if (cpu_is_stopped(cpu)) { return true; } - if (!cpu->halted || cpu_has_work(cpu) || - kvm_halt_in_kernel() || whpx_apic_in_platform()) { + if (!cpu->halted || cpu_has_work(cpu)) { return false; } + if (cpus_accel->cpu_thread_is_idle) { + return cpus_accel->cpu_thread_is_idle(cpu); + } return true; } @@ -122,11 +129,6 @@ void hw_error(const char *fmt, ...) abort(); } -/* - * The chosen accelerator is supposed to register this. - */ -static const AccelOpsClass *cpus_accel; - void cpu_synchronize_all_states(void) { CPUState *cpu; @@ -193,7 +195,10 @@ void cpu_synchronize_pre_loadvm(CPUState *cpu) bool cpus_are_resettable(void) { - return cpu_check_are_resettable(); + if (cpus_accel->cpus_are_resettable) { + return cpus_accel->cpus_are_resettable(); + } + return true; } int64_t cpus_get_virtual_clock(void) diff --git a/softmmu/globals.c b/softmmu/globals.c index 7d0fc81183..3ebd718e35 100644 --- a/softmmu/globals.c +++ b/softmmu/globals.c @@ -25,8 +25,6 @@ #include "qemu/osdep.h" #include "exec/cpu-common.h" #include "hw/display/vga.h" -#include "hw/i386/pc.h" -#include "hw/i386/x86.h" #include "hw/loader.h" #include "hw/xen/xen.h" #include "net/net.h" diff --git a/softmmu/memory_mapping.c b/softmmu/memory_mapping.c index a62eaa49cc..8320165ea2 100644 --- a/softmmu/memory_mapping.c +++ b/softmmu/memory_mapping.c @@ -17,6 +17,7 @@ #include "sysemu/memory_mapping.h" #include "exec/memory.h" #include "exec/address-spaces.h" +#include "hw/core/cpu.h" //#define DEBUG_GUEST_PHYS_REGION_ADD diff --git a/softmmu/meson.build b/softmmu/meson.build index 39f766ce7c..8138248661 100644 --- a/softmmu/meson.build +++ b/softmmu/meson.build @@ -1,20 +1,9 @@ specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files( 'arch_init.c', - 'balloon.c', - 'cpus.c', - 'cpu-throttle.c', - 'datadir.c', - 'globals.c', - 'physmem.c', 'ioport.c', - 'rtc.c', - 'runstate.c', 'memory.c', - 'memory_mapping.c', + 'physmem.c', 'qtest.c', - 'vl.c', - 'cpu-timers.c', - 'runstate-action.c', )]) specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: [files( @@ -22,9 +11,20 @@ specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: [files( )]) softmmu_ss.add(files( + 'balloon.c', 'bootdevice.c', + 'cpus.c', + 'cpu-throttle.c', + 'cpu-timers.c', + 'datadir.c', 'dma-helpers.c', + 'globals.c', + 'memory_mapping.c', 'qdev-monitor.c', + 'rtc.c', + 'runstate-action.c', + 'runstate.c', + 'vl.c', ), sdl, libpmem, libdaxctl) if have_tpm diff --git a/softmmu/physmem.c b/softmmu/physmem.c index a13289a594..43ae70fbe2 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -42,6 +42,7 @@ #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qemu/qemu-print.h" +#include "qemu/memalign.h" #include "exec/memory.h" #include "exec/ioport.h" #include "sysemu/dma.h" @@ -61,7 +62,6 @@ #include "exec/memory-internal.h" #include "exec/ram_addr.h" -#include "exec/log.h" #include "qemu/pmem.h" @@ -3436,11 +3436,11 @@ address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr, #include "memory_ldst.c.inc" /* virtual memory access for debug (includes writing to ROM) */ -int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, - void *ptr, target_ulong len, bool is_write) +int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, + void *ptr, size_t len, bool is_write) { hwaddr phys_addr; - target_ulong l, page; + vaddr l, page; uint8_t *buf = ptr; cpu_synchronize_state(cpu); diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c index fe6cf268ff..12fe60c467 100644 --- a/softmmu/qdev-monitor.c +++ b/softmmu/qdev-monitor.c @@ -1038,6 +1038,13 @@ int qemu_global_option(const char *str) if (!opts) { return -1; } + if (!qemu_opt_get(opts, "driver") + || !qemu_opt_get(opts, "property") + || !qemu_opt_get(opts, "value")) { + error_report("options 'driver', 'property', and 'value'" + " are required"); + return -1; + } return 0; } diff --git a/softmmu/vl.c b/softmmu/vl.c index 1fe028800f..0b81f61535 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2815,10 +2815,7 @@ void qemu_init(int argc, char **argv, char **envp) error_init(argv[0]); qemu_init_exec_dir(argv[0]); -#ifdef CONFIG_MODULES - module_init_info(qemu_modinfo); - module_allow_arch(TARGET_NAME); -#endif + qemu_init_arch_modules(); qemu_init_subsystems(); diff --git a/target/alpha/cpu-qom.h b/target/alpha/cpu-qom.h index 7bb9173c57..1f200724b6 100644 --- a/target/alpha/cpu-qom.h +++ b/target/alpha/cpu-qom.h @@ -25,8 +25,7 @@ #define TYPE_ALPHA_CPU "alpha-cpu" -OBJECT_DECLARE_TYPE(AlphaCPU, AlphaCPUClass, - ALPHA_CPU) +OBJECT_DECLARE_CPU_TYPE(AlphaCPU, AlphaCPUClass, ALPHA_CPU) /** * AlphaCPUClass: diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h index e819211503..58f00b7814 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -197,9 +197,7 @@ enum { #define MMU_USER_IDX 1 #define MMU_PHYS_IDX 2 -typedef struct CPUAlphaState CPUAlphaState; - -struct CPUAlphaState { +typedef struct CPUArchState { uint64_t ir[31]; float64 fir[31]; uint64_t pc; @@ -251,7 +249,7 @@ struct CPUAlphaState { uint32_t features; uint32_t amask; int implver; -}; +} CPUAlphaState; /** * AlphaCPU: @@ -259,7 +257,7 @@ struct CPUAlphaState { * * An Alpha CPU. */ -struct AlphaCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -285,9 +283,6 @@ int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); #define cpu_list alpha_cpu_list -typedef CPUAlphaState CPUArchState; -typedef AlphaCPU ArchCPU; - #include "exec/cpu-all.h" enum { diff --git a/target/alpha/translate.c b/target/alpha/translate.c index ca78a0faed..66768ab47a 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "sysemu/cpus.h" -#include "sysemu/cpu-timers.h" #include "disas/disas.h" #include "qemu/host-utils.h" #include "exec/exec-all.h" diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h index a22bd506d0..64c44cef2d 100644 --- a/target/arm/cpu-qom.h +++ b/target/arm/cpu-qom.h @@ -27,8 +27,7 @@ struct arm_boot_info; #define TYPE_ARM_CPU "arm-cpu" -OBJECT_DECLARE_TYPE(ARMCPU, ARMCPUClass, - ARM_CPU) +OBJECT_DECLARE_CPU_TYPE(ARMCPU, ARMCPUClass, ARM_CPU) #define TYPE_ARM_MAX_CPU "max-" TYPE_ARM_CPU diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 7091684a16..185d4e774d 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1392,6 +1392,12 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp) error_propagate(errp, local_err); return; } + + arm_cpu_lpa2_finalize(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } } if (kvm_enabled()) { diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 24d9fff170..157f214cce 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -204,10 +204,12 @@ typedef struct { # define ARM_MAX_VQ 16 void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp); void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp); +void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp); #else # define ARM_MAX_VQ 1 static inline void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { } static inline void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) { } +static inline void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) { } #endif typedef struct ARMVectorReg { @@ -232,7 +234,7 @@ typedef struct CPUARMTBFlags { target_ulong flags2; } CPUARMTBFlags; -typedef struct CPUARMState { +typedef struct CPUArchState { /* Regs for current mode. */ uint32_t regs[16]; @@ -774,7 +776,7 @@ typedef struct ARMISARegisters ARMISARegisters; * * An ARM CPU core. */ -struct ARMCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -975,10 +977,11 @@ struct ARMCPU { /* * Intermediate values used during property parsing. - * Once finalized, the values should be read from ID_AA64ISAR1. + * Once finalized, the values should be read from ID_AA64*. */ bool prop_pauth; bool prop_pauth_impdef; + bool prop_lpa2; /* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */ uint32_t dcz_blocksize; @@ -3410,9 +3413,6 @@ static inline bool arm_cpu_data_is_big_endian(CPUARMState *env) } } -typedef CPUARMState CPUArchState; -typedef ARMCPU ArchCPU; - #include "exec/cpu-all.h" /* diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 2fdc16bf18..eb44c05822 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -688,6 +688,29 @@ void aarch64_add_pauth_properties(Object *obj) } } +static Property arm_cpu_lpa2_property = + DEFINE_PROP_BOOL("lpa2", ARMCPU, prop_lpa2, true); + +void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) +{ + uint64_t t; + + /* + * We only install the property for tcg -cpu max; this is the + * only situation in which the cpu field can be true. + */ + if (!cpu->prop_lpa2) { + return; + } + + t = cpu->isar.id_aa64mmfr0; + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16, 2); /* 16k pages w/ LPA2 */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4, 1); /* 4k pages w/ LPA2 */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 3); /* 16k stage2 w/ LPA2 */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 3); /* 4k stage2 w/ LPA2 */ + cpu->isar.id_aa64mmfr0 = t; +} + static void aarch64_host_initfn(Object *obj) { #if defined(CONFIG_KVM) @@ -897,6 +920,7 @@ static void aarch64_max_initfn(Object *obj) aarch64_add_sve_properties(obj); object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq, cpu_max_set_sve_max_vq, NULL, NULL); + qdev_property_add_static(DEVICE(obj), &arm_cpu_lpa2_property); } static void aarch64_a64fx_initfn(Object *obj) diff --git a/target/arm/hvf_arm.h b/target/arm/hvf_arm.h index ea238cff83..9a9d1a0bf5 100644 --- a/target/arm/hvf_arm.h +++ b/target/arm/hvf_arm.h @@ -13,6 +13,6 @@ #include "cpu.h" -void hvf_arm_set_cpu_features_from_host(struct ARMCPU *cpu); +void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu); #endif diff --git a/target/arm/translate-neon.c b/target/arm/translate-neon.c index 3854dd3516..384604c009 100644 --- a/target/arm/translate-neon.c +++ b/target/arm/translate-neon.c @@ -657,21 +657,24 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) /* Catch the UNDEF cases. This is unavoidably a bit messy. */ switch (nregs) { case 1: + if (a->stride != 1) { + return false; + } if (((a->align & (1 << a->size)) != 0) || (a->size == 2 && (a->align == 1 || a->align == 2))) { return false; } break; - case 3: - if ((a->align & 1) != 0) { - return false; - } - /* fall through */ case 2: if (a->size == 2 && (a->align & 2) != 0) { return false; } break; + case 3: + if (a->align != 0) { + return false; + } + break; case 4: if (a->size == 2 && a->align == 3) { return false; diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h index 14e5b3ce72..32a1c762e6 100644 --- a/target/avr/cpu-qom.h +++ b/target/avr/cpu-qom.h @@ -26,8 +26,7 @@ #define TYPE_AVR_CPU "avr-cpu" -OBJECT_DECLARE_TYPE(AVRCPU, AVRCPUClass, - AVR_CPU) +OBJECT_DECLARE_CPU_TYPE(AVRCPU, AVRCPUClass, AVR_CPU) /** * AVRCPUClass: diff --git a/target/avr/cpu.h b/target/avr/cpu.h index dceacf3cd7..55497f851d 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -108,9 +108,7 @@ typedef enum AVRFeature { AVR_FEATURE_RAMPZ, } AVRFeature; -typedef struct CPUAVRState CPUAVRState; - -struct CPUAVRState { +typedef struct CPUArchState { uint32_t pc_w; /* 0x003fffff up to 22 bits */ uint32_t sregC; /* 0x00000001 1 bit */ @@ -137,7 +135,7 @@ struct CPUAVRState { bool fullacc; /* CPU/MEM if true MEM only otherwise */ uint64_t features; -}; +} CPUAVRState; /** * AVRCPU: @@ -145,14 +143,14 @@ struct CPUAVRState { * * A AVR CPU. */ -typedef struct AVRCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ CPUNegativeOffsetState neg; CPUAVRState env; -} AVRCPU; +}; extern const struct VMStateDescription vms_avr_cpu; @@ -247,9 +245,6 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); -typedef CPUAVRState CPUArchState; -typedef AVRCPU ArchCPU; - #include "exec/cpu-all.h" #endif /* !defined (QEMU_AVR_CPU_H) */ diff --git a/target/cris/cpu-qom.h b/target/cris/cpu-qom.h index 2596edc7e3..71e8af0e70 100644 --- a/target/cris/cpu-qom.h +++ b/target/cris/cpu-qom.h @@ -25,8 +25,7 @@ #define TYPE_CRIS_CPU "cris-cpu" -OBJECT_DECLARE_TYPE(CRISCPU, CRISCPUClass, - CRIS_CPU) +OBJECT_DECLARE_CPU_TYPE(CRISCPU, CRISCPUClass, CRIS_CPU) /** * CRISCPUClass: diff --git a/target/cris/cpu.h b/target/cris/cpu.h index b445b194ea..e6776f25b1 100644 --- a/target/cris/cpu.h +++ b/target/cris/cpu.h @@ -105,7 +105,7 @@ typedef struct { uint32_t lo; } TLBSet; -typedef struct CPUCRISState { +typedef struct CPUArchState { uint32_t regs[16]; /* P0 - P15 are referred to as special registers in the docs. */ uint32_t pregs[16]; @@ -173,7 +173,7 @@ typedef struct CPUCRISState { * * A CRIS CPU. */ -struct CRISCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -265,9 +265,6 @@ static inline int cpu_mmu_index (CPUCRISState *env, bool ifetch) #define SFR_RW_MM_TLB_LO env->pregs[PR_SRS]][5 #define SFR_RW_MM_TLB_HI env->pregs[PR_SRS]][6 -typedef CPUCRISState CPUArchState; -typedef CRISCPU ArchCPU; - #include "exec/cpu-all.h" static inline void cpu_get_tb_cpu_state(CPUCRISState *env, target_ulong *pc, diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 58a0d3870b..2a65a57bab 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -1,5 +1,5 @@ /* - * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved. * * 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 @@ -18,14 +18,13 @@ #ifndef HEXAGON_CPU_H #define HEXAGON_CPU_H -/* Forward declaration needed by some of the header files */ -typedef struct CPUHexagonState CPUHexagonState; - #include "fpu/softfloat-types.h" #include "exec/cpu-defs.h" #include "hex_regs.h" #include "mmvec/mmvec.h" +#include "qom/object.h" +#include "hw/core/cpu.h" #define NUM_PREGS 4 #define TOTAL_PER_THREAD_REGS 64 @@ -75,7 +74,7 @@ typedef struct { /* Maximum number of vector temps in a packet */ #define VECTOR_TEMPS_MAX 4 -struct CPUHexagonState { +typedef struct CPUArchState { target_ulong gpr[TOTAL_PER_THREAD_REGS]; target_ulong pred[NUM_PREGS]; target_ulong branch_taken; @@ -129,14 +128,9 @@ struct CPUHexagonState { target_ulong vstore_pending[VSTORES_MAX]; bool vtcm_pending; VTCMStoreLog vtcm_log; -}; +} CPUHexagonState; -#define HEXAGON_CPU_CLASS(klass) \ - OBJECT_CLASS_CHECK(HexagonCPUClass, (klass), TYPE_HEXAGON_CPU) -#define HEXAGON_CPU(obj) \ - OBJECT_CHECK(HexagonCPU, (obj), TYPE_HEXAGON_CPU) -#define HEXAGON_CPU_GET_CLASS(obj) \ - OBJECT_GET_CLASS(HexagonCPUClass, (obj), TYPE_HEXAGON_CPU) +OBJECT_DECLARE_CPU_TYPE(HexagonCPU, HexagonCPUClass, HEXAGON_CPU) typedef struct HexagonCPUClass { /*< private >*/ @@ -146,7 +140,7 @@ typedef struct HexagonCPUClass { DeviceReset parent_reset; } HexagonCPUClass; -typedef struct HexagonCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -155,7 +149,7 @@ typedef struct HexagonCPU { bool lldb_compat; target_ulong lldb_stack_adjust; -} HexagonCPU; +}; #include "cpu_bits.h" @@ -180,7 +174,6 @@ static inline int cpu_mmu_index(CPUHexagonState *env, bool ifetch) #endif } -typedef struct CPUHexagonState CPUArchState; typedef HexagonCPU ArchCPU; void hexagon_translate_init(void); diff --git a/target/hppa/cpu-qom.h b/target/hppa/cpu-qom.h index d424f88370..b96e0318c7 100644 --- a/target/hppa/cpu-qom.h +++ b/target/hppa/cpu-qom.h @@ -25,8 +25,7 @@ #define TYPE_HPPA_CPU "hppa-cpu" -OBJECT_DECLARE_TYPE(HPPACPU, HPPACPUClass, - HPPA_CPU) +OBJECT_DECLARE_CPU_TYPE(HPPACPU, HPPACPUClass, HPPA_CPU) /** * HPPACPUClass: diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 93c119532a..4cc936b6bf 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -138,8 +138,6 @@ #define CR_IPSW 22 #define CR_EIRR 23 -typedef struct CPUHPPAState CPUHPPAState; - #if TARGET_REGISTER_BITS == 32 typedef uint32_t target_ureg; typedef int32_t target_sreg; @@ -168,7 +166,7 @@ typedef struct { unsigned access_id : 16; } hppa_tlb_entry; -struct CPUHPPAState { +typedef struct CPUArchState { target_ureg gr[32]; uint64_t fr[32]; uint64_t sr[8]; /* stored shifted into place for gva */ @@ -207,7 +205,7 @@ struct CPUHPPAState { /* ??? We should use a more intelligent data structure. */ hppa_tlb_entry tlb[HPPA_TLB_ENTRIES]; uint32_t tlb_last; -}; +} CPUHPPAState; /** * HPPACPU: @@ -215,7 +213,7 @@ struct CPUHPPAState { * * An HPPA CPU. */ -struct HPPACPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -225,10 +223,6 @@ struct HPPACPU { QEMUTimer *alarm_timer; }; - -typedef CPUHPPAState CPUArchState; -typedef HPPACPU ArchCPU; - #include "exec/cpu-all.h" static inline int cpu_mmu_index(CPUHPPAState *env, bool ifetch) diff --git a/target/i386/cpu-qom.h b/target/i386/cpu-qom.h index f9923cee04..c557a522e1 100644 --- a/target/i386/cpu-qom.h +++ b/target/i386/cpu-qom.h @@ -30,8 +30,7 @@ #define TYPE_X86_CPU "i386-cpu" #endif -OBJECT_DECLARE_TYPE(X86CPU, X86CPUClass, - X86_CPU) +OBJECT_DECLARE_CPU_TYPE(X86CPU, X86CPUClass, X86_CPU) typedef struct X86CPUModel X86CPUModel; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index e69ab5dd78..e11734ba86 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1431,7 +1431,7 @@ typedef struct HVFX86LazyFlags { target_ulong auxbits; } HVFX86LazyFlags; -typedef struct CPUX86State { +typedef struct CPUArchState { /* standard registers */ target_ulong regs[CPU_NB_REGS]; target_ulong eip; @@ -1707,7 +1707,7 @@ struct kvm_msrs; * * An x86 CPU. */ -struct X86CPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -2074,9 +2074,6 @@ static inline int cpu_mmu_index_kernel(CPUX86State *env) #define CC_SRC2 (env->cc_src2) #define CC_OP (env->cc_op) -typedef CPUX86State CPUArchState; -typedef X86CPU ArchCPU; - #include "exec/cpu-all.h" #include "svm.h" diff --git a/target/i386/hax/hax-all.c b/target/i386/hax/hax-all.c index bf65ed6fa9..81f665e212 100644 --- a/target/i386/hax/hax-all.c +++ b/target/i386/hax/hax-all.c @@ -49,18 +49,13 @@ const uint32_t hax_cur_version = 0x4; /* API v4: unmapping and MMIO moves */ /* Minimum HAX kernel version */ const uint32_t hax_min_version = 0x4; /* API v4: supports unmapping */ -static bool hax_allowed; +bool hax_allowed; struct hax_state hax_global; static void hax_vcpu_sync_state(CPUArchState *env, int modified); static int hax_arch_get_registers(CPUArchState *env); -int hax_enabled(void) -{ - return hax_allowed; -} - int valid_hax_tunnel_size(uint16_t size) { return size >= sizeof(struct hax_tunnel); @@ -227,7 +222,7 @@ int hax_init_vcpu(CPUState *cpu) cpu->hax_vcpu = hax_global.vm->vcpus[cpu->cpu_index]; cpu->vcpu_dirty = true; - qemu_register_reset(hax_reset_vcpu_state, (CPUArchState *) (cpu->env_ptr)); + qemu_register_reset(hax_reset_vcpu_state, cpu->env_ptr); return ret; } @@ -674,7 +669,7 @@ void hax_cpu_synchronize_pre_loadvm(CPUState *cpu) int hax_smp_cpu_exec(CPUState *cpu) { - CPUArchState *env = (CPUArchState *) (cpu->env_ptr); + CPUArchState *env = cpu->env_ptr; int fatal; int ret; diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 4ba6e82fab..fc12c02fb2 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -49,6 +49,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/error-report.h" +#include "qemu/memalign.h" #include "sysemu/hvf.h" #include "sysemu/hvf_int.h" diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 7c8203b21f..050428795b 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -171,12 +171,12 @@ void write_val_to_reg(target_ulong reg_ptr, target_ulong val, int size) } } -static bool is_host_reg(struct CPUX86State *env, target_ulong ptr) +static bool is_host_reg(CPUX86State *env, target_ulong ptr) { return (ptr - (target_ulong)&env->regs[0]) < sizeof(env->regs); } -void write_val_ext(struct CPUX86State *env, target_ulong ptr, target_ulong val, int size) +void write_val_ext(CPUX86State *env, target_ulong ptr, target_ulong val, int size) { if (is_host_reg(env, ptr)) { write_val_to_reg(ptr, val, size); @@ -185,14 +185,14 @@ void write_val_ext(struct CPUX86State *env, target_ulong ptr, target_ulong val, vmx_write_mem(env_cpu(env), ptr, &val, size); } -uint8_t *read_mmio(struct CPUX86State *env, target_ulong ptr, int bytes) +uint8_t *read_mmio(CPUX86State *env, target_ulong ptr, int bytes) { vmx_read_mem(env_cpu(env), env->hvf_mmio_buf, ptr, bytes); return env->hvf_mmio_buf; } -target_ulong read_val_ext(struct CPUX86State *env, target_ulong ptr, int size) +target_ulong read_val_ext(CPUX86State *env, target_ulong ptr, int size) { target_ulong val; uint8_t *mmio_ptr; @@ -222,7 +222,7 @@ target_ulong read_val_ext(struct CPUX86State *env, target_ulong ptr, int size) return val; } -static void fetch_operands(struct CPUX86State *env, struct x86_decode *decode, +static void fetch_operands(CPUX86State *env, struct x86_decode *decode, int n, bool val_op0, bool val_op1, bool val_op2) { int i; @@ -261,7 +261,7 @@ static void fetch_operands(struct CPUX86State *env, struct x86_decode *decode, } } -static void exec_mov(struct CPUX86State *env, struct x86_decode *decode) +static void exec_mov(CPUX86State *env, struct x86_decode *decode) { fetch_operands(env, decode, 2, false, true, false); write_val_ext(env, decode->op[0].ptr, decode->op[1].val, @@ -270,49 +270,49 @@ static void exec_mov(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_add(struct CPUX86State *env, struct x86_decode *decode) +static void exec_add(CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); env->eip += decode->len; } -static void exec_or(struct CPUX86State *env, struct x86_decode *decode) +static void exec_or(CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, |, SET_FLAGS_OSZAPC_LOGIC, true); env->eip += decode->len; } -static void exec_adc(struct CPUX86State *env, struct x86_decode *decode) +static void exec_adc(CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, +get_CF(env)+, SET_FLAGS_OSZAPC_ADD, true); env->eip += decode->len; } -static void exec_sbb(struct CPUX86State *env, struct x86_decode *decode) +static void exec_sbb(CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, -get_CF(env)-, SET_FLAGS_OSZAPC_SUB, true); env->eip += decode->len; } -static void exec_and(struct CPUX86State *env, struct x86_decode *decode) +static void exec_and(CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, true); env->eip += decode->len; } -static void exec_sub(struct CPUX86State *env, struct x86_decode *decode) +static void exec_sub(CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, true); env->eip += decode->len; } -static void exec_xor(struct CPUX86State *env, struct x86_decode *decode) +static void exec_xor(CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, ^, SET_FLAGS_OSZAPC_LOGIC, true); env->eip += decode->len; } -static void exec_neg(struct CPUX86State *env, struct x86_decode *decode) +static void exec_neg(CPUX86State *env, struct x86_decode *decode) { /*EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false);*/ int32_t val; @@ -335,13 +335,13 @@ static void exec_neg(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_cmp(struct CPUX86State *env, struct x86_decode *decode) +static void exec_cmp(CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); env->eip += decode->len; } -static void exec_inc(struct CPUX86State *env, struct x86_decode *decode) +static void exec_inc(CPUX86State *env, struct x86_decode *decode) { decode->op[1].type = X86_VAR_IMMEDIATE; decode->op[1].val = 0; @@ -351,7 +351,7 @@ static void exec_inc(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_dec(struct CPUX86State *env, struct x86_decode *decode) +static void exec_dec(CPUX86State *env, struct x86_decode *decode) { decode->op[1].type = X86_VAR_IMMEDIATE; decode->op[1].val = 0; @@ -360,13 +360,13 @@ static void exec_dec(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_tst(struct CPUX86State *env, struct x86_decode *decode) +static void exec_tst(CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, false); env->eip += decode->len; } -static void exec_not(struct CPUX86State *env, struct x86_decode *decode) +static void exec_not(CPUX86State *env, struct x86_decode *decode) { fetch_operands(env, decode, 1, true, false, false); @@ -375,7 +375,7 @@ static void exec_not(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -void exec_movzx(struct CPUX86State *env, struct x86_decode *decode) +void exec_movzx(CPUX86State *env, struct x86_decode *decode) { int src_op_size; int op_size = decode->operand_size; @@ -395,7 +395,7 @@ void exec_movzx(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_out(struct CPUX86State *env, struct x86_decode *decode) +static void exec_out(CPUX86State *env, struct x86_decode *decode) { switch (decode->opcode[0]) { case 0xe6: @@ -419,7 +419,7 @@ static void exec_out(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_in(struct CPUX86State *env, struct x86_decode *decode) +static void exec_in(CPUX86State *env, struct x86_decode *decode) { target_ulong val = 0; switch (decode->opcode[0]) { @@ -455,7 +455,7 @@ static void exec_in(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static inline void string_increment_reg(struct CPUX86State *env, int reg, +static inline void string_increment_reg(CPUX86State *env, int reg, struct x86_decode *decode) { target_ulong val = read_reg(env, reg, decode->addressing_size); @@ -467,8 +467,8 @@ static inline void string_increment_reg(struct CPUX86State *env, int reg, write_reg(env, reg, val, decode->addressing_size); } -static inline void string_rep(struct CPUX86State *env, struct x86_decode *decode, - void (*func)(struct CPUX86State *env, +static inline void string_rep(CPUX86State *env, struct x86_decode *decode, + void (*func)(CPUX86State *env, struct x86_decode *ins), int rep) { target_ulong rcx = read_reg(env, R_ECX, decode->addressing_size); @@ -484,7 +484,7 @@ static inline void string_rep(struct CPUX86State *env, struct x86_decode *decode } } -static void exec_ins_single(struct CPUX86State *env, struct x86_decode *decode) +static void exec_ins_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr = linear_addr_size(env_cpu(env), RDI(env), decode->addressing_size, R_ES); @@ -497,7 +497,7 @@ static void exec_ins_single(struct CPUX86State *env, struct x86_decode *decode) string_increment_reg(env, R_EDI, decode); } -static void exec_ins(struct CPUX86State *env, struct x86_decode *decode) +static void exec_ins(CPUX86State *env, struct x86_decode *decode) { if (decode->rep) { string_rep(env, decode, exec_ins_single, 0); @@ -508,7 +508,7 @@ static void exec_ins(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_outs_single(struct CPUX86State *env, struct x86_decode *decode) +static void exec_outs_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr = decode_linear_addr(env, decode, RSI(env), R_DS); @@ -520,7 +520,7 @@ static void exec_outs_single(struct CPUX86State *env, struct x86_decode *decode) string_increment_reg(env, R_ESI, decode); } -static void exec_outs(struct CPUX86State *env, struct x86_decode *decode) +static void exec_outs(CPUX86State *env, struct x86_decode *decode) { if (decode->rep) { string_rep(env, decode, exec_outs_single, 0); @@ -531,7 +531,7 @@ static void exec_outs(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_movs_single(struct CPUX86State *env, struct x86_decode *decode) +static void exec_movs_single(CPUX86State *env, struct x86_decode *decode) { target_ulong src_addr; target_ulong dst_addr; @@ -548,7 +548,7 @@ static void exec_movs_single(struct CPUX86State *env, struct x86_decode *decode) string_increment_reg(env, R_EDI, decode); } -static void exec_movs(struct CPUX86State *env, struct x86_decode *decode) +static void exec_movs(CPUX86State *env, struct x86_decode *decode) { if (decode->rep) { string_rep(env, decode, exec_movs_single, 0); @@ -559,7 +559,7 @@ static void exec_movs(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_cmps_single(struct CPUX86State *env, struct x86_decode *decode) +static void exec_cmps_single(CPUX86State *env, struct x86_decode *decode) { target_ulong src_addr; target_ulong dst_addr; @@ -579,7 +579,7 @@ static void exec_cmps_single(struct CPUX86State *env, struct x86_decode *decode) string_increment_reg(env, R_EDI, decode); } -static void exec_cmps(struct CPUX86State *env, struct x86_decode *decode) +static void exec_cmps(CPUX86State *env, struct x86_decode *decode) { if (decode->rep) { string_rep(env, decode, exec_cmps_single, decode->rep); @@ -590,7 +590,7 @@ static void exec_cmps(struct CPUX86State *env, struct x86_decode *decode) } -static void exec_stos_single(struct CPUX86State *env, struct x86_decode *decode) +static void exec_stos_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr; target_ulong val; @@ -604,7 +604,7 @@ static void exec_stos_single(struct CPUX86State *env, struct x86_decode *decode) } -static void exec_stos(struct CPUX86State *env, struct x86_decode *decode) +static void exec_stos(CPUX86State *env, struct x86_decode *decode) { if (decode->rep) { string_rep(env, decode, exec_stos_single, 0); @@ -615,7 +615,7 @@ static void exec_stos(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_scas_single(struct CPUX86State *env, struct x86_decode *decode) +static void exec_scas_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr; @@ -628,7 +628,7 @@ static void exec_scas_single(struct CPUX86State *env, struct x86_decode *decode) string_increment_reg(env, R_EDI, decode); } -static void exec_scas(struct CPUX86State *env, struct x86_decode *decode) +static void exec_scas(CPUX86State *env, struct x86_decode *decode) { decode->op[0].type = X86_VAR_REG; decode->op[0].reg = R_EAX; @@ -641,7 +641,7 @@ static void exec_scas(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_lods_single(struct CPUX86State *env, struct x86_decode *decode) +static void exec_lods_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr; target_ulong val = 0; @@ -653,7 +653,7 @@ static void exec_lods_single(struct CPUX86State *env, struct x86_decode *decode) string_increment_reg(env, R_ESI, decode); } -static void exec_lods(struct CPUX86State *env, struct x86_decode *decode) +static void exec_lods(CPUX86State *env, struct x86_decode *decode) { if (decode->rep) { string_rep(env, decode, exec_lods_single, 0); @@ -760,7 +760,7 @@ void simulate_rdmsr(struct CPUState *cpu) RDX(env) = (uint32_t)(val >> 32); } -static void exec_rdmsr(struct CPUX86State *env, struct x86_decode *decode) +static void exec_rdmsr(CPUX86State *env, struct x86_decode *decode) { simulate_rdmsr(env_cpu(env)); env->eip += decode->len; @@ -855,7 +855,7 @@ void simulate_wrmsr(struct CPUState *cpu) printf("write msr %llx\n", RCX(cpu));*/ } -static void exec_wrmsr(struct CPUX86State *env, struct x86_decode *decode) +static void exec_wrmsr(CPUX86State *env, struct x86_decode *decode) { simulate_wrmsr(env_cpu(env)); env->eip += decode->len; @@ -865,7 +865,7 @@ static void exec_wrmsr(struct CPUX86State *env, struct x86_decode *decode) * flag: * 0 - bt, 1 - btc, 2 - bts, 3 - btr */ -static void do_bt(struct CPUX86State *env, struct x86_decode *decode, int flag) +static void do_bt(CPUX86State *env, struct x86_decode *decode, int flag) { int32_t displacement; uint8_t index; @@ -911,31 +911,31 @@ static void do_bt(struct CPUX86State *env, struct x86_decode *decode, int flag) set_CF(env, cf); } -static void exec_bt(struct CPUX86State *env, struct x86_decode *decode) +static void exec_bt(CPUX86State *env, struct x86_decode *decode) { do_bt(env, decode, 0); env->eip += decode->len; } -static void exec_btc(struct CPUX86State *env, struct x86_decode *decode) +static void exec_btc(CPUX86State *env, struct x86_decode *decode) { do_bt(env, decode, 1); env->eip += decode->len; } -static void exec_btr(struct CPUX86State *env, struct x86_decode *decode) +static void exec_btr(CPUX86State *env, struct x86_decode *decode) { do_bt(env, decode, 3); env->eip += decode->len; } -static void exec_bts(struct CPUX86State *env, struct x86_decode *decode) +static void exec_bts(CPUX86State *env, struct x86_decode *decode) { do_bt(env, decode, 2); env->eip += decode->len; } -void exec_shl(struct CPUX86State *env, struct x86_decode *decode) +void exec_shl(CPUX86State *env, struct x86_decode *decode) { uint8_t count; int of = 0, cf = 0; @@ -1022,7 +1022,7 @@ void exec_movsx(CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -void exec_ror(struct CPUX86State *env, struct x86_decode *decode) +void exec_ror(CPUX86State *env, struct x86_decode *decode) { uint8_t count; @@ -1100,7 +1100,7 @@ void exec_ror(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -void exec_rol(struct CPUX86State *env, struct x86_decode *decode) +void exec_rol(CPUX86State *env, struct x86_decode *decode) { uint8_t count; @@ -1182,7 +1182,7 @@ void exec_rol(struct CPUX86State *env, struct x86_decode *decode) } -void exec_rcl(struct CPUX86State *env, struct x86_decode *decode) +void exec_rcl(CPUX86State *env, struct x86_decode *decode) { uint8_t count; int of = 0, cf = 0; @@ -1267,7 +1267,7 @@ void exec_rcl(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -void exec_rcr(struct CPUX86State *env, struct x86_decode *decode) +void exec_rcr(CPUX86State *env, struct x86_decode *decode) { uint8_t count; int of = 0, cf = 0; @@ -1342,7 +1342,7 @@ void exec_rcr(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_xchg(struct CPUX86State *env, struct x86_decode *decode) +static void exec_xchg(CPUX86State *env, struct x86_decode *decode) { fetch_operands(env, decode, 2, true, true, false); @@ -1354,7 +1354,7 @@ static void exec_xchg(struct CPUX86State *env, struct x86_decode *decode) env->eip += decode->len; } -static void exec_xadd(struct CPUX86State *env, struct x86_decode *decode) +static void exec_xadd(CPUX86State *env, struct x86_decode *decode) { EXEC_2OP_FLAGS_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); write_val_ext(env, decode->op[1].ptr, decode->op[0].val, @@ -1365,7 +1365,7 @@ static void exec_xadd(struct CPUX86State *env, struct x86_decode *decode) static struct cmd_handler { enum x86_decode_cmd cmd; - void (*handler)(struct CPUX86State *env, struct x86_decode *ins); + void (*handler)(CPUX86State *env, struct x86_decode *ins); } handlers[] = { {X86_DECODE_CMD_INVL, NULL,}, {X86_DECODE_CMD_MOV, exec_mov}, @@ -1465,7 +1465,7 @@ void store_regs(struct CPUState *cpu) macvm_set_rip(cpu, env->eip); } -bool exec_instruction(struct CPUX86State *env, struct x86_decode *ins) +bool exec_instruction(CPUX86State *env, struct x86_decode *ins) { /*if (hvf_vcpu_id(cpu)) printf("%d, %llx: exec_instruction %s\n", hvf_vcpu_id(cpu), env->eip, diff --git a/target/i386/hvf/x86_emu.h b/target/i386/hvf/x86_emu.h index 233f7b8daa..640da90b30 100644 --- a/target/i386/hvf/x86_emu.h +++ b/target/i386/hvf/x86_emu.h @@ -24,7 +24,7 @@ #include "cpu.h" void init_emu(void); -bool exec_instruction(struct CPUX86State *env, struct x86_decode *ins); +bool exec_instruction(CPUX86State *env, struct x86_decode *ins); void load_regs(struct CPUState *cpu); void store_regs(struct CPUState *cpu); @@ -36,15 +36,15 @@ target_ulong read_reg(CPUX86State *env, int reg, int size); void write_reg(CPUX86State *env, int reg, target_ulong val, int size); target_ulong read_val_from_reg(target_ulong reg_ptr, int size); void write_val_to_reg(target_ulong reg_ptr, target_ulong val, int size); -void write_val_ext(struct CPUX86State *env, target_ulong ptr, target_ulong val, int size); -uint8_t *read_mmio(struct CPUX86State *env, target_ulong ptr, int bytes); -target_ulong read_val_ext(struct CPUX86State *env, target_ulong ptr, int size); +void write_val_ext(CPUX86State *env, target_ulong ptr, target_ulong val, int size); +uint8_t *read_mmio(CPUX86State *env, target_ulong ptr, int bytes); +target_ulong read_val_ext(CPUX86State *env, target_ulong ptr, int size); -void exec_movzx(struct CPUX86State *env, struct x86_decode *decode); -void exec_shl(struct CPUX86State *env, struct x86_decode *decode); -void exec_movsx(struct CPUX86State *env, struct x86_decode *decode); -void exec_ror(struct CPUX86State *env, struct x86_decode *decode); -void exec_rol(struct CPUX86State *env, struct x86_decode *decode); -void exec_rcl(struct CPUX86State *env, struct x86_decode *decode); -void exec_rcr(struct CPUX86State *env, struct x86_decode *decode); +void exec_movzx(CPUX86State *env, struct x86_decode *decode); +void exec_shl(CPUX86State *env, struct x86_decode *decode); +void exec_movsx(CPUX86State *env, struct x86_decode *decode); +void exec_ror(CPUX86State *env, struct x86_decode *decode); +void exec_rol(CPUX86State *env, struct x86_decode *decode); +void exec_rcl(CPUX86State *env, struct x86_decode *decode); +void exec_rcr(CPUX86State *env, struct x86_decode *decode); #endif diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 2c8feb4a6f..83d0988302 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -37,6 +37,7 @@ #include "qemu/main-loop.h" #include "qemu/config-file.h" #include "qemu/error-report.h" +#include "qemu/memalign.h" #include "hw/i386/x86.h" #include "hw/i386/apic.h" #include "hw/i386/apic_internal.h" diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index 9af261eea3..b97d091a50 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -85,7 +85,7 @@ nvmm_set_segment(struct nvmm_x64_state_seg *nseg, const SegmentCache *qseg) static void nvmm_set_registers(CPUState *cpu) { - struct CPUX86State *env = (CPUArchState *)cpu->env_ptr; + CPUX86State *env = cpu->env_ptr; struct nvmm_machine *mach = get_nvmm_mach(); struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); struct nvmm_vcpu *vcpu = &qcpu->vcpu; @@ -222,7 +222,7 @@ nvmm_get_segment(SegmentCache *qseg, const struct nvmm_x64_state_seg *nseg) static void nvmm_get_registers(CPUState *cpu) { - struct CPUX86State *env = (CPUArchState *)cpu->env_ptr; + CPUX86State *env = cpu->env_ptr; struct nvmm_machine *mach = get_nvmm_mach(); struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); struct nvmm_vcpu *vcpu = &qcpu->vcpu; @@ -347,7 +347,7 @@ nvmm_get_registers(CPUState *cpu) static bool nvmm_can_take_int(CPUState *cpu) { - struct CPUX86State *env = (CPUArchState *)cpu->env_ptr; + CPUX86State *env = cpu->env_ptr; struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); struct nvmm_vcpu *vcpu = &qcpu->vcpu; struct nvmm_machine *mach = get_nvmm_mach(); @@ -394,7 +394,7 @@ nvmm_can_take_nmi(CPUState *cpu) static void nvmm_vcpu_pre_run(CPUState *cpu) { - struct CPUX86State *env = (CPUArchState *)cpu->env_ptr; + CPUX86State *env = cpu->env_ptr; struct nvmm_machine *mach = get_nvmm_mach(); struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); struct nvmm_vcpu *vcpu = &qcpu->vcpu; @@ -480,7 +480,7 @@ static void nvmm_vcpu_post_run(CPUState *cpu, struct nvmm_vcpu_exit *exit) { struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); - struct CPUX86State *env = (CPUArchState *)cpu->env_ptr; + CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); uint64_t tpr; @@ -652,7 +652,7 @@ static int nvmm_handle_halted(struct nvmm_machine *mach, CPUState *cpu, struct nvmm_vcpu_exit *exit) { - struct CPUX86State *env = (CPUArchState *)cpu->env_ptr; + CPUX86State *env = cpu->env_ptr; int ret = 0; qemu_mutex_lock_iothread(); @@ -685,7 +685,7 @@ nvmm_inject_ud(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) static int nvmm_vcpu_loop(CPUState *cpu) { - struct CPUX86State *env = (CPUArchState *)cpu->env_ptr; + CPUX86State *env = cpu->env_ptr; struct nvmm_machine *mach = get_nvmm_mach(); struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu); struct nvmm_vcpu *vcpu = &qcpu->vcpu; diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 5ba739fbed..5627772e7c 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/exec-all.h" #include "tcg/helper-tcg.h" int get_pg_mode(CPUX86State *env) diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c index 9ccaa054c4..3715c1e262 100644 --- a/target/i386/tcg/sysemu/misc_helper.c +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -23,6 +23,7 @@ #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" #include "exec/address-spaces.h" +#include "exec/exec-all.h" #include "tcg/helper-tcg.h" void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) diff --git a/target/i386/whpx/whpx-accel-ops.c b/target/i386/whpx/whpx-accel-ops.c index 6bc47c5309..1d30e4e2ed 100644 --- a/target/i386/whpx/whpx-accel-ops.c +++ b/target/i386/whpx/whpx-accel-ops.c @@ -83,12 +83,18 @@ static void whpx_kick_vcpu_thread(CPUState *cpu) } } +static bool whpx_vcpu_thread_is_idle(CPUState *cpu) +{ + return !whpx_apic_in_platform(); +} + static void whpx_accel_ops_class_init(ObjectClass *oc, void *data) { AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); ops->create_vcpu_thread = whpx_start_vcpu_thread; ops->kick_vcpu_thread = whpx_kick_vcpu_thread; + ops->cpu_thread_is_idle = whpx_vcpu_thread_is_idle; ops->synchronize_post_reset = whpx_cpu_synchronize_post_reset; ops->synchronize_post_init = whpx_cpu_synchronize_post_init; diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index ef896da0a2..c7e25abf42 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -221,7 +221,7 @@ static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs) static int whpx_set_tsc(CPUState *cpu) { - struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + CPUX86State *env = cpu->env_ptr; WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc; WHV_REGISTER_VALUE tsc_val; HRESULT hr; @@ -260,7 +260,7 @@ static void whpx_set_registers(CPUState *cpu, int level) { struct whpx_state *whpx = &whpx_global; struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); - struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); struct whpx_register_set vcxt; HRESULT hr; @@ -428,7 +428,7 @@ static void whpx_set_registers(CPUState *cpu, int level) static int whpx_get_tsc(CPUState *cpu) { - struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + CPUX86State *env = cpu->env_ptr; WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc; WHV_REGISTER_VALUE tsc_val; HRESULT hr; @@ -449,7 +449,7 @@ static void whpx_get_registers(CPUState *cpu) { struct whpx_state *whpx = &whpx_global; struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); - struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); struct whpx_register_set vcxt; uint64_t tpr, apic_base; @@ -760,7 +760,7 @@ static int whpx_handle_portio(CPUState *cpu, static int whpx_handle_halt(CPUState *cpu) { - struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + CPUX86State *env = cpu->env_ptr; int ret = 0; qemu_mutex_lock_iothread(); @@ -781,7 +781,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu) HRESULT hr; struct whpx_state *whpx = &whpx_global; struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); - struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); int irq; uint8_t tpr; @@ -903,7 +903,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu) static void whpx_vcpu_post_run(CPUState *cpu) { struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); - struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); env->eflags = vcpu->exit_ctx.VpContext.Rflags; @@ -927,7 +927,7 @@ static void whpx_vcpu_post_run(CPUState *cpu) static void whpx_vcpu_process_async_events(CPUState *cpu) { - struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); @@ -1333,7 +1333,7 @@ int whpx_init_vcpu(CPUState *cpu) struct whpx_state *whpx = &whpx_global; struct whpx_vcpu *vcpu = NULL; Error *local_error = NULL; - struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); + CPUX86State *env = cpu->env_ptr; X86CPU *x86_cpu = X86_CPU(cpu); UINT64 freq = 0; int ret; diff --git a/target/m68k/cpu-qom.h b/target/m68k/cpu-qom.h index 1ceb160ecb..cd9687192c 100644 --- a/target/m68k/cpu-qom.h +++ b/target/m68k/cpu-qom.h @@ -25,8 +25,7 @@ #define TYPE_M68K_CPU "m68k-cpu" -OBJECT_DECLARE_TYPE(M68kCPU, M68kCPUClass, - M68K_CPU) +OBJECT_DECLARE_CPU_TYPE(M68kCPU, M68kCPUClass, M68K_CPU) /* * M68kCPUClass: diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index a3423729ef..872e8ce637 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -79,7 +79,7 @@ typedef CPU_LDoubleU FPReg; -typedef struct CPUM68KState { +typedef struct CPUArchState { uint32_t dregs[8]; uint32_t aregs[8]; uint32_t pc; @@ -156,7 +156,7 @@ typedef struct CPUM68KState { * * A Motorola 68k CPU. */ -struct M68kCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -574,9 +574,6 @@ void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, int mmu_idx, MemTxAttrs attrs, MemTxResult response, uintptr_t retaddr); -typedef CPUM68KState CPUArchState; -typedef M68kCPU ArchCPU; - #include "exec/cpu-all.h" /* TB flags */ diff --git a/target/microblaze/cpu-qom.h b/target/microblaze/cpu-qom.h index e520eefb12..255b39a45d 100644 --- a/target/microblaze/cpu-qom.h +++ b/target/microblaze/cpu-qom.h @@ -25,8 +25,7 @@ #define TYPE_MICROBLAZE_CPU "microblaze-cpu" -OBJECT_DECLARE_TYPE(MicroBlazeCPU, MicroBlazeCPUClass, - MICROBLAZE_CPU) +OBJECT_DECLARE_CPU_TYPE(MicroBlazeCPU, MicroBlazeCPUClass, MICROBLAZE_CPU) /** * MicroBlazeCPUClass: diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index e9cd0b88de..0a0ce71b6a 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -24,7 +24,7 @@ #include "exec/cpu-defs.h" #include "fpu/softfloat-types.h" -typedef struct CPUMBState CPUMBState; +typedef struct CPUArchState CPUMBState; #if !defined(CONFIG_USER_ONLY) #include "mmu.h" #endif @@ -239,7 +239,7 @@ typedef struct CPUMBState CPUMBState; #define USE_NON_SECURE_M_AXI_DC_MASK 0x4 #define USE_NON_SECURE_M_AXI_IC_MASK 0x8 -struct CPUMBState { +struct CPUArchState { uint32_t bvalue; /* TCG temporary, only valid during a TB */ uint32_t btarget; /* Full resolved branch destination */ @@ -339,7 +339,7 @@ typedef struct { * * A MicroBlaze CPU. */ -struct MicroBlazeCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; @@ -394,9 +394,6 @@ void mb_tcg_init(void); #define MMU_USER_IDX 2 /* See NB_MMU_MODES further up the file. */ -typedef CPUMBState CPUArchState; -typedef MicroBlazeCPU ArchCPU; - #include "exec/cpu-all.h" /* Ensure there is no overlap between the two masks. */ diff --git a/target/microblaze/mmu.h b/target/microblaze/mmu.h index b6b4b9ad60..1068bd2d52 100644 --- a/target/microblaze/mmu.h +++ b/target/microblaze/mmu.h @@ -20,6 +20,8 @@ #ifndef TARGET_MICROBLAZE_MMU_H #define TARGET_MICROBLAZE_MMU_H +#include "cpu.h" + #define MMU_R_PID 0 #define MMU_R_ZPR 1 #define MMU_R_TLBX 2 diff --git a/target/mips/cpu-qom.h b/target/mips/cpu-qom.h index dda0c911fa..e28b529607 100644 --- a/target/mips/cpu-qom.h +++ b/target/mips/cpu-qom.h @@ -29,8 +29,7 @@ #define TYPE_MIPS_CPU "mips-cpu" #endif -OBJECT_DECLARE_TYPE(MIPSCPU, MIPSCPUClass, - MIPS_CPU) +OBJECT_DECLARE_CPU_TYPE(MIPSCPU, MIPSCPUClass, MIPS_CPU) /** * MIPSCPUClass: diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 4aae23934b..af287177d5 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -434,14 +434,13 @@ static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info) * Since commit 6af0bf9c7c3 this model assumes a CPU clocked at 200MHz. */ #define CPU_FREQ_HZ_DEFAULT 200000000 -#define CP0_COUNT_RATE_DEFAULT 2 static void mips_cp0_period_set(MIPSCPU *cpu) { CPUMIPSState *env = &cpu->env; env->cp0_count_ns = clock_ticks_to_ns(MIPS_CPU(cpu)->clock, - cpu->cp0_count_rate); + env->cpu_model->CCRes); assert(env->cp0_count_ns); } @@ -514,13 +513,6 @@ static ObjectClass *mips_cpu_class_by_name(const char *cpu_model) return oc; } -static Property mips_cpu_properties[] = { - /* CP0 timer running at half the clock of the CPU */ - DEFINE_PROP_UINT32("cp0-count-rate", MIPSCPU, cp0_count_rate, - CP0_COUNT_RATE_DEFAULT), - DEFINE_PROP_END_OF_LIST() -}; - #ifndef CONFIG_USER_ONLY #include "hw/core/sysemu-cpu-ops.h" @@ -560,7 +552,6 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) device_class_set_parent_realize(dc, mips_cpu_realizefn, &mcc->parent_realize); device_class_set_parent_reset(dc, mips_cpu_reset, &mcc->parent_reset); - device_class_set_props(dc, mips_cpu_properties); cc->class_by_name = mips_cpu_class_by_name; cc->has_work = mips_cpu_has_work; diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 56b1cbd091..52ce08a94d 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -524,8 +524,7 @@ struct TCState { }; struct MIPSITUState; -typedef struct CPUMIPSState CPUMIPSState; -struct CPUMIPSState { +typedef struct CPUArchState { TCState active_tc; CPUMIPSFPUContext active_fpu; @@ -1161,18 +1160,17 @@ struct CPUMIPSState { QEMUTimer *timer; /* Internal timer */ target_ulong exception_base; /* ExceptionBase input to the core */ uint64_t cp0_count_ns; /* CP0_Count clock period (in nanoseconds) */ -}; +} CPUMIPSState; /** * MIPSCPU: * @env: #CPUMIPSState * @clock: this CPU input clock (may be connected * to an output clock from another device). - * @cp0_count_rate: rate at which the coprocessor 0 counter increments * * A MIPS CPU. */ -struct MIPSCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -1180,14 +1178,6 @@ struct MIPSCPU { Clock *clock; CPUNegativeOffsetState neg; CPUMIPSState env; - /* - * The Count register acts as a timer, incrementing at a constant rate, - * whether or not an instruction is executed, retired, or any forward - * progress is made through the pipeline. The rate at which the counter - * increments is implementation dependent, and is a function of the - * pipeline clock of the processor, not the issue width of the processor. - */ - unsigned cp0_count_rate; }; @@ -1218,9 +1208,6 @@ static inline int cpu_mmu_index(CPUMIPSState *env, bool ifetch) return hflags_mmu_index(env->hflags); } -typedef CPUMIPSState CPUArchState; -typedef MIPSCPU ArchCPU; - #include "exec/cpu-all.h" /* Exceptions */ diff --git a/target/mips/internal.h b/target/mips/internal.h index daddb05fd4..57b312689a 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -12,6 +12,7 @@ #ifdef CONFIG_TCG #include "tcg/tcg-internal.h" #endif +#include "cpu.h" /* * MMU types, the first four entries have the same layout as the @@ -46,6 +47,15 @@ struct mips_def_t { target_ulong CP0_LLAddr_rw_bitmask; int CP0_LLAddr_shift; int32_t SYNCI_Step; + /* + * @CCRes: rate at which the coprocessor 0 counter increments + * + * The Count register acts as a timer, incrementing at a constant rate, + * whether or not an instruction is executed, retired, or any forward + * progress is made through the pipeline. The rate at which the counter + * increments is implementation dependent, and is a function of the + * pipeline clock of the processor, not the issue width of the processor. + */ int32_t CCRes; int32_t CP0_Status_rw_bitmask; int32_t CP0_TCStatus_rw_bitmask; @@ -133,14 +143,14 @@ struct r4k_tlb_t { struct CPUMIPSTLBContext { uint32_t nb_tlb; uint32_t tlb_in_use; - int (*map_address)(struct CPUMIPSState *env, hwaddr *physical, int *prot, + int (*map_address)(CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong address, MMUAccessType access_type); - void (*helper_tlbwi)(struct CPUMIPSState *env); - void (*helper_tlbwr)(struct CPUMIPSState *env); - void (*helper_tlbp)(struct CPUMIPSState *env); - void (*helper_tlbr)(struct CPUMIPSState *env); - void (*helper_tlbinv)(struct CPUMIPSState *env); - void (*helper_tlbinvf)(struct CPUMIPSState *env); + void (*helper_tlbwi)(CPUMIPSState *env); + void (*helper_tlbwr)(CPUMIPSState *env); + void (*helper_tlbp)(CPUMIPSState *env); + void (*helper_tlbr)(CPUMIPSState *env); + void (*helper_tlbinv)(CPUMIPSState *env); + void (*helper_tlbinvf)(CPUMIPSState *env); union { struct { r4k_tlb_t tlb[MIPS_TLB_MAX]; diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h index a00e4229ce..ca0f3420cd 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -25,15 +25,14 @@ #include "hw/core/cpu.h" #include "qom/object.h" -typedef struct CPUNios2State CPUNios2State; +typedef struct CPUArchState CPUNios2State; #if !defined(CONFIG_USER_ONLY) #include "mmu.h" #endif #define TYPE_NIOS2_CPU "nios2-cpu" -OBJECT_DECLARE_TYPE(Nios2CPU, Nios2CPUClass, - NIOS2_CPU) +OBJECT_DECLARE_CPU_TYPE(Nios2CPU, Nios2CPUClass, NIOS2_CPU) /** * Nios2CPUClass: @@ -155,7 +154,7 @@ struct Nios2CPUClass { #define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3 -struct CPUNios2State { +struct CPUArchState { uint32_t regs[NUM_CORE_REGS]; #if !defined(CONFIG_USER_ONLY) @@ -170,7 +169,7 @@ struct CPUNios2State { * * A Nios2 CPU. */ -struct Nios2CPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ diff --git a/target/nios2/mmu.h b/target/nios2/mmu.h index b7785b46c0..5b085900fb 100644 --- a/target/nios2/mmu.h +++ b/target/nios2/mmu.h @@ -21,6 +21,8 @@ #ifndef NIOS2_MMU_H #define NIOS2_MMU_H +#include "cpu.h" + typedef struct Nios2TLBEntry { target_ulong tag; target_ulong data; diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index ee069b080c..bdf29d2dc4 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -24,13 +24,9 @@ #include "hw/core/cpu.h" #include "qom/object.h" -/* cpu_openrisc_map_address_* in CPUOpenRISCTLBContext need this decl. */ -struct OpenRISCCPU; - #define TYPE_OPENRISC_CPU "or1k-cpu" -OBJECT_DECLARE_TYPE(OpenRISCCPU, OpenRISCCPUClass, - OPENRISC_CPU) +OBJECT_DECLARE_CPU_TYPE(OpenRISCCPU, OpenRISCCPUClass, OPENRISC_CPU) /** * OpenRISCCPUClass: @@ -231,18 +227,18 @@ typedef struct CPUOpenRISCTLBContext { OpenRISCTLBEntry itlb[TLB_SIZE]; OpenRISCTLBEntry dtlb[TLB_SIZE]; - int (*cpu_openrisc_map_address_code)(struct OpenRISCCPU *cpu, + int (*cpu_openrisc_map_address_code)(OpenRISCCPU *cpu, hwaddr *physical, int *prot, target_ulong address, int rw); - int (*cpu_openrisc_map_address_data)(struct OpenRISCCPU *cpu, + int (*cpu_openrisc_map_address_data)(OpenRISCCPU *cpu, hwaddr *physical, int *prot, target_ulong address, int rw); } CPUOpenRISCTLBContext; #endif -typedef struct CPUOpenRISCState { +typedef struct CPUArchState { target_ulong shadow_gpr[16][32]; /* Shadow registers */ target_ulong pc; /* Program counter */ @@ -301,7 +297,7 @@ typedef struct CPUOpenRISCState { * * A OpenRISC CPU. */ -struct OpenRISCCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -348,9 +344,6 @@ void cpu_openrisc_count_stop(OpenRISCCPU *cpu); #define OPENRISC_CPU_TYPE_NAME(model) model OPENRISC_CPU_TYPE_SUFFIX #define CPU_RESOLVING_TYPE TYPE_OPENRISC_CPU -typedef CPUOpenRISCState CPUArchState; -typedef OpenRISCCPU ArchCPU; - #include "exec/cpu-all.h" #define TB_FLAGS_SM SR_SM diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h index 98facee9fa..ad7e3c3db9 100644 --- a/target/ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h @@ -29,10 +29,9 @@ #define TYPE_POWERPC_CPU "powerpc-cpu" #endif -OBJECT_DECLARE_TYPE(PowerPCCPU, PowerPCCPUClass, - POWERPC_CPU) +OBJECT_DECLARE_CPU_TYPE(PowerPCCPU, PowerPCCPUClass, POWERPC_CPU) -typedef struct CPUPPCState CPUPPCState; +typedef struct CPUArchState CPUPPCState; typedef struct ppc_tb_t ppc_tb_t; typedef struct ppc_dcr_t ppc_dcr_t; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 1b687521c7..047b24ba50 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1077,7 +1077,7 @@ struct ppc_radix_page_info { #define PPC_CPU_OPCODES_LEN 0x40 #define PPC_CPU_INDIRECT_OPCODES_LEN 0x20 -struct CPUPPCState { +struct CPUArchState { /* Most commonly used resources during translated code execution first */ target_ulong gpr[32]; /* general purpose registers */ target_ulong gprh[32]; /* storage for GPR MSB, used by the SPE extension */ @@ -1275,7 +1275,7 @@ typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass; * * A PowerPC CPU. */ -struct PowerPCCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -1477,9 +1477,6 @@ void ppc_compat_add_property(Object *obj, const char *name, uint32_t *compat_pvr, const char *basedesc); #endif /* defined(TARGET_PPC64) */ -typedef CPUPPCState CPUArchState; -typedef PowerPCCPU ArchCPU; - #include "exec/cpu-all.h" /*****************************************************************************/ diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 9ba05042ed..c069fe85fa 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -98,7 +98,7 @@ enum { #define MAX_RISCV_PMPS (16) -typedef struct CPURISCVState CPURISCVState; +typedef struct CPUArchState CPURISCVState; #if !defined(CONFIG_USER_ONLY) #include "pmp.h" @@ -113,7 +113,7 @@ FIELD(VTYPE, VMA, 7, 1) FIELD(VTYPE, VEDIV, 8, 2) FIELD(VTYPE, RESERVED, 10, sizeof(target_ulong) * 8 - 11) -struct CPURISCVState { +struct CPUArchState { target_ulong gpr[32]; target_ulong gprh[32]; /* 64 top bits of the 128-bit registers */ uint64_t fpr[32]; /* assume both F and D extensions */ @@ -320,8 +320,7 @@ struct CPURISCVState { uint64_t kvm_timer_frequency; }; -OBJECT_DECLARE_TYPE(RISCVCPU, RISCVCPUClass, - RISCV_CPU) +OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU) /** * RISCVCPUClass: @@ -395,7 +394,7 @@ typedef struct RISCVCPUConfig RISCVCPUConfig; * * A RISCV CPU. */ -struct RISCVCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -499,8 +498,6 @@ void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong); #define TB_FLAGS_MSTATUS_FS MSTATUS_FS #define TB_FLAGS_MSTATUS_VS MSTATUS_VS -typedef CPURISCVState CPUArchState; -typedef RISCVCPU ArchCPU; #include "exec/cpu-all.h" FIELD(TB_FLAGS, MEM_IDX, 0, 3) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index aea82dff4a..0606cd0ea8 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -23,6 +23,7 @@ #include "cpu.h" #include "qemu/main-loop.h" #include "exec/exec-all.h" +#include "sysemu/cpu-timers.h" /* CSR function table public API */ void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops) diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h index a9a0b363a7..fcb6b7c467 100644 --- a/target/riscv/pmp.h +++ b/target/riscv/pmp.h @@ -22,6 +22,8 @@ #ifndef RISCV_PMP_H #define RISCV_PMP_H +#include "cpu.h" + typedef enum { PMP_READ = 1 << 0, PMP_WRITE = 1 << 1, diff --git a/target/rx/cpu-qom.h b/target/rx/cpu-qom.h index 7310558e0c..4533759d96 100644 --- a/target/rx/cpu-qom.h +++ b/target/rx/cpu-qom.h @@ -26,8 +26,7 @@ #define TYPE_RX62N_CPU RX_CPU_TYPE_NAME("rx62n") -OBJECT_DECLARE_TYPE(RXCPU, RXCPUClass, - RX_CPU) +OBJECT_DECLARE_CPU_TYPE(RXCPU, RXCPUClass, RX_CPU) /* * RXCPUClass: @@ -45,6 +44,4 @@ struct RXCPUClass { DeviceReset parent_reset; }; -#define CPUArchState struct CPURXState - #endif diff --git a/target/rx/cpu.h b/target/rx/cpu.h index 58adf9edf6..b4abd90ccd 100644 --- a/target/rx/cpu.h +++ b/target/rx/cpu.h @@ -65,7 +65,7 @@ enum { NUM_REGS = 16, }; -typedef struct CPURXState { +typedef struct CPUArchState { /* CPU registers */ uint32_t regs[NUM_REGS]; /* general registers */ uint32_t psw_o; /* O bit of status register */ @@ -105,7 +105,7 @@ typedef struct CPURXState { * * A RX CPU */ -struct RXCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -114,8 +114,6 @@ struct RXCPU { CPURXState env; }; -typedef RXCPU ArchCPU; - #define RX_CPU_TYPE_SUFFIX "-" TYPE_RX_CPU #define RX_CPU_TYPE_NAME(model) model RX_CPU_TYPE_SUFFIX #define CPU_RESOLVING_TYPE TYPE_RX_CPU diff --git a/target/s390x/cpu-qom.h b/target/s390x/cpu-qom.h index 9f3a0d86c5..00cae2b131 100644 --- a/target/s390x/cpu-qom.h +++ b/target/s390x/cpu-qom.h @@ -25,12 +25,13 @@ #define TYPE_S390_CPU "s390x-cpu" -OBJECT_DECLARE_TYPE(S390CPU, S390CPUClass, - S390_CPU) +OBJECT_DECLARE_CPU_TYPE(S390CPU, S390CPUClass, S390_CPU) typedef struct S390CPUModel S390CPUModel; typedef struct S390CPUDef S390CPUDef; +typedef struct CPUArchState CPUS390XState; + typedef enum cpu_reset_type { S390_CPU_RESET_NORMAL, S390_CPU_RESET_INITIAL, @@ -63,6 +64,4 @@ struct S390CPUClass { void (*reset)(CPUState *cpu, cpu_reset_type type); }; -typedef struct CPUS390XState CPUS390XState; - #endif diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index a75e559134..c49c8466e7 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -51,7 +51,7 @@ typedef struct PSW { uint64_t addr; } PSW; -struct CPUS390XState { +struct CPUArchState { uint64_t regs[16]; /* GP registers */ /* * The floating point registers are part of the vector registers. @@ -163,7 +163,7 @@ static inline uint64_t *get_freg(CPUS390XState *cs, int nr) * * An S/390 CPU. */ -struct S390CPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -840,9 +840,6 @@ uint64_t s390_cpu_get_psw_mask(CPUS390XState *env); /* outside of target/s390x/ */ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); -typedef CPUS390XState CPUArchState; -typedef S390CPU ArchCPU; - #include "exec/cpu-all.h" #endif diff --git a/target/sh4/cpu-qom.h b/target/sh4/cpu-qom.h index 8903b4b9c7..d4192d1090 100644 --- a/target/sh4/cpu-qom.h +++ b/target/sh4/cpu-qom.h @@ -29,8 +29,7 @@ #define TYPE_SH7751R_CPU SUPERH_CPU_TYPE_NAME("sh7751r") #define TYPE_SH7785_CPU SUPERH_CPU_TYPE_NAME("sh7785") -OBJECT_DECLARE_TYPE(SuperHCPU, SuperHCPUClass, - SUPERH_CPU) +OBJECT_DECLARE_CPU_TYPE(SuperHCPU, SuperHCPUClass, SUPERH_CPU) /** * SuperHCPUClass: diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index fb9dd9db2f..c72a30edfd 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -130,7 +130,7 @@ typedef struct memory_content { struct memory_content *next; } memory_content; -typedef struct CPUSH4State { +typedef struct CPUArchState { uint32_t flags; /* general execution flags */ uint32_t gregs[24]; /* general registers */ float32 fregs[32]; /* floating point registers */ @@ -195,7 +195,7 @@ typedef struct CPUSH4State { * * A SuperH CPU. */ -struct SuperHCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -264,9 +264,6 @@ static inline int cpu_mmu_index (CPUSH4State *env, bool ifetch) } } -typedef CPUSH4State CPUArchState; -typedef SuperHCPU ArchCPU; - #include "exec/cpu-all.h" /* MMU control register */ diff --git a/target/sparc/cpu-qom.h b/target/sparc/cpu-qom.h index f33949aaee..86ed37d933 100644 --- a/target/sparc/cpu-qom.h +++ b/target/sparc/cpu-qom.h @@ -29,8 +29,7 @@ #define TYPE_SPARC_CPU "sparc-cpu" #endif -OBJECT_DECLARE_TYPE(SPARCCPU, SPARCCPUClass, - SPARC_CPU) +OBJECT_DECLARE_CPU_TYPE(SPARCCPU, SPARCCPUClass, SPARC_CPU) typedef struct sparc_def_t sparc_def_t; /** diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 5a7f1ed5d6..abb38db674 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -420,7 +420,7 @@ struct CPUTimer typedef struct CPUTimer CPUTimer; -typedef struct CPUSPARCState CPUSPARCState; +typedef struct CPUArchState CPUSPARCState; #if defined(TARGET_SPARC64) typedef union { uint64_t mmuregs[16]; @@ -439,7 +439,7 @@ typedef union { }; } SparcV9MMU; #endif -struct CPUSPARCState { +struct CPUArchState { target_ulong gregs[8]; /* general registers */ target_ulong *regwptr; /* pointer to current register window */ target_ulong pc; /* program counter */ @@ -556,7 +556,7 @@ struct CPUSPARCState { * * A SPARC CPU. */ -struct SPARCCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -743,9 +743,6 @@ static inline int cpu_pil_allowed(CPUSPARCState *env1, int pil) #endif } -typedef CPUSPARCState CPUArchState; -typedef SPARCCPU ArchCPU; - #include "exec/cpu-all.h" #ifdef TARGET_SPARC64 diff --git a/target/tricore/cpu-qom.h b/target/tricore/cpu-qom.h index 59bfd01bbc..ee24e9fa76 100644 --- a/target/tricore/cpu-qom.h +++ b/target/tricore/cpu-qom.h @@ -24,8 +24,7 @@ #define TYPE_TRICORE_CPU "tricore-cpu" -OBJECT_DECLARE_TYPE(TriCoreCPU, TriCoreCPUClass, - TRICORE_CPU) +OBJECT_DECLARE_CPU_TYPE(TriCoreCPU, TriCoreCPUClass, TRICORE_CPU) struct TriCoreCPUClass { /*< private >*/ diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index c461387e71..108d6b8288 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -28,8 +28,7 @@ struct tricore_boot_info; typedef struct tricore_def_t tricore_def_t; -typedef struct CPUTriCoreState CPUTriCoreState; -struct CPUTriCoreState { +typedef struct CPUArchState { /* GPR Register */ uint32_t gpr_a[16]; uint32_t gpr_d[16]; @@ -189,7 +188,7 @@ struct CPUTriCoreState { const tricore_def_t *cpu_model; void *irq[8]; struct QEMUTimer *timer; /* Internal timer */ -}; +} CPUTriCoreState; /** * TriCoreCPU: @@ -197,7 +196,7 @@ struct CPUTriCoreState { * * A TriCore CPU. */ -struct TriCoreCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -369,9 +368,6 @@ static inline int cpu_mmu_index(CPUTriCoreState *env, bool ifetch) return 0; } -typedef CPUTriCoreState CPUArchState; -typedef TriCoreCPU ArchCPU; - #include "exec/cpu-all.h" void cpu_state_reset(CPUTriCoreState *s); diff --git a/target/xtensa/cpu-qom.h b/target/xtensa/cpu-qom.h index 41d9859673..4fc35ee49b 100644 --- a/target/xtensa/cpu-qom.h +++ b/target/xtensa/cpu-qom.h @@ -34,8 +34,7 @@ #define TYPE_XTENSA_CPU "xtensa-cpu" -OBJECT_DECLARE_TYPE(XtensaCPU, XtensaCPUClass, - XTENSA_CPU) +OBJECT_DECLARE_CPU_TYPE(XtensaCPU, XtensaCPUClass, XTENSA_CPU) typedef struct XtensaConfig XtensaConfig; diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 02143f2f77..4515f682aa 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -306,7 +306,7 @@ typedef enum { INTTYPE_MAX } interrupt_type; -struct CPUXtensaState; +typedef struct CPUArchState CPUXtensaState; typedef struct xtensa_tlb_entry { uint32_t vaddr; @@ -344,7 +344,7 @@ typedef struct XtensaGdbRegmap { } XtensaGdbRegmap; typedef struct XtensaCcompareTimer { - struct CPUXtensaState *env; + CPUXtensaState *env; QEMUTimer *timer; } XtensaCcompareTimer; @@ -506,7 +506,7 @@ enum { }; #endif -typedef struct CPUXtensaState { +struct CPUArchState { const XtensaConfig *config; uint32_t regs[16]; uint32_t pc; @@ -545,7 +545,7 @@ typedef struct CPUXtensaState { /* Watchpoints for DBREAK registers */ struct CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK]; -} CPUXtensaState; +}; /** * XtensaCPU: @@ -553,7 +553,7 @@ typedef struct CPUXtensaState { * * An Xtensa CPU. */ -struct XtensaCPU { +struct ArchCPU { /*< private >*/ CPUState parent_obj; /*< public >*/ @@ -722,9 +722,6 @@ static inline int cpu_mmu_index(CPUXtensaState *env, bool ifetch) #define XTENSA_CSBASE_LBEG_OFF_MASK 0x00ff0000 #define XTENSA_CSBASE_LBEG_OFF_SHIFT 16 -typedef CPUXtensaState CPUArchState; -typedef XtensaCPU ArchCPU; - #include "exec/cpu-all.h" static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, diff --git a/tcg/region.c b/tcg/region.c index 72afb35738..97ca5291d5 100644 --- a/tcg/region.c +++ b/tcg/region.c @@ -26,6 +26,7 @@ #include "qemu/units.h" #include "qemu/madvise.h" #include "qemu/mprotect.h" +#include "qemu/memalign.h" #include "qemu/cacheinfo.h" #include "qapi/error.h" #include "exec/exec-all.h" diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py index 75063c0c30..9b056b5ce5 100644 --- a/tests/avocado/avocado_qemu/__init__.py +++ b/tests/avocado/avocado_qemu/__init__.py @@ -603,6 +603,8 @@ class LinuxTest(LinuxSSHMixIn, QemuSystemTest): try: cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso') self.phone_home_port = network.find_free_port() + if not self.phone_home_port: + self.cancel('Failed to get a free port') pubkey_content = None if ssh_pubkey: with open(ssh_pubkey) as pubkey: diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py index ab19146d1e..ee584d2fdf 100644 --- a/tests/avocado/boot_linux.py +++ b/tests/avocado/boot_linux.py @@ -79,6 +79,7 @@ class BootLinuxAarch64(LinuxTest): """ self.require_accelerator("tcg") self.vm.add_args("-accel", "tcg") + self.vm.add_args("-cpu", "max,lpa2=off") self.vm.add_args("-machine", "virt,gic-version=2") self.add_common_args() self.launch_and_wait(set_up_ssh_connection=False) @@ -91,6 +92,7 @@ class BootLinuxAarch64(LinuxTest): """ self.require_accelerator("tcg") self.vm.add_args("-accel", "tcg") + self.vm.add_args("-cpu", "max,lpa2=off") self.vm.add_args("-machine", "virt,gic-version=3") self.add_common_args() self.launch_and_wait(set_up_ssh_connection=False) diff --git a/tests/avocado/linux_ssh_mips_malta.py b/tests/avocado/linux_ssh_mips_malta.py index c0f0be5ade..0179d8a6ca 100644 --- a/tests/avocado/linux_ssh_mips_malta.py +++ b/tests/avocado/linux_ssh_mips_malta.py @@ -23,6 +23,9 @@ from avocado.utils import ssh @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') @skipUnless(ssh.SSH_CLIENT_BINARY, 'No SSH client available') class LinuxSSH(QemuSystemTest, LinuxSSHMixIn): + """ + :avocado: tags=accel:tcg + """ timeout = 150 # Not for 'configure --enable-debug --enable-debug-tcg' diff --git a/tests/bench/atomic_add-bench.c b/tests/bench/atomic_add-bench.c index f05471ab45..8a6faad6ec 100644 --- a/tests/bench/atomic_add-bench.c +++ b/tests/bench/atomic_add-bench.c @@ -2,6 +2,7 @@ #include "qemu/thread.h" #include "qemu/host-utils.h" #include "qemu/processor.h" +#include "qemu/memalign.h" struct thread_info { uint64_t r; diff --git a/tests/bench/qht-bench.c b/tests/bench/qht-bench.c index 2e5b70ccd0..8afe161d10 100644 --- a/tests/bench/qht-bench.c +++ b/tests/bench/qht-bench.c @@ -10,6 +10,7 @@ #include "qemu/qht.h" #include "qemu/rcu.h" #include "qemu/xxhash.h" +#include "qemu/memalign.h" struct thread_stats { size_t rd; diff --git a/tests/data/acpi/q35/FACP b/tests/data/acpi/q35/FACP Binary files differindex f6a864cc86..a8f6a89611 100644 --- a/tests/data/acpi/q35/FACP +++ b/tests/data/acpi/q35/FACP diff --git a/tests/data/acpi/q35/FACP.nosmm b/tests/data/acpi/q35/FACP.nosmm Binary files differindex 6a9aa5f370..c4e6d18ee5 100644 --- a/tests/data/acpi/q35/FACP.nosmm +++ b/tests/data/acpi/q35/FACP.nosmm diff --git a/tests/data/acpi/q35/FACP.slic b/tests/data/acpi/q35/FACP.slic Binary files differindex 15986e095c..48bbb1cf5a 100644 --- a/tests/data/acpi/q35/FACP.slic +++ b/tests/data/acpi/q35/FACP.slic diff --git a/tests/data/acpi/q35/FACP.xapic b/tests/data/acpi/q35/FACP.xapic Binary files differindex 2d3659c9c6..31fa5dd19c 100644 --- a/tests/data/acpi/q35/FACP.xapic +++ b/tests/data/acpi/q35/FACP.xapic diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index 4cf4d536b4..9479b92185 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -15,7 +15,6 @@ Testing: fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -43,7 +42,6 @@ Testing: -fda TEST_DIR/t.qcow2 fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -81,7 +79,6 @@ Testing: -fdb TEST_DIR/t.qcow2 fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -135,7 +132,6 @@ Testing: -fda TEST_DIR/t.qcow2 -fdb TEST_DIR/t.qcow2.2 fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -190,7 +186,6 @@ Testing: -fdb fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -230,7 +225,6 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -268,7 +262,6 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2,index=1 fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -322,7 +315,6 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=floppy,file=TEST_DIR/t fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -380,7 +372,6 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0 fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -418,7 +409,6 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,unit=1 fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -456,7 +446,6 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -520,7 +509,6 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -575,7 +563,6 @@ Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -630,7 +617,6 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -685,7 +671,6 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -749,7 +734,6 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -804,7 +788,6 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -865,7 +848,6 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -global floppy.drive=none0 -device fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -933,7 +915,6 @@ Testing: -device floppy fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -958,7 +939,6 @@ Testing: -device floppy,drive-type=120 fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -983,7 +963,6 @@ Testing: -device floppy,drive-type=144 fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -1008,7 +987,6 @@ Testing: -device floppy,drive-type=288 fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -1036,7 +1014,6 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -1074,7 +1051,6 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,drive-t fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -1115,7 +1091,6 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" @@ -1153,7 +1128,6 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physica fdtypeA = "auto" fdtypeB = "auto" fallback = "288" - isa irq 6 bus: floppy-bus.0 type floppy-bus dev: floppy, id "" diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c index 502e5ad0c7..01ca076afe 100644 --- a/tests/qtest/virtio-9p-test.c +++ b/tests/qtest/virtio-9p-test.c @@ -1253,7 +1253,7 @@ static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc) /* ... and is actually a directory */ g_assert((st.st_mode & S_IFMT) == S_IFDIR); - do_unlinkat(v9p, "/", "02", AT_REMOVEDIR); + do_unlinkat(v9p, "/", "02", P9_DOTL_AT_REMOVEDIR); /* directory should be gone now */ g_assert(stat(new_dir, &st) != 0); } diff --git a/tests/qtest/virtio-iommu-test.c b/tests/qtest/virtio-iommu-test.c index 47e68388a0..068e7a9e6c 100644 --- a/tests/qtest/virtio-iommu-test.c +++ b/tests/qtest/virtio-iommu-test.c @@ -31,11 +31,13 @@ static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc) uint64_t input_range_end = qvirtio_config_readq(dev, 16); uint32_t domain_range_start = qvirtio_config_readl(dev, 24); uint32_t domain_range_end = qvirtio_config_readl(dev, 28); + uint8_t bypass = qvirtio_config_readb(dev, 36); g_assert_cmpint(input_range_start, ==, 0); g_assert_cmphex(input_range_end, ==, UINT64_MAX); g_assert_cmpint(domain_range_start, ==, 0); g_assert_cmpint(domain_range_end, ==, UINT32_MAX); + g_assert_cmpint(bypass, ==, 1); } static int read_tail_status(struct virtio_iommu_req_tail *buffer) diff --git a/tests/tcg/s390x/exrl-trt.c b/tests/tcg/s390x/exrl-trt.c index 16711a3181..451f777b9d 100644 --- a/tests/tcg/s390x/exrl-trt.c +++ b/tests/tcg/s390x/exrl-trt.c @@ -5,8 +5,8 @@ int main(void) { char op1[] = "hello"; char op2[256]; - uint64_t r1 = 0xffffffffffffffffull; - uint64_t r2 = 0xffffffffffffffffull; + register uint64_t r1 asm("r1") = 0xffffffffffffffffull; + register uint64_t r2 asm("r2") = 0xffffffffffffffffull; uint64_t cc; int i; @@ -21,8 +21,6 @@ int main(void) " j 2f\n" "1: trt 0(1,%[op1]),%[op2]\n" "2: exrl %[op1_len],1b\n" - " lgr %[r1],%%r1\n" - " lgr %[r2],%%r2\n" " ipm %[cc]\n" : [r1] "+r" (r1), [r2] "+r" (r2), @@ -30,7 +28,7 @@ int main(void) : [op1] "a" (&op1), [op1_len] "a" (5), [op2] "Q" (op2) - : "r1", "r2", "cc"); + : "cc"); cc = (cc >> 28) & 3; if (cc != 2) { write(1, "bad cc\n", 7); diff --git a/tests/tcg/s390x/exrl-trtr.c b/tests/tcg/s390x/exrl-trtr.c index 5f30cda6bd..422f7f385a 100644 --- a/tests/tcg/s390x/exrl-trtr.c +++ b/tests/tcg/s390x/exrl-trtr.c @@ -5,8 +5,8 @@ int main(void) { char op1[] = {0, 1, 2, 3}; char op2[256]; - uint64_t r1 = 0xffffffffffffffffull; - uint64_t r2 = 0xffffffffffffffffull; + register uint64_t r1 asm("r1") = 0xffffffffffffffffull; + register uint64_t r2 asm("r2") = 0xffffffffffffffffull; uint64_t cc; int i; @@ -21,8 +21,6 @@ int main(void) " j 2f\n" "1: trtr 3(1,%[op1]),%[op2]\n" "2: exrl %[op1_len],1b\n" - " lgr %[r1],%%r1\n" - " lgr %[r2],%%r2\n" " ipm %[cc]\n" : [r1] "+r" (r1), [r2] "+r" (r2), @@ -30,7 +28,7 @@ int main(void) : [op1] "a" (&op1), [op1_len] "a" (3), [op2] "Q" (op2) - : "r1", "r2", "cc"); + : "cc"); cc = (cc >> 28) & 3; if (cc != 1) { write(1, "bad cc\n", 7); diff --git a/tests/tcg/s390x/mie3-mvcrl.c b/tests/tcg/s390x/mie3-mvcrl.c index 57b08e48d0..93c7b0a290 100644 --- a/tests/tcg/s390x/mie3-mvcrl.c +++ b/tests/tcg/s390x/mie3-mvcrl.c @@ -1,15 +1,17 @@ #include <stdint.h> #include <string.h> + static inline void mvcrl_8(const char *dst, const char *src) { asm volatile ( - "llill %%r0, 8\n" - ".insn sse, 0xE50A00000000, 0(%[dst]), 0(%[src])" - : : [dst] "d" (dst), [src] "d" (src) - : "memory"); + "llill %%r0, 8\n" + ".insn sse, 0xE50A00000000, 0(%[dst]), 0(%[src])" + : : [dst] "d" (dst), [src] "d" (src) + : "r0", "memory"); } + int main(int argc, char *argv[]) { const char *alpha = "abcdefghijklmnop"; diff --git a/tests/tcg/s390x/mie3-sel.c b/tests/tcg/s390x/mie3-sel.c index b0c5c9857d..0dfd532ed4 100644 --- a/tests/tcg/s390x/mie3-sel.c +++ b/tests/tcg/s390x/mie3-sel.c @@ -1,32 +1,27 @@ #include <stdint.h> + #define Fi3(S, ASM) uint64_t S(uint64_t a, uint64_t b, uint64_t c) \ -{ \ - uint64_t res = 0; \ - asm ( \ - "lg %%r2, %[a]\n" \ - "lg %%r3, %[b]\n" \ - "lg %%r0, %[c]\n" \ - "ltgr %%r0, %%r0\n" \ - ASM \ - "stg %%r0, %[res] " \ - : [res] "=m" (res) \ - : [a] "m" (a), \ - [b] "m" (b), \ - [c] "m" (c) \ - : "r0", "r2", \ - "r3", "r4" \ - ); \ - return res; \ +{ \ +asm volatile ( \ + "ltgr %[c], %[c]\n" \ + ASM \ + : [c] "+r" (c) \ + : [a] "r" (a) \ + , [b] "r" (b) \ +); \ + return c; \ } -Fi3 (_selre, ".insn rrf, 0xB9F00000, %%r0, %%r3, %%r2, 8\n") -Fi3 (_selgrz, ".insn rrf, 0xB9E30000, %%r0, %%r3, %%r2, 8\n") -Fi3 (_selfhrnz, ".insn rrf, 0xB9C00000, %%r0, %%r3, %%r2, 7\n") +Fi3 (_selre, ".insn rrf, 0xB9F00000, %[c], %[b], %[a], 8\n") +Fi3 (_selgrz, ".insn rrf, 0xB9E30000, %[c], %[b], %[a], 8\n") +Fi3 (_selfhrnz, ".insn rrf, 0xB9C00000, %[c], %[b], %[a], 7\n") + int main(int argc, char *argv[]) { uint64_t a = ~0, b = ~0, c = ~0; + a = _selre(0x066600000066ull, 0x066600000006ull, a); b = _selgrz(0xF00D00000005ull, 0xF00D00000055ull, b); c = _selfhrnz(0x043200000044ull, 0x065400000004ull, c); diff --git a/tests/tcg/s390x/mvc.c b/tests/tcg/s390x/mvc.c index aa552d52e5..7ae4c44550 100644 --- a/tests/tcg/s390x/mvc.c +++ b/tests/tcg/s390x/mvc.c @@ -20,8 +20,8 @@ static inline void mvc_256(const char *dst, const char *src) asm volatile ( " mvc 0(256,%[dst]),0(%[src])\n" : - : [dst] "d" (dst), - [src] "d" (src) + : [dst] "a" (dst), + [src] "a" (src) : "memory"); } diff --git a/tests/tcg/s390x/mvo.c b/tests/tcg/s390x/mvo.c index 5546fe2a97..0c3ecdde2e 100644 --- a/tests/tcg/s390x/mvo.c +++ b/tests/tcg/s390x/mvo.c @@ -11,8 +11,8 @@ int main(void) asm volatile ( " mvo 0(4,%[dest]),0(3,%[src])\n" : - : [dest] "d" (dest + 1), - [src] "d" (src + 1) + : [dest] "a" (dest + 1), + [src] "a" (src + 1) : "memory"); for (i = 0; i < sizeof(expected); i++) { diff --git a/tests/tcg/s390x/pack.c b/tests/tcg/s390x/pack.c index 4be36f29a7..55e7e214e8 100644 --- a/tests/tcg/s390x/pack.c +++ b/tests/tcg/s390x/pack.c @@ -9,7 +9,7 @@ int main(void) asm volatile( " pack 2(4,%[data]),2(4,%[data])\n" : - : [data] "r" (&data[0]) + : [data] "a" (&data[0]) : "memory"); for (i = 0; i < 8; i++) { if (data[i] != exp[i]) { diff --git a/tests/unit/ptimer-test-stubs.c b/tests/unit/ptimer-test-stubs.c index 2a3ef58799..f5e75a96b6 100644 --- a/tests/unit/ptimer-test-stubs.c +++ b/tests/unit/ptimer-test-stubs.c @@ -12,7 +12,6 @@ #include "qemu/main-loop.h" #include "sysemu/replay.h" #include "migration/vmstate.h" -#include "sysemu/cpu-timers.h" #include "ptimer-test.h" diff --git a/tests/vm/haiku.x86_64 b/tests/vm/haiku.x86_64 index 2eb736dae1..936f7d2ae2 100755 --- a/tests/vm/haiku.x86_64 +++ b/tests/vm/haiku.x86_64 @@ -2,7 +2,7 @@ # # Haiku VM image # -# Copyright 2020 Haiku, Inc. +# Copyright 2020-2022 Haiku, Inc. # # Authors: # Alexander von Gluck IV <kallisti5@unixzen.com> @@ -48,8 +48,8 @@ class HaikuVM(basevm.BaseVM): name = "haiku" arch = "x86_64" - link = "https://app.vagrantup.com/haiku-os/boxes/r1beta2-x86_64/versions/20200702/providers/libvirt.box" - csum = "41c38b316e0cbdbc66b5dbaf3612b866700a4f35807cb1eb266a5bf83e9e68d5" + link = "https://app.vagrantup.com/haiku-os/boxes/r1beta3-x86_64/versions/20220216/providers/libvirt.box" + csum = "e67d4aacbcc687013d5cc91990ddd86cc5d70a5d28432ae2691944f8ce5d5041" poweroff = "shutdown" @@ -99,7 +99,7 @@ class HaikuVM(basevm.BaseVM): self.print_step("Extracting disk image") - subprocess.check_call(["tar", "xzf", tarball, "./box.img", "-O"], + subprocess.check_call(["tar", "xzf", tarball, "box.img", "-O"], stdout=open(img, 'wb')) self.print_step("Preparing disk image") diff --git a/ui/cocoa.m b/ui/cocoa.m index 8ab9ab5e84..c88149852b 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -83,7 +83,7 @@ static void cocoa_switch(DisplayChangeListener *dcl, static void cocoa_refresh(DisplayChangeListener *dcl); -static NSWindow *normalWindow, *about_window; +static NSWindow *normalWindow; static const DisplayChangeListenerOps dcl_ops = { .dpy_name = "cocoa", .dpy_gfx_update = cocoa_update, @@ -1140,7 +1140,6 @@ QemuCocoaView *cocoaView; - (BOOL)verifyQuit; - (void)openDocumentation:(NSString *)filename; - (IBAction) do_about_menu_item: (id) sender; -- (void)make_about_window; - (void)adjustSpeed:(id)sender; @end @@ -1186,8 +1185,6 @@ QemuCocoaView *cocoaView; [pauseLabel setFont: [NSFont fontWithName: @"Helvetica" size: 90]]; [pauseLabel setTextColor: [NSColor blackColor]]; [pauseLabel sizeToFit]; - - [self make_about_window]; } return self; } @@ -1471,92 +1468,29 @@ QemuCocoaView *cocoaView; /* The action method for the About menu item */ - (IBAction) do_about_menu_item: (id) sender { - [about_window makeKeyAndOrderFront: nil]; -} - -/* Create and display the about dialog */ -- (void)make_about_window -{ - /* Make the window */ - int x = 0, y = 0, about_width = 400, about_height = 200; - NSRect window_rect = NSMakeRect(x, y, about_width, about_height); - about_window = [[NSWindow alloc] initWithContentRect:window_rect - styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable - backing:NSBackingStoreBuffered - defer:NO]; - [about_window setTitle: @"About"]; - [about_window setReleasedWhenClosed: NO]; - [about_window center]; - NSView *superView = [about_window contentView]; - - /* Create the dimensions of the picture */ - int picture_width = 80, picture_height = 80; - x = (about_width - picture_width)/2; - y = about_height - picture_height - 10; - NSRect picture_rect = NSMakeRect(x, y, picture_width, picture_height); - - /* Make the picture of QEMU */ - NSImageView *picture_view = [[NSImageView alloc] initWithFrame: - picture_rect]; - char *qemu_image_path_c = get_relocated_path(CONFIG_QEMU_ICONDIR "/hicolor/512x512/apps/qemu.png"); - NSString *qemu_image_path = [NSString stringWithUTF8String:qemu_image_path_c]; - g_free(qemu_image_path_c); - NSImage *qemu_image = [[NSImage alloc] initWithContentsOfFile:qemu_image_path]; - [picture_view setImage: qemu_image]; - [picture_view setImageScaling: NSImageScaleProportionallyUpOrDown]; - [superView addSubview: picture_view]; - - /* Make the name label */ - NSBundle *bundle = [NSBundle mainBundle]; - if (bundle) { - x = 0; - y = y - 25; - int name_width = about_width, name_height = 20; - NSRect name_rect = NSMakeRect(x, y, name_width, name_height); - NSTextField *name_label = [[NSTextField alloc] initWithFrame: name_rect]; - [name_label setEditable: NO]; - [name_label setBezeled: NO]; - [name_label setDrawsBackground: NO]; - [name_label setAlignment: NSTextAlignmentCenter]; - NSString *qemu_name = [[bundle executablePath] lastPathComponent]; - [name_label setStringValue: qemu_name]; - [superView addSubview: name_label]; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + char *icon_path_c = get_relocated_path(CONFIG_QEMU_ICONDIR "/hicolor/512x512/apps/qemu.png"); + NSString *icon_path = [NSString stringWithUTF8String:icon_path_c]; + g_free(icon_path_c); + NSImage *icon = [[NSImage alloc] initWithContentsOfFile:icon_path]; + NSString *version = @"QEMU emulator version " QEMU_FULL_VERSION; + NSString *copyright = @QEMU_COPYRIGHT; + NSDictionary *options; + if (icon) { + options = @{ + NSAboutPanelOptionApplicationIcon : icon, + NSAboutPanelOptionApplicationVersion : version, + @"Copyright" : copyright, + }; + [icon release]; + } else { + options = @{ + NSAboutPanelOptionApplicationVersion : version, + @"Copyright" : copyright, + }; } - - /* Set the version label's attributes */ - x = 0; - y = 50; - int version_width = about_width, version_height = 20; - NSRect version_rect = NSMakeRect(x, y, version_width, version_height); - NSTextField *version_label = [[NSTextField alloc] initWithFrame: - version_rect]; - [version_label setEditable: NO]; - [version_label setBezeled: NO]; - [version_label setAlignment: NSTextAlignmentCenter]; - [version_label setDrawsBackground: NO]; - - /* Create the version string*/ - NSString *version_string; - version_string = [[NSString alloc] initWithFormat: - @"QEMU emulator version %s", QEMU_FULL_VERSION]; - [version_label setStringValue: version_string]; - [superView addSubview: version_label]; - - /* Make copyright label */ - x = 0; - y = 35; - int copyright_width = about_width, copyright_height = 20; - NSRect copyright_rect = NSMakeRect(x, y, copyright_width, copyright_height); - NSTextField *copyright_label = [[NSTextField alloc] initWithFrame: - copyright_rect]; - [copyright_label setEditable: NO]; - [copyright_label setBezeled: NO]; - [copyright_label setDrawsBackground: NO]; - [copyright_label setAlignment: NSTextAlignmentCenter]; - [copyright_label setStringValue: [NSString stringWithFormat: @"%s", - QEMU_COPYRIGHT]]; - [superView addSubview: copyright_label]; + [NSApp orderFrontStandardAboutPanelWithOptions:options]; + [pool release]; } /* Used by the Speed menu items */ diff --git a/util/atomic64.c b/util/atomic64.c index 22983a970f..c20d071d8e 100644 --- a/util/atomic64.c +++ b/util/atomic64.c @@ -8,6 +8,7 @@ #include "qemu/atomic.h" #include "qemu/thread.h" #include "qemu/cacheinfo.h" +#include "qemu/memalign.h" #ifdef CONFIG_ATOMIC64 #error This file must only be compiled if !CONFIG_ATOMIC64 diff --git a/util/event_notifier-posix.c b/util/event_notifier-posix.c index 8307013c5d..16294e98d4 100644 --- a/util/event_notifier-posix.c +++ b/util/event_notifier-posix.c @@ -99,6 +99,11 @@ int event_notifier_get_fd(const EventNotifier *e) return e->rfd; } +int event_notifier_get_wfd(const EventNotifier *e) +{ + return e->wfd; +} + int event_notifier_set(EventNotifier *e) { static const uint64_t value = 1; diff --git a/util/memalign.c b/util/memalign.c new file mode 100644 index 0000000000..c199ae7073 --- /dev/null +++ b/util/memalign.c @@ -0,0 +1,92 @@ +/* + * memalign.c: Allocate an aligned memory region + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2010-2016 Red Hat, Inc. + * Copyright (c) 2022 Linaro Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/host-utils.h" +#include "qemu/memalign.h" +#include "trace.h" + +void *qemu_try_memalign(size_t alignment, size_t size) +{ + void *ptr; + + if (alignment < sizeof(void*)) { + alignment = sizeof(void*); + } else { + g_assert(is_power_of_2(alignment)); + } + + /* + * Handling of 0 allocations varies among the different + * platform APIs (for instance _aligned_malloc() will + * fail) -- ensure that we always return a valid non-NULL + * pointer that can be freed by qemu_vfree(). + */ + if (size == 0) { + size++; + } +#if defined(CONFIG_POSIX_MEMALIGN) + int ret; + ret = posix_memalign(&ptr, alignment, size); + if (ret != 0) { + errno = ret; + ptr = NULL; + } +#elif defined(CONFIG_ALIGNED_MALLOC) + ptr = _aligned_malloc(size, alignment); +#elif defined(CONFIG_VALLOC) + ptr = valloc(size); +#elif defined(CONFIG_MEMALIGN) + ptr = memalign(alignment, size); +#else + #error No function to allocate aligned memory available +#endif + trace_qemu_memalign(alignment, size, ptr); + return ptr; +} + +void *qemu_memalign(size_t alignment, size_t size) +{ + void *p = qemu_try_memalign(alignment, size); + if (p) { + return p; + } + fprintf(stderr, + "qemu_memalign: failed to allocate %zu bytes at alignment %zu: %s\n", + size, alignment, strerror(errno)); + abort(); +} + +void qemu_vfree(void *ptr) +{ + trace_qemu_vfree(ptr); +#if !defined(CONFIG_POSIX_MEMALIGN) && defined(CONFIG_ALIGNED_MALLOC) + /* Only Windows _aligned_malloc needs a special free function */ + _aligned_free(ptr); +#else + free(ptr); +#endif +} diff --git a/util/meson.build b/util/meson.build index 3736988b9f..f6ee74ad0c 100644 --- a/util/meson.build +++ b/util/meson.build @@ -51,6 +51,7 @@ util_ss.add(when: 'CONFIG_POSIX', if_true: files('drm.c')) util_ss.add(files('guest-random.c')) util_ss.add(files('yank.c')) util_ss.add(files('int128.c')) +util_ss.add(files('memalign.c')) if have_user util_ss.add(files('selfmap.c')) diff --git a/util/osdep.c b/util/osdep.c index 723cdcb004..7c4deda6fe 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -33,7 +33,6 @@ extern int madvise(char *, size_t, int); #endif -#include <dirent.h> #include "qemu-common.h" #include "qemu/cutils.h" #include "qemu/sockets.h" @@ -619,23 +618,3 @@ writev(int fd, const struct iovec *iov, int iov_cnt) return readv_writev(fd, iov, iov_cnt, true); } #endif - -struct dirent * -qemu_dirent_dup(struct dirent *dent) -{ - size_t sz = 0; -#if defined _DIRENT_HAVE_D_RECLEN - /* Avoid use of strlen() if platform supports d_reclen. */ - sz = dent->d_reclen; -#endif - /* - * Test sz for zero even if d_reclen is available - * because some drivers may set d_reclen to zero. - */ - if (sz == 0) { - /* Fallback to the most portable way. */ - sz = offsetof(struct dirent, d_name) + - strlen(dent->d_name) + 1; - } - return g_memdup(dent, sz); -} diff --git a/util/oslib-posix.c b/util/oslib-posix.c index f2be7321c5..2ebfb75057 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -199,46 +199,6 @@ fail_close: return false; } -void *qemu_oom_check(void *ptr) -{ - if (ptr == NULL) { - fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno)); - abort(); - } - return ptr; -} - -void *qemu_try_memalign(size_t alignment, size_t size) -{ - void *ptr; - - if (alignment < sizeof(void*)) { - alignment = sizeof(void*); - } else { - g_assert(is_power_of_2(alignment)); - } - -#if defined(CONFIG_POSIX_MEMALIGN) - int ret; - ret = posix_memalign(&ptr, alignment, size); - if (ret != 0) { - errno = ret; - ptr = NULL; - } -#elif defined(CONFIG_BSD) - ptr = valloc(size); -#else - ptr = memalign(alignment, size); -#endif - trace_qemu_memalign(alignment, size, ptr); - return ptr; -} - -void *qemu_memalign(size_t alignment, size_t size) -{ - return qemu_oom_check(qemu_try_memalign(alignment, size)); -} - /* alloc shared memory pages */ void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared, bool noreserve) @@ -260,12 +220,6 @@ void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared, return ptr; } -void qemu_vfree(void *ptr) -{ - trace_qemu_vfree(ptr); - free(ptr); -} - void qemu_anon_ram_free(void *ptr, size_t size) { trace_qemu_anon_ram_free(ptr, size); diff --git a/util/oslib-win32.c b/util/oslib-win32.c index af559ef339..4b1ce0be4b 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -44,35 +44,6 @@ /* this must come after including "trace.h" */ #include <shlobj.h> -void *qemu_oom_check(void *ptr) -{ - if (ptr == NULL) { - fprintf(stderr, "Failed to allocate memory: %lu\n", GetLastError()); - abort(); - } - return ptr; -} - -void *qemu_try_memalign(size_t alignment, size_t size) -{ - void *ptr; - - g_assert(size != 0); - if (alignment < sizeof(void *)) { - alignment = sizeof(void *); - } else { - g_assert(is_power_of_2(alignment)); - } - ptr = _aligned_malloc(size, alignment); - trace_qemu_memalign(alignment, size, ptr); - return ptr; -} - -void *qemu_memalign(size_t alignment, size_t size) -{ - return qemu_oom_check(qemu_try_memalign(alignment, size)); -} - static int get_allocation_granularity(void) { SYSTEM_INFO system_info; @@ -104,12 +75,6 @@ void *qemu_anon_ram_alloc(size_t size, uint64_t *align, bool shared, return ptr; } -void qemu_vfree(void *ptr) -{ - trace_qemu_vfree(ptr); - _aligned_free(ptr); -} - void qemu_anon_ram_free(void *ptr, size_t size) { trace_qemu_anon_ram_free(ptr, size); diff --git a/util/qht.c b/util/qht.c index 079605121b..065fc501f4 100644 --- a/util/qht.c +++ b/util/qht.c @@ -69,6 +69,7 @@ #include "qemu/qht.h" #include "qemu/atomic.h" #include "qemu/rcu.h" +#include "qemu/memalign.h" //#define QHT_DEBUG |