aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap3
-rw-r--r--MAINTAINERS5
-rw-r--r--accel/hvf/hvf-accel-ops.c21
-rw-r--r--accel/kvm/kvm-all.c5
-rw-r--r--accel/stubs/kvm-stub.c1
-rw-r--r--accel/tcg/tcg-accel-ops-mttcg.c4
-rw-r--r--accel/tcg/tcg-accel-ops-rr.c3
-rw-r--r--audio/dbusaudio.c43
-rw-r--r--block.c114
-rw-r--r--block/bochs.c7
-rw-r--r--block/cloop.c9
-rw-r--r--block/dmg.c21
-rw-r--r--block/file-posix.c29
-rw-r--r--block/graph-lock.c43
-rw-r--r--block/io.c14
-rw-r--r--block/parallels.c4
-rw-r--r--block/qcow.c30
-rw-r--r--block/qcow2-bitmap.c26
-rw-r--r--block/qcow2-cluster.c24
-rw-r--r--block/qcow2-refcount.c134
-rw-r--r--block/qcow2.c20
-rw-r--r--block/qcow2.h33
-rw-r--r--block/qed-check.c5
-rw-r--r--block/qed-table.c6
-rw-r--r--block/qed.c15
-rw-r--r--block/raw-format.c4
-rw-r--r--block/vhdx-log.c36
-rw-r--r--block/vhdx.c73
-rw-r--r--block/vhdx.h5
-rw-r--r--block/vmdk.c55
-rw-r--r--block/vpc.c52
-rw-r--r--blockjob.c17
-rw-r--r--chardev/char-win-stdio.c2
-rw-r--r--docs/devel/testing.rst2
-rw-r--r--docs/system/device-emulation.rst1
-rw-r--r--docs/system/devices/keyboard.rst129
-rw-r--r--docs/system/devices/nvme.rst37
-rw-r--r--docs/system/target-sparc.rst2
-rw-r--r--hw/arm/sbsa-ref.c2
-rw-r--r--hw/arm/virt-acpi-build.c2
-rw-r--r--hw/arm/virt.c1
-rw-r--r--hw/arm/xen_arm.c2
-rw-r--r--hw/char/escc.c79
-rw-r--r--hw/core/qdev-properties-system.c8
-rw-r--r--hw/display/virtio-gpu-udmabuf.c3
-rw-r--r--hw/display/virtio-gpu-virgl.c43
-rw-r--r--hw/display/virtio-gpu.c99
-rw-r--r--hw/i386/xen/xen-hvm.c2
-rw-r--r--hw/intc/arm_gic_common.c11
-rw-r--r--hw/intc/arm_gicv3_common.c14
-rw-r--r--hw/intc/arm_gicv3_its_common.c12
-rw-r--r--hw/net/vhost_net.c7
-rw-r--r--hw/nvme/ctrl.c34
-rw-r--r--hw/nvme/ns.c53
-rw-r--r--hw/nvme/subsys.c6
-rw-r--r--hw/ppc/e500.c2
-rw-r--r--hw/ppc/ppce500_spin.c2
-rw-r--r--hw/remote/proxy-memory-listener.c2
-rw-r--r--hw/sparc64/niagara.c6
-rw-r--r--hw/virtio/vhost.c2
-rw-r--r--hw/xen/xen-hvm-common.c2
-rw-r--r--hw/xen/xen_pt.c4
-rw-r--r--include/block/block-io.h7
-rw-r--r--include/block/graph-lock.h6
-rw-r--r--include/exec/memory.h4
-rw-r--r--include/hw/char/escc.h1
-rw-r--r--include/hw/core/cpu.h10
-rw-r--r--include/hw/intc/arm_gic.h2
-rw-r--r--include/hw/intc/arm_gicv3_common.h10
-rw-r--r--include/hw/intc/arm_gicv3_its_common.h9
-rw-r--r--include/hw/virtio/virtio-gpu.h3
-rw-r--r--include/qemu/typedefs.h1
-rw-r--r--include/sysemu/hax.h2
-rw-r--r--include/sysemu/hvf_int.h2
-rw-r--r--include/sysemu/kvm.h3
-rw-r--r--include/sysemu/nvmm.h2
-rw-r--r--include/sysemu/os-win32.h3
-rw-r--r--include/sysemu/tcg.h2
-rw-r--r--include/sysemu/whpx.h2
-rw-r--r--include/sysemu/xen.h2
-rw-r--r--include/ui/console.h30
-rw-r--r--include/ui/egl-helpers.h11
-rw-r--r--include/ui/gtk.h6
-rw-r--r--include/ui/sdl2.h3
-rw-r--r--meson.build14
-rw-r--r--qapi/ui.json5
-rw-r--r--scripts/meson.build2
-rw-r--r--scripts/xml-preprocess-test.py136
-rwxr-xr-xscripts/xml-preprocess.py293
-rw-r--r--target/arm/cpu.h2
-rw-r--r--target/arm/hvf/hvf.c108
-rw-r--r--target/arm/kvm.c1
-rw-r--r--target/arm/kvm_arm.h45
-rw-r--r--target/i386/hax/hax-accel-ops.c5
-rw-r--r--target/i386/hax/hax-all.c26
-rw-r--r--target/i386/hax/hax-i386.h12
-rw-r--r--target/i386/hax/hax-mem.c2
-rw-r--r--target/i386/hax/hax-posix.c4
-rw-r--r--target/i386/hax/hax-windows.c6
-rw-r--r--target/i386/hvf/hvf.c106
-rw-r--r--target/i386/hvf/vmx.h22
-rw-r--r--target/i386/hvf/x86.c28
-rw-r--r--target/i386/hvf/x86_descr.c26
-rw-r--r--target/i386/hvf/x86_emu.c62
-rw-r--r--target/i386/hvf/x86_mmu.c4
-rw-r--r--target/i386/hvf/x86_task.c10
-rw-r--r--target/i386/hvf/x86hvf.c372
-rw-r--r--target/i386/hvf/x86hvf.h18
-rw-r--r--target/i386/nvmm/nvmm-all.c44
-rw-r--r--target/i386/whpx/whpx-accel-ops.c3
-rw-r--r--target/i386/whpx/whpx-all.c55
-rw-r--r--target/i386/whpx/whpx-internal.h4
-rw-r--r--target/ppc/cpu.h2
-rw-r--r--target/ppc/mmu_common.c4
-rw-r--r--target/riscv/cpu.c2
-rw-r--r--target/riscv/cpu.h2
-rw-r--r--target/riscv/machine.c8
-rw-r--r--target/sparc/translate.c402
-rwxr-xr-xtests/qemu-iotests/tests/iothreads-commit-active85
-rw-r--r--tests/qemu-iotests/tests/iothreads-commit-active.out23
-rw-r--r--tests/qtest/dbus-display-test.c43
-rw-r--r--tests/qtest/libqtest.c5
-rw-r--r--tests/qtest/libqtest.h9
-rw-r--r--tests/qtest/meson.build2
-rw-r--r--tests/unit/test-block-iothread.c7
-rw-r--r--ui/console.c137
-rw-r--r--ui/dbus-chardev.c20
-rw-r--r--ui/dbus-console.c124
-rw-r--r--ui/dbus-display1.xml285
-rw-r--r--ui/dbus-listener.c527
-rw-r--r--ui/dbus.c4
-rw-r--r--ui/dbus.h6
-rw-r--r--ui/egl-context.c10
-rw-r--r--ui/egl-headless.c25
-rw-r--r--ui/egl-helpers.c104
-rw-r--r--ui/gtk-egl.c16
-rw-r--r--ui/gtk-gl-area.c6
-rw-r--r--ui/gtk.c66
-rw-r--r--ui/meson.build15
-rw-r--r--ui/qemu-pixman.c1
-rw-r--r--ui/sdl2-gl.c3
-rw-r--r--ui/sdl2.c18
-rw-r--r--ui/spice-display.c3
-rw-r--r--ui/trace-events9
-rw-r--r--util/oslib-win32.c33
-rw-r--r--util/trace-events4
146 files changed, 3669 insertions, 1309 deletions
diff --git a/.mailmap b/.mailmap
index b57da4827e..64ef9f4de6 100644
--- a/.mailmap
+++ b/.mailmap
@@ -76,9 +76,10 @@ Paul Burton <paulburton@kernel.org> <pburton@wavecomp.com>
Philippe Mathieu-Daudé <philmd@linaro.org> <f4bug@amsat.org>
Philippe Mathieu-Daudé <philmd@linaro.org> <philmd@redhat.com>
Philippe Mathieu-Daudé <philmd@linaro.org> <philmd@fungible.com>
+Roman Bolshakov <rbolshakov@ddn.com> <r.bolshakov@yadro.com>
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
-Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
Taylor Simpson <ltaylorsimpson@gmail.com> <tsimpson@quicinc.com>
+Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
# Also list preferred name forms where people have changed their
# git author config, or had utf8/latin1 encoding issues.
diff --git a/MAINTAINERS b/MAINTAINERS
index e07746ac7d..aba07722f6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -498,14 +498,14 @@ F: target/arm/hvf/
X86 HVF CPUs
M: Cameron Esfahani <dirty@apple.com>
-M: Roman Bolshakov <r.bolshakov@yadro.com>
+M: Roman Bolshakov <rbolshakov@ddn.com>
W: https://wiki.qemu.org/Features/HVF
S: Maintained
F: target/i386/hvf/
HVF
M: Cameron Esfahani <dirty@apple.com>
-M: Roman Bolshakov <r.bolshakov@yadro.com>
+M: Roman Bolshakov <rbolshakov@ddn.com>
W: https://wiki.qemu.org/Features/HVF
S: Maintained
F: accel/hvf/
@@ -3202,6 +3202,7 @@ F: docs/interop/dbus*
F: docs/sphinx/dbus*
F: docs/sphinx/fakedbusdoc.py
F: tests/qtest/dbus*
+F: scripts/xml-preprocess*
Seccomp
M: Daniel P. Berrange <berrange@redhat.com>
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
index 9c3da03c94..a44cf1c144 100644
--- a/accel/hvf/hvf-accel-ops.c
+++ b/accel/hvf/hvf-accel-ops.c
@@ -304,7 +304,7 @@ static void hvf_region_del(MemoryListener *listener,
static MemoryListener hvf_memory_listener = {
.name = "hvf",
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
.region_add = hvf_region_add,
.region_del = hvf_region_del,
.log_start = hvf_log_start,
@@ -372,19 +372,19 @@ type_init(hvf_type_init);
static void hvf_vcpu_destroy(CPUState *cpu)
{
- hv_return_t ret = hv_vcpu_destroy(cpu->hvf->fd);
+ hv_return_t ret = hv_vcpu_destroy(cpu->accel->fd);
assert_hvf_ok(ret);
hvf_arch_vcpu_destroy(cpu);
- g_free(cpu->hvf);
- cpu->hvf = NULL;
+ g_free(cpu->accel);
+ cpu->accel = NULL;
}
static int hvf_init_vcpu(CPUState *cpu)
{
int r;
- cpu->hvf = g_malloc0(sizeof(*cpu->hvf));
+ cpu->accel = g_new0(AccelCPUState, 1);
/* init cpu signals */
struct sigaction sigact;
@@ -393,18 +393,19 @@ static int hvf_init_vcpu(CPUState *cpu)
sigact.sa_handler = dummy_signal;
sigaction(SIG_IPI, &sigact, NULL);
- pthread_sigmask(SIG_BLOCK, NULL, &cpu->hvf->unblock_ipi_mask);
- sigdelset(&cpu->hvf->unblock_ipi_mask, SIG_IPI);
+ pthread_sigmask(SIG_BLOCK, NULL, &cpu->accel->unblock_ipi_mask);
+ sigdelset(&cpu->accel->unblock_ipi_mask, SIG_IPI);
#ifdef __aarch64__
- r = hv_vcpu_create(&cpu->hvf->fd, (hv_vcpu_exit_t **)&cpu->hvf->exit, NULL);
+ r = hv_vcpu_create(&cpu->accel->fd,
+ (hv_vcpu_exit_t **)&cpu->accel->exit, NULL);
#else
- r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf->fd, HV_VCPU_DEFAULT);
+ r = hv_vcpu_create((hv_vcpuid_t *)&cpu->accel->fd, HV_VCPU_DEFAULT);
#endif
cpu->vcpu_dirty = 1;
assert_hvf_ok(r);
- cpu->hvf->guest_debug_enabled = false;
+ cpu->accel->guest_debug_enabled = false;
return hvf_arch_init_vcpu(cpu);
}
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 9aa898db14..373d876c05 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -1105,6 +1105,7 @@ static MemoryListener kvm_coalesced_pio_listener = {
.name = "kvm-coalesced-pio",
.coalesced_io_add = kvm_coalesce_pio_add,
.coalesced_io_del = kvm_coalesce_pio_del,
+ .priority = MEMORY_LISTENER_PRIORITY_MIN,
};
int kvm_check_extension(KVMState *s, unsigned int extension)
@@ -1777,7 +1778,7 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
kml->listener.commit = kvm_region_commit;
kml->listener.log_start = kvm_log_start;
kml->listener.log_stop = kvm_log_stop;
- kml->listener.priority = 10;
+ kml->listener.priority = MEMORY_LISTENER_PRIORITY_ACCEL;
kml->listener.name = name;
if (s->kvm_dirty_ring_size) {
@@ -1802,7 +1803,7 @@ static MemoryListener kvm_io_listener = {
.name = "kvm-io",
.eventfd_add = kvm_io_ioeventfd_add,
.eventfd_del = kvm_io_ioeventfd_del,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_DEV_BACKEND,
};
int kvm_set_irq(KVMState *s, int irq, int level)
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index 5d2dd8f351..235dc661bc 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -27,6 +27,7 @@ bool kvm_allowed;
bool kvm_readonly_mem_allowed;
bool kvm_ioeventfd_any_length_allowed;
bool kvm_msi_use_devid;
+bool kvm_direct_msi_allowed;
void kvm_flush_coalesced_mmio_buffer(void)
{
diff --git a/accel/tcg/tcg-accel-ops-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c
index b320ff0037..b276262007 100644
--- a/accel/tcg/tcg-accel-ops-mttcg.c
+++ b/accel/tcg/tcg-accel-ops-mttcg.c
@@ -152,8 +152,4 @@ void mttcg_start_vcpu_thread(CPUState *cpu)
qemu_thread_create(cpu->thread, thread_name, mttcg_cpu_thread_fn,
cpu, QEMU_THREAD_JOINABLE);
-
-#ifdef _WIN32
- cpu->hThread = qemu_thread_get_handle(cpu->thread);
-#endif
}
diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c
index 23e4d0f452..2d523289a8 100644
--- a/accel/tcg/tcg-accel-ops-rr.c
+++ b/accel/tcg/tcg-accel-ops-rr.c
@@ -329,9 +329,6 @@ void rr_start_vcpu_thread(CPUState *cpu)
single_tcg_halt_cond = cpu->halt_cond;
single_tcg_cpu_thread = cpu->thread;
-#ifdef _WIN32
- cpu->hThread = qemu_thread_get_handle(cpu->thread);
-#endif
} else {
/* we share the thread */
cpu->thread = single_tcg_cpu_thread;
diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c
index fece74f78c..7a11fbfb42 100644
--- a/audio/dbusaudio.c
+++ b/audio/dbusaudio.c
@@ -29,7 +29,11 @@
#include "qemu/timer.h"
#include "qemu/dbus.h"
+#ifdef G_OS_UNIX
#include <gio/gunixfdlist.h>
+#endif
+
+#include "ui/dbus.h"
#include "ui/dbus-display1.h"
#define AUDIO_CAP "dbus"
@@ -444,7 +448,9 @@ listener_in_vanished_cb(GDBusConnection *connection,
static gboolean
dbus_audio_register_listener(AudioState *s,
GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
GUnixFDList *fd_list,
+#endif
GVariant *arg_listener,
bool out)
{
@@ -471,6 +477,11 @@ dbus_audio_register_listener(AudioState *s,
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#ifdef G_OS_WIN32
+ if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+#else
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
if (err) {
g_dbus_method_invocation_return_error(invocation,
@@ -480,6 +491,7 @@ dbus_audio_register_listener(AudioState *s,
err->message);
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#endif
socket = g_socket_new_from_fd(fd, &err);
if (err) {
@@ -488,15 +500,28 @@ dbus_audio_register_listener(AudioState *s,
DBUS_DISPLAY_ERROR_FAILED,
"Couldn't make a socket: %s",
err->message);
+#ifdef G_OS_WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif
return DBUS_METHOD_INVOCATION_HANDLED;
}
socket_conn = g_socket_connection_factory_create_connection(socket);
if (out) {
qemu_dbus_display1_audio_complete_register_out_listener(
- da->iface, invocation, NULL);
+ da->iface, invocation
+#ifdef G_OS_UNIX
+ , NULL
+#endif
+ );
} else {
qemu_dbus_display1_audio_complete_register_in_listener(
- da->iface, invocation, NULL);
+ da->iface, invocation
+#ifdef G_OS_UNIX
+ , NULL
+#endif
+ );
}
listener_conn =
@@ -574,22 +599,32 @@ dbus_audio_register_listener(AudioState *s,
static gboolean
dbus_audio_register_out_listener(AudioState *s,
GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
GUnixFDList *fd_list,
+#endif
GVariant *arg_listener)
{
return dbus_audio_register_listener(s, invocation,
- fd_list, arg_listener, true);
+#ifdef G_OS_UNIX
+ fd_list,
+#endif
+ arg_listener, true);
}
static gboolean
dbus_audio_register_in_listener(AudioState *s,
GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
GUnixFDList *fd_list,
+#endif
GVariant *arg_listener)
{
return dbus_audio_register_listener(s, invocation,
- fd_list, arg_listener, false);
+#ifdef G_OS_UNIX
+ fd_list,
+#endif
+ arg_listener, false);
}
static void
diff --git a/block.c b/block.c
index 0637265c26..a307c151a8 100644
--- a/block.c
+++ b/block.c
@@ -555,8 +555,9 @@ int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
* On success, return @blk's actual length.
* Otherwise, return -errno.
*/
-static int64_t create_file_fallback_truncate(BlockBackend *blk,
- int64_t minimum_size, Error **errp)
+static int64_t coroutine_fn GRAPH_UNLOCKED
+create_file_fallback_truncate(BlockBackend *blk, int64_t minimum_size,
+ Error **errp)
{
Error *local_err = NULL;
int64_t size;
@@ -564,14 +565,14 @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
GLOBAL_STATE_CODE();
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
- &local_err);
+ ret = blk_co_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
+ &local_err);
if (ret < 0 && ret != -ENOTSUP) {
error_propagate(errp, local_err);
return ret;
}
- size = blk_getlength(blk);
+ size = blk_co_getlength(blk);
if (size < 0) {
error_free(local_err);
error_setg_errno(errp, -size,
@@ -2854,7 +2855,7 @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
* Replaces the node that a BdrvChild points to without updating permissions.
*
* If @new_bs is non-NULL, the parent of @child must already be drained through
- * @child.
+ * @child and the caller must hold the AioContext lock for @new_bs.
*/
static void bdrv_replace_child_noperm(BdrvChild *child,
BlockDriverState *new_bs)
@@ -2893,7 +2894,7 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
}
/* TODO Pull this up into the callers to avoid polling here */
- bdrv_graph_wrlock();
+ bdrv_graph_wrlock(new_bs);
if (old_bs) {
if (child->klass->detach) {
child->klass->detach(child);
@@ -2989,6 +2990,10 @@ static TransactionActionDrv bdrv_attach_child_common_drv = {
* Function doesn't update permissions, caller is responsible for this.
*
* Returns new created child.
+ *
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
+ * @child_bs can move to a different AioContext in this function. Callers must
+ * make sure that their AioContext locking is still correct after this.
*/
static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
const char *child_name,
@@ -2999,7 +3004,7 @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
Transaction *tran, Error **errp)
{
BdrvChild *new_child;
- AioContext *parent_ctx;
+ AioContext *parent_ctx, *new_child_ctx;
AioContext *child_ctx = bdrv_get_aio_context(child_bs);
assert(child_class->get_parent_desc);
@@ -3050,6 +3055,12 @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
}
}
+ new_child_ctx = bdrv_get_aio_context(child_bs);
+ if (new_child_ctx != child_ctx) {
+ aio_context_release(child_ctx);
+ aio_context_acquire(new_child_ctx);
+ }
+
bdrv_ref(child_bs);
/*
* Let every new BdrvChild start with a drained parent. Inserting the child
@@ -3079,11 +3090,20 @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
};
tran_add(tran, &bdrv_attach_child_common_drv, s);
+ if (new_child_ctx != child_ctx) {
+ aio_context_release(new_child_ctx);
+ aio_context_acquire(child_ctx);
+ }
+
return new_child;
}
/*
* Function doesn't update permissions, caller is responsible for this.
+ *
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
+ * @child_bs can move to a different AioContext in this function. Callers must
+ * make sure that their AioContext locking is still correct after this.
*/
static BdrvChild *bdrv_attach_child_noperm(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
@@ -3347,6 +3367,10 @@ static BdrvChildRole bdrv_backing_role(BlockDriverState *bs)
* callers which don't need their own reference any more must call bdrv_unref().
*
* Function doesn't update permissions, caller is responsible for this.
+ *
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
+ * @child_bs can move to a different AioContext in this function. Callers must
+ * make sure that their AioContext locking is still correct after this.
*/
static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
@@ -3435,6 +3459,11 @@ out:
return 0;
}
+/*
+ * The caller must hold the AioContext lock for @backing_hd. Both @bs and
+ * @backing_hd can move to a different AioContext in this function. Callers must
+ * make sure that their AioContext locking is still correct after this.
+ */
static int bdrv_set_backing_noperm(BlockDriverState *bs,
BlockDriverState *backing_hd,
Transaction *tran, Error **errp)
@@ -3498,6 +3527,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
int ret = 0;
bool implicit_backing = false;
BlockDriverState *backing_hd;
+ AioContext *backing_hd_ctx;
QDict *options;
QDict *tmp_parent_options = NULL;
Error *local_err = NULL;
@@ -3582,8 +3612,12 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
/* Hook up the backing file link; drop our reference, bs owns the
* backing_hd reference now */
+ backing_hd_ctx = bdrv_get_aio_context(backing_hd);
+ aio_context_acquire(backing_hd_ctx);
ret = bdrv_set_backing_hd(bs, backing_hd, errp);
bdrv_unref(backing_hd);
+ aio_context_release(backing_hd_ctx);
+
if (ret < 0) {
goto free_exit;
}
@@ -3654,6 +3688,7 @@ done:
*
* The BlockdevRef will be removed from the options QDict.
*
+ * The caller must hold the lock of the main AioContext and no other AioContext.
* @parent can move to a different AioContext in this function. Callers must
* make sure that their AioContext locking is still correct after this.
*/
@@ -3665,6 +3700,8 @@ BdrvChild *bdrv_open_child(const char *filename,
bool allow_none, Error **errp)
{
BlockDriverState *bs;
+ BdrvChild *child;
+ AioContext *ctx;
GLOBAL_STATE_CODE();
@@ -3674,13 +3711,19 @@ BdrvChild *bdrv_open_child(const char *filename,
return NULL;
}
- return bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
- errp);
+ ctx = bdrv_get_aio_context(bs);
+ aio_context_acquire(ctx);
+ child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
+ errp);
+ aio_context_release(ctx);
+
+ return child;
}
/*
* Wrapper on bdrv_open_child() for most popular case: open primary child of bs.
*
+ * The caller must hold the lock of the main AioContext and no other AioContext.
* @parent can move to a different AioContext in this function. Callers must
* make sure that their AioContext locking is still correct after this.
*/
@@ -3757,6 +3800,7 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
int64_t total_size;
QemuOpts *opts = NULL;
BlockDriverState *bs_snapshot = NULL;
+ AioContext *ctx = bdrv_get_aio_context(bs);
int ret;
GLOBAL_STATE_CODE();
@@ -3765,7 +3809,10 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
instead of opening 'filename' directly */
/* Get the required size from the image */
+ aio_context_acquire(ctx);
total_size = bdrv_getlength(bs);
+ aio_context_release(ctx);
+
if (total_size < 0) {
error_setg_errno(errp, -total_size, "Could not get image size");
goto out;
@@ -3799,7 +3846,10 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
goto out;
}
+ aio_context_acquire(ctx);
ret = bdrv_append(bs_snapshot, bs, errp);
+ aio_context_release(ctx);
+
if (ret < 0) {
bs_snapshot = NULL;
goto out;
@@ -3843,6 +3893,7 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
Error *local_err = NULL;
QDict *snapshot_options = NULL;
int snapshot_flags = 0;
+ AioContext *ctx = qemu_get_aio_context();
assert(!child_class || !flags);
assert(!child_class == !parent);
@@ -3980,9 +4031,13 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
/* Not requesting BLK_PERM_CONSISTENT_READ because we're only
* looking at the header to guess the image format. This works even
* in cases where a guest would not see a consistent state. */
- file = blk_new(bdrv_get_aio_context(file_bs), 0, BLK_PERM_ALL);
+ ctx = bdrv_get_aio_context(file_bs);
+ aio_context_acquire(ctx);
+ file = blk_new(ctx, 0, BLK_PERM_ALL);
blk_insert_bs(file, file_bs, &local_err);
bdrv_unref(file_bs);
+ aio_context_release(ctx);
+
if (local_err) {
goto fail;
}
@@ -4028,8 +4083,13 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
goto fail;
}
+ /* The AioContext could have changed during bdrv_open_common() */
+ ctx = bdrv_get_aio_context(bs);
+
if (file) {
+ aio_context_acquire(ctx);
blk_unref(file);
+ aio_context_release(ctx);
file = NULL;
}
@@ -4087,13 +4147,16 @@ bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
* (snapshot_bs); thus, we have to drop the strong reference to bs
* (which we obtained by calling bdrv_new()). bs will not be deleted,
* though, because the overlay still has a reference to it. */
+ aio_context_acquire(ctx);
bdrv_unref(bs);
+ aio_context_release(ctx);
bs = snapshot_bs;
}
return bs;
fail:
+ aio_context_acquire(ctx);
blk_unref(file);
qobject_unref(snapshot_options);
qobject_unref(bs->explicit_options);
@@ -4102,11 +4165,14 @@ fail:
bs->options = NULL;
bs->explicit_options = NULL;
bdrv_unref(bs);
+ aio_context_release(ctx);
error_propagate(errp, local_err);
return NULL;
close_and_fail:
+ aio_context_acquire(ctx);
bdrv_unref(bs);
+ aio_context_release(ctx);
qobject_unref(snapshot_options);
qobject_unref(options);
error_propagate(errp, local_err);
@@ -4578,6 +4644,11 @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
* backing BlockDriverState (or NULL).
*
* Return 0 on success, otherwise return < 0 and set @errp.
+ *
+ * The caller must hold the AioContext lock of @reopen_state->bs.
+ * @reopen_state->bs can move to a different AioContext in this function.
+ * Callers must make sure that their AioContext locking is still correct after
+ * this.
*/
static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
bool is_backing, Transaction *tran,
@@ -4590,6 +4661,8 @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
const char *child_name = is_backing ? "backing" : "file";
QObject *value;
const char *str;
+ AioContext *ctx, *old_ctx;
+ int ret;
GLOBAL_STATE_CODE();
@@ -4654,8 +4727,22 @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
reopen_state->old_file_bs = old_child_bs;
}
- return bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
- tran, errp);
+ old_ctx = bdrv_get_aio_context(bs);
+ ctx = bdrv_get_aio_context(new_child_bs);
+ if (old_ctx != ctx) {
+ aio_context_release(old_ctx);
+ aio_context_acquire(ctx);
+ }
+
+ ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
+ tran, errp);
+
+ if (old_ctx != ctx) {
+ aio_context_release(ctx);
+ aio_context_acquire(old_ctx);
+ }
+
+ return ret;
}
/*
@@ -4674,6 +4761,7 @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
* It is the responsibility of the caller to then call the abort() or
* commit() for any other BDS that have been left in a prepare() state
*
+ * The caller must hold the AioContext lock of @reopen_state->bs.
*/
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
BlockReopenQueue *queue,
diff --git a/block/bochs.c b/block/bochs.c
index 2f5ae52c90..66e7a58e5e 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -203,7 +203,8 @@ static void bochs_refresh_limits(BlockDriverState *bs, Error **errp)
bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
}
-static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
+static int64_t coroutine_fn GRAPH_RDLOCK
+seek_to_sector(BlockDriverState *bs, int64_t sector_num)
{
BDRVBochsState *s = bs->opaque;
uint64_t offset = sector_num * 512;
@@ -224,8 +225,8 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
(s->extent_blocks + s->bitmap_blocks));
/* read in bitmap for current extent */
- ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8), 1,
- &bitmap_entry, 0);
+ ret = bdrv_co_pread(bs->file, bitmap_offset + (extent_offset / 8), 1,
+ &bitmap_entry, 0);
if (ret < 0) {
return ret;
}
diff --git a/block/cloop.c b/block/cloop.c
index 1e5a52d6b2..835a0fe3da 100644
--- a/block/cloop.c
+++ b/block/cloop.c
@@ -212,7 +212,8 @@ static void cloop_refresh_limits(BlockDriverState *bs, Error **errp)
bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
}
-static inline int cloop_read_block(BlockDriverState *bs, int block_num)
+static int coroutine_fn GRAPH_RDLOCK
+cloop_read_block(BlockDriverState *bs, int block_num)
{
BDRVCloopState *s = bs->opaque;
@@ -220,8 +221,8 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num)
int ret;
uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
- ret = bdrv_pread(bs->file, s->offsets[block_num], bytes,
- s->compressed_block, 0);
+ ret = bdrv_co_pread(bs->file, s->offsets[block_num], bytes,
+ s->compressed_block, 0);
if (ret < 0) {
return -1;
}
@@ -244,7 +245,7 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num)
return 0;
}
-static int coroutine_fn
+static int coroutine_fn GRAPH_RDLOCK
cloop_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags)
{
diff --git a/block/dmg.c b/block/dmg.c
index 2769900359..06a0244a9c 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -616,7 +616,8 @@ err:
return s->n_chunks; /* error */
}
-static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
+static int coroutine_fn GRAPH_RDLOCK
+dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
{
BDRVDMGState *s = bs->opaque;
@@ -633,8 +634,8 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
case UDZO: { /* zlib compressed */
/* we need to buffer, because only the chunk as whole can be
* inflated. */
- ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
- s->compressed_chunk, 0);
+ ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
+ s->compressed_chunk, 0);
if (ret < 0) {
return -1;
}
@@ -659,8 +660,8 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
}
/* we need to buffer, because only the chunk as whole can be
* inflated. */
- ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
- s->compressed_chunk, 0);
+ ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
+ s->compressed_chunk, 0);
if (ret < 0) {
return -1;
}
@@ -680,8 +681,8 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
}
/* we need to buffer, because only the chunk as whole can be
* inflated. */
- ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
- s->compressed_chunk, 0);
+ ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
+ s->compressed_chunk, 0);
if (ret < 0) {
return -1;
}
@@ -696,8 +697,8 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
}
break;
case UDRW: /* copy */
- ret = bdrv_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
- s->uncompressed_chunk, 0);
+ ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk],
+ s->uncompressed_chunk, 0);
if (ret < 0) {
return -1;
}
@@ -713,7 +714,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
return 0;
}
-static int coroutine_fn
+static int coroutine_fn GRAPH_RDLOCK
dmg_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags)
{
diff --git a/block/file-posix.c b/block/file-posix.c
index ac1ed54811..9e8e3d8ca5 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -193,7 +193,7 @@ static int fd_open(BlockDriverState *bs)
return -EIO;
}
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs);
+static int64_t raw_getlength(BlockDriverState *bs);
typedef struct RawPosixAIOData {
BlockDriverState *bs;
@@ -1974,7 +1974,7 @@ static int handle_aiocb_write_zeroes(void *opaque)
#ifdef CONFIG_FALLOCATE
/* Last resort: we are trying to extend the file with zeroed data. This
* can be done via fallocate(fd, 0) */
- len = raw_co_getlength(aiocb->bs);
+ len = raw_getlength(aiocb->bs);
if (s->has_fallocate && len >= 0 && aiocb->aio_offset >= len) {
int ret = do_fallocate(s->fd, 0, aiocb->aio_offset, aiocb->aio_nbytes);
if (ret == 0 || ret != -ENOTSUP) {
@@ -2666,7 +2666,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
}
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
- int64_t cur_length = raw_co_getlength(bs);
+ int64_t cur_length = raw_getlength(bs);
if (offset != cur_length && exact) {
error_setg(errp, "Cannot resize device files");
@@ -2684,7 +2684,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
}
#ifdef __OpenBSD__
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
+static int64_t raw_getlength(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
int fd = s->fd;
@@ -2703,7 +2703,7 @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
return st.st_size;
}
#elif defined(__NetBSD__)
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
+static int64_t raw_getlength(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
int fd = s->fd;
@@ -2728,7 +2728,7 @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
return st.st_size;
}
#elif defined(__sun__)
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
+static int64_t raw_getlength(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
struct dk_minfo minfo;
@@ -2759,7 +2759,7 @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
return size;
}
#elif defined(CONFIG_BSD)
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
+static int64_t raw_getlength(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
int fd = s->fd;
@@ -2831,7 +2831,7 @@ again:
return size;
}
#else
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
+static int64_t raw_getlength(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
int ret;
@@ -2850,6 +2850,11 @@ static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
}
#endif
+static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
+{
+ return raw_getlength(bs);
+}
+
static int64_t coroutine_fn raw_co_get_allocated_file_size(BlockDriverState *bs)
{
struct stat st;
@@ -3215,7 +3220,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
* round up if necessary.
*/
if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
- int64_t file_length = raw_co_getlength(bs);
+ int64_t file_length = raw_getlength(bs);
if (file_length > 0) {
/* Ignore errors, this is just a safeguard */
assert(hole == file_length);
@@ -3237,7 +3242,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
#if defined(__linux__)
/* Verify that the file is not in the page cache */
-static void coroutine_fn check_cache_dropped(BlockDriverState *bs, Error **errp)
+static void check_cache_dropped(BlockDriverState *bs, Error **errp)
{
const size_t window_size = 128 * 1024 * 1024;
BDRVRawState *s = bs->opaque;
@@ -3252,7 +3257,7 @@ static void coroutine_fn check_cache_dropped(BlockDriverState *bs, Error **errp)
page_size = sysconf(_SC_PAGESIZE);
vec = g_malloc(DIV_ROUND_UP(window_size, page_size));
- end = raw_co_getlength(bs);
+ end = raw_getlength(bs);
for (offset = 0; offset < end; offset += window_size) {
void *new_window;
@@ -4468,7 +4473,7 @@ static int cdrom_reopen(BlockDriverState *bs)
static bool coroutine_fn cdrom_co_is_inserted(BlockDriverState *bs)
{
- return raw_co_getlength(bs) > 0;
+ return raw_getlength(bs) > 0;
}
static void coroutine_fn cdrom_co_eject(BlockDriverState *bs, bool eject_flag)
diff --git a/block/graph-lock.c b/block/graph-lock.c
index a92c6ae219..5e66f01ae8 100644
--- a/block/graph-lock.c
+++ b/block/graph-lock.c
@@ -30,10 +30,8 @@ BdrvGraphLock graph_lock;
/* Protects the list of aiocontext and orphaned_reader_count */
static QemuMutex aio_context_list_lock;
-#if 0
/* Written and read with atomic operations. */
static int has_writer;
-#endif
/*
* A reader coroutine could move from an AioContext to another.
@@ -90,7 +88,6 @@ void unregister_aiocontext(AioContext *ctx)
g_free(ctx->bdrv_graph);
}
-#if 0
static uint32_t reader_count(void)
{
BdrvGraphRWlock *brdv_graph;
@@ -108,18 +105,26 @@ static uint32_t reader_count(void)
assert((int32_t)rd >= 0);
return rd;
}
-#endif
-void bdrv_graph_wrlock(void)
+void bdrv_graph_wrlock(BlockDriverState *bs)
{
+ AioContext *ctx = NULL;
+
GLOBAL_STATE_CODE();
+ assert(!qatomic_read(&has_writer));
+
/*
- * TODO Some callers hold an AioContext lock when this is called, which
- * causes deadlocks. Reenable once the AioContext locking is cleaned up (or
- * AioContext locks are gone).
+ * Release only non-mainloop AioContext. The mainloop often relies on the
+ * BQL and doesn't lock the main AioContext before doing things.
*/
-#if 0
- assert(!qatomic_read(&has_writer));
+ if (bs) {
+ ctx = bdrv_get_aio_context(bs);
+ if (ctx != qemu_get_aio_context()) {
+ aio_context_release(ctx);
+ } else {
+ ctx = NULL;
+ }
+ }
/* Make sure that constantly arriving new I/O doesn't cause starvation */
bdrv_drain_all_begin_nopoll();
@@ -149,13 +154,15 @@ void bdrv_graph_wrlock(void)
} while (reader_count() >= 1);
bdrv_drain_all_end();
-#endif
+
+ if (ctx) {
+ aio_context_acquire(bdrv_get_aio_context(bs));
+ }
}
void bdrv_graph_wrunlock(void)
{
GLOBAL_STATE_CODE();
-#if 0
QEMU_LOCK_GUARD(&aio_context_list_lock);
assert(qatomic_read(&has_writer));
@@ -167,13 +174,10 @@ void bdrv_graph_wrunlock(void)
/* Wake up all coroutine that are waiting to read the graph */
qemu_co_enter_all(&reader_queue, &aio_context_list_lock);
-#endif
}
void coroutine_fn bdrv_graph_co_rdlock(void)
{
- /* TODO Reenable when wrlock is reenabled */
-#if 0
BdrvGraphRWlock *bdrv_graph;
bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
@@ -233,12 +237,10 @@ void coroutine_fn bdrv_graph_co_rdlock(void)
qemu_co_queue_wait(&reader_queue, &aio_context_list_lock);
}
}
-#endif
}
void coroutine_fn bdrv_graph_co_rdunlock(void)
{
-#if 0
BdrvGraphRWlock *bdrv_graph;
bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
@@ -256,7 +258,6 @@ void coroutine_fn bdrv_graph_co_rdunlock(void)
if (qatomic_read(&has_writer)) {
aio_wait_kick();
}
-#endif
}
void bdrv_graph_rdlock_main_loop(void)
@@ -274,19 +275,13 @@ void bdrv_graph_rdunlock_main_loop(void)
void assert_bdrv_graph_readable(void)
{
/* reader_count() is slow due to aio_context_list_lock lock contention */
- /* TODO Reenable when wrlock is reenabled */
-#if 0
#ifdef CONFIG_DEBUG_GRAPH_LOCK
assert(qemu_in_main_thread() || reader_count());
#endif
-#endif
}
void assert_bdrv_graph_writable(void)
{
assert(qemu_in_main_thread());
- /* TODO Reenable when wrlock is reenabled */
-#if 0
assert(qatomic_read(&has_writer));
-#endif
}
diff --git a/block/io.c b/block/io.c
index 30748f0b59..e8293d6b26 100644
--- a/block/io.c
+++ b/block/io.c
@@ -1379,7 +1379,7 @@ bdrv_aligned_preadv(BdrvChild *child, BdrvTrackedRequest *req,
}
/* Forward the request to the BlockDriver, possibly fragmenting it */
- total_bytes = bdrv_getlength(bs);
+ total_bytes = bdrv_co_getlength(bs);
if (total_bytes < 0) {
ret = total_bytes;
goto out;
@@ -2388,7 +2388,7 @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
assert(pnum);
assert_bdrv_graph_readable();
*pnum = 0;
- total_size = bdrv_getlength(bs);
+ total_size = bdrv_co_getlength(bs);
if (total_size < 0) {
ret = total_size;
goto early_out;
@@ -2408,7 +2408,7 @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
bytes = n;
}
- /* Must be non-NULL or bdrv_getlength() would have failed */
+ /* Must be non-NULL or bdrv_co_getlength() would have failed */
assert(bs->drv);
has_filtered_child = bdrv_filter_child(bs);
if (!bs->drv->bdrv_co_block_status && !has_filtered_child) {
@@ -2546,7 +2546,7 @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
if (!cow_bs) {
ret |= BDRV_BLOCK_ZERO;
} else if (want_zero) {
- int64_t size2 = bdrv_getlength(cow_bs);
+ int64_t size2 = bdrv_co_getlength(cow_bs);
if (size2 >= 0 && offset >= size2) {
ret |= BDRV_BLOCK_ZERO;
@@ -3011,7 +3011,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
}
/* Write back cached data to the OS even with cache=unsafe */
- BLKDBG_EVENT(primary_child, BLKDBG_FLUSH_TO_OS);
+ BLKDBG_CO_EVENT(primary_child, BLKDBG_FLUSH_TO_OS);
if (bs->drv->bdrv_co_flush_to_os) {
ret = bs->drv->bdrv_co_flush_to_os(bs);
if (ret < 0) {
@@ -3029,7 +3029,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
goto flush_children;
}
- BLKDBG_EVENT(primary_child, BLKDBG_FLUSH_TO_DISK);
+ BLKDBG_CO_EVENT(primary_child, BLKDBG_FLUSH_TO_DISK);
if (!bs->drv) {
/* bs->drv->bdrv_co_flush() might have ejected the BDS
* (even in case of apparent success) */
@@ -3592,7 +3592,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
return ret;
}
- old_size = bdrv_getlength(bs);
+ old_size = bdrv_co_getlength(bs);
if (old_size < 0) {
error_setg_errno(errp, -old_size, "Failed to get old image size");
return old_size;
diff --git a/block/parallels.c b/block/parallels.c
index 7c263d5085..18e34aef28 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -200,7 +200,7 @@ allocate_clusters(BlockDriverState *bs, int64_t sector_num,
assert(idx < s->bat_size && idx + to_allocate <= s->bat_size);
space = to_allocate * s->tracks;
- len = bdrv_getlength(bs->file->bs);
+ len = bdrv_co_getlength(bs->file->bs);
if (len < 0) {
return len;
}
@@ -448,7 +448,7 @@ parallels_check_outside_image(BlockDriverState *bs, BdrvCheckResult *res,
uint32_t i;
int64_t off, high_off, size;
- size = bdrv_getlength(bs->file->bs);
+ size = bdrv_co_getlength(bs->file->bs);
if (size < 0) {
res->check_errors++;
return size;
diff --git a/block/qcow.c b/block/qcow.c
index 3644bbf5cb..577bd70324 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -370,7 +370,7 @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
if (!allocate)
return 0;
/* allocate a new l2 entry */
- l2_offset = bdrv_getlength(bs->file->bs);
+ l2_offset = bdrv_co_getlength(bs->file->bs);
if (l2_offset < 0) {
return l2_offset;
}
@@ -379,7 +379,7 @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
/* update the L1 entry */
s->l1_table[l1_index] = l2_offset;
tmp = cpu_to_be64(l2_offset);
- BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L1_UPDATE);
ret = bdrv_co_pwrite_sync(bs->file,
s->l1_table_offset + l1_index * sizeof(tmp),
sizeof(tmp), &tmp, 0);
@@ -410,7 +410,7 @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
}
}
l2_table = s->l2_cache + (min_index << s->l2_bits);
- BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L2_LOAD);
if (new_l2_table) {
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
ret = bdrv_co_pwrite_sync(bs->file, l2_offset,
@@ -434,7 +434,7 @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
if (!allocate)
return 0;
- BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
assert(QEMU_IS_ALIGNED(n_start | n_end, BDRV_SECTOR_SIZE));
/* allocate a new cluster */
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
@@ -445,20 +445,20 @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
if (decompress_cluster(bs, cluster_offset) < 0) {
return -EIO;
}
- cluster_offset = bdrv_getlength(bs->file->bs);
+ cluster_offset = bdrv_co_getlength(bs->file->bs);
if ((int64_t) cluster_offset < 0) {
return cluster_offset;
}
cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
/* write the cluster content */
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = bdrv_co_pwrite(bs->file, cluster_offset, s->cluster_size,
s->cluster_cache, 0);
if (ret < 0) {
return ret;
}
} else {
- cluster_offset = bdrv_getlength(bs->file->bs);
+ cluster_offset = bdrv_co_getlength(bs->file->bs);
if ((int64_t) cluster_offset < 0) {
return cluster_offset;
}
@@ -491,7 +491,7 @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
NULL) < 0) {
return -EIO;
}
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = bdrv_co_pwrite(bs->file, cluster_offset + i,
BDRV_SECTOR_SIZE,
s->cluster_data, 0);
@@ -510,9 +510,9 @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
tmp = cpu_to_be64(cluster_offset);
l2_table[l2_index] = tmp;
if (allocate == 2) {
- BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
} else {
- BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L2_UPDATE);
}
ret = bdrv_co_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
sizeof(tmp), &tmp, 0);
@@ -595,7 +595,7 @@ decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
if (s->cluster_cache_offset != coffset) {
csize = cluster_offset >> (63 - s->cluster_bits);
csize &= (s->cluster_size - 1);
- BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_co_pread(bs->file, coffset, csize, s->cluster_data, 0);
if (ret < 0)
return -1;
@@ -657,7 +657,7 @@ qcow_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
/* read from the base image */
qemu_co_mutex_unlock(&s->lock);
/* qcow2 emits this on bs->file instead of bs->backing */
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
ret = bdrv_co_pread(bs->backing, offset, n, buf, 0);
qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
@@ -680,7 +680,7 @@ qcow_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
break;
}
qemu_co_mutex_unlock(&s->lock);
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
ret = bdrv_co_pread(bs->file, cluster_offset + offset_in_cluster,
n, buf, 0);
qemu_co_mutex_lock(&s->lock);
@@ -765,7 +765,7 @@ qcow_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
}
qemu_co_mutex_unlock(&s->lock);
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = bdrv_co_pwrite(bs->file, cluster_offset + offset_in_cluster,
n, buf, 0);
qemu_co_mutex_lock(&s->lock);
@@ -1114,7 +1114,7 @@ qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
}
cluster_offset &= s->cluster_offset_mask;
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
ret = bdrv_co_pwrite(bs->file, cluster_offset, out_len, out_buf, 0);
if (ret < 0) {
goto fail;
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index a952fd58d8..037fa2d435 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -283,10 +283,9 @@ static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
/* load_bitmap_data
* @bitmap_table entries must satisfy specification constraints.
* @bitmap must be cleared */
-static int load_bitmap_data(BlockDriverState *bs,
- const uint64_t *bitmap_table,
- uint32_t bitmap_table_size,
- BdrvDirtyBitmap *bitmap)
+static int coroutine_fn GRAPH_RDLOCK
+load_bitmap_data(BlockDriverState *bs, const uint64_t *bitmap_table,
+ uint32_t bitmap_table_size, BdrvDirtyBitmap *bitmap)
{
int ret = 0;
BDRVQcow2State *s = bs->opaque;
@@ -319,7 +318,7 @@ static int load_bitmap_data(BlockDriverState *bs,
* already cleared */
}
} else {
- ret = bdrv_pread(bs->file, data_offset, s->cluster_size, buf, 0);
+ ret = bdrv_co_pread(bs->file, data_offset, s->cluster_size, buf, 0);
if (ret < 0) {
goto finish;
}
@@ -337,8 +336,9 @@ finish:
return ret;
}
-static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
- Qcow2Bitmap *bm, Error **errp)
+static coroutine_fn GRAPH_RDLOCK
+BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
+ Qcow2Bitmap *bm, Error **errp)
{
int ret;
uint64_t *bitmap_table = NULL;
@@ -649,9 +649,10 @@ fail:
return NULL;
}
-int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
- void **refcount_table,
- int64_t *refcount_table_size)
+int coroutine_fn
+qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size)
{
int ret;
BDRVQcow2State *s = bs->opaque;
@@ -957,8 +958,9 @@ static void set_readonly_helper(gpointer bitmap, gpointer value)
* If header_updated is not NULL then it is set appropriately regardless of
* the return value.
*/
-bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs,
- bool *header_updated, Error **errp)
+bool coroutine_fn GRAPH_RDLOCK
+qcow2_load_dirty_bitmaps(BlockDriverState *bs,
+ bool *header_updated, Error **errp)
{
BDRVQcow2State *s = bs->opaque;
Qcow2BitmapList *bm_list;
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 2e76de027c..f4f6cd6ad0 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -48,7 +48,7 @@ int coroutine_fn qcow2_shrink_l1_table(BlockDriverState *bs,
fprintf(stderr, "shrink l1_table from %d to %d\n", s->l1_size, new_l1_size);
#endif
- BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE);
ret = bdrv_co_pwrite_zeroes(bs->file,
s->l1_table_offset + new_l1_size * L1E_SIZE,
(s->l1_size - new_l1_size) * L1E_SIZE, 0);
@@ -61,7 +61,7 @@ int coroutine_fn qcow2_shrink_l1_table(BlockDriverState *bs,
goto fail;
}
- BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_FREE_L2_CLUSTERS);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L1_SHRINK_FREE_L2_CLUSTERS);
for (i = s->l1_size - 1; i > new_l1_size - 1; i--) {
if ((s->l1_table[i] & L1E_OFFSET_MASK) == 0) {
continue;
@@ -501,7 +501,7 @@ do_perform_cow_read(BlockDriverState *bs, uint64_t src_cluster_offset,
return 0;
}
- BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_COW_READ);
if (!bs->drv) {
return -ENOMEDIUM;
@@ -551,7 +551,7 @@ do_perform_cow_write(BlockDriverState *bs, uint64_t cluster_offset,
return ret;
}
- BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_COW_WRITE);
ret = bdrv_co_pwritev(s->data_file, cluster_offset + offset_in_cluster,
qiov->size, qiov, 0);
if (ret < 0) {
@@ -823,10 +823,9 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
*
* Return 0 on success and -errno in error cases
*/
-int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
- uint64_t offset,
- int compressed_size,
- uint64_t *host_offset)
+int coroutine_fn GRAPH_RDLOCK
+qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset,
+ int compressed_size, uint64_t *host_offset)
{
BDRVQcow2State *s = bs->opaque;
int l2_index, ret;
@@ -872,7 +871,7 @@ int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
/* compressed clusters never have the copied flag */
- BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
set_l2_entry(s, l2_slice, l2_index, cluster_offset);
if (has_subclusters(s)) {
@@ -992,7 +991,7 @@ perform_cow(BlockDriverState *bs, QCowL2Meta *m)
/* NOTE: we have a write_aio blkdebug event here followed by
* a cow_write one in do_perform_cow_write(), but there's only
* one single I/O operation */
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
} else {
/* If there's no guest data then write both COW regions separately */
@@ -2038,8 +2037,9 @@ fail:
* all clusters in the same L2 slice) and returns the number of zeroed
* clusters.
*/
-static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
- uint64_t nb_clusters, int flags)
+static int coroutine_fn
+zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
+ uint64_t nb_clusters, int flags)
{
BDRVQcow2State *s = bs->opaque;
uint64_t *l2_slice;
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 4cf91bd955..5095e99a37 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -118,7 +118,7 @@ int coroutine_fn qcow2_refcount_init(BlockDriverState *bs)
ret = -ENOMEM;
goto fail;
}
- BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
ret = bdrv_co_pread(bs->file, s->refcount_table_offset,
refcount_table_size2, s->refcount_table, 0);
if (ret < 0) {
@@ -1069,14 +1069,14 @@ int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offs
/* only used to allocate compressed sectors. We try to allocate
contiguous sectors. size must be <= cluster_size */
-int64_t coroutine_fn qcow2_alloc_bytes(BlockDriverState *bs, int size)
+int64_t coroutine_fn GRAPH_RDLOCK qcow2_alloc_bytes(BlockDriverState *bs, int size)
{
BDRVQcow2State *s = bs->opaque;
int64_t offset;
size_t free_in_cluster;
int ret;
- BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_BYTES);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_BYTES);
assert(size > 0 && size <= s->cluster_size);
assert(!s->free_byte_offset || offset_into_cluster(s, s->free_byte_offset));
@@ -1524,10 +1524,11 @@ static int realloc_refcount_array(BDRVQcow2State *s, void **array,
*
* Modifies the number of errors in res.
*/
-int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
- void **refcount_table,
- int64_t *refcount_table_size,
- int64_t offset, int64_t size)
+int coroutine_fn GRAPH_RDLOCK
+qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size,
+ int64_t offset, int64_t size)
{
BDRVQcow2State *s = bs->opaque;
uint64_t start, last, cluster_offset, k, refcount;
@@ -1538,7 +1539,7 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
return 0;
}
- file_len = bdrv_getlength(bs->file->bs);
+ file_len = bdrv_co_getlength(bs->file->bs);
if (file_len < 0) {
return file_len;
}
@@ -1600,10 +1601,11 @@ enum {
*
* On failure in-memory @l2_table may be modified.
*/
-static int fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
- uint64_t l2_offset,
- uint64_t *l2_table, int l2_index, bool active,
- bool *metadata_overlap)
+static int coroutine_fn GRAPH_RDLOCK
+fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
+ uint64_t l2_offset, uint64_t *l2_table,
+ int l2_index, bool active,
+ bool *metadata_overlap)
{
BDRVQcow2State *s = bs->opaque;
int ret;
@@ -1634,8 +1636,8 @@ static int fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
goto fail;
}
- ret = bdrv_pwrite_sync(bs->file, l2e_offset, l2_entry_size(s),
- &l2_table[idx], 0);
+ ret = bdrv_co_pwrite_sync(bs->file, l2e_offset, l2_entry_size(s),
+ &l2_table[idx], 0);
if (ret < 0) {
fprintf(stderr, "ERROR: Failed to overwrite L2 "
"table entry: %s\n", strerror(-ret));
@@ -1659,10 +1661,11 @@ fail:
* Returns the number of errors found by the checks or -errno if an internal
* error occurred.
*/
-static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
- void **refcount_table,
- int64_t *refcount_table_size, int64_t l2_offset,
- int flags, BdrvCheckMode fix, bool active)
+static int coroutine_fn GRAPH_RDLOCK
+check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size, int64_t l2_offset,
+ int flags, BdrvCheckMode fix, bool active)
{
BDRVQcow2State *s = bs->opaque;
uint64_t l2_entry, l2_bitmap;
@@ -1673,7 +1676,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
bool metadata_overlap;
/* Read L2 table from disk */
- ret = bdrv_pread(bs->file, l2_offset, l2_size_bytes, l2_table, 0);
+ ret = bdrv_co_pread(bs->file, l2_offset, l2_size_bytes, l2_table, 0);
if (ret < 0) {
fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
res->check_errors++;
@@ -1858,12 +1861,11 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
* Returns the number of errors found by the checks or -errno if an internal
* error occurred.
*/
-static int check_refcounts_l1(BlockDriverState *bs,
- BdrvCheckResult *res,
- void **refcount_table,
- int64_t *refcount_table_size,
- int64_t l1_table_offset, int l1_size,
- int flags, BdrvCheckMode fix, bool active)
+static int coroutine_fn GRAPH_RDLOCK
+check_refcounts_l1(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table, int64_t *refcount_table_size,
+ int64_t l1_table_offset, int l1_size,
+ int flags, BdrvCheckMode fix, bool active)
{
BDRVQcow2State *s = bs->opaque;
size_t l1_size_bytes = l1_size * L1E_SIZE;
@@ -1889,7 +1891,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
}
/* Read L1 table entries from disk */
- ret = bdrv_pread(bs->file, l1_table_offset, l1_size_bytes, l1_table, 0);
+ ret = bdrv_co_pread(bs->file, l1_table_offset, l1_size_bytes, l1_table, 0);
if (ret < 0) {
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
res->check_errors++;
@@ -1949,8 +1951,8 @@ static int check_refcounts_l1(BlockDriverState *bs,
* have been already detected and sufficiently signaled by the calling function
* (qcow2_check_refcounts) by the time this function is called).
*/
-static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
- BdrvCheckMode fix)
+static int coroutine_fn GRAPH_RDLOCK
+check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
{
BDRVQcow2State *s = bs->opaque;
uint64_t *l2_table = qemu_blockalign(bs, s->cluster_size);
@@ -2005,8 +2007,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
}
}
- ret = bdrv_pread(bs->file, l2_offset, s->l2_size * l2_entry_size(s),
- l2_table, 0);
+ ret = bdrv_co_pread(bs->file, l2_offset, s->l2_size * l2_entry_size(s),
+ l2_table, 0);
if (ret < 0) {
fprintf(stderr, "ERROR: Could not read L2 table: %s\n",
strerror(-ret));
@@ -2059,8 +2061,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
goto fail;
}
- ret = bdrv_pwrite(bs->file, l2_offset, s->cluster_size, l2_table,
- 0);
+ ret = bdrv_co_pwrite(bs->file, l2_offset, s->cluster_size, l2_table, 0);
if (ret < 0) {
fprintf(stderr, "ERROR: Could not write L2 table: %s\n",
strerror(-ret));
@@ -2083,9 +2084,10 @@ fail:
* Checks consistency of refblocks and accounts for each refblock in
* *refcount_table.
*/
-static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
- BdrvCheckMode fix, bool *rebuild,
- void **refcount_table, int64_t *nb_clusters)
+static int coroutine_fn GRAPH_RDLOCK
+check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
+ BdrvCheckMode fix, bool *rebuild,
+ void **refcount_table, int64_t *nb_clusters)
{
BDRVQcow2State *s = bs->opaque;
int64_t i, size;
@@ -2127,13 +2129,13 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
goto resize_fail;
}
- ret = bdrv_truncate(bs->file, offset + s->cluster_size, false,
- PREALLOC_MODE_OFF, 0, &local_err);
+ ret = bdrv_co_truncate(bs->file, offset + s->cluster_size, false,
+ PREALLOC_MODE_OFF, 0, &local_err);
if (ret < 0) {
error_report_err(local_err);
goto resize_fail;
}
- size = bdrv_getlength(bs->file->bs);
+ size = bdrv_co_getlength(bs->file->bs);
if (size < 0) {
ret = size;
goto resize_fail;
@@ -2197,9 +2199,10 @@ resize_fail:
/*
* Calculates an in-memory refcount table.
*/
-static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
- BdrvCheckMode fix, bool *rebuild,
- void **refcount_table, int64_t *nb_clusters)
+static int coroutine_fn GRAPH_RDLOCK
+calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
+ BdrvCheckMode fix, bool *rebuild,
+ void **refcount_table, int64_t *nb_clusters)
{
BDRVQcow2State *s = bs->opaque;
int64_t i;
@@ -2299,10 +2302,11 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
* Compares the actual reference count for each cluster in the image against the
* refcount as reported by the refcount structures on-disk.
*/
-static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
- BdrvCheckMode fix, bool *rebuild,
- int64_t *highest_cluster,
- void *refcount_table, int64_t nb_clusters)
+static void coroutine_fn
+compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
+ BdrvCheckMode fix, bool *rebuild,
+ int64_t *highest_cluster,
+ void *refcount_table, int64_t nb_clusters)
{
BDRVQcow2State *s = bs->opaque;
int64_t i;
@@ -2463,7 +2467,8 @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs,
* Return whether the on-disk reftable array was resized (true/false),
* or -errno on error.
*/
-static int rebuild_refcounts_write_refblocks(
+static int coroutine_fn GRAPH_RDLOCK
+rebuild_refcounts_write_refblocks(
BlockDriverState *bs, void **refcount_table, int64_t *nb_clusters,
int64_t first_cluster, int64_t end_cluster,
uint64_t **on_disk_reftable_ptr, uint32_t *on_disk_reftable_entries_ptr,
@@ -2578,8 +2583,8 @@ static int rebuild_refcounts_write_refblocks(
on_disk_refblock = (void *)((char *) *refcount_table +
refblock_index * s->cluster_size);
- ret = bdrv_pwrite(bs->file, refblock_offset, s->cluster_size,
- on_disk_refblock, 0);
+ ret = bdrv_co_pwrite(bs->file, refblock_offset, s->cluster_size,
+ on_disk_refblock, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "ERROR writing refblock");
return ret;
@@ -2601,11 +2606,10 @@ static int rebuild_refcounts_write_refblocks(
* On success, the old refcount structure is leaked (it will be covered by the
* new refcount structure).
*/
-static int rebuild_refcount_structure(BlockDriverState *bs,
- BdrvCheckResult *res,
- void **refcount_table,
- int64_t *nb_clusters,
- Error **errp)
+static int coroutine_fn GRAPH_RDLOCK
+rebuild_refcount_structure(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table, int64_t *nb_clusters,
+ Error **errp)
{
BDRVQcow2State *s = bs->opaque;
int64_t reftable_offset = -1;
@@ -2734,8 +2738,8 @@ static int rebuild_refcount_structure(BlockDriverState *bs,
}
assert(reftable_length < INT_MAX);
- ret = bdrv_pwrite(bs->file, reftable_offset, reftable_length,
- on_disk_reftable, 0);
+ ret = bdrv_co_pwrite(bs->file, reftable_offset, reftable_length,
+ on_disk_reftable, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "ERROR writing reftable");
goto fail;
@@ -2745,10 +2749,10 @@ static int rebuild_refcount_structure(BlockDriverState *bs,
reftable_offset_and_clusters.reftable_offset = cpu_to_be64(reftable_offset);
reftable_offset_and_clusters.reftable_clusters =
cpu_to_be32(reftable_clusters);
- ret = bdrv_pwrite_sync(bs->file,
- offsetof(QCowHeader, refcount_table_offset),
- sizeof(reftable_offset_and_clusters),
- &reftable_offset_and_clusters, 0);
+ ret = bdrv_co_pwrite_sync(bs->file,
+ offsetof(QCowHeader, refcount_table_offset),
+ sizeof(reftable_offset_and_clusters),
+ &reftable_offset_and_clusters, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "ERROR setting reftable");
goto fail;
@@ -2777,8 +2781,8 @@ fail:
* Returns 0 if no errors are found, the number of errors in case the image is
* detected as corrupted, and -errno when an internal error occurred.
*/
-int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
- BdrvCheckMode fix)
+int coroutine_fn GRAPH_RDLOCK
+qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
{
BDRVQcow2State *s = bs->opaque;
BdrvCheckResult pre_compare_res;
@@ -2787,7 +2791,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
bool rebuild = false;
int ret;
- size = bdrv_getlength(bs->file->bs);
+ size = bdrv_co_getlength(bs->file->bs);
if (size < 0) {
res->check_errors++;
return size;
@@ -3541,7 +3545,8 @@ done:
return ret;
}
-static int64_t get_refblock_offset(BlockDriverState *bs, uint64_t offset)
+static int64_t coroutine_fn get_refblock_offset(BlockDriverState *bs,
+ uint64_t offset)
{
BDRVQcow2State *s = bs->opaque;
uint32_t index = offset_to_reftable_index(s, offset);
@@ -3707,7 +3712,8 @@ int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
return -EIO;
}
-int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs)
+int coroutine_fn GRAPH_RDLOCK
+qcow2_detect_metadata_preallocation(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
int64_t i, end_cluster, cluster_count = 0, threshold;
diff --git a/block/qcow2.c b/block/qcow2.c
index e23edd48c2..c51388e99d 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -570,7 +570,7 @@ int qcow2_mark_corrupt(BlockDriverState *bs)
* Marks the image as consistent, i.e., unsets the corrupt bit, and flushes
* before if necessary.
*/
-int qcow2_mark_consistent(BlockDriverState *bs)
+static int coroutine_fn qcow2_mark_consistent(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
@@ -2225,7 +2225,7 @@ qcow2_co_preadv_encrypted(BlockDriverState *bs,
return -ENOMEM;
}
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
ret = bdrv_co_pread(s->data_file, host_offset, bytes, buf, 0);
if (ret < 0) {
goto fail;
@@ -2315,7 +2315,7 @@ qcow2_co_preadv_task(BlockDriverState *bs, QCow2SubclusterType subc_type,
case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
assert(bs->backing); /* otherwise handled in qcow2_co_preadv_part */
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
return bdrv_co_preadv_part(bs->backing, offset, bytes,
qiov, qiov_offset, 0);
@@ -2329,7 +2329,7 @@ qcow2_co_preadv_task(BlockDriverState *bs, QCow2SubclusterType subc_type,
offset, bytes, qiov, qiov_offset);
}
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
return bdrv_co_preadv_part(s->data_file, host_offset,
bytes, qiov, qiov_offset, 0);
@@ -2539,7 +2539,7 @@ handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta)
return ret;
}
- BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_SPACE);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_SPACE);
ret = bdrv_co_pwrite_zeroes(s->data_file, start_offset, nb_bytes,
BDRV_REQ_NO_FALLBACK);
if (ret < 0) {
@@ -2604,7 +2604,7 @@ int qcow2_co_pwritev_task(BlockDriverState *bs, uint64_t host_offset,
* guest data now.
*/
if (!merge_cow(offset, bytes, qiov, qiov_offset, l2meta)) {
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
trace_qcow2_writev_data(qemu_coroutine_self(), host_offset);
ret = bdrv_co_pwritev_part(s->data_file, host_offset,
bytes, qiov, qiov_offset, 0);
@@ -4678,7 +4678,7 @@ qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
goto fail;
}
- BLKDBG_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED);
+ BLKDBG_CO_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED);
ret = bdrv_co_pwrite(s->data_file, cluster_offset, out_len, out_buf, 0);
if (ret < 0) {
goto fail;
@@ -4797,7 +4797,7 @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
out_buf = qemu_blockalign(bs, s->cluster_size);
- BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_co_pread(bs->file, coffset, csize, buf, 0);
if (ret < 0) {
goto fail;
@@ -5344,7 +5344,7 @@ qcow2_co_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
return offset;
}
- BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0);
}
@@ -5356,7 +5356,7 @@ qcow2_co_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
return offset;
}
- BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
}
diff --git a/block/qcow2.h b/block/qcow2.h
index ea9adb5706..f789ce3ae0 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -836,7 +836,6 @@ int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
int qcow2_mark_dirty(BlockDriverState *bs);
int qcow2_mark_corrupt(BlockDriverState *bs);
-int qcow2_mark_consistent(BlockDriverState *bs);
int qcow2_update_header(BlockDriverState *bs);
void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
@@ -867,7 +866,7 @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t offset,
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
int64_t nb_clusters);
-int64_t coroutine_fn qcow2_alloc_bytes(BlockDriverState *bs, int size);
+int64_t coroutine_fn GRAPH_RDLOCK qcow2_alloc_bytes(BlockDriverState *bs, int size);
void qcow2_free_clusters(BlockDriverState *bs,
int64_t offset, int64_t size,
enum qcow2_discard_type type);
@@ -879,8 +878,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
int qcow2_flush_caches(BlockDriverState *bs);
int qcow2_write_caches(BlockDriverState *bs);
-int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
- BdrvCheckMode fix);
+int coroutine_fn qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
+ BdrvCheckMode fix);
void qcow2_process_discards(BlockDriverState *bs, int ret);
@@ -888,10 +887,10 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
int64_t size);
int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
int64_t size, bool data_file);
-int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
- void **refcount_table,
- int64_t *refcount_table_size,
- int64_t offset, int64_t size);
+int coroutine_fn qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size,
+ int64_t offset, int64_t size);
int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
BlockDriverAmendStatusCB *status_cb,
@@ -919,10 +918,9 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes,
uint64_t *host_offset, QCowL2Meta **m);
-int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
- uint64_t offset,
- int compressed_size,
- uint64_t *host_offset);
+int coroutine_fn GRAPH_RDLOCK
+qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset,
+ int compressed_size, uint64_t *host_offset);
void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
uint64_t *coffset, int *csize);
@@ -992,11 +990,12 @@ void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset);
void qcow2_cache_discard(Qcow2Cache *c, void *table);
/* qcow2-bitmap.c functions */
-int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
- void **refcount_table,
- int64_t *refcount_table_size);
-bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs,
- bool *header_updated, Error **errp);
+int coroutine_fn
+qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size);
+bool coroutine_fn GRAPH_RDLOCK
+qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, Error **errp);
bool qcow2_get_bitmap_info_list(BlockDriverState *bs,
Qcow2BitmapInfoList **info_list, Error **errp);
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
diff --git a/block/qed-check.c b/block/qed-check.c
index 8fd94f405e..6a01b94f9c 100644
--- a/block/qed-check.c
+++ b/block/qed-check.c
@@ -200,7 +200,8 @@ static void qed_check_for_leaks(QEDCheck *check)
/**
* Mark an image clean once it passes check or has been repaired
*/
-static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
+static void coroutine_fn GRAPH_RDLOCK
+qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
{
/* Skip if there were unfixable corruptions or I/O errors */
if (result->corruptions > 0 || result->check_errors > 0) {
@@ -213,7 +214,7 @@ static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
}
/* Ensure fixes reach storage before clearing check bit */
- bdrv_flush(s->bs);
+ bdrv_co_flush(s->bs);
s->header.features &= ~QED_F_NEED_CHECK;
qed_write_header_sync(s);
diff --git a/block/qed-table.c b/block/qed-table.c
index 3b331ce709..f04520d4c8 100644
--- a/block/qed-table.c
+++ b/block/qed-table.c
@@ -122,7 +122,7 @@ int coroutine_fn qed_read_l1_table_sync(BDRVQEDState *s)
int coroutine_fn qed_write_l1_table(BDRVQEDState *s, unsigned int index,
unsigned int n)
{
- BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
return qed_write_table(s, s->header.l1_table_offset,
s->l1_table, index, n, false);
}
@@ -150,7 +150,7 @@ int coroutine_fn qed_read_l2_table(BDRVQEDState *s, QEDRequest *request,
request->l2_table = qed_alloc_l2_cache_entry(&s->l2_cache);
request->l2_table->table = qed_alloc_table(s);
- BLKDBG_EVENT(s->bs->file, BLKDBG_L2_LOAD);
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_L2_LOAD);
ret = qed_read_table(s, offset, request->l2_table->table);
if (ret) {
@@ -183,7 +183,7 @@ int coroutine_fn qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
unsigned int index, unsigned int n,
bool flush)
{
- BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
return qed_write_table(s, request->l2_table->offset,
request->l2_table->table, index, n, flush);
}
diff --git a/block/qed.c b/block/qed.c
index 9a0350b534..b2604d9dad 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -195,14 +195,15 @@ static bool qed_is_image_size_valid(uint64_t image_size, uint32_t cluster_size,
*
* The string is NUL-terminated.
*/
-static int qed_read_string(BdrvChild *file, uint64_t offset, size_t n,
- char *buf, size_t buflen)
+static int coroutine_fn GRAPH_RDLOCK
+qed_read_string(BdrvChild *file, uint64_t offset,
+ size_t n, char *buf, size_t buflen)
{
int ret;
if (n >= buflen) {
return -EINVAL;
}
- ret = bdrv_pread(file, offset, n, buf, 0);
+ ret = bdrv_co_pread(file, offset, n, buf, 0);
if (ret < 0) {
return ret;
}
@@ -882,7 +883,7 @@ static int coroutine_fn GRAPH_RDLOCK
qed_read_backing_file(BDRVQEDState *s, uint64_t pos, QEMUIOVector *qiov)
{
if (s->bs->backing) {
- BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
return bdrv_co_preadv(s->bs->backing, pos, qiov->size, qiov, 0);
}
qemu_iovec_memset(qiov, 0, 0, qiov->size);
@@ -917,7 +918,7 @@ qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos, uint64_t len,
goto out;
}
- BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE);
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_COW_WRITE);
ret = bdrv_co_pwritev(s->bs->file, offset, qiov.size, &qiov, 0);
if (ret < 0) {
goto out;
@@ -1069,7 +1070,7 @@ static int coroutine_fn GRAPH_RDLOCK qed_aio_write_main(QEDAIOCB *acb)
trace_qed_aio_write_main(s, acb, 0, offset, acb->cur_qiov.size);
- BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
+ BLKDBG_CO_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
return bdrv_co_pwritev(s->bs->file, offset, acb->cur_qiov.size,
&acb->cur_qiov, 0);
}
@@ -1323,7 +1324,7 @@ qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
} else if (ret != QED_CLUSTER_FOUND) {
r = qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov);
} else {
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
r = bdrv_co_preadv(bs->file, offset, acb->cur_qiov.size,
&acb->cur_qiov, 0);
}
diff --git a/block/raw-format.c b/block/raw-format.c
index e4f35268e6..a8bdee5279 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -214,7 +214,7 @@ raw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
return ret;
}
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_AIO);
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
}
@@ -268,7 +268,7 @@ raw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
goto fail;
}
- BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_WRITE_AIO);
ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
fail:
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
index 38148f107a..d8ed651b70 100644
--- a/block/vhdx-log.c
+++ b/block/vhdx-log.c
@@ -169,9 +169,10 @@ exit:
* It is assumed that 'buffer' is at least 4096*num_sectors large.
*
* 0 is returned on success, -errno otherwise */
-static int vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log,
- uint32_t *sectors_written, void *buffer,
- uint32_t num_sectors)
+static int coroutine_fn GRAPH_RDLOCK
+vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log,
+ uint32_t *sectors_written, void *buffer,
+ uint32_t num_sectors)
{
int ret = 0;
uint64_t offset;
@@ -195,8 +196,7 @@ static int vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log,
/* full */
break;
}
- ret = bdrv_pwrite(bs->file, offset, VHDX_LOG_SECTOR_SIZE, buffer_tmp,
- 0);
+ ret = bdrv_co_pwrite(bs->file, offset, VHDX_LOG_SECTOR_SIZE, buffer_tmp, 0);
if (ret < 0) {
goto exit;
}
@@ -853,8 +853,9 @@ static void vhdx_log_raw_to_le_sector(VHDXLogDescriptor *desc,
}
-static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
- void *data, uint32_t length, uint64_t offset)
+static int coroutine_fn GRAPH_RDLOCK
+vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
+ void *data, uint32_t length, uint64_t offset)
{
int ret = 0;
void *buffer = NULL;
@@ -924,7 +925,7 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
sectors += partial_sectors;
- file_length = bdrv_getlength(bs->file->bs);
+ file_length = bdrv_co_getlength(bs->file->bs);
if (file_length < 0) {
ret = file_length;
goto exit;
@@ -971,8 +972,8 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
if (i == 0 && leading_length) {
/* partial sector at the front of the buffer */
- ret = bdrv_pread(bs->file, file_offset, VHDX_LOG_SECTOR_SIZE,
- merged_sector, 0);
+ ret = bdrv_co_pread(bs->file, file_offset, VHDX_LOG_SECTOR_SIZE,
+ merged_sector, 0);
if (ret < 0) {
goto exit;
}
@@ -981,9 +982,9 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
sector_write = merged_sector;
} else if (i == sectors - 1 && trailing_length) {
/* partial sector at the end of the buffer */
- ret = bdrv_pread(bs->file, file_offset + trailing_length,
- VHDX_LOG_SECTOR_SIZE - trailing_length,
- merged_sector + trailing_length, 0);
+ ret = bdrv_co_pread(bs->file, file_offset + trailing_length,
+ VHDX_LOG_SECTOR_SIZE - trailing_length,
+ merged_sector + trailing_length, 0);
if (ret < 0) {
goto exit;
}
@@ -1036,8 +1037,9 @@ exit:
}
/* Perform a log write, and then immediately flush the entire log */
-int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
- void *data, uint32_t length, uint64_t offset)
+int coroutine_fn
+vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
+ void *data, uint32_t length, uint64_t offset)
{
int ret = 0;
VHDXLogSequence logs = { .valid = true,
@@ -1047,7 +1049,7 @@ int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
/* Make sure data written (new and/or changed blocks) is stable
* on disk, before creating log entry */
- ret = bdrv_flush(bs);
+ ret = bdrv_co_flush(bs);
if (ret < 0) {
goto exit;
}
@@ -1059,7 +1061,7 @@ int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
logs.log = s->log;
/* Make sure log is stable on disk */
- ret = bdrv_flush(bs);
+ ret = bdrv_co_flush(bs);
if (ret < 0) {
goto exit;
}
diff --git a/block/vhdx.c b/block/vhdx.c
index 89913cba87..f2c3a80190 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -1250,12 +1250,13 @@ exit:
*
* Returns the file offset start of the new payload block
*/
-static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
- uint64_t *new_offset, bool *need_zero)
+static int coroutine_fn GRAPH_RDLOCK
+vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
+ uint64_t *new_offset, bool *need_zero)
{
int64_t current_len;
- current_len = bdrv_getlength(bs->file->bs);
+ current_len = bdrv_co_getlength(bs->file->bs);
if (current_len < 0) {
return current_len;
}
@@ -1271,16 +1272,16 @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
if (*need_zero) {
int ret;
- ret = bdrv_truncate(bs->file, *new_offset + s->block_size, false,
- PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE, NULL);
+ ret = bdrv_co_truncate(bs->file, *new_offset + s->block_size, false,
+ PREALLOC_MODE_OFF, BDRV_REQ_ZERO_WRITE, NULL);
if (ret != -ENOTSUP) {
*need_zero = false;
return ret;
}
}
- return bdrv_truncate(bs->file, *new_offset + s->block_size, false,
- PREALLOC_MODE_OFF, 0, NULL);
+ return bdrv_co_truncate(bs->file, *new_offset + s->block_size, false,
+ PREALLOC_MODE_OFF, 0, NULL);
}
/*
@@ -1572,12 +1573,10 @@ exit:
* The first 64KB of the Metadata section is reserved for the metadata
* header and entries; beyond that, the metadata items themselves reside.
*/
-static int vhdx_create_new_metadata(BlockBackend *blk,
- uint64_t image_size,
- uint32_t block_size,
- uint32_t sector_size,
- uint64_t metadata_offset,
- VHDXImageType type)
+static int coroutine_fn
+vhdx_create_new_metadata(BlockBackend *blk, uint64_t image_size,
+ uint32_t block_size, uint32_t sector_size,
+ uint64_t metadata_offset, VHDXImageType type)
{
int ret = 0;
uint32_t offset = 0;
@@ -1668,13 +1667,13 @@ static int vhdx_create_new_metadata(BlockBackend *blk,
VHDX_META_FLAGS_IS_VIRTUAL_DISK;
vhdx_metadata_entry_le_export(&md_table_entry[4]);
- ret = blk_pwrite(blk, metadata_offset, VHDX_HEADER_BLOCK_SIZE, buffer, 0);
+ ret = blk_co_pwrite(blk, metadata_offset, VHDX_HEADER_BLOCK_SIZE, buffer, 0);
if (ret < 0) {
goto exit;
}
- ret = blk_pwrite(blk, metadata_offset + (64 * KiB),
- VHDX_METADATA_ENTRY_BUFFER_SIZE, entry_buffer, 0);
+ ret = blk_co_pwrite(blk, metadata_offset + (64 * KiB),
+ VHDX_METADATA_ENTRY_BUFFER_SIZE, entry_buffer, 0);
if (ret < 0) {
goto exit;
}
@@ -1694,10 +1693,11 @@ exit:
* Fixed images: default state of the BAT is fully populated, with
* file offsets and state PAYLOAD_BLOCK_FULLY_PRESENT.
*/
-static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
- uint64_t image_size, VHDXImageType type,
- bool use_zero_blocks, uint64_t file_offset,
- uint32_t length, Error **errp)
+static int coroutine_fn
+vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
+ uint64_t image_size, VHDXImageType type,
+ bool use_zero_blocks, uint64_t file_offset,
+ uint32_t length, Error **errp)
{
int ret = 0;
uint64_t data_file_offset;
@@ -1718,14 +1718,14 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
if (type == VHDX_TYPE_DYNAMIC) {
/* All zeroes, so we can just extend the file - the end of the BAT
* is the furthest thing we have written yet */
- ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
- 0, errp);
+ ret = blk_co_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
+ 0, errp);
if (ret < 0) {
goto exit;
}
} else if (type == VHDX_TYPE_FIXED) {
- ret = blk_truncate(blk, data_file_offset + image_size, false,
- PREALLOC_MODE_OFF, 0, errp);
+ ret = blk_co_truncate(blk, data_file_offset + image_size, false,
+ PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) {
goto exit;
}
@@ -1759,7 +1759,7 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
s->bat[sinfo.bat_idx] = cpu_to_le64(s->bat[sinfo.bat_idx]);
sector_num += s->sectors_per_block;
}
- ret = blk_pwrite(blk, file_offset, length, s->bat, 0);
+ ret = blk_co_pwrite(blk, file_offset, length, s->bat, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to write the BAT");
goto exit;
@@ -1780,15 +1780,12 @@ exit:
* to create the BAT itself, we will also cause the BAT to be
* created.
*/
-static int vhdx_create_new_region_table(BlockBackend *blk,
- uint64_t image_size,
- uint32_t block_size,
- uint32_t sector_size,
- uint32_t log_size,
- bool use_zero_blocks,
- VHDXImageType type,
- uint64_t *metadata_offset,
- Error **errp)
+static int coroutine_fn
+vhdx_create_new_region_table(BlockBackend *blk, uint64_t image_size,
+ uint32_t block_size, uint32_t sector_size,
+ uint32_t log_size, bool use_zero_blocks,
+ VHDXImageType type, uint64_t *metadata_offset,
+ Error **errp)
{
int ret = 0;
uint32_t offset = 0;
@@ -1863,15 +1860,15 @@ static int vhdx_create_new_region_table(BlockBackend *blk,
}
/* Now write out the region headers to disk */
- ret = blk_pwrite(blk, VHDX_REGION_TABLE_OFFSET, VHDX_HEADER_BLOCK_SIZE,
- buffer, 0);
+ ret = blk_co_pwrite(blk, VHDX_REGION_TABLE_OFFSET, VHDX_HEADER_BLOCK_SIZE,
+ buffer, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to write first region table");
goto exit;
}
- ret = blk_pwrite(blk, VHDX_REGION_TABLE2_OFFSET, VHDX_HEADER_BLOCK_SIZE,
- buffer, 0);
+ ret = blk_co_pwrite(blk, VHDX_REGION_TABLE2_OFFSET, VHDX_HEADER_BLOCK_SIZE,
+ buffer, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to write second region table");
goto exit;
diff --git a/block/vhdx.h b/block/vhdx.h
index 0b74924cee..7db746cd18 100644
--- a/block/vhdx.h
+++ b/block/vhdx.h
@@ -413,8 +413,9 @@ bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset);
int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
Error **errp);
-int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
- void *data, uint32_t length, uint64_t offset);
+int coroutine_fn GRAPH_RDLOCK
+vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
+ void *data, uint32_t length, uint64_t offset);
static inline void leguid_to_cpus(MSGUID *guid)
{
diff --git a/block/vmdk.c b/block/vmdk.c
index e3e86608ec..70066c2b01 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -339,7 +339,8 @@ out:
return ret;
}
-static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
+static int coroutine_fn GRAPH_RDLOCK
+vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
{
char *desc, *tmp_desc;
char *p_name, *tmp_str;
@@ -348,7 +349,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
desc = g_malloc0(DESC_SIZE);
tmp_desc = g_malloc0(DESC_SIZE);
- ret = bdrv_pread(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
+ ret = bdrv_co_pread(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
if (ret < 0) {
goto out;
}
@@ -368,7 +369,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
pstrcat(desc, DESC_SIZE, tmp_desc);
}
- ret = bdrv_pwrite_sync(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
+ ret = bdrv_co_pwrite_sync(bs->file, s->desc_offset, DESC_SIZE, desc, 0);
out:
g_free(desc);
@@ -1437,7 +1438,7 @@ get_whole_cluster(BlockDriverState *bs, VmdkExtent *extent,
if (skip_start_bytes > 0) {
if (copy_from_backing) {
/* qcow2 emits this on bs->file instead of bs->backing */
- BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_COW_READ);
ret = bdrv_co_pread(bs->backing, offset, skip_start_bytes,
whole_grain, 0);
if (ret < 0) {
@@ -1445,7 +1446,7 @@ get_whole_cluster(BlockDriverState *bs, VmdkExtent *extent,
goto exit;
}
}
- BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_COW_WRITE);
ret = bdrv_co_pwrite(extent->file, cluster_offset, skip_start_bytes,
whole_grain, 0);
if (ret < 0) {
@@ -1457,7 +1458,7 @@ get_whole_cluster(BlockDriverState *bs, VmdkExtent *extent,
if (skip_end_bytes < cluster_bytes) {
if (copy_from_backing) {
/* qcow2 emits this on bs->file instead of bs->backing */
- BLKDBG_EVENT(extent->file, BLKDBG_COW_READ);
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_COW_READ);
ret = bdrv_co_pread(bs->backing, offset + skip_end_bytes,
cluster_bytes - skip_end_bytes,
whole_grain + skip_end_bytes, 0);
@@ -1466,7 +1467,7 @@ get_whole_cluster(BlockDriverState *bs, VmdkExtent *extent,
goto exit;
}
}
- BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE);
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_COW_WRITE);
ret = bdrv_co_pwrite(extent->file, cluster_offset + skip_end_bytes,
cluster_bytes - skip_end_bytes,
whole_grain + skip_end_bytes, 0);
@@ -1487,7 +1488,7 @@ vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, uint32_t offset)
{
offset = cpu_to_le32(offset);
/* update L2 table */
- BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE);
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_L2_UPDATE);
if (bdrv_co_pwrite(extent->file,
((int64_t)m_data->l2_offset * 512)
+ (m_data->l2_index * sizeof(offset)),
@@ -1617,7 +1618,7 @@ get_cluster_offset(BlockDriverState *bs, VmdkExtent *extent,
}
}
l2_table = (char *)extent->l2_cache + (min_index * l2_size_bytes);
- BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD);
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_L2_LOAD);
if (bdrv_co_pread(extent->file,
(int64_t)l2_offset * 512,
l2_size_bytes,
@@ -1828,12 +1829,12 @@ vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
n_bytes = buf_len + sizeof(VmdkGrainMarker);
qemu_iovec_init_buf(&local_qiov, data, n_bytes);
- BLKDBG_EVENT(extent->file, BLKDBG_WRITE_COMPRESSED);
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_WRITE_COMPRESSED);
} else {
qemu_iovec_init(&local_qiov, qiov->niov);
qemu_iovec_concat(&local_qiov, qiov, qiov_offset, n_bytes);
- BLKDBG_EVENT(extent->file, BLKDBG_WRITE_AIO);
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_WRITE_AIO);
}
write_offset = cluster_offset + offset_in_cluster;
@@ -1875,7 +1876,7 @@ vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
if (!extent->compressed) {
- BLKDBG_EVENT(extent->file, BLKDBG_READ_AIO);
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_READ_AIO);
ret = bdrv_co_preadv(extent->file,
cluster_offset + offset_in_cluster, bytes,
qiov, 0);
@@ -1889,7 +1890,7 @@ vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
buf_bytes = cluster_bytes * 2;
cluster_buf = g_malloc(buf_bytes);
uncomp_buf = g_malloc(cluster_bytes);
- BLKDBG_EVENT(extent->file, BLKDBG_READ_COMPRESSED);
+ BLKDBG_CO_EVENT(extent->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_co_pread(extent->file, cluster_offset, buf_bytes, cluster_buf,
0);
if (ret < 0) {
@@ -1967,7 +1968,7 @@ vmdk_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
/* qcow2 emits this on bs->file instead of bs->backing */
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
+ BLKDBG_CO_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
ret = bdrv_co_preadv(bs->backing, offset, n_bytes,
&local_qiov, 0);
if (ret < 0) {
@@ -2131,7 +2132,7 @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
int64_t length;
for (i = 0; i < s->num_extents; i++) {
- length = bdrv_getlength(s->extents[i].file->bs);
+ length = bdrv_co_getlength(s->extents[i].file->bs);
if (length < 0) {
return length;
}
@@ -2165,7 +2166,7 @@ vmdk_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
return ret;
}
-static int GRAPH_UNLOCKED
+static int coroutine_fn GRAPH_UNLOCKED
vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
bool zeroed_grain, Error **errp)
{
@@ -2176,7 +2177,7 @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
int gd_buf_size;
if (flat) {
- ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
+ ret = blk_co_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
goto exit;
}
magic = cpu_to_be32(VMDK4_MAGIC);
@@ -2228,19 +2229,19 @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
header.check_bytes[3] = 0xa;
/* write all the data */
- ret = blk_pwrite(blk, 0, sizeof(magic), &magic, 0);
+ ret = blk_co_pwrite(blk, 0, sizeof(magic), &magic, 0);
if (ret < 0) {
error_setg(errp, QERR_IO_ERROR);
goto exit;
}
- ret = blk_pwrite(blk, sizeof(magic), sizeof(header), &header, 0);
+ ret = blk_co_pwrite(blk, sizeof(magic), sizeof(header), &header, 0);
if (ret < 0) {
error_setg(errp, QERR_IO_ERROR);
goto exit;
}
- ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
- PREALLOC_MODE_OFF, 0, errp);
+ ret = blk_co_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
+ PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) {
goto exit;
}
@@ -2252,8 +2253,8 @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
i < gt_count; i++, tmp += gt_size) {
gd_buf[i] = cpu_to_le32(tmp);
}
- ret = blk_pwrite(blk, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE,
- gd_buf_size, gd_buf, 0);
+ ret = blk_co_pwrite(blk, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE,
+ gd_buf_size, gd_buf, 0);
if (ret < 0) {
error_setg(errp, QERR_IO_ERROR);
goto exit;
@@ -2264,8 +2265,8 @@ vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
i < gt_count; i++, tmp += gt_size) {
gd_buf[i] = cpu_to_le32(tmp);
}
- ret = blk_pwrite(blk, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE,
- gd_buf_size, gd_buf, 0);
+ ret = blk_co_pwrite(blk, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE,
+ gd_buf_size, gd_buf, 0);
if (ret < 0) {
error_setg(errp, QERR_IO_ERROR);
}
@@ -2908,7 +2909,7 @@ vmdk_co_check(BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix)
BDRVVmdkState *s = bs->opaque;
VmdkExtent *extent = NULL;
int64_t sector_num = 0;
- int64_t total_sectors = bdrv_nb_sectors(bs);
+ int64_t total_sectors = bdrv_co_nb_sectors(bs);
int ret;
uint64_t cluster_offset;
@@ -2938,7 +2939,7 @@ vmdk_co_check(BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix)
break;
}
if (ret == VMDK_OK) {
- int64_t extent_len = bdrv_getlength(extent->file->bs);
+ int64_t extent_len = bdrv_co_getlength(extent->file->bs);
if (extent_len < 0) {
fprintf(stderr,
"ERROR: could not get extent file length for sector %"
diff --git a/block/vpc.c b/block/vpc.c
index 7ee7c7b4e0..3810a601a3 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -486,8 +486,8 @@ static int vpc_reopen_prepare(BDRVReopenState *state,
* operation (the block bitmaps is updated then), 0 otherwise.
* If write is true then err must not be NULL.
*/
-static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
- bool write, int *err)
+static int64_t coroutine_fn GRAPH_RDLOCK
+get_image_offset(BlockDriverState *bs, uint64_t offset, bool write, int *err)
{
BDRVVPCState *s = bs->opaque;
uint64_t bitmap_offset, block_offset;
@@ -515,8 +515,7 @@ static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
s->last_bitmap_offset = bitmap_offset;
memset(bitmap, 0xff, s->bitmap_size);
- r = bdrv_pwrite_sync(bs->file, bitmap_offset, s->bitmap_size, bitmap,
- 0);
+ r = bdrv_co_pwrite_sync(bs->file, bitmap_offset, s->bitmap_size, bitmap, 0);
if (r < 0) {
*err = r;
return -2;
@@ -532,13 +531,13 @@ static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
*
* Returns 0 on success and < 0 on error
*/
-static int rewrite_footer(BlockDriverState *bs)
+static int coroutine_fn GRAPH_RDLOCK rewrite_footer(BlockDriverState *bs)
{
int ret;
BDRVVPCState *s = bs->opaque;
int64_t offset = s->free_data_block_offset;
- ret = bdrv_pwrite_sync(bs->file, offset, sizeof(s->footer), &s->footer, 0);
+ ret = bdrv_co_pwrite_sync(bs->file, offset, sizeof(s->footer), &s->footer, 0);
if (ret < 0)
return ret;
@@ -552,7 +551,8 @@ static int rewrite_footer(BlockDriverState *bs)
*
* Returns the sectors' offset in the image file on success and < 0 on error
*/
-static int64_t alloc_block(BlockDriverState *bs, int64_t offset)
+static int64_t coroutine_fn GRAPH_RDLOCK
+alloc_block(BlockDriverState *bs, int64_t offset)
{
BDRVVPCState *s = bs->opaque;
int64_t bat_offset;
@@ -572,8 +572,8 @@ static int64_t alloc_block(BlockDriverState *bs, int64_t offset)
/* Initialize the block's bitmap */
memset(bitmap, 0xff, s->bitmap_size);
- ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset,
- s->bitmap_size, bitmap, 0);
+ ret = bdrv_co_pwrite_sync(bs->file, s->free_data_block_offset,
+ s->bitmap_size, bitmap, 0);
if (ret < 0) {
return ret;
}
@@ -587,7 +587,7 @@ static int64_t alloc_block(BlockDriverState *bs, int64_t offset)
/* Write BAT entry to disk */
bat_offset = s->bat_offset + (4 * index);
bat_value = cpu_to_be32(s->pagetable[index]);
- ret = bdrv_pwrite_sync(bs->file, bat_offset, 4, &bat_value, 0);
+ ret = bdrv_co_pwrite_sync(bs->file, bat_offset, 4, &bat_value, 0);
if (ret < 0)
goto fail;
@@ -718,11 +718,11 @@ fail:
return ret;
}
-static int coroutine_fn vpc_co_block_status(BlockDriverState *bs,
- bool want_zero,
- int64_t offset, int64_t bytes,
- int64_t *pnum, int64_t *map,
- BlockDriverState **file)
+static int coroutine_fn GRAPH_RDLOCK
+vpc_co_block_status(BlockDriverState *bs, bool want_zero,
+ int64_t offset, int64_t bytes,
+ int64_t *pnum, int64_t *map,
+ BlockDriverState **file)
{
BDRVVPCState *s = bs->opaque;
int64_t image_offset;
@@ -820,8 +820,8 @@ static int calculate_geometry(int64_t total_sectors, uint16_t *cyls,
return 0;
}
-static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
- int64_t total_sectors)
+static int coroutine_fn create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
+ int64_t total_sectors)
{
VHDDynDiskHeader dyndisk_header;
uint8_t bat_sector[512];
@@ -834,13 +834,13 @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
block_size = 0x200000;
num_bat_entries = DIV_ROUND_UP(total_sectors, block_size / 512);
- ret = blk_pwrite(blk, offset, sizeof(*footer), footer, 0);
+ ret = blk_co_pwrite(blk, offset, sizeof(*footer), footer, 0);
if (ret < 0) {
goto fail;
}
offset = 1536 + ((num_bat_entries * 4 + 511) & ~511);
- ret = blk_pwrite(blk, offset, sizeof(*footer), footer, 0);
+ ret = blk_co_pwrite(blk, offset, sizeof(*footer), footer, 0);
if (ret < 0) {
goto fail;
}
@@ -850,7 +850,7 @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
memset(bat_sector, 0xFF, 512);
for (i = 0; i < DIV_ROUND_UP(num_bat_entries * 4, 512); i++) {
- ret = blk_pwrite(blk, offset, 512, bat_sector, 0);
+ ret = blk_co_pwrite(blk, offset, 512, bat_sector, 0);
if (ret < 0) {
goto fail;
}
@@ -878,7 +878,7 @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
/* Write the header */
offset = 512;
- ret = blk_pwrite(blk, offset, sizeof(dyndisk_header), &dyndisk_header, 0);
+ ret = blk_co_pwrite(blk, offset, sizeof(dyndisk_header), &dyndisk_header, 0);
if (ret < 0) {
goto fail;
}
@@ -888,21 +888,21 @@ static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer,
return ret;
}
-static int create_fixed_disk(BlockBackend *blk, VHDFooter *footer,
- int64_t total_size, Error **errp)
+static int coroutine_fn create_fixed_disk(BlockBackend *blk, VHDFooter *footer,
+ int64_t total_size, Error **errp)
{
int ret;
/* Add footer to total size */
total_size += sizeof(*footer);
- ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
+ ret = blk_co_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
if (ret < 0) {
return ret;
}
- ret = blk_pwrite(blk, total_size - sizeof(*footer), sizeof(*footer),
- footer, 0);
+ ret = blk_co_pwrite(blk, total_size - sizeof(*footer), sizeof(*footer),
+ footer, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "Unable to write VHD header");
return ret;
diff --git a/blockjob.c b/blockjob.c
index 913da3cbf7..25fe8e625d 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -230,20 +230,27 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
uint64_t perm, uint64_t shared_perm, Error **errp)
{
BdrvChild *c;
+ AioContext *ctx = bdrv_get_aio_context(bs);
bool need_context_ops;
GLOBAL_STATE_CODE();
bdrv_ref(bs);
- need_context_ops = bdrv_get_aio_context(bs) != job->job.aio_context;
+ need_context_ops = ctx != job->job.aio_context;
- if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) {
- aio_context_release(job->job.aio_context);
+ if (need_context_ops) {
+ if (job->job.aio_context != qemu_get_aio_context()) {
+ aio_context_release(job->job.aio_context);
+ }
+ aio_context_acquire(ctx);
}
c = bdrv_root_attach_child(bs, name, &child_job, 0, perm, shared_perm, job,
errp);
- if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) {
- aio_context_acquire(job->job.aio_context);
+ if (need_context_ops) {
+ aio_context_release(ctx);
+ if (job->job.aio_context != qemu_get_aio_context()) {
+ aio_context_acquire(job->job.aio_context);
+ }
}
if (c == NULL) {
return -EPERM;
diff --git a/chardev/char-win-stdio.c b/chardev/char-win-stdio.c
index eb830eabd9..1a18999e78 100644
--- a/chardev/char-win-stdio.c
+++ b/chardev/char-win-stdio.c
@@ -190,7 +190,7 @@ static void qemu_chr_open_stdio(Chardev *chr,
}
}
- dwMode |= ENABLE_LINE_INPUT;
+ dwMode |= ENABLE_LINE_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT;
if (is_console) {
/* set the terminal in raw mode */
diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst
index 203facb417..e85e26c4ca 100644
--- a/docs/devel/testing.rst
+++ b/docs/devel/testing.rst
@@ -558,7 +558,7 @@ When CI tasks, maintainers or yourself report a Docker test failure, follow the
below steps to debug it:
1. Locally reproduce the failure with the reported command line. E.g. run
- ``make docker-test-mingw@fedora J=8``.
+ ``make docker-test-mingw@fedora-win64-cross J=8``.
2. Add "V=1" to the command line, try again, to see the verbose output.
3. Further add "DEBUG=1" to the command line. This will pause in a shell prompt
in the container right before testing starts. You could either manually
diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst
index 8d4a1821fa..4491c4cbf7 100644
--- a/docs/system/device-emulation.rst
+++ b/docs/system/device-emulation.rst
@@ -86,6 +86,7 @@ Emulated Devices
devices/ccid.rst
devices/cxl.rst
devices/ivshmem.rst
+ devices/keyboard.rst
devices/net.rst
devices/nvme.rst
devices/usb.rst
diff --git a/docs/system/devices/keyboard.rst b/docs/system/devices/keyboard.rst
new file mode 100644
index 0000000000..a8f9fbebae
--- /dev/null
+++ b/docs/system/devices/keyboard.rst
@@ -0,0 +1,129 @@
+.. _keyboard:
+
+Sparc32 keyboard
+----------------
+SUN Type 4, 5 and 5c keyboards have dip switches to choose the language layout
+of the keyboard. Solaris makes an ioctl to query the value of the dipswitches
+and uses that value to select keyboard layout. Also the SUN bios like the one
+in the file ss5.bin uses this value to support at least some keyboard layouts.
+However, the OpenBIOS provided with qemu is hardcoded to always use an
+US keyboard layout.
+
+With the escc.chnA-sunkbd-layout driver property it is possible to select
+keyboard layout. Example:
+
+-global escc.chnA-sunkbd-layout=de
+
+Depending on type of keyboard, the keyboard can have 6 or 5 dip-switches to
+select keyboard layout, giving up to 64 different layouts. Not all
+combinations are supported by Solaris and even less by Sun OpenBoot BIOS.
+
+The dip switch settings can be given as hexadecimal number, decimal number
+or in some cases as a language string. Examples:
+
+-global escc.chnA-sunkbd-layout=0x2b
+
+-global escc.chnA-sunkbd-layout=43
+
+-global escc.chnA-sunkbd-layout=sv
+
+The above 3 examples all select a swedish keyboard layout. Table 3-15 at
+https://docs.oracle.com/cd/E19683-01/806-6642/new-43/index.html explains which
+keytable file is used for different dip switch settings. The information
+in that table can be summarized in this table:
+
+.. list-table:: Language selection values for escc.chnA-sunkbd-layout
+ :widths: 10 10 10
+ :header-rows: 1
+
+ * - Hexadecimal value
+ - Decimal value
+ - Language code
+ * - 0x21
+ - 33
+ - en-us
+ * - 0x23
+ - 35
+ - fr
+ * - 0x24
+ - 36
+ - da
+ * - 0x25
+ - 37
+ - de
+ * - 0x26
+ - 38
+ - it
+ * - 0x27
+ - 39
+ - nl
+ * - 0x28
+ - 40
+ - no
+ * - 0x29
+ - 41
+ - pt
+ * - 0x2a
+ - 42
+ - es
+ * - 0x2b
+ - 43
+ - sv
+ * - 0x2c
+ - 44
+ - fr-ch
+ * - 0x2d
+ - 45
+ - de-ch
+ * - 0x2e
+ - 46
+ - en-gb
+ * - 0x2f
+ - 47
+ - ko
+ * - 0x30
+ - 48
+ - tw
+ * - 0x31
+ - 49
+ - ja
+ * - 0x32
+ - 50
+ - fr-ca
+ * - 0x33
+ - 51
+ - hu
+ * - 0x34
+ - 52
+ - pl
+ * - 0x35
+ - 53
+ - cz
+ * - 0x36
+ - 54
+ - ru
+ * - 0x37
+ - 55
+ - lv
+ * - 0x38
+ - 56
+ - tr
+ * - 0x39
+ - 57
+ - gr
+ * - 0x3a
+ - 58
+ - ar
+ * - 0x3b
+ - 59
+ - lt
+ * - 0x3c
+ - 60
+ - nl-be
+ * - 0x3c
+ - 60
+ - be
+
+Not all dip switch values have a corresponding language code and both "be" and
+"nl-be" correspond to the same dip switch value. By default, if no value is
+given to escc.chnA-sunkbd-layout 0x21 (en-us) will be used.
diff --git a/docs/system/devices/nvme.rst b/docs/system/devices/nvme.rst
index 30f841ef62..a8bb8d729c 100644
--- a/docs/system/devices/nvme.rst
+++ b/docs/system/devices/nvme.rst
@@ -212,6 +212,41 @@ The namespace may be configured with additional parameters
the minimum memory page size (CAP.MPSMIN). The default value (``0``)
has this property inherit the ``mdts`` value.
+Flexible Data Placement
+-----------------------
+
+The device may be configured to support TP4146 ("Flexible Data Placement") by
+configuring it (``fdp=on``) on the subsystem::
+
+ -device nvme-subsys,id=nvme-subsys-0,nqn=subsys0,fdp=on,fdp.nruh=16
+
+The subsystem emulates a single Endurance Group, on which Flexible Data
+Placement will be supported. Also note that the device emulation deviates
+slightly from the specification, by always enabling the "FDP Mode" feature on
+the controller if the subsystems is configured for Flexible Data Placement.
+
+Enabling Flexible Data Placement on the subsyste enables the following
+parameters:
+
+``fdp.nrg`` (default: ``1``)
+ Set the number of Reclaim Groups.
+
+``fdp.nruh`` (default: ``0``)
+ Set the number of Reclaim Unit Handles. This is a mandatory paramater and
+ must be non-zero.
+
+``fdp.runs`` (default: ``96M``)
+ Set the Reclaim Unit Nominal Size. Defaults to 96 MiB.
+
+Namespaces within this subsystem may requests Reclaim Unit Handles::
+
+ -device nvme-ns,drive=nvm-1,fdp.ruhs=RUHLIST
+
+The ``RUHLIST`` is a semicolon separated list (i.e. ``0;1;2;3``) and may
+include ranges (i.e. ``0;8-15``). If no reclaim unit handle list is specified,
+the controller will assign the controller-specified reclaim unit handle to
+placement handle identifier 0.
+
Metadata
--------
@@ -320,4 +355,4 @@ controller are:
.. code-block:: console
- echo 0000:01:00.1 > /sys/bus/pci/drivers/nvme/bind \ No newline at end of file
+ echo 0000:01:00.1 > /sys/bus/pci/drivers/nvme/bind
diff --git a/docs/system/target-sparc.rst b/docs/system/target-sparc.rst
index b55f8d09e9..9ec8c90c14 100644
--- a/docs/system/target-sparc.rst
+++ b/docs/system/target-sparc.rst
@@ -38,7 +38,7 @@ QEMU emulates the following sun4m peripherals:
- Non Volatile RAM M48T02/M48T08
- Slave I/O: timers, interrupt controllers, Zilog serial ports,
- keyboard and power/reset logic
+ :ref:`keyboard` and power/reset logic
- ESP SCSI controller with hard disk and CD-ROM support
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index b774d80291..82a28b2e0b 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -23,6 +23,7 @@
#include "qemu/error-report.h"
#include "qemu/units.h"
#include "sysemu/device_tree.h"
+#include "sysemu/kvm.h"
#include "sysemu/numa.h"
#include "sysemu/runstate.h"
#include "sysemu/sysemu.h"
@@ -36,6 +37,7 @@
#include "hw/ide/internal.h"
#include "hw/ide/ahci_internal.h"
#include "hw/intc/arm_gicv3_common.h"
+#include "hw/intc/arm_gicv3_its_common.h"
#include "hw/loader.h"
#include "hw/pci-host/gpex.h"
#include "hw/qdev-properties.h"
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 4af0de8b24..55f2706bc9 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -48,12 +48,12 @@
#include "hw/pci/pci_bus.h"
#include "hw/pci-host/gpex.h"
#include "hw/arm/virt.h"
+#include "hw/intc/arm_gicv3_its_common.h"
#include "hw/mem/nvdimm.h"
#include "hw/platform-bus.h"
#include "sysemu/numa.h"
#include "sysemu/reset.h"
#include "sysemu/tpm.h"
-#include "kvm_arm.h"
#include "migration/vmstate.h"
#include "hw/acpi/ghes.h"
#include "hw/acpi/viot.h"
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 3937e30477..3196db556e 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -63,6 +63,7 @@
#include "hw/arm/fdt.h"
#include "hw/intc/arm_gic.h"
#include "hw/intc/arm_gicv3_common.h"
+#include "hw/intc/arm_gicv3_its_common.h"
#include "hw/irq.h"
#include "kvm_arm.h"
#include "hw/firmware/smbios.h"
diff --git a/hw/arm/xen_arm.c b/hw/arm/xen_arm.c
index 19b1cb81ad..044093fec7 100644
--- a/hw/arm/xen_arm.c
+++ b/hw/arm/xen_arm.c
@@ -45,7 +45,7 @@ static MemoryListener xen_memory_listener = {
.log_sync = NULL,
.log_global_start = NULL,
.log_global_stop = NULL,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
};
struct XenArmState {
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 17a908c59b..4f3872bfe9 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -31,6 +31,8 @@
#include "qemu/module.h"
#include "hw/char/escc.h"
#include "ui/console.h"
+
+#include "qemu/cutils.h"
#include "trace.h"
/*
@@ -190,6 +192,7 @@
#define R_MISC1I 14
#define R_EXTINT 15
+static uint8_t sunkbd_layout_dip_switch(const char *sunkbd_layout);
static void handle_kbd_command(ESCCChannelState *s, int val);
static int serial_can_receive(void *opaque);
static void serial_receive_byte(ESCCChannelState *s, int ch);
@@ -846,6 +849,79 @@ static QemuInputHandler sunkbd_handler = {
.event = sunkbd_handle_event,
};
+static uint8_t sunkbd_layout_dip_switch(const char *kbd_layout)
+{
+ /* Return the value of the dip-switches in a SUN Type 5 keyboard */
+ static uint8_t ret = 0xff;
+
+ if ((ret == 0xff) && kbd_layout) {
+ int i;
+ struct layout_values {
+ const char *lang;
+ uint8_t dip;
+ } languages[] =
+ /*
+ * Dip values from table 3-16 Layouts for Type 4, 5 and 5c Keyboards
+ */
+ {
+ {"en-us", 0x21}, /* U.S.A. (US5.kt) */
+ /* 0x22 is some other US (US_UNIX5.kt) */
+ {"fr", 0x23}, /* France (France5.kt) */
+ {"da", 0x24}, /* Denmark (Denmark5.kt) */
+ {"de", 0x25}, /* Germany (Germany5.kt) */
+ {"it", 0x26}, /* Italy (Italy5.kt) */
+ {"nl", 0x27}, /* The Netherlands (Netherland5.kt) */
+ {"no", 0x28}, /* Norway (Norway.kt) */
+ {"pt", 0x29}, /* Portugal (Portugal5.kt) */
+ {"es", 0x2a}, /* Spain (Spain5.kt) */
+ {"sv", 0x2b}, /* Sweden (Sweden5.kt) */
+ {"fr-ch", 0x2c}, /* Switzerland/French (Switzer_Fr5.kt) */
+ {"de-ch", 0x2d}, /* Switzerland/German (Switzer_Ge5.kt) */
+ {"en-gb", 0x2e}, /* Great Britain (UK5.kt) */
+ {"ko", 0x2f}, /* Korea (Korea5.kt) */
+ {"tw", 0x30}, /* Taiwan (Taiwan5.kt) */
+ {"ja", 0x31}, /* Japan (Japan5.kt) */
+ {"fr-ca", 0x32}, /* Canada/French (Canada_Fr5.kt) */
+ {"hu", 0x33}, /* Hungary (Hungary5.kt) */
+ {"pl", 0x34}, /* Poland (Poland5.kt) */
+ {"cz", 0x35}, /* Czech (Czech5.kt) */
+ {"ru", 0x36}, /* Russia (Russia5.kt) */
+ {"lv", 0x37}, /* Latvia (Latvia5.kt) */
+ {"tr", 0x38}, /* Turkey-Q5 (TurkeyQ5.kt) */
+ {"gr", 0x39}, /* Greece (Greece5.kt) */
+ {"ar", 0x3a}, /* Arabic (Arabic5.kt) */
+ {"lt", 0x3b}, /* Lithuania (Lithuania5.kt) */
+ {"nl-be", 0x3c}, /* Belgium (Belgian5.kt) */
+ {"be", 0x3c}, /* Belgium (Belgian5.kt) */
+ };
+
+ for (i = 0;
+ i < sizeof(languages) / sizeof(struct layout_values);
+ i++) {
+ if (!strcmp(kbd_layout, languages[i].lang)) {
+ ret = languages[i].dip;
+ return ret;
+ }
+ }
+
+ /* Found no known language code */
+ if ((kbd_layout[0] >= '0') && (kbd_layout[0] <= '9')) {
+ unsigned int tmp;
+
+ /* As a fallback we also accept numeric dip switch value */
+ if (!qemu_strtoui(kbd_layout, NULL, 0, &tmp)) {
+ ret = tmp;
+ }
+ }
+ }
+
+ if (ret == 0xff) {
+ /* Final fallback if keyboard_layout was not set or recognized */
+ ret = 0x21; /* en-us layout */
+ }
+ return ret;
+}
+
static void handle_kbd_command(ESCCChannelState *s, int val)
{
trace_escc_kbd_command(val);
@@ -867,7 +943,7 @@ static void handle_kbd_command(ESCCChannelState *s, int val)
case 0xf:
clear_queue(s);
put_queue(s, 0xfe);
- put_queue(s, 0x21); /* en-us layout */
+ put_queue(s, sunkbd_layout_dip_switch(s->sunkbd_layout));
break;
default:
break;
@@ -976,6 +1052,7 @@ static Property escc_properties[] = {
DEFINE_PROP_UINT32("chnAtype", ESCCState, chn[1].type, 0),
DEFINE_PROP_CHR("chrB", ESCCState, chn[0].chr),
DEFINE_PROP_CHR("chrA", ESCCState, chn[1].chr),
+ DEFINE_PROP_STRING("chnA-sunkbd-layout", ESCCState, chn[1].sunkbd_layout),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index d42493f630..6d5d43eda2 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -143,11 +143,15 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name,
* aware of iothreads require their BlockBackends to be in the main
* AioContext.
*/
- ctx = iothread ? bdrv_get_aio_context(bs) : qemu_get_aio_context();
- blk = blk_new(ctx, 0, BLK_PERM_ALL);
+ ctx = bdrv_get_aio_context(bs);
+ blk = blk_new(iothread ? ctx : qemu_get_aio_context(),
+ 0, BLK_PERM_ALL);
blk_created = true;
+ aio_context_acquire(ctx);
ret = blk_insert_bs(blk, bs, errp);
+ aio_context_release(ctx);
+
if (ret < 0) {
goto fail;
}
diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c
index 69e2cf0bd6..ef1a740de5 100644
--- a/hw/display/virtio-gpu-udmabuf.c
+++ b/hw/display/virtio-gpu-udmabuf.c
@@ -132,7 +132,8 @@ void virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res)
void *pdata = NULL;
res->dmabuf_fd = -1;
- if (res->iov_cnt == 1) {
+ if (res->iov_cnt == 1 &&
+ res->iov[0].iov_len < 4096) {
pdata = res->iov[0].iov_base;
} else {
virtio_gpu_create_udmabuf(res);
diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index 1c47603d40..8bb7a2c21f 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -18,9 +18,17 @@
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-gpu.h"
+#include "ui/egl-helpers.h"
+
#include <virglrenderer.h>
-static struct virgl_renderer_callbacks virtio_gpu_3d_cbs;
+#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
+static void *
+virgl_get_egl_display(G_GNUC_UNUSED void *cookie)
+{
+ return qemu_egl_display;
+}
+#endif
static void virgl_cmd_create_resource_2d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
@@ -145,7 +153,6 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
struct virtio_gpu_set_scanout ss;
- struct virgl_renderer_resource_info info;
int ret;
VIRTIO_GPU_FILL_CMD(ss);
@@ -160,10 +167,20 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
}
g->parent_obj.enable = 1;
- memset(&info, 0, sizeof(info));
-
if (ss.resource_id && ss.r.width && ss.r.height) {
+ struct virgl_renderer_resource_info info;
+ void *d3d_tex2d = NULL;
+
+#ifdef HAVE_VIRGL_D3D_INFO_EXT
+ struct virgl_renderer_resource_info_ext ext;
+ memset(&ext, 0, sizeof(ext));
+ ret = virgl_renderer_resource_get_info_ext(ss.resource_id, &ext);
+ info = ext.base;
+ d3d_tex2d = ext.d3d_tex2d;
+#else
+ memset(&info, 0, sizeof(info));
ret = virgl_renderer_resource_get_info(ss.resource_id, &info);
+#endif
if (ret == -1) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: illegal resource specified %d\n",
@@ -178,7 +195,8 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
g->parent_obj.scanout[ss.scanout_id].con, info.tex_id,
info.flags & VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP,
info.width, info.height,
- ss.r.x, ss.r.y, ss.r.width, ss.r.height);
+ ss.r.x, ss.r.y, ss.r.width, ss.r.height,
+ d3d_tex2d);
} else {
dpy_gfx_replace_surface(
g->parent_obj.scanout[ss.scanout_id].con, NULL);
@@ -607,8 +625,21 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g)
int virtio_gpu_virgl_init(VirtIOGPU *g)
{
int ret;
+ uint32_t flags = 0;
+
+#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
+ if (qemu_egl_display) {
+ virtio_gpu_3d_cbs.version = 4;
+ virtio_gpu_3d_cbs.get_egl_display = virgl_get_egl_display;
+ }
+#endif
+#ifdef VIRGL_RENDERER_D3D11_SHARE_TEXTURE
+ if (qemu_egl_angle_d3d) {
+ flags |= VIRGL_RENDERER_D3D11_SHARE_TEXTURE;
+ }
+#endif
- ret = virgl_renderer_init(g, 0, &virtio_gpu_3d_cbs);
+ ret = virgl_renderer_init(g, flags, &virtio_gpu_3d_cbs);
if (ret != 0) {
error_report("virgl could not be initialized: %d", ret);
return ret;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 66cddd94d9..347e17d490 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -258,6 +258,16 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat,
return height * stride;
}
+#ifdef WIN32
+static void
+win32_pixman_image_destroy(pixman_image_t *image, void *data)
+{
+ HANDLE handle = data;
+
+ qemu_win32_map_free(pixman_image_get_data(image), handle, &error_warn);
+}
+#endif
+
static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
@@ -304,12 +314,27 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
if (res->hostmem + g->hostmem < g->conf_max_hostmem) {
+ void *bits = NULL;
+#ifdef WIN32
+ bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
+ if (!bits) {
+ goto end;
+ }
+#endif
res->image = pixman_image_create_bits(pformat,
c2d.width,
c2d.height,
- NULL, 0);
+ bits, res->hostmem / c2d.height);
+#ifdef WIN32
+ if (res->image) {
+ pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
+ }
+#endif
}
+#ifdef WIN32
+end:
+#endif
if (!res->image) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: resource creation failed %d %d %d\n",
@@ -438,11 +463,11 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
struct virtio_gpu_simple_resource *res;
- int h;
+ int h, bpp;
uint32_t src_offset, dst_offset, stride;
- int bpp;
pixman_format_code_t format;
struct virtio_gpu_transfer_to_host_2d t2d;
+ void *img_data;
VIRTIO_GPU_FILL_CMD(t2d);
virtio_gpu_t2d_bswap(&t2d);
@@ -471,23 +496,23 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
format = pixman_image_get_format(res->image);
bpp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8);
stride = pixman_image_get_stride(res->image);
+ img_data = pixman_image_get_data(res->image);
- if (t2d.offset || t2d.r.x || t2d.r.y ||
- t2d.r.width != pixman_image_get_width(res->image)) {
- void *img_data = pixman_image_get_data(res->image);
+ if (t2d.r.x || t2d.r.width != pixman_image_get_width(res->image)) {
for (h = 0; h < t2d.r.height; h++) {
src_offset = t2d.offset + stride * h;
dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp);
iov_to_buf(res->iov, res->iov_cnt, src_offset,
- (uint8_t *)img_data
- + dst_offset, t2d.r.width * bpp);
+ (uint8_t *)img_data + dst_offset,
+ t2d.r.width * bpp);
}
} else {
- iov_to_buf(res->iov, res->iov_cnt, 0,
- pixman_image_get_data(res->image),
- pixman_image_get_stride(res->image)
- * pixman_image_get_height(res->image));
+ src_offset = t2d.offset;
+ dst_offset = t2d.r.y * stride + t2d.r.x * bpp;
+ iov_to_buf(res->iov, res->iov_cnt, src_offset,
+ (uint8_t *)img_data + dst_offset,
+ stride * t2d.r.height);
}
}
@@ -498,6 +523,8 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
struct virtio_gpu_resource_flush rf;
struct virtio_gpu_scanout *scanout;
pixman_region16_t flush_region;
+ bool within_bounds = false;
+ bool update_submitted = false;
int i;
VIRTIO_GPU_FILL_CMD(rf);
@@ -518,13 +545,28 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
rf.r.x < scanout->x + scanout->width &&
rf.r.x + rf.r.width >= scanout->x &&
rf.r.y < scanout->y + scanout->height &&
- rf.r.y + rf.r.height >= scanout->y &&
- console_has_gl(scanout->con)) {
- dpy_gl_update(scanout->con, 0, 0, scanout->width,
- scanout->height);
+ rf.r.y + rf.r.height >= scanout->y) {
+ within_bounds = true;
+
+ if (console_has_gl(scanout->con)) {
+ dpy_gl_update(scanout->con, 0, 0, scanout->width,
+ scanout->height);
+ update_submitted = true;
+ }
}
}
- return;
+
+ if (update_submitted) {
+ return;
+ }
+ if (!within_bounds) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside scanouts"
+ " bounds for flush %d: %d %d %d %d\n",
+ __func__, rf.resource_id, rf.r.x, rf.r.y,
+ rf.r.width, rf.r.height);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
}
if (!res->blob &&
@@ -634,8 +676,10 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
if (console_has_gl(scanout->con)) {
if (!virtio_gpu_update_dmabuf(g, scanout_id, res, fb, r)) {
virtio_gpu_update_scanout(g, scanout_id, res, r);
- return;
+ } else {
+ *error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
}
+ return;
}
data = res->blob;
@@ -666,6 +710,9 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g,
*error = VIRTIO_GPU_RESP_ERR_UNSPEC;
return;
}
+#ifdef WIN32
+ qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, fb->offset);
+#endif
pixman_image_unref(rect);
dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con,
@@ -1209,6 +1256,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
struct virtio_gpu_simple_resource *res;
struct virtio_gpu_scanout *scanout;
uint32_t resource_id, pformat;
+ void *bits = NULL;
int i;
g->hostmem = 0;
@@ -1233,15 +1281,23 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
g_free(res);
return -EINVAL;
}
+
+ res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
+#ifdef WIN32
+ bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
+ if (!bits) {
+ g_free(res);
+ return -EINVAL;
+ }
+#endif
res->image = pixman_image_create_bits(pformat,
res->width, res->height,
- NULL, 0);
+ bits, res->hostmem / res->height);
if (!res->image) {
g_free(res);
return -EINVAL;
}
- res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
res->addrs = g_new(uint64_t, res->iov_cnt);
res->iov = g_new(struct iovec, res->iov_cnt);
@@ -1302,6 +1358,9 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
if (!scanout->ds) {
return -EINVAL;
}
+#ifdef WIN32
+ qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0);
+#endif
dpy_gfx_replace_surface(scanout->con, scanout->ds);
dpy_gfx_update_full(scanout->con);
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index 5dc5e80535..3da5a2b23f 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -467,7 +467,7 @@ static MemoryListener xen_memory_listener = {
.log_sync = xen_log_sync,
.log_global_start = xen_log_global_start,
.log_global_stop = xen_log_global_stop,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
};
static void regs_to_cpu(vmware_regs_t *vmport_regs, ioreq_t *req)
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
index a379cea395..7c28504ace 100644
--- a/hw/intc/arm_gic_common.c
+++ b/hw/intc/arm_gic_common.c
@@ -21,10 +21,12 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
+#include "qemu/error-report.h"
#include "gic_internal.h"
#include "hw/arm/linux-boot-if.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
+#include "sysemu/kvm.h"
static int gic_pre_save(void *opaque)
{
@@ -233,12 +235,12 @@ static void arm_gic_common_realize(DeviceState *dev, Error **errp)
}
}
-static inline void arm_gic_common_reset_irq_state(GICState *s, int first_cpu,
+static inline void arm_gic_common_reset_irq_state(GICState *s, int cidx,
int resetprio)
{
int i, j;
- for (i = first_cpu; i < first_cpu + s->num_cpu; i++) {
+ for (i = cidx; i < cidx + s->num_cpu; i++) {
if (s->revision == REV_11MPCORE) {
s->priority_mask[i] = 0xf0;
} else {
@@ -393,3 +395,8 @@ static void register_types(void)
}
type_init(register_types)
+
+const char *gic_class_name(void)
+{
+ return kvm_irqchip_in_kernel() ? "kvm-arm-gic" : "arm_gic";
+}
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 642a8243ed..2ebf880ead 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
+#include "qemu/error-report.h"
#include "hw/core/cpu.h"
#include "hw/intc/arm_gicv3_common.h"
#include "hw/qdev-properties.h"
@@ -608,3 +609,16 @@ static void register_types(void)
}
type_init(register_types)
+
+const char *gicv3_class_name(void)
+{
+ if (kvm_irqchip_in_kernel()) {
+ return "kvm-arm-gicv3";
+ } else {
+ if (kvm_enabled()) {
+ error_report("Userspace GICv3 is not supported with KVM");
+ exit(1);
+ }
+ return "arm-gicv3";
+ }
+}
diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c
index d7532a7a89..abaf77057e 100644
--- a/hw/intc/arm_gicv3_its_common.c
+++ b/hw/intc/arm_gicv3_its_common.c
@@ -24,6 +24,7 @@
#include "hw/intc/arm_gicv3_its_common.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "sysemu/kvm.h"
static int gicv3_its_pre_save(void *opaque)
{
@@ -158,3 +159,14 @@ static void gicv3_its_common_register_types(void)
}
type_init(gicv3_its_common_register_types)
+
+const char *its_class_name(void)
+{
+ if (kvm_irqchip_in_kernel()) {
+ /* KVM implementation requires this capability */
+ return kvm_direct_msi_enabled() ? "arm-its-kvm" : NULL;
+ } else {
+ /* Software emulation based model */
+ return "arm-gicv3-its";
+ }
+}
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 6db23ca323..6b958d6363 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -507,7 +507,12 @@ VHostNetState *get_vhost_net(NetClientState *nc)
switch (nc->info->type) {
case NET_CLIENT_DRIVER_TAP:
vhost_net = tap_get_vhost_net(nc);
- assert(vhost_net);
+ /*
+ * tap_get_vhost_net() can return NULL if a tap net-device backend is
+ * created with 'vhost=off' option, 'vhostforce=off' or no vhost or
+ * vhostforce or vhostfd options at all. Please see net_init_tap_one().
+ * Hence, we omit the assertion here.
+ */
break;
#ifdef CONFIG_VHOST_NET_USER
case NET_CLIENT_DRIVER_VHOST_USER:
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index fd917fcda1..355668bdf8 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -43,7 +43,14 @@
* subsys=<subsys_id>
* -device nvme-ns,drive=<drive_id>,bus=<bus_name>,nsid=<nsid>,\
* zoned=<true|false[optional]>, \
- * subsys=<subsys_id>,detached=<true|false[optional]>
+ * subsys=<subsys_id>,shared=<true|false[optional]>, \
+ * detached=<true|false[optional]>, \
+ * zoned.zone_size=<N[optional]>, \
+ * zoned.zone_capacity=<N[optional]>, \
+ * zoned.descr_ext_size=<N[optional]>, \
+ * zoned.max_active=<N[optional]>, \
+ * zoned.max_open=<N[optional]>, \
+ * zoned.cross_read=<true|false[optional]>
*
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
* offset 0 in BAR2 and supports only WDS, RDS and SQS for now. By default, the
@@ -1748,6 +1755,7 @@ static void nvme_aio_err(NvmeRequest *req, int ret)
case NVME_CMD_WRITE:
case NVME_CMD_WRITE_ZEROES:
case NVME_CMD_ZONE_APPEND:
+ case NVME_CMD_COPY:
status = NVME_WRITE_FAULT;
break;
default:
@@ -2847,6 +2855,25 @@ static void nvme_copy_source_range_parse(void *ranges, int idx, uint8_t format,
}
}
+static inline uint16_t nvme_check_copy_mcl(NvmeNamespace *ns,
+ NvmeCopyAIOCB *iocb, uint16_t nr)
+{
+ uint32_t copy_len = 0;
+
+ for (int idx = 0; idx < nr; idx++) {
+ uint32_t nlb;
+ nvme_copy_source_range_parse(iocb->ranges, idx, iocb->format, NULL,
+ &nlb, NULL, NULL, NULL);
+ copy_len += nlb + 1;
+ }
+
+ if (copy_len > ns->id_ns.mcl) {
+ return NVME_CMD_SIZE_LIMIT | NVME_DNR;
+ }
+
+ return NVME_SUCCESS;
+}
+
static void nvme_copy_out_completed_cb(void *opaque, int ret)
{
NvmeCopyAIOCB *iocb = opaque;
@@ -3159,6 +3186,11 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
}
}
+ status = nvme_check_copy_mcl(ns, iocb, nr);
+ if (status) {
+ goto invalid;
+ }
+
iocb->req = req;
iocb->ret = 0;
iocb->nr = nr;
diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c
index 547c0b1543..44aba8f4d9 100644
--- a/hw/nvme/ns.c
+++ b/hw/nvme/ns.c
@@ -400,8 +400,9 @@ static bool nvme_ns_init_fdp(NvmeNamespace *ns, Error **errp)
NvmeRuHandle *ruh;
uint8_t lbafi = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
g_autofree unsigned int *ruhids = NULL;
- unsigned int *ruhid;
- char *r, *p, *token;
+ unsigned int n, m, *ruhid;
+ const char *endptr, *token;
+ char *r, *p;
uint16_t *ph;
if (!ns->params.fdp.ruhs) {
@@ -438,23 +439,55 @@ static bool nvme_ns_init_fdp(NvmeNamespace *ns, Error **errp)
/* parse the placement handle identifiers */
while ((token = qemu_strsep(&p, ";")) != NULL) {
- ns->fdp.nphs += 1;
- if (ns->fdp.nphs > NVME_FDP_MAXPIDS ||
- ns->fdp.nphs == endgrp->fdp.nruh) {
- error_setg(errp, "too many placement handles");
+ if (qemu_strtoui(token, &endptr, 0, &n) < 0) {
+ error_setg(errp, "cannot parse reclaim unit handle identifier");
free(r);
return false;
}
- if (qemu_strtoui(token, NULL, 0, ruhid++) < 0) {
- error_setg(errp, "cannot parse reclaim unit handle identifier");
- free(r);
- return false;
+ m = n;
+
+ /* parse range */
+ if (*endptr == '-') {
+ token = endptr + 1;
+
+ if (qemu_strtoui(token, NULL, 0, &m) < 0) {
+ error_setg(errp, "cannot parse reclaim unit handle identifier");
+ free(r);
+ return false;
+ }
+
+ if (m < n) {
+ error_setg(errp, "invalid reclaim unit handle identifier range");
+ free(r);
+ return false;
+ }
+ }
+
+ for (; n <= m; n++) {
+ if (ns->fdp.nphs++ == endgrp->fdp.nruh) {
+ error_setg(errp, "too many placement handles");
+ free(r);
+ return false;
+ }
+
+ *ruhid++ = n;
}
}
free(r);
+ /* verify that the ruhids are unique */
+ for (unsigned int i = 0; i < ns->fdp.nphs; i++) {
+ for (unsigned int j = i + 1; j < ns->fdp.nphs; j++) {
+ if (ruhids[i] == ruhids[j]) {
+ error_setg(errp, "duplicate reclaim unit handle identifier: %u",
+ ruhids[i]);
+ return false;
+ }
+ }
+ }
+
ph = ns->fdp.phs = g_new(uint16_t, ns->fdp.nphs);
ruhid = ruhids;
diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c
index 24ddec860e..d30bb8bfd5 100644
--- a/hw/nvme/subsys.c
+++ b/hw/nvme/subsys.c
@@ -158,8 +158,10 @@ static bool nvme_subsys_setup_fdp(NvmeSubsystem *subsys, Error **errp)
endgrp->fdp.nrg = subsys->params.fdp.nrg;
- if (!subsys->params.fdp.nruh) {
- error_setg(errp, "fdp.nruh must be non-zero");
+ if (!subsys->params.fdp.nruh ||
+ subsys->params.fdp.nruh > NVME_FDP_MAXPIDS) {
+ error_setg(errp, "fdp.nruh must be non-zero and less than %u",
+ NVME_FDP_MAXPIDS);
return false;
}
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index b6eb599751..67793a86f1 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -765,7 +765,9 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env)
tlb->mas7_3 = 0;
tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+#ifdef CONFIG_KVM
env->tlb_dirty = true;
+#endif
}
static void ppce500_cpu_reset_sec(void *opaque)
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index d57b199797..bbce63e8a4 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -83,7 +83,9 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
tlb->mas7_3 = pa & TARGET_PAGE_MASK;
tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
+#ifdef CONFIG_KVM
env->tlb_dirty = true;
+#endif
}
static void spin_kick(CPUState *cs, run_on_cpu_data data)
diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c
index 18d96a1d04..a926f61ebe 100644
--- a/hw/remote/proxy-memory-listener.c
+++ b/hw/remote/proxy-memory-listener.c
@@ -217,7 +217,7 @@ void proxy_memory_listener_configure(ProxyMemoryListener *proxy_listener,
proxy_listener->listener.commit = proxy_memory_listener_commit;
proxy_listener->listener.region_add = proxy_memory_listener_region_addnop;
proxy_listener->listener.region_nop = proxy_memory_listener_region_addnop;
- proxy_listener->listener.priority = 10;
+ proxy_listener->listener.priority = MEMORY_LISTENER_PRIORITY_DEV_BACKEND;
proxy_listener->listener.name = "proxy";
memory_listener_register(&proxy_listener->listener,
diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c
index 6725cc61fd..ab3c4ec346 100644
--- a/hw/sparc64/niagara.c
+++ b/hw/sparc64/niagara.c
@@ -23,6 +23,7 @@
*/
#include "qemu/osdep.h"
+#include "block/block_int-common.h"
#include "qemu/units.h"
#include "cpu.h"
#include "hw/boards.h"
@@ -143,9 +144,10 @@ static void niagara_init(MachineState *machine)
memory_region_add_subregion(get_system_memory(),
NIAGARA_VDISK_BASE, &s->vdisk_ram);
dinfo->is_default = 1;
- rom_add_file_fixed(blk_name(blk), NIAGARA_VDISK_BASE, -1);
+ rom_add_file_fixed(blk_bs(blk)->filename, NIAGARA_VDISK_BASE, -1);
} else {
- error_report("could not load ram disk '%s'", blk_name(blk));
+ error_report("could not load ram disk '%s'",
+ blk_bs(blk)->filename);
exit(1);
}
}
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index d116c2d6a1..82394331bf 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1444,7 +1444,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
.log_sync = vhost_log_sync,
.log_global_start = vhost_log_global_start,
.log_global_stop = vhost_log_global_stop,
- .priority = 10
+ .priority = MEMORY_LISTENER_PRIORITY_DEV_BACKEND
};
hdev->iommu_listener = (MemoryListener) {
diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c
index 42339c96bd..886c3ee944 100644
--- a/hw/xen/xen-hvm-common.c
+++ b/hw/xen/xen-hvm-common.c
@@ -155,7 +155,7 @@ MemoryListener xen_io_listener = {
.name = "xen-io",
.region_add = xen_io_add,
.region_del = xen_io_del,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
};
DeviceListener xen_device_listener = {
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index a540149639..36e6f93c37 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -691,14 +691,14 @@ static const MemoryListener xen_pt_memory_listener = {
.name = "xen-pt-mem",
.region_add = xen_pt_region_add,
.region_del = xen_pt_region_del,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
};
static const MemoryListener xen_pt_io_listener = {
.name = "xen-pt-io",
.region_add = xen_pt_io_region_add,
.region_del = xen_pt_io_region_del,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
};
/* destroy. */
diff --git a/include/block/block-io.h b/include/block/block-io.h
index 43af816d75..4415506e40 100644
--- a/include/block/block-io.h
+++ b/include/block/block-io.h
@@ -224,6 +224,13 @@ bdrv_co_debug_event(BlockDriverState *bs, BlkdebugEvent event);
void co_wrapper_mixed_bdrv_rdlock
bdrv_debug_event(BlockDriverState *bs, BlkdebugEvent event);
+#define BLKDBG_CO_EVENT(child, evt) \
+ do { \
+ if (child) { \
+ bdrv_co_debug_event(child->bs, evt); \
+ } \
+ } while (0)
+
#define BLKDBG_EVENT(child, evt) \
do { \
if (child) { \
diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
index 7574a2de5b..7e04f98ff0 100644
--- a/include/block/graph-lock.h
+++ b/include/block/graph-lock.h
@@ -111,10 +111,12 @@ void unregister_aiocontext(AioContext *ctx);
* The wrlock can only be taken from the main loop, with BQL held, as only the
* main loop is allowed to modify the graph.
*
+ * If @bs is non-NULL, its AioContext is temporarily released.
+ *
* This function polls. Callers must not hold the lock of any AioContext other
- * than the current one.
+ * than the current one and the one of @bs.
*/
-void bdrv_graph_wrlock(void) TSA_ACQUIRE(graph_lock) TSA_NO_TSA;
+void bdrv_graph_wrlock(BlockDriverState *bs) TSA_ACQUIRE(graph_lock) TSA_NO_TSA;
/*
* bdrv_graph_wrunlock:
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 47c2e0221c..7f5c11a0cc 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -811,6 +811,10 @@ struct IOMMUMemoryRegion {
#define IOMMU_NOTIFIER_FOREACH(n, mr) \
QLIST_FOREACH((n), &(mr)->iommu_notify, node)
+#define MEMORY_LISTENER_PRIORITY_MIN 0
+#define MEMORY_LISTENER_PRIORITY_ACCEL 10
+#define MEMORY_LISTENER_PRIORITY_DEV_BACKEND 10
+
/**
* struct MemoryListener: callbacks structure for updates to the physical memory map
*
diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h
index 7e9482dee2..5669a5b811 100644
--- a/include/hw/char/escc.h
+++ b/include/hw/char/escc.h
@@ -45,6 +45,7 @@ typedef struct ESCCChannelState {
ESCCChnType type;
uint8_t rx, tx;
QemuInputHandlerState *hs;
+ char *sunkbd_layout;
} ESCCChannelState;
struct ESCCState {
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index eda0230a02..b08f8b7079 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -241,9 +241,6 @@ typedef struct SavedIOTLB {
struct KVMState;
struct kvm_run;
-struct hax_vcpu_state;
-struct hvf_vcpu_state;
-
/* work queue */
/* The union type allows passing of 64 bit target pointers on 32 bit
@@ -309,6 +306,7 @@ struct qemu_work_item;
* @next_cpu: Next CPU sharing TB cache.
* @opaque: User data.
* @mem_io_pc: Host Program Counter at which the memory was accessed.
+ * @accel: Pointer to accelerator specific state.
* @kvm_fd: vCPU file descriptor for KVM.
* @work_mutex: Lock to prevent multiple access to @work_list.
* @work_list: List of pending asynchronous work.
@@ -338,7 +336,6 @@ struct CPUState {
struct QemuThread *thread;
#ifdef _WIN32
- HANDLE hThread;
QemuSemaphore sem;
#endif
int thread_id;
@@ -424,6 +421,7 @@ struct CPUState {
uint32_t can_do_io;
int32_t exception_index;
+ AccelCPUState *accel;
/* shared by kvm, hax and hvf */
bool vcpu_dirty;
@@ -443,10 +441,6 @@ struct CPUState {
/* Used for user-only emulation of prctl(PR_SET_UNALIGN). */
bool prctl_unalign_sigbus;
- struct hax_vcpu_state *hax_vcpu;
-
- struct hvf_vcpu_state *hvf;
-
/* track IOMMUs whose translations we've cached in the TCG TLB */
GArray *iommu_notifiers;
};
diff --git a/include/hw/intc/arm_gic.h b/include/hw/intc/arm_gic.h
index 116ccbb5a9..48f6a51a70 100644
--- a/include/hw/intc/arm_gic.h
+++ b/include/hw/intc/arm_gic.h
@@ -86,4 +86,6 @@ struct ARMGICClass {
DeviceRealize parent_realize;
};
+const char *gic_class_name(void);
+
#endif
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index ab5182a28a..4e2fb518e7 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -329,4 +329,14 @@ struct ARMGICv3CommonClass {
void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
const MemoryRegionOps *ops);
+/**
+ * gicv3_class_name
+ *
+ * Return name of GICv3 class to use depending on whether KVM acceleration is
+ * in use. May throw an error if the chosen implementation is not available.
+ *
+ * Returns: class name to use
+ */
+const char *gicv3_class_name(void);
+
#endif
diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h
index a11a0f6654..7dc712b38d 100644
--- a/include/hw/intc/arm_gicv3_its_common.h
+++ b/include/hw/intc/arm_gicv3_its_common.h
@@ -122,5 +122,14 @@ struct GICv3ITSCommonClass {
void (*post_load)(GICv3ITSState *s);
};
+/**
+ * its_class_name:
+ *
+ * Return the ITS class name to use depending on whether KVM acceleration
+ * and KVM CAP_SIGNAL_MSI are supported
+ *
+ * Returns: class name to use or NULL
+ */
+const char *its_class_name(void);
#endif
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 2e28507efe..7a5f8056ea 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -48,6 +48,9 @@ struct virtio_gpu_simple_resource {
unsigned int iov_cnt;
uint32_t scanout_bitmask;
pixman_image_t *image;
+#ifdef WIN32
+ HANDLE handle;
+#endif
uint64_t hostmem;
uint64_t blob_size;
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 8c1840bfc1..834b0e47a0 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -21,6 +21,7 @@
* Incomplete struct types
* Please keep this list in case-insensitive alphabetical order.
*/
+typedef struct AccelCPUState AccelCPUState;
typedef struct AccelState AccelState;
typedef struct AdapterInfo AdapterInfo;
typedef struct AddressSpace AddressSpace;
diff --git a/include/sysemu/hax.h b/include/sysemu/hax.h
index bf8f99a824..80fc716f80 100644
--- a/include/sysemu/hax.h
+++ b/include/sysemu/hax.h
@@ -19,6 +19,8 @@
*
*/
+/* header to be included in non-HAX-specific code */
+
#ifndef QEMU_HAX_H
#define QEMU_HAX_H
diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h
index 6ab119e49f..718beddcdd 100644
--- a/include/sysemu/hvf_int.h
+++ b/include/sysemu/hvf_int.h
@@ -49,7 +49,7 @@ struct HVFState {
};
extern HVFState *hvf_state;
-struct hvf_vcpu_state {
+struct AccelCPUState {
uint64_t fd;
void *exit;
bool vtimer_masked;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 88f5ccfbce..115f0cca79 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -11,9 +11,12 @@
*
*/
+/* header to be included in non-KVM-specific code */
+
#ifndef QEMU_KVM_H
#define QEMU_KVM_H
+#include "exec/memattrs.h"
#include "qemu/accel.h"
#include "qom/object.h"
diff --git a/include/sysemu/nvmm.h b/include/sysemu/nvmm.h
index 833670fccb..be7bc9a62d 100644
--- a/include/sysemu/nvmm.h
+++ b/include/sysemu/nvmm.h
@@ -7,6 +7,8 @@
* See the COPYING file in the top-level directory.
*/
+/* header to be included in non-NVMM-specific code */
+
#ifndef QEMU_NVMM_H
#define QEMU_NVMM_H
diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h
index 65f6c9ea57..91aa0d7ec0 100644
--- a/include/sysemu/os-win32.h
+++ b/include/sysemu/os-win32.h
@@ -263,6 +263,9 @@ EXCEPTION_DISPOSITION
win32_close_exception_handler(struct _EXCEPTION_RECORD*, void*,
struct _CONTEXT*, void*);
+void *qemu_win32_map_alloc(size_t size, HANDLE *h, Error **errp);
+void qemu_win32_map_free(void *ptr, HANDLE h, Error **errp);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/sysemu/tcg.h b/include/sysemu/tcg.h
index 53352450ff..5e2ca9aab3 100644
--- a/include/sysemu/tcg.h
+++ b/include/sysemu/tcg.h
@@ -5,6 +5,8 @@
* See the COPYING file in the top-level directory.
*/
+/* header to be included in non-TCG-specific code */
+
#ifndef SYSEMU_TCG_H
#define SYSEMU_TCG_H
diff --git a/include/sysemu/whpx.h b/include/sysemu/whpx.h
index 2889fa2278..781ca5b2b6 100644
--- a/include/sysemu/whpx.h
+++ b/include/sysemu/whpx.h
@@ -10,6 +10,8 @@
*
*/
+/* header to be included in non-WHPX-specific code */
+
#ifndef QEMU_WHPX_H
#define QEMU_WHPX_H
diff --git a/include/sysemu/xen.h b/include/sysemu/xen.h
index 0ca25697e4..bc13ad5692 100644
--- a/include/sysemu/xen.h
+++ b/include/sysemu/xen.h
@@ -5,6 +5,8 @@
* See the COPYING file in the top-level directory.
*/
+/* header to be included in non-Xen-specific code */
+
#ifndef SYSEMU_XEN_H
#define SYSEMU_XEN_H
diff --git a/include/ui/console.h b/include/ui/console.h
index ae5ec466c1..f27b2aad4f 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -5,6 +5,7 @@
#include "qom/object.h"
#include "qemu/notify.h"
#include "qapi/qapi-types-ui.h"
+#include "ui/input.h"
#ifdef CONFIG_OPENGL
# include <epoxy/gl.h>
@@ -95,6 +96,20 @@ bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl);
void kbd_put_string_console(QemuConsole *s, const char *str, int len);
void kbd_put_keysym(int keysym);
+/* Touch devices */
+typedef struct touch_slot {
+ int x;
+ int y;
+ int tracking_id;
+} touch_slot;
+
+void console_handle_touch_event(QemuConsole *con,
+ struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
+ uint64_t num_slot,
+ int width, int height,
+ double x, double y,
+ InputMultiTouchType type,
+ Error **errp);
/* consoles */
#define TYPE_QEMU_CONSOLE "qemu-console"
@@ -117,6 +132,7 @@ typedef struct ScanoutTexture {
uint32_t y;
uint32_t width;
uint32_t height;
+ void *d3d_tex2d;
} ScanoutTexture;
typedef struct DisplaySurface {
@@ -128,6 +144,10 @@ typedef struct DisplaySurface {
GLenum gltype;
GLuint texture;
#endif
+#ifdef WIN32
+ HANDLE handle;
+ uint32_t handle_offset;
+#endif
} DisplaySurface;
typedef struct QemuUIInfo {
@@ -251,7 +271,8 @@ typedef struct DisplayChangeListenerOps {
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h);
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d);
/* optional (default to true if has dpy_gl_scanout_dmabuf) */
bool (*dpy_has_dmabuf)(DisplayChangeListener *dcl);
/* optional */
@@ -314,6 +335,10 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image);
DisplaySurface *qemu_create_placeholder_surface(int w, int h,
const char *msg);
+#ifdef WIN32
+void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
+ HANDLE h, uint32_t offset);
+#endif
PixelFormat qemu_default_pixelformat(int bpp);
DisplaySurface *qemu_create_displaysurface(int width, int height);
@@ -355,7 +380,8 @@ void dpy_gl_scanout_disable(QemuConsole *con);
void dpy_gl_scanout_texture(QemuConsole *con,
uint32_t backing_id, bool backing_y_0_top,
uint32_t backing_width, uint32_t backing_height,
- uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+ uint32_t x, uint32_t y, uint32_t w, uint32_t h,
+ void *d3d_tex2d);
void dpy_gl_scanout_dmabuf(QemuConsole *con,
QemuDmaBuf *dmabuf);
void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h
index 53d953ddf4..4b8c0d2281 100644
--- a/include/ui/egl-helpers.h
+++ b/include/ui/egl-helpers.h
@@ -12,6 +12,7 @@
extern EGLDisplay *qemu_egl_display;
extern EGLConfig qemu_egl_config;
extern DisplayGLMode qemu_egl_mode;
+extern bool qemu_egl_angle_d3d;
typedef struct egl_fb {
int width;
@@ -31,16 +32,18 @@ void egl_fb_setup_for_tex(egl_fb *fb, int width, int height,
void egl_fb_setup_new_tex(egl_fb *fb, int width, int height);
void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip);
void egl_fb_read(DisplaySurface *dst, egl_fb *src);
+void egl_fb_read_rect(DisplaySurface *dst, egl_fb *src, int x, int y, int w, int h);
void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip);
void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip,
int x, int y, double scale_x, double scale_y);
+extern EGLContext qemu_egl_rn_ctx;
+
#ifdef CONFIG_GBM
extern int qemu_egl_rn_fd;
extern struct gbm_device *qemu_egl_rn_gbm_dev;
-extern EGLContext qemu_egl_rn_ctx;
int egl_rendernode_init(const char *rendernode, DisplayGLMode mode);
int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc,
@@ -62,9 +65,15 @@ int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode);
#endif
+#ifdef WIN32
+int qemu_egl_init_dpy_win32(EGLNativeDisplayType dpy, DisplayGLMode mode);
+#endif
+
EGLContext qemu_egl_init_ctx(void);
bool qemu_egl_has_dmabuf(void);
bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp);
+const char *qemu_egl_get_error_string(void);
+
#endif /* EGL_HELPERS_H */
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index ae0f53740d..aa3d637029 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -175,7 +175,8 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h);
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d);
void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
QemuDmaBuf *dmabuf);
void gd_egl_cursor_dmabuf(DisplayChangeListener *dcl,
@@ -211,7 +212,8 @@ void gd_gl_area_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h);
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d);
void gd_gl_area_scanout_disable(DisplayChangeListener *dcl);
void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h
index 8fb7e08262..e3acc7c82a 100644
--- a/include/ui/sdl2.h
+++ b/include/ui/sdl2.h
@@ -90,7 +90,8 @@ void sdl2_gl_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h);
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d);
void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h);
diff --git a/meson.build b/meson.build
index b409788832..a9ba0bfab3 100644
--- a/meson.build
+++ b/meson.build
@@ -661,8 +661,8 @@ endif
if get_option('whpx').allowed() and targetos == 'windows'
if get_option('whpx').enabled() and host_machine.cpu() != 'x86_64'
error('WHPX requires 64-bit host')
- elif cc.has_header('WinHvPlatform.h', required: get_option('whpx')) and \
- cc.has_header('WinHvEmulation.h', required: get_option('whpx'))
+ elif cc.has_header('winhvplatform.h', required: get_option('whpx')) and \
+ cc.has_header('winhvemulation.h', required: get_option('whpx'))
accelerators += 'CONFIG_WHPX'
endif
endif
@@ -838,6 +838,8 @@ if gdbus_codegen.found() and get_option('cfi')
gdbus_codegen_error = '@0@ uses gdbus-codegen, which does not support control flow integrity'
endif
+xml_pp = find_program('scripts/xml-preprocess.py')
+
lttng = not_found
if 'ust' in get_option('trace_backends')
lttng = dependency('lttng-ust', required: true, version: '>= 2.1',
@@ -1070,6 +1072,12 @@ if not get_option('virglrenderer').auto() or have_system or have_vhost_user_gpu
virgl = dependency('virglrenderer',
method: 'pkg-config',
required: get_option('virglrenderer'))
+ if virgl.found()
+ config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT',
+ cc.has_member('struct virgl_renderer_resource_info_ext', 'd3d_tex2d',
+ prefix: '#include <virglrenderer.h>',
+ dependencies: virgl))
+ endif
endif
blkio = not_found
if not get_option('blkio').auto() or have_block
@@ -1985,8 +1993,6 @@ dbus_display = get_option('dbus_display') \
error_message: '-display dbus requires glib>=2.64') \
.require(gdbus_codegen.found(),
error_message: gdbus_codegen_error.format('-display dbus')) \
- .require(targetos != 'windows',
- error_message: '-display dbus is not available on Windows') \
.allowed()
have_virtfs = get_option('virtfs') \
diff --git a/qapi/ui.json b/qapi/ui.json
index 2755395483..bb06fb6039 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1484,8 +1484,7 @@
{ 'name': 'none' },
{ 'name': 'gtk', 'if': 'CONFIG_GTK' },
{ 'name': 'sdl', 'if': 'CONFIG_SDL' },
- { 'name': 'egl-headless',
- 'if': { 'all': ['CONFIG_OPENGL', 'CONFIG_GBM'] } },
+ { 'name': 'egl-headless', 'if': 'CONFIG_OPENGL' },
{ 'name': 'curses', 'if': 'CONFIG_CURSES' },
{ 'name': 'cocoa', 'if': 'CONFIG_COCOA' },
{ 'name': 'spice-app', 'if': 'CONFIG_SPICE' },
@@ -1525,7 +1524,7 @@
'cocoa': { 'type': 'DisplayCocoa', 'if': 'CONFIG_COCOA' },
'curses': { 'type': 'DisplayCurses', 'if': 'CONFIG_CURSES' },
'egl-headless': { 'type': 'DisplayEGLHeadless',
- 'if': { 'all': ['CONFIG_OPENGL', 'CONFIG_GBM'] } },
+ 'if': 'CONFIG_OPENGL' },
'dbus': { 'type': 'DisplayDBus', 'if': 'CONFIG_DBUS_DISPLAY' },
'sdl': { 'type': 'DisplaySDL', 'if': 'CONFIG_SDL' }
}
diff --git a/scripts/meson.build b/scripts/meson.build
index 1c89e10a76..532277f5a2 100644
--- a/scripts/meson.build
+++ b/scripts/meson.build
@@ -1,3 +1,5 @@
if stap.found()
install_data('qemu-trace-stap', install_dir: get_option('bindir'))
endif
+
+test('xml-preprocess', files('xml-preprocess-test.py'), suite: ['unit'])
diff --git a/scripts/xml-preprocess-test.py b/scripts/xml-preprocess-test.py
new file mode 100644
index 0000000000..dd92579969
--- /dev/null
+++ b/scripts/xml-preprocess-test.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2023 Red Hat, Inc.
+#
+# SPDX-License-Identifier: MIT
+"""Unit tests for xml-preprocess"""
+
+import contextlib
+import importlib
+import os
+import platform
+import subprocess
+import tempfile
+import unittest
+from io import StringIO
+
+xmlpp = importlib.import_module("xml-preprocess")
+
+
+class TestXmlPreprocess(unittest.TestCase):
+ """Tests for xml-preprocess.Preprocessor"""
+
+ def test_preprocess_xml(self):
+ with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_file:
+ temp_file.write("<root></root>")
+ temp_file_name = temp_file.name
+ result = xmlpp.preprocess_xml(temp_file_name)
+ self.assertEqual(result, "<root></root>")
+ os.remove(temp_file_name)
+
+ def test_save_xml(self):
+ with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_file:
+ temp_file_name = temp_file.name
+ xmlpp.save_xml("<root></root>", temp_file_name)
+ self.assertTrue(os.path.isfile(temp_file_name))
+ os.remove(temp_file_name)
+
+ def test_include(self):
+ with tempfile.NamedTemporaryFile(mode="w", delete=False) as inc_file:
+ inc_file.write("<included>Content from included file</included>")
+ inc_file_name = inc_file.name
+ xml_str = f"<?include {inc_file_name} ?>"
+ expected = "<included>Content from included file</included>"
+ xpp = xmlpp.Preprocessor()
+ result = xpp.preprocess(xml_str)
+ self.assertEqual(result, expected)
+ os.remove(inc_file_name)
+ self.assertRaises(FileNotFoundError, xpp.preprocess, xml_str)
+
+ def test_envvar(self):
+ os.environ["TEST_ENV_VAR"] = "TestValue"
+ xml_str = "<root>$(env.TEST_ENV_VAR)</root>"
+ expected = "<root>TestValue</root>"
+ xpp = xmlpp.Preprocessor()
+ result = xpp.preprocess(xml_str)
+ self.assertEqual(result, expected)
+ self.assertRaises(KeyError, xpp.preprocess, "$(env.UNKNOWN)")
+
+ def test_sys_var(self):
+ xml_str = "<root>$(sys.ARCH)</root>"
+ expected = f"<root>{platform.architecture()[0]}</root>"
+ xpp = xmlpp.Preprocessor()
+ result = xpp.preprocess(xml_str)
+ self.assertEqual(result, expected)
+ self.assertRaises(KeyError, xpp.preprocess, "$(sys.UNKNOWN)")
+
+ def test_cus_var(self):
+ xml_str = "<root>$(var.USER)</root>"
+ expected = "<root></root>"
+ xpp = xmlpp.Preprocessor()
+ result = xpp.preprocess(xml_str)
+ self.assertEqual(result, expected)
+ xml_str = "<?define USER=FOO?><root>$(var.USER)</root>"
+ expected = "<root>FOO</root>"
+ xpp = xmlpp.Preprocessor()
+ result = xpp.preprocess(xml_str)
+ self.assertEqual(result, expected)
+
+ def test_error_warning(self):
+ xml_str = "<root><?warning \"test warn\"?></root>"
+ expected = "<root></root>"
+ xpp = xmlpp.Preprocessor()
+ out = StringIO()
+ with contextlib.redirect_stdout(out):
+ result = xpp.preprocess(xml_str)
+ self.assertEqual(result, expected)
+ self.assertEqual(out.getvalue(), "[Warning]: test warn\n")
+ self.assertRaises(RuntimeError, xpp.preprocess, "<?error \"test\"?>")
+
+ def test_cmd(self):
+ xpp = xmlpp.Preprocessor()
+ result = xpp.preprocess('<root><?cmd "echo hello world"?></root>')
+ self.assertEqual(result, "<root>hello world</root>")
+ self.assertRaises(
+ subprocess.CalledProcessError,
+ xpp.preprocess, '<?cmd "test-unknown-cmd"?>'
+ )
+
+ def test_foreach(self):
+ xpp = xmlpp.Preprocessor()
+ result = xpp.preprocess(
+ '<root><?foreach x in a;b;c?>$(var.x)<?endforeach?></root>'
+ )
+ self.assertEqual(result, "<root>abc</root>")
+
+ def test_if_elseif(self):
+ xpp = xmlpp.Preprocessor()
+ result = xpp.preprocess('<root><?if True?>ok<?endif?></root>')
+ self.assertEqual(result, "<root>ok</root>")
+ result = xpp.preprocess('<root><?if False?>ok<?endif?></root>')
+ self.assertEqual(result, "<root></root>")
+ result = xpp.preprocess('<root><?if True?>ok<?else?>ko<?endif?></root>')
+ self.assertEqual(result, "<root>ok</root>")
+ result = xpp.preprocess('<root><?if False?>ok<?else?>ko<?endif?></root>')
+ self.assertEqual(result, "<root>ko</root>")
+ result = xpp.preprocess(
+ '<root><?if False?>ok<?elseif True?>ok2<?else?>ko<?endif?></root>'
+ )
+ self.assertEqual(result, "<root>ok2</root>")
+ result = xpp.preprocess(
+ '<root><?if False?>ok<?elseif False?>ok<?else?>ko<?endif?></root>'
+ )
+ self.assertEqual(result, "<root>ko</root>")
+
+ def test_ifdef(self):
+ xpp = xmlpp.Preprocessor()
+ result = xpp.preprocess('<root><?ifdef USER?>ok<?else?>ko<?endif?></root>')
+ self.assertEqual(result, "<root>ko</root>")
+ result = xpp.preprocess(
+ '<?define USER=FOO?><root><?ifdef USER?>ok<?else?>ko<?endif?></root>'
+ )
+ self.assertEqual(result, "<root>ok</root>")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/scripts/xml-preprocess.py b/scripts/xml-preprocess.py
new file mode 100755
index 0000000000..57f1d28912
--- /dev/null
+++ b/scripts/xml-preprocess.py
@@ -0,0 +1,293 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2017-2019 Tony Su
+# Copyright (c) 2023 Red Hat, Inc.
+#
+# SPDX-License-Identifier: MIT
+#
+# Adapted from https://github.com/peitaosu/XML-Preprocessor
+#
+"""This is a XML Preprocessor which can be used to process your XML file before
+you use it, to process conditional statements, variables, iteration
+statements, error/warning, execute command, etc.
+
+## XML Schema
+
+### Include Files
+```
+<?include path/to/file ?>
+```
+
+### Variables
+```
+$(env.EnvironmentVariable)
+
+$(sys.SystemVariable)
+
+$(var.CustomVariable)
+```
+
+### Conditional Statements
+```
+<?if ?>
+
+<?ifdef ?>
+
+<?ifndef ?>
+
+<?else?>
+
+<?elseif ?>
+
+<?endif?>
+```
+
+### Iteration Statements
+```
+<?foreach VARNAME in 1;2;3?>
+ $(var.VARNAME)
+<?endforeach?>
+```
+
+### Errors and Warnings
+```
+<?error "This is error message!" ?>
+
+<?warning "This is warning message!" ?>
+```
+
+### Commands
+```
+<? cmd "echo hello world" ?>
+```
+"""
+
+import os
+import platform
+import re
+import subprocess
+import sys
+from typing import Optional
+from xml.dom import minidom
+
+
+class Preprocessor():
+ """This class holds the XML preprocessing state"""
+
+ def __init__(self):
+ self.sys_vars = {
+ "ARCH": platform.architecture()[0],
+ "SOURCE": os.path.abspath(__file__),
+ "CURRENT": os.getcwd(),
+ }
+ self.cus_vars = {}
+
+ def _pp_include(self, xml_str: str) -> str:
+ include_regex = r"(<\?include([\w\s\\/.:_-]+)\s*\?>)"
+ matches = re.findall(include_regex, xml_str)
+ for group_inc, group_xml in matches:
+ inc_file_path = group_xml.strip()
+ with open(inc_file_path, "r", encoding="utf-8") as inc_file:
+ inc_file_content = inc_file.read()
+ xml_str = xml_str.replace(group_inc, inc_file_content)
+ return xml_str
+
+ def _pp_env_var(self, xml_str: str) -> str:
+ envvar_regex = r"(\$\(env\.(\w+)\))"
+ matches = re.findall(envvar_regex, xml_str)
+ for group_env, group_var in matches:
+ xml_str = xml_str.replace(group_env, os.environ[group_var])
+ return xml_str
+
+ def _pp_sys_var(self, xml_str: str) -> str:
+ sysvar_regex = r"(\$\(sys\.(\w+)\))"
+ matches = re.findall(sysvar_regex, xml_str)
+ for group_sys, group_var in matches:
+ xml_str = xml_str.replace(group_sys, self.sys_vars[group_var])
+ return xml_str
+
+ def _pp_cus_var(self, xml_str: str) -> str:
+ define_regex = r"(<\?define\s*(\w+)\s*=\s*([\w\s\"]+)\s*\?>)"
+ matches = re.findall(define_regex, xml_str)
+ for group_def, group_name, group_var in matches:
+ group_name = group_name.strip()
+ group_var = group_var.strip().strip("\"")
+ self.cus_vars[group_name] = group_var
+ xml_str = xml_str.replace(group_def, "")
+ cusvar_regex = r"(\$\(var\.(\w+)\))"
+ matches = re.findall(cusvar_regex, xml_str)
+ for group_cus, group_var in matches:
+ xml_str = xml_str.replace(
+ group_cus,
+ self.cus_vars.get(group_var, "")
+ )
+ return xml_str
+
+ def _pp_foreach(self, xml_str: str) -> str:
+ foreach_regex = r"(<\?foreach\s+(\w+)\s+in\s+([\w;]+)\s*\?>(.*)<\?endforeach\?>)"
+ matches = re.findall(foreach_regex, xml_str)
+ for group_for, group_name, group_vars, group_text in matches:
+ group_texts = ""
+ for var in group_vars.split(";"):
+ self.cus_vars[group_name] = var
+ group_texts += self._pp_cus_var(group_text)
+ xml_str = xml_str.replace(group_for, group_texts)
+ return xml_str
+
+ def _pp_error_warning(self, xml_str: str) -> str:
+ error_regex = r"<\?error\s*\"([^\"]+)\"\s*\?>"
+ matches = re.findall(error_regex, xml_str)
+ for group_var in matches:
+ raise RuntimeError("[Error]: " + group_var)
+ warning_regex = r"(<\?warning\s*\"([^\"]+)\"\s*\?>)"
+ matches = re.findall(warning_regex, xml_str)
+ for group_wrn, group_var in matches:
+ print("[Warning]: " + group_var)
+ xml_str = xml_str.replace(group_wrn, "")
+ return xml_str
+
+ def _pp_if_eval(self, xml_str: str) -> str:
+ ifelif_regex = (
+ r"(<\?(if|elseif)\s*([^\"\s=<>!]+)\s*([!=<>]+)\s*\"*([^\"=<>!]+)\"*\s*\?>)"
+ )
+ matches = re.findall(ifelif_regex, xml_str)
+ for ifelif, tag, left, operator, right in matches:
+ if "<" in operator or ">" in operator:
+ result = eval(f"{left} {operator} {right}")
+ else:
+ result = eval(f'"{left}" {operator} "{right}"')
+ xml_str = xml_str.replace(ifelif, f"<?{tag} {result}?>")
+ return xml_str
+
+ def _pp_ifdef_ifndef(self, xml_str: str) -> str:
+ ifndef_regex = r"(<\?(ifdef|ifndef)\s*([\w]+)\s*\?>)"
+ matches = re.findall(ifndef_regex, xml_str)
+ for group_ifndef, group_tag, group_var in matches:
+ if group_tag == "ifdef":
+ result = group_var in self.cus_vars
+ else:
+ result = group_var not in self.cus_vars
+ xml_str = xml_str.replace(group_ifndef, f"<?if {result}?>")
+ return xml_str
+
+ def _pp_if_elseif(self, xml_str: str) -> str:
+ if_elif_else_regex = (
+ r"(<\?if\s(True|False)\?>"
+ r"(.*?)"
+ r"<\?elseif\s(True|False)\?>"
+ r"(.*?)"
+ r"<\?else\?>"
+ r"(.*?)"
+ r"<\?endif\?>)"
+ )
+ if_else_regex = (
+ r"(<\?if\s(True|False)\?>"
+ r"(.*?)"
+ r"<\?else\?>"
+ r"(.*?)"
+ r"<\?endif\?>)"
+ )
+ if_regex = r"(<\?if\s(True|False)\?>(.*?)<\?endif\?>)"
+ matches = re.findall(if_elif_else_regex, xml_str, re.DOTALL)
+ for (group_full, group_if, group_if_elif, group_elif,
+ group_elif_else, group_else) in matches:
+ result = ""
+ if group_if == "True":
+ result = group_if_elif
+ elif group_elif == "True":
+ result = group_elif_else
+ else:
+ result = group_else
+ xml_str = xml_str.replace(group_full, result)
+ matches = re.findall(if_else_regex, xml_str, re.DOTALL)
+ for group_full, group_if, group_if_else, group_else in matches:
+ result = ""
+ if group_if == "True":
+ result = group_if_else
+ else:
+ result = group_else
+ xml_str = xml_str.replace(group_full, result)
+ matches = re.findall(if_regex, xml_str, re.DOTALL)
+ for group_full, group_if, group_text in matches:
+ result = ""
+ if group_if == "True":
+ result = group_text
+ xml_str = xml_str.replace(group_full, result)
+ return xml_str
+
+ def _pp_command(self, xml_str: str) -> str:
+ cmd_regex = r"(<\?cmd\s*\"([^\"]+)\"\s*\?>)"
+ matches = re.findall(cmd_regex, xml_str)
+ for group_cmd, group_exec in matches:
+ output = subprocess.check_output(
+ group_exec, shell=True,
+ text=True, stderr=subprocess.STDOUT
+ )
+ xml_str = xml_str.replace(group_cmd, output)
+ return xml_str
+
+ def _pp_blanks(self, xml_str: str) -> str:
+ right_blank_regex = r">[\n\s\t\r]*"
+ left_blank_regex = r"[\n\s\t\r]*<"
+ xml_str = re.sub(right_blank_regex, ">", xml_str)
+ xml_str = re.sub(left_blank_regex, "<", xml_str)
+ return xml_str
+
+ def preprocess(self, xml_str: str) -> str:
+ fns = [
+ self._pp_blanks,
+ self._pp_include,
+ self._pp_foreach,
+ self._pp_env_var,
+ self._pp_sys_var,
+ self._pp_cus_var,
+ self._pp_if_eval,
+ self._pp_ifdef_ifndef,
+ self._pp_if_elseif,
+ self._pp_command,
+ self._pp_error_warning,
+ ]
+
+ while True:
+ changed = False
+ for func in fns:
+ out_xml = func(xml_str)
+ if not changed and out_xml != xml_str:
+ changed = True
+ xml_str = out_xml
+ if not changed:
+ break
+
+ return xml_str
+
+
+def preprocess_xml(path: str) -> str:
+ with open(path, "r", encoding="utf-8") as original_file:
+ input_xml = original_file.read()
+
+ proc = Preprocessor()
+ return proc.preprocess(input_xml)
+
+
+def save_xml(xml_str: str, path: Optional[str]):
+ xml = minidom.parseString(xml_str)
+ with open(path, "w", encoding="utf-8") if path else sys.stdout as output_file:
+ output_file.write(xml.toprettyxml())
+
+
+def main():
+ if len(sys.argv) < 2:
+ print("Usage: xml-preprocessor input.xml [output.xml]")
+ sys.exit(1)
+
+ output_file = None
+ if len(sys.argv) == 3:
+ output_file = sys.argv[2]
+
+ input_file = sys.argv[1]
+ output_xml = preprocess_xml(input_file)
+ save_xml(output_xml, output_file)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 00e675f58f..4d6c0f95d5 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -961,6 +961,7 @@ struct ArchCPU {
*/
uint32_t kvm_target;
+#ifdef CONFIG_KVM
/* KVM init features for this CPU */
uint32_t kvm_init_features[7];
@@ -973,6 +974,7 @@ struct ArchCPU {
/* KVM steal time */
OnOffAuto kvm_steal_time;
+#endif /* CONFIG_KVM */
/* Uniprocessor system with MP extensions */
bool mp_is_up;
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 8f72624586..8fce64bbf6 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -544,29 +544,29 @@ int hvf_get_registers(CPUState *cpu)
int i;
for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) {
- ret = hv_vcpu_get_reg(cpu->hvf->fd, hvf_reg_match[i].reg, &val);
+ ret = hv_vcpu_get_reg(cpu->accel->fd, hvf_reg_match[i].reg, &val);
*(uint64_t *)((void *)env + hvf_reg_match[i].offset) = val;
assert_hvf_ok(ret);
}
for (i = 0; i < ARRAY_SIZE(hvf_fpreg_match); i++) {
- ret = hv_vcpu_get_simd_fp_reg(cpu->hvf->fd, hvf_fpreg_match[i].reg,
+ ret = hv_vcpu_get_simd_fp_reg(cpu->accel->fd, hvf_fpreg_match[i].reg,
&fpval);
memcpy((void *)env + hvf_fpreg_match[i].offset, &fpval, sizeof(fpval));
assert_hvf_ok(ret);
}
val = 0;
- ret = hv_vcpu_get_reg(cpu->hvf->fd, HV_REG_FPCR, &val);
+ ret = hv_vcpu_get_reg(cpu->accel->fd, HV_REG_FPCR, &val);
assert_hvf_ok(ret);
vfp_set_fpcr(env, val);
val = 0;
- ret = hv_vcpu_get_reg(cpu->hvf->fd, HV_REG_FPSR, &val);
+ ret = hv_vcpu_get_reg(cpu->accel->fd, HV_REG_FPSR, &val);
assert_hvf_ok(ret);
vfp_set_fpsr(env, val);
- ret = hv_vcpu_get_reg(cpu->hvf->fd, HV_REG_CPSR, &val);
+ ret = hv_vcpu_get_reg(cpu->accel->fd, HV_REG_CPSR, &val);
assert_hvf_ok(ret);
pstate_write(env, val);
@@ -575,7 +575,7 @@ int hvf_get_registers(CPUState *cpu)
continue;
}
- if (cpu->hvf->guest_debug_enabled) {
+ if (cpu->accel->guest_debug_enabled) {
/* Handle debug registers */
switch (hvf_sreg_match[i].reg) {
case HV_SYS_REG_DBGBVR0_EL1:
@@ -661,7 +661,7 @@ int hvf_get_registers(CPUState *cpu)
}
}
- ret = hv_vcpu_get_sys_reg(cpu->hvf->fd, hvf_sreg_match[i].reg, &val);
+ ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_sreg_match[i].reg, &val);
assert_hvf_ok(ret);
arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
@@ -684,24 +684,24 @@ int hvf_put_registers(CPUState *cpu)
for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) {
val = *(uint64_t *)((void *)env + hvf_reg_match[i].offset);
- ret = hv_vcpu_set_reg(cpu->hvf->fd, hvf_reg_match[i].reg, val);
+ ret = hv_vcpu_set_reg(cpu->accel->fd, hvf_reg_match[i].reg, val);
assert_hvf_ok(ret);
}
for (i = 0; i < ARRAY_SIZE(hvf_fpreg_match); i++) {
memcpy(&fpval, (void *)env + hvf_fpreg_match[i].offset, sizeof(fpval));
- ret = hv_vcpu_set_simd_fp_reg(cpu->hvf->fd, hvf_fpreg_match[i].reg,
+ ret = hv_vcpu_set_simd_fp_reg(cpu->accel->fd, hvf_fpreg_match[i].reg,
fpval);
assert_hvf_ok(ret);
}
- ret = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_FPCR, vfp_get_fpcr(env));
+ ret = hv_vcpu_set_reg(cpu->accel->fd, HV_REG_FPCR, vfp_get_fpcr(env));
assert_hvf_ok(ret);
- ret = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_FPSR, vfp_get_fpsr(env));
+ ret = hv_vcpu_set_reg(cpu->accel->fd, HV_REG_FPSR, vfp_get_fpsr(env));
assert_hvf_ok(ret);
- ret = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_CPSR, pstate_read(env));
+ ret = hv_vcpu_set_reg(cpu->accel->fd, HV_REG_CPSR, pstate_read(env));
assert_hvf_ok(ret);
aarch64_save_sp(env, arm_current_el(env));
@@ -712,7 +712,7 @@ int hvf_put_registers(CPUState *cpu)
continue;
}
- if (cpu->hvf->guest_debug_enabled) {
+ if (cpu->accel->guest_debug_enabled) {
/* Handle debug registers */
switch (hvf_sreg_match[i].reg) {
case HV_SYS_REG_DBGBVR0_EL1:
@@ -789,11 +789,11 @@ int hvf_put_registers(CPUState *cpu)
}
val = arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx];
- ret = hv_vcpu_set_sys_reg(cpu->hvf->fd, hvf_sreg_match[i].reg, val);
+ ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_sreg_match[i].reg, val);
assert_hvf_ok(ret);
}
- ret = hv_vcpu_set_vtimer_offset(cpu->hvf->fd, hvf_state->vtimer_offset);
+ ret = hv_vcpu_set_vtimer_offset(cpu->accel->fd, hvf_state->vtimer_offset);
assert_hvf_ok(ret);
return 0;
@@ -814,7 +814,7 @@ static void hvf_set_reg(CPUState *cpu, int rt, uint64_t val)
flush_cpu_state(cpu);
if (rt < 31) {
- r = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_X0 + rt, val);
+ r = hv_vcpu_set_reg(cpu->accel->fd, HV_REG_X0 + rt, val);
assert_hvf_ok(r);
}
}
@@ -827,7 +827,7 @@ static uint64_t hvf_get_reg(CPUState *cpu, int rt)
flush_cpu_state(cpu);
if (rt < 31) {
- r = hv_vcpu_get_reg(cpu->hvf->fd, HV_REG_X0 + rt, &val);
+ r = hv_vcpu_get_reg(cpu->accel->fd, HV_REG_X0 + rt, &val);
assert_hvf_ok(r);
}
@@ -969,22 +969,22 @@ int hvf_arch_init_vcpu(CPUState *cpu)
assert(write_cpustate_to_list(arm_cpu, false));
/* Set CP_NO_RAW system registers on init */
- ret = hv_vcpu_set_sys_reg(cpu->hvf->fd, HV_SYS_REG_MIDR_EL1,
+ ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_MIDR_EL1,
arm_cpu->midr);
assert_hvf_ok(ret);
- ret = hv_vcpu_set_sys_reg(cpu->hvf->fd, HV_SYS_REG_MPIDR_EL1,
+ ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_MPIDR_EL1,
arm_cpu->mp_affinity);
assert_hvf_ok(ret);
- ret = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_ID_AA64PFR0_EL1, &pfr);
+ ret = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64PFR0_EL1, &pfr);
assert_hvf_ok(ret);
pfr |= env->gicv3state ? (1 << 24) : 0;
- ret = hv_vcpu_set_sys_reg(cpu->hvf->fd, HV_SYS_REG_ID_AA64PFR0_EL1, pfr);
+ ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64PFR0_EL1, pfr);
assert_hvf_ok(ret);
/* We're limited to underlying hardware caps, override internal versions */
- ret = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_ID_AA64MMFR0_EL1,
+ ret = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64MMFR0_EL1,
&arm_cpu->isar.id_aa64mmfr0);
assert_hvf_ok(ret);
@@ -994,7 +994,7 @@ int hvf_arch_init_vcpu(CPUState *cpu)
void hvf_kick_vcpu_thread(CPUState *cpu)
{
cpus_kick_thread(cpu);
- hv_vcpus_exit(&cpu->hvf->fd, 1);
+ hv_vcpus_exit(&cpu->accel->fd, 1);
}
static void hvf_raise_exception(CPUState *cpu, uint32_t excp,
@@ -1678,13 +1678,13 @@ static int hvf_inject_interrupts(CPUState *cpu)
{
if (cpu->interrupt_request & CPU_INTERRUPT_FIQ) {
trace_hvf_inject_fiq();
- hv_vcpu_set_pending_interrupt(cpu->hvf->fd, HV_INTERRUPT_TYPE_FIQ,
+ hv_vcpu_set_pending_interrupt(cpu->accel->fd, HV_INTERRUPT_TYPE_FIQ,
true);
}
if (cpu->interrupt_request & CPU_INTERRUPT_HARD) {
trace_hvf_inject_irq();
- hv_vcpu_set_pending_interrupt(cpu->hvf->fd, HV_INTERRUPT_TYPE_IRQ,
+ hv_vcpu_set_pending_interrupt(cpu->accel->fd, HV_INTERRUPT_TYPE_IRQ,
true);
}
@@ -1718,7 +1718,7 @@ static void hvf_wait_for_ipi(CPUState *cpu, struct timespec *ts)
*/
qatomic_set_mb(&cpu->thread_kicked, false);
qemu_mutex_unlock_iothread();
- pselect(0, 0, 0, 0, ts, &cpu->hvf->unblock_ipi_mask);
+ pselect(0, 0, 0, 0, ts, &cpu->accel->unblock_ipi_mask);
qemu_mutex_lock_iothread();
}
@@ -1739,7 +1739,7 @@ static void hvf_wfi(CPUState *cpu)
return;
}
- r = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_CNTV_CTL_EL0, &ctl);
+ r = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTV_CTL_EL0, &ctl);
assert_hvf_ok(r);
if (!(ctl & 1) || (ctl & 2)) {
@@ -1748,7 +1748,7 @@ static void hvf_wfi(CPUState *cpu)
return;
}
- r = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_CNTV_CVAL_EL0, &cval);
+ r = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTV_CVAL_EL0, &cval);
assert_hvf_ok(r);
ticks_to_sleep = cval - hvf_vtimer_val();
@@ -1781,12 +1781,12 @@ static void hvf_sync_vtimer(CPUState *cpu)
uint64_t ctl;
bool irq_state;
- if (!cpu->hvf->vtimer_masked) {
+ if (!cpu->accel->vtimer_masked) {
/* We will get notified on vtimer changes by hvf, nothing to do */
return;
}
- r = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_CNTV_CTL_EL0, &ctl);
+ r = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTV_CTL_EL0, &ctl);
assert_hvf_ok(r);
irq_state = (ctl & (TMR_CTL_ENABLE | TMR_CTL_IMASK | TMR_CTL_ISTATUS)) ==
@@ -1795,8 +1795,8 @@ static void hvf_sync_vtimer(CPUState *cpu)
if (!irq_state) {
/* Timer no longer asserting, we can unmask it */
- hv_vcpu_set_vtimer_mask(cpu->hvf->fd, false);
- cpu->hvf->vtimer_masked = false;
+ hv_vcpu_set_vtimer_mask(cpu->accel->fd, false);
+ cpu->accel->vtimer_masked = false;
}
}
@@ -1805,7 +1805,7 @@ int hvf_vcpu_exec(CPUState *cpu)
ARMCPU *arm_cpu = ARM_CPU(cpu);
CPUARMState *env = &arm_cpu->env;
int ret;
- hv_vcpu_exit_t *hvf_exit = cpu->hvf->exit;
+ hv_vcpu_exit_t *hvf_exit = cpu->accel->exit;
hv_return_t r;
bool advance_pc = false;
@@ -1821,7 +1821,7 @@ int hvf_vcpu_exec(CPUState *cpu)
flush_cpu_state(cpu);
qemu_mutex_unlock_iothread();
- assert_hvf_ok(hv_vcpu_run(cpu->hvf->fd));
+ assert_hvf_ok(hv_vcpu_run(cpu->accel->fd));
/* handle VMEXIT */
uint64_t exit_reason = hvf_exit->reason;
@@ -1836,7 +1836,7 @@ int hvf_vcpu_exec(CPUState *cpu)
break;
case HV_EXIT_REASON_VTIMER_ACTIVATED:
qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 1);
- cpu->hvf->vtimer_masked = true;
+ cpu->accel->vtimer_masked = true;
return 0;
case HV_EXIT_REASON_CANCELED:
/* we got kicked, no exit to process */
@@ -1990,10 +1990,10 @@ int hvf_vcpu_exec(CPUState *cpu)
flush_cpu_state(cpu);
- r = hv_vcpu_get_reg(cpu->hvf->fd, HV_REG_PC, &pc);
+ r = hv_vcpu_get_reg(cpu->accel->fd, HV_REG_PC, &pc);
assert_hvf_ok(r);
pc += 4;
- r = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_PC, pc);
+ r = hv_vcpu_set_reg(cpu->accel->fd, HV_REG_PC, pc);
assert_hvf_ok(r);
/* Handle single-stepping over instructions which trigger a VM exit */
@@ -2113,29 +2113,29 @@ static void hvf_put_gdbstub_debug_registers(CPUState *cpu)
for (i = 0; i < cur_hw_bps; i++) {
HWBreakpoint *bp = get_hw_bp(i);
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbcr_regs[i], bp->bcr);
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgbcr_regs[i], bp->bcr);
assert_hvf_ok(r);
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbvr_regs[i], bp->bvr);
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgbvr_regs[i], bp->bvr);
assert_hvf_ok(r);
}
for (i = cur_hw_bps; i < max_hw_bps; i++) {
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbcr_regs[i], 0);
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgbcr_regs[i], 0);
assert_hvf_ok(r);
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbvr_regs[i], 0);
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgbvr_regs[i], 0);
assert_hvf_ok(r);
}
for (i = 0; i < cur_hw_wps; i++) {
HWWatchpoint *wp = get_hw_wp(i);
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwcr_regs[i], wp->wcr);
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgwcr_regs[i], wp->wcr);
assert_hvf_ok(r);
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwvr_regs[i], wp->wvr);
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgwvr_regs[i], wp->wvr);
assert_hvf_ok(r);
}
for (i = cur_hw_wps; i < max_hw_wps; i++) {
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwcr_regs[i], 0);
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgwcr_regs[i], 0);
assert_hvf_ok(r);
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwvr_regs[i], 0);
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgwvr_regs[i], 0);
assert_hvf_ok(r);
}
}
@@ -2152,19 +2152,19 @@ static void hvf_put_guest_debug_registers(CPUState *cpu)
int i;
for (i = 0; i < max_hw_bps; i++) {
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbcr_regs[i],
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgbcr_regs[i],
env->cp15.dbgbcr[i]);
assert_hvf_ok(r);
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbvr_regs[i],
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgbvr_regs[i],
env->cp15.dbgbvr[i]);
assert_hvf_ok(r);
}
for (i = 0; i < max_hw_wps; i++) {
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwcr_regs[i],
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgwcr_regs[i],
env->cp15.dbgwcr[i]);
assert_hvf_ok(r);
- r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwvr_regs[i],
+ r = hv_vcpu_set_sys_reg(cpu->accel->fd, dbgwvr_regs[i],
env->cp15.dbgwvr[i]);
assert_hvf_ok(r);
}
@@ -2184,16 +2184,16 @@ static void hvf_arch_set_traps(void)
/* Check whether guest debugging is enabled for at least one vCPU; if it
* is, enable exiting the guest on all vCPUs */
CPU_FOREACH(cpu) {
- should_enable_traps |= cpu->hvf->guest_debug_enabled;
+ should_enable_traps |= cpu->accel->guest_debug_enabled;
}
CPU_FOREACH(cpu) {
/* Set whether debug exceptions exit the guest */
- r = hv_vcpu_set_trap_debug_exceptions(cpu->hvf->fd,
+ r = hv_vcpu_set_trap_debug_exceptions(cpu->accel->fd,
should_enable_traps);
assert_hvf_ok(r);
/* Set whether accesses to debug registers exit the guest */
- r = hv_vcpu_set_trap_debug_reg_accesses(cpu->hvf->fd,
+ r = hv_vcpu_set_trap_debug_reg_accesses(cpu->accel->fd,
should_enable_traps);
assert_hvf_ok(r);
}
@@ -2205,12 +2205,12 @@ void hvf_arch_update_guest_debug(CPUState *cpu)
CPUARMState *env = &arm_cpu->env;
/* Check whether guest debugging is enabled */
- cpu->hvf->guest_debug_enabled = cpu->singlestep_enabled ||
+ cpu->accel->guest_debug_enabled = cpu->singlestep_enabled ||
hvf_sw_breakpoints_active(cpu) ||
hvf_arm_hw_debug_active(cpu);
/* Update debug registers */
- if (cpu->hvf->guest_debug_enabled) {
+ if (cpu->accel->guest_debug_enabled) {
hvf_put_gdbstub_debug_registers(cpu);
} else {
hvf_put_guest_debug_registers(cpu);
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 84da49332c..b4c7654f49 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -341,6 +341,7 @@ static MemoryListener devlistener = {
.name = "kvm-arm",
.region_add = kvm_arm_devlistener_add,
.region_del = kvm_arm_devlistener_del,
+ .priority = MEMORY_LISTENER_PRIORITY_MIN,
};
static void kvm_arm_set_device_addr(KVMDevice *kd)
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 330fbe5c72..051a0da41c 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -453,32 +453,6 @@ static inline uint32_t kvm_arm_sve_get_vls(CPUState *cs)
#endif
-static inline const char *gic_class_name(void)
-{
- return kvm_irqchip_in_kernel() ? "kvm-arm-gic" : "arm_gic";
-}
-
-/**
- * gicv3_class_name
- *
- * Return name of GICv3 class to use depending on whether KVM acceleration is
- * in use. May throw an error if the chosen implementation is not available.
- *
- * Returns: class name to use
- */
-static inline const char *gicv3_class_name(void)
-{
- if (kvm_irqchip_in_kernel()) {
- return "kvm-arm-gicv3";
- } else {
- if (kvm_enabled()) {
- error_report("Userspace GICv3 is not supported with KVM");
- exit(1);
- }
- return "arm-gicv3";
- }
-}
-
/**
* kvm_arm_handle_debug:
* @cs: CPUState
@@ -516,23 +490,4 @@ void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr);
*/
bool kvm_arm_verify_ext_dabt_pending(CPUState *cs);
-/**
- * its_class_name:
- *
- * Return the ITS class name to use depending on whether KVM acceleration
- * and KVM CAP_SIGNAL_MSI are supported
- *
- * Returns: class name to use or NULL
- */
-static inline const char *its_class_name(void)
-{
- if (kvm_irqchip_in_kernel()) {
- /* KVM implementation requires this capability */
- return kvm_direct_msi_enabled() ? "arm-its-kvm" : NULL;
- } else {
- /* Software emulation based model */
- return "arm-gicv3-its";
- }
-}
-
#endif
diff --git a/target/i386/hax/hax-accel-ops.c b/target/i386/hax/hax-accel-ops.c
index 18114fe34d..5031096760 100644
--- a/target/i386/hax/hax-accel-ops.c
+++ b/target/i386/hax/hax-accel-ops.c
@@ -53,6 +53,8 @@ static void *hax_cpu_thread_fn(void *arg)
qemu_wait_io_event(cpu);
} while (!cpu->unplug || cpu_can_run(cpu));
+ hax_vcpu_destroy(cpu);
+ cpu_thread_signal_destroyed(cpu);
rcu_unregister_thread();
return NULL;
}
@@ -69,8 +71,9 @@ static void hax_start_vcpu_thread(CPUState *cpu)
cpu->cpu_index);
qemu_thread_create(cpu->thread, thread_name, hax_cpu_thread_fn,
cpu, QEMU_THREAD_JOINABLE);
+ assert(cpu->accel);
#ifdef _WIN32
- cpu->hThread = qemu_thread_get_handle(cpu->thread);
+ cpu->accel->hThread = qemu_thread_get_handle(cpu->thread);
#endif
}
diff --git a/target/i386/hax/hax-all.c b/target/i386/hax/hax-all.c
index 3e5992a63b..18d78e5b6b 100644
--- a/target/i386/hax/hax-all.c
+++ b/target/i386/hax/hax-all.c
@@ -62,7 +62,7 @@ int valid_hax_tunnel_size(uint16_t size)
hax_fd hax_vcpu_get_fd(CPUArchState *env)
{
- struct hax_vcpu_state *vcpu = env_cpu(env)->hax_vcpu;
+ AccelCPUState *vcpu = env_cpu(env)->accel;
if (!vcpu) {
return HAX_INVALID_FD;
}
@@ -136,7 +136,7 @@ static int hax_version_support(struct hax_state *hax)
int hax_vcpu_create(int id)
{
- struct hax_vcpu_state *vcpu = NULL;
+ AccelCPUState *vcpu = NULL;
int ret;
if (!hax_global.vm) {
@@ -149,7 +149,7 @@ int hax_vcpu_create(int id)
return 0;
}
- vcpu = g_new0(struct hax_vcpu_state, 1);
+ vcpu = g_new0(AccelCPUState, 1);
ret = hax_host_create_vcpu(hax_global.vm->fd, id);
if (ret) {
@@ -188,7 +188,7 @@ int hax_vcpu_create(int id)
int hax_vcpu_destroy(CPUState *cpu)
{
- struct hax_vcpu_state *vcpu = cpu->hax_vcpu;
+ AccelCPUState *vcpu = cpu->accel;
if (!hax_global.vm) {
fprintf(stderr, "vcpu %x destroy failed, vm is null\n", vcpu->vcpu_id);
@@ -205,7 +205,11 @@ int hax_vcpu_destroy(CPUState *cpu)
*/
hax_close_fd(vcpu->fd);
hax_global.vm->vcpus[vcpu->vcpu_id] = NULL;
+#ifdef _WIN32
+ CloseHandle(vcpu->hThread);
+#endif
g_free(vcpu);
+ cpu->accel = NULL;
return 0;
}
@@ -219,7 +223,7 @@ int hax_init_vcpu(CPUState *cpu)
exit(-1);
}
- cpu->hax_vcpu = hax_global.vm->vcpus[cpu->cpu_index];
+ cpu->accel = hax_global.vm->vcpus[cpu->cpu_index];
cpu->vcpu_dirty = true;
qemu_register_reset(hax_reset_vcpu_state, cpu->env_ptr);
@@ -259,7 +263,7 @@ struct hax_vm *hax_vm_create(struct hax_state *hax, int max_cpus)
}
vm->numvcpus = max_cpus;
- vm->vcpus = g_new0(struct hax_vcpu_state *, vm->numvcpus);
+ vm->vcpus = g_new0(AccelCPUState *, vm->numvcpus);
for (i = 0; i < vm->numvcpus; i++) {
vm->vcpus[i] = NULL;
}
@@ -411,7 +415,7 @@ static int hax_handle_io(CPUArchState *env, uint32_t df, uint16_t port,
static int hax_vcpu_interrupt(CPUArchState *env)
{
CPUState *cpu = env_cpu(env);
- struct hax_vcpu_state *vcpu = cpu->hax_vcpu;
+ AccelCPUState *vcpu = cpu->accel;
struct hax_tunnel *ht = vcpu->tunnel;
/*
@@ -443,7 +447,7 @@ static int hax_vcpu_interrupt(CPUArchState *env)
void hax_raise_event(CPUState *cpu)
{
- struct hax_vcpu_state *vcpu = cpu->hax_vcpu;
+ AccelCPUState *vcpu = cpu->accel;
if (!vcpu) {
return;
@@ -464,7 +468,7 @@ static int hax_vcpu_hax_exec(CPUArchState *env)
int ret = 0;
CPUState *cpu = env_cpu(env);
X86CPU *x86_cpu = X86_CPU(cpu);
- struct hax_vcpu_state *vcpu = cpu->hax_vcpu;
+ AccelCPUState *vcpu = cpu->accel;
struct hax_tunnel *ht = vcpu->tunnel;
if (!hax_enabled()) {
@@ -1110,8 +1114,8 @@ void hax_reset_vcpu_state(void *opaque)
{
CPUState *cpu;
for (cpu = first_cpu; cpu != NULL; cpu = CPU_NEXT(cpu)) {
- cpu->hax_vcpu->tunnel->user_event_pending = 0;
- cpu->hax_vcpu->tunnel->ready_for_interrupt_injection = 0;
+ cpu->accel->tunnel->user_event_pending = 0;
+ cpu->accel->tunnel->ready_for_interrupt_injection = 0;
}
}
diff --git a/target/i386/hax/hax-i386.h b/target/i386/hax/hax-i386.h
index 409ebdb4af..87153f40ab 100644
--- a/target/i386/hax/hax-i386.h
+++ b/target/i386/hax/hax-i386.h
@@ -25,7 +25,11 @@ typedef HANDLE hax_fd;
#endif
extern struct hax_state hax_global;
-struct hax_vcpu_state {
+
+struct AccelCPUState {
+#ifdef _WIN32
+ HANDLE hThread;
+#endif
hax_fd fd;
int vcpu_id;
struct hax_tunnel *tunnel;
@@ -46,7 +50,7 @@ struct hax_vm {
hax_fd fd;
int id;
int numvcpus;
- struct hax_vcpu_state **vcpus;
+ AccelCPUState **vcpus;
};
/* Functions exported to host specific mode */
@@ -57,7 +61,7 @@ int valid_hax_tunnel_size(uint16_t size);
int hax_mod_version(struct hax_state *hax, struct hax_module_version *version);
int hax_inject_interrupt(CPUArchState *env, int vector);
struct hax_vm *hax_vm_create(struct hax_state *hax, int max_cpus);
-int hax_vcpu_run(struct hax_vcpu_state *vcpu);
+int hax_vcpu_run(AccelCPUState *vcpu);
int hax_vcpu_create(int id);
void hax_kick_vcpu_thread(CPUState *cpu);
@@ -76,7 +80,7 @@ int hax_host_create_vm(struct hax_state *hax, int *vm_id);
hax_fd hax_host_open_vm(struct hax_state *hax, int vm_id);
int hax_host_create_vcpu(hax_fd vm_fd, int vcpuid);
hax_fd hax_host_open_vcpu(int vmid, int vcpuid);
-int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu);
+int hax_host_setup_vcpu_channel(AccelCPUState *vcpu);
hax_fd hax_mod_open(void);
void hax_memory_init(void);
diff --git a/target/i386/hax/hax-mem.c b/target/i386/hax/hax-mem.c
index 05dbe8cce3..bb5ffbc9ac 100644
--- a/target/i386/hax/hax-mem.c
+++ b/target/i386/hax/hax-mem.c
@@ -291,7 +291,7 @@ static MemoryListener hax_memory_listener = {
.region_add = hax_region_add,
.region_del = hax_region_del,
.log_sync = hax_log_sync,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
};
static void hax_ram_block_added(RAMBlockNotifier *n, void *host, size_t size,
diff --git a/target/i386/hax/hax-posix.c b/target/i386/hax/hax-posix.c
index ac1a51096e..a057a5bd94 100644
--- a/target/i386/hax/hax-posix.c
+++ b/target/i386/hax/hax-posix.c
@@ -205,7 +205,7 @@ hax_fd hax_host_open_vcpu(int vmid, int vcpuid)
return fd;
}
-int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu)
+int hax_host_setup_vcpu_channel(AccelCPUState *vcpu)
{
int ret;
struct hax_tunnel_info info;
@@ -227,7 +227,7 @@ int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu)
return 0;
}
-int hax_vcpu_run(struct hax_vcpu_state *vcpu)
+int hax_vcpu_run(AccelCPUState *vcpu)
{
return ioctl(vcpu->fd, HAX_VCPU_IOCTL_RUN, NULL);
}
diff --git a/target/i386/hax/hax-windows.c b/target/i386/hax/hax-windows.c
index 59afa213a6..4bf6cc08d2 100644
--- a/target/i386/hax/hax-windows.c
+++ b/target/i386/hax/hax-windows.c
@@ -301,7 +301,7 @@ hax_fd hax_host_open_vcpu(int vmid, int vcpuid)
return hDeviceVCPU;
}
-int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu)
+int hax_host_setup_vcpu_channel(AccelCPUState *vcpu)
{
hax_fd hDeviceVCPU = vcpu->fd;
int ret;
@@ -327,7 +327,7 @@ int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu)
return 0;
}
-int hax_vcpu_run(struct hax_vcpu_state *vcpu)
+int hax_vcpu_run(AccelCPUState *vcpu)
{
int ret;
HANDLE hDeviceVCPU = vcpu->fd;
@@ -476,7 +476,7 @@ void hax_kick_vcpu_thread(CPUState *cpu)
*/
cpu->exit_request = 1;
if (!qemu_cpu_is_self(cpu)) {
- if (!QueueUserAPC(dummy_apc_func, cpu->hThread, 0)) {
+ if (!QueueUserAPC(dummy_apc_func, cpu->accel->hThread, 0)) {
fprintf(stderr, "%s: QueueUserAPC failed with error %lu\n",
__func__, GetLastError());
exit(1);
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index f6775c942a..b9cbcc02a8 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -81,11 +81,11 @@ void vmx_update_tpr(CPUState *cpu)
int tpr = cpu_get_apic_tpr(x86_cpu->apic_state) << 4;
int irr = apic_get_highest_priority_irr(x86_cpu->apic_state);
- wreg(cpu->hvf->fd, HV_X86_TPR, tpr);
+ wreg(cpu->accel->fd, HV_X86_TPR, tpr);
if (irr == -1) {
- wvmcs(cpu->hvf->fd, VMCS_TPR_THRESHOLD, 0);
+ wvmcs(cpu->accel->fd, VMCS_TPR_THRESHOLD, 0);
} else {
- wvmcs(cpu->hvf->fd, VMCS_TPR_THRESHOLD, (irr > tpr) ? tpr >> 4 :
+ wvmcs(cpu->accel->fd, VMCS_TPR_THRESHOLD, (irr > tpr) ? tpr >> 4 :
irr >> 4);
}
}
@@ -93,7 +93,7 @@ void vmx_update_tpr(CPUState *cpu)
static void update_apic_tpr(CPUState *cpu)
{
X86CPU *x86_cpu = X86_CPU(cpu);
- int tpr = rreg(cpu->hvf->fd, HV_X86_TPR) >> 4;
+ int tpr = rreg(cpu->accel->fd, HV_X86_TPR) >> 4;
cpu_set_apic_tpr(x86_cpu->apic_state, tpr);
}
@@ -256,12 +256,12 @@ int hvf_arch_init_vcpu(CPUState *cpu)
}
/* set VMCS control fields */
- wvmcs(cpu->hvf->fd, VMCS_PIN_BASED_CTLS,
+ wvmcs(cpu->accel->fd, VMCS_PIN_BASED_CTLS,
cap2ctrl(hvf_state->hvf_caps->vmx_cap_pinbased,
VMCS_PIN_BASED_CTLS_EXTINT |
VMCS_PIN_BASED_CTLS_NMI |
VMCS_PIN_BASED_CTLS_VNMI));
- wvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS,
+ wvmcs(cpu->accel->fd, VMCS_PRI_PROC_BASED_CTLS,
cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased,
VMCS_PRI_PROC_BASED_CTLS_HLT |
VMCS_PRI_PROC_BASED_CTLS_MWAIT |
@@ -276,14 +276,14 @@ int hvf_arch_init_vcpu(CPUState *cpu)
reqCap |= VMCS_PRI_PROC_BASED2_CTLS_RDTSCP;
}
- wvmcs(cpu->hvf->fd, VMCS_SEC_PROC_BASED_CTLS,
+ wvmcs(cpu->accel->fd, VMCS_SEC_PROC_BASED_CTLS,
cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased2, reqCap));
- wvmcs(cpu->hvf->fd, VMCS_ENTRY_CTLS, cap2ctrl(hvf_state->hvf_caps->vmx_cap_entry,
- 0));
- wvmcs(cpu->hvf->fd, VMCS_EXCEPTION_BITMAP, 0); /* Double fault */
+ wvmcs(cpu->accel->fd, VMCS_ENTRY_CTLS,
+ cap2ctrl(hvf_state->hvf_caps->vmx_cap_entry, 0));
+ wvmcs(cpu->accel->fd, VMCS_EXCEPTION_BITMAP, 0); /* Double fault */
- wvmcs(cpu->hvf->fd, VMCS_TPR_THRESHOLD, 0);
+ wvmcs(cpu->accel->fd, VMCS_TPR_THRESHOLD, 0);
x86cpu = X86_CPU(cpu);
x86cpu->env.xsave_buf_len = 4096;
@@ -295,18 +295,18 @@ int hvf_arch_init_vcpu(CPUState *cpu)
*/
assert(hvf_get_supported_cpuid(0xd, 0, R_ECX) <= x86cpu->env.xsave_buf_len);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_STAR, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_LSTAR, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_CSTAR, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_FMASK, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_FSBASE, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_GSBASE, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_KERNELGSBASE, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_TSC_AUX, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_IA32_TSC, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_IA32_SYSENTER_CS, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_IA32_SYSENTER_EIP, 1);
- hv_vcpu_enable_native_msr(cpu->hvf->fd, MSR_IA32_SYSENTER_ESP, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_STAR, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_LSTAR, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_CSTAR, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_FMASK, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_FSBASE, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_GSBASE, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_KERNELGSBASE, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_TSC_AUX, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_IA32_TSC, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_IA32_SYSENTER_CS, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_IA32_SYSENTER_EIP, 1);
+ hv_vcpu_enable_native_msr(cpu->accel->fd, MSR_IA32_SYSENTER_ESP, 1);
return 0;
}
@@ -347,16 +347,16 @@ static void hvf_store_events(CPUState *cpu, uint32_t ins_len, uint64_t idtvec_in
}
if (idtvec_info & VMCS_IDT_VEC_ERRCODE_VALID) {
env->has_error_code = true;
- env->error_code = rvmcs(cpu->hvf->fd, VMCS_IDT_VECTORING_ERROR);
+ env->error_code = rvmcs(cpu->accel->fd, VMCS_IDT_VECTORING_ERROR);
}
}
- if ((rvmcs(cpu->hvf->fd, VMCS_GUEST_INTERRUPTIBILITY) &
+ if ((rvmcs(cpu->accel->fd, VMCS_GUEST_INTERRUPTIBILITY) &
VMCS_INTERRUPTIBILITY_NMI_BLOCKING)) {
env->hflags2 |= HF2_NMI_MASK;
} else {
env->hflags2 &= ~HF2_NMI_MASK;
}
- if (rvmcs(cpu->hvf->fd, VMCS_GUEST_INTERRUPTIBILITY) &
+ if (rvmcs(cpu->accel->fd, VMCS_GUEST_INTERRUPTIBILITY) &
(VMCS_INTERRUPTIBILITY_STI_BLOCKING |
VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)) {
env->hflags |= HF_INHIBIT_IRQ_MASK;
@@ -435,20 +435,20 @@ int hvf_vcpu_exec(CPUState *cpu)
return EXCP_HLT;
}
- hv_return_t r = hv_vcpu_run(cpu->hvf->fd);
+ hv_return_t r = hv_vcpu_run(cpu->accel->fd);
assert_hvf_ok(r);
/* handle VMEXIT */
- uint64_t exit_reason = rvmcs(cpu->hvf->fd, VMCS_EXIT_REASON);
- uint64_t exit_qual = rvmcs(cpu->hvf->fd, VMCS_EXIT_QUALIFICATION);
- uint32_t ins_len = (uint32_t)rvmcs(cpu->hvf->fd,
+ uint64_t exit_reason = rvmcs(cpu->accel->fd, VMCS_EXIT_REASON);
+ uint64_t exit_qual = rvmcs(cpu->accel->fd, VMCS_EXIT_QUALIFICATION);
+ uint32_t ins_len = (uint32_t)rvmcs(cpu->accel->fd,
VMCS_EXIT_INSTRUCTION_LENGTH);
- uint64_t idtvec_info = rvmcs(cpu->hvf->fd, VMCS_IDT_VECTORING_INFO);
+ uint64_t idtvec_info = rvmcs(cpu->accel->fd, VMCS_IDT_VECTORING_INFO);
hvf_store_events(cpu, ins_len, idtvec_info);
- rip = rreg(cpu->hvf->fd, HV_X86_RIP);
- env->eflags = rreg(cpu->hvf->fd, HV_X86_RFLAGS);
+ rip = rreg(cpu->accel->fd, HV_X86_RIP);
+ env->eflags = rreg(cpu->accel->fd, HV_X86_RFLAGS);
qemu_mutex_lock_iothread();
@@ -478,7 +478,7 @@ int hvf_vcpu_exec(CPUState *cpu)
case EXIT_REASON_EPT_FAULT:
{
hvf_slot *slot;
- uint64_t gpa = rvmcs(cpu->hvf->fd, VMCS_GUEST_PHYSICAL_ADDRESS);
+ uint64_t gpa = rvmcs(cpu->accel->fd, VMCS_GUEST_PHYSICAL_ADDRESS);
if (((idtvec_info & VMCS_IDT_VEC_VALID) == 0) &&
((exit_qual & EXIT_QUAL_NMIUDTI) != 0)) {
@@ -523,7 +523,7 @@ int hvf_vcpu_exec(CPUState *cpu)
store_regs(cpu);
break;
} else if (!string && !in) {
- RAX(env) = rreg(cpu->hvf->fd, HV_X86_RAX);
+ RAX(env) = rreg(cpu->accel->fd, HV_X86_RAX);
hvf_handle_io(env, port, &RAX(env), 1, size, 1);
macvm_set_rip(cpu, rip + ins_len);
break;
@@ -539,21 +539,21 @@ int hvf_vcpu_exec(CPUState *cpu)
break;
}
case EXIT_REASON_CPUID: {
- uint32_t rax = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RAX);
- uint32_t rbx = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RBX);
- uint32_t rcx = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RCX);
- uint32_t rdx = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RDX);
+ uint32_t rax = (uint32_t)rreg(cpu->accel->fd, HV_X86_RAX);
+ uint32_t rbx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RBX);
+ uint32_t rcx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RCX);
+ uint32_t rdx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RDX);
if (rax == 1) {
/* CPUID1.ecx.OSXSAVE needs to know CR4 */
- env->cr[4] = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR4);
+ env->cr[4] = rvmcs(cpu->accel->fd, VMCS_GUEST_CR4);
}
hvf_cpu_x86_cpuid(env, rax, rcx, &rax, &rbx, &rcx, &rdx);
- wreg(cpu->hvf->fd, HV_X86_RAX, rax);
- wreg(cpu->hvf->fd, HV_X86_RBX, rbx);
- wreg(cpu->hvf->fd, HV_X86_RCX, rcx);
- wreg(cpu->hvf->fd, HV_X86_RDX, rdx);
+ wreg(cpu->accel->fd, HV_X86_RAX, rax);
+ wreg(cpu->accel->fd, HV_X86_RBX, rbx);
+ wreg(cpu->accel->fd, HV_X86_RCX, rcx);
+ wreg(cpu->accel->fd, HV_X86_RDX, rdx);
macvm_set_rip(cpu, rip + ins_len);
break;
@@ -561,16 +561,16 @@ int hvf_vcpu_exec(CPUState *cpu)
case EXIT_REASON_XSETBV: {
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
- uint32_t eax = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RAX);
- uint32_t ecx = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RCX);
- uint32_t edx = (uint32_t)rreg(cpu->hvf->fd, HV_X86_RDX);
+ uint32_t eax = (uint32_t)rreg(cpu->accel->fd, HV_X86_RAX);
+ uint32_t ecx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RCX);
+ uint32_t edx = (uint32_t)rreg(cpu->accel->fd, HV_X86_RDX);
if (ecx) {
macvm_set_rip(cpu, rip + ins_len);
break;
}
env->xcr0 = ((uint64_t)edx << 32) | eax;
- wreg(cpu->hvf->fd, HV_X86_XCR0, env->xcr0 | 1);
+ wreg(cpu->accel->fd, HV_X86_XCR0, env->xcr0 | 1);
macvm_set_rip(cpu, rip + ins_len);
break;
}
@@ -609,11 +609,11 @@ int hvf_vcpu_exec(CPUState *cpu)
switch (cr) {
case 0x0: {
- macvm_set_cr0(cpu->hvf->fd, RRX(env, reg));
+ macvm_set_cr0(cpu->accel->fd, RRX(env, reg));
break;
}
case 4: {
- macvm_set_cr4(cpu->hvf->fd, RRX(env, reg));
+ macvm_set_cr4(cpu->accel->fd, RRX(env, reg));
break;
}
case 8: {
@@ -649,7 +649,7 @@ int hvf_vcpu_exec(CPUState *cpu)
break;
}
case EXIT_REASON_TASK_SWITCH: {
- uint64_t vinfo = rvmcs(cpu->hvf->fd, VMCS_IDT_VECTORING_INFO);
+ uint64_t vinfo = rvmcs(cpu->accel->fd, VMCS_IDT_VECTORING_INFO);
x68_segment_selector sel = {.sel = exit_qual & 0xffff};
vmx_handle_task_switch(cpu, sel, (exit_qual >> 30) & 0x3,
vinfo & VMCS_INTR_VALID, vinfo & VECTORING_INFO_VECTOR_MASK, vinfo
@@ -662,8 +662,8 @@ int hvf_vcpu_exec(CPUState *cpu)
break;
}
case EXIT_REASON_RDPMC:
- wreg(cpu->hvf->fd, HV_X86_RAX, 0);
- wreg(cpu->hvf->fd, HV_X86_RDX, 0);
+ wreg(cpu->accel->fd, HV_X86_RAX, 0);
+ wreg(cpu->accel->fd, HV_X86_RDX, 0);
macvm_set_rip(cpu, rip + ins_len);
break;
case VMX_REASON_VMCALL:
diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h
index fcd9a95e5b..0fffcfa46c 100644
--- a/target/i386/hvf/vmx.h
+++ b/target/i386/hvf/vmx.h
@@ -180,15 +180,15 @@ static inline void macvm_set_rip(CPUState *cpu, uint64_t rip)
uint64_t val;
/* BUG, should take considering overlap.. */
- wreg(cpu->hvf->fd, HV_X86_RIP, rip);
+ wreg(cpu->accel->fd, HV_X86_RIP, rip);
env->eip = rip;
/* after moving forward in rip, we need to clean INTERRUPTABILITY */
- val = rvmcs(cpu->hvf->fd, VMCS_GUEST_INTERRUPTIBILITY);
+ val = rvmcs(cpu->accel->fd, VMCS_GUEST_INTERRUPTIBILITY);
if (val & (VMCS_INTERRUPTIBILITY_STI_BLOCKING |
VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)) {
env->hflags &= ~HF_INHIBIT_IRQ_MASK;
- wvmcs(cpu->hvf->fd, VMCS_GUEST_INTERRUPTIBILITY,
+ wvmcs(cpu->accel->fd, VMCS_GUEST_INTERRUPTIBILITY,
val & ~(VMCS_INTERRUPTIBILITY_STI_BLOCKING |
VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING));
}
@@ -200,9 +200,9 @@ static inline void vmx_clear_nmi_blocking(CPUState *cpu)
CPUX86State *env = &x86_cpu->env;
env->hflags2 &= ~HF2_NMI_MASK;
- uint32_t gi = (uint32_t) rvmcs(cpu->hvf->fd, VMCS_GUEST_INTERRUPTIBILITY);
+ uint32_t gi = (uint32_t) rvmcs(cpu->accel->fd, VMCS_GUEST_INTERRUPTIBILITY);
gi &= ~VMCS_INTERRUPTIBILITY_NMI_BLOCKING;
- wvmcs(cpu->hvf->fd, VMCS_GUEST_INTERRUPTIBILITY, gi);
+ wvmcs(cpu->accel->fd, VMCS_GUEST_INTERRUPTIBILITY, gi);
}
static inline void vmx_set_nmi_blocking(CPUState *cpu)
@@ -211,16 +211,16 @@ static inline void vmx_set_nmi_blocking(CPUState *cpu)
CPUX86State *env = &x86_cpu->env;
env->hflags2 |= HF2_NMI_MASK;
- uint32_t gi = (uint32_t)rvmcs(cpu->hvf->fd, VMCS_GUEST_INTERRUPTIBILITY);
+ uint32_t gi = (uint32_t)rvmcs(cpu->accel->fd, VMCS_GUEST_INTERRUPTIBILITY);
gi |= VMCS_INTERRUPTIBILITY_NMI_BLOCKING;
- wvmcs(cpu->hvf->fd, VMCS_GUEST_INTERRUPTIBILITY, gi);
+ wvmcs(cpu->accel->fd, VMCS_GUEST_INTERRUPTIBILITY, gi);
}
static inline void vmx_set_nmi_window_exiting(CPUState *cpu)
{
uint64_t val;
- val = rvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS);
- wvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS, val |
+ val = rvmcs(cpu->accel->fd, VMCS_PRI_PROC_BASED_CTLS);
+ wvmcs(cpu->accel->fd, VMCS_PRI_PROC_BASED_CTLS, val |
VMCS_PRI_PROC_BASED_CTLS_NMI_WINDOW_EXITING);
}
@@ -229,8 +229,8 @@ static inline void vmx_clear_nmi_window_exiting(CPUState *cpu)
{
uint64_t val;
- val = rvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS);
- wvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS, val &
+ val = rvmcs(cpu->accel->fd, VMCS_PRI_PROC_BASED_CTLS);
+ wvmcs(cpu->accel->fd, VMCS_PRI_PROC_BASED_CTLS, val &
~VMCS_PRI_PROC_BASED_CTLS_NMI_WINDOW_EXITING);
}
diff --git a/target/i386/hvf/x86.c b/target/i386/hvf/x86.c
index d086584f26..8ceea6398e 100644
--- a/target/i386/hvf/x86.c
+++ b/target/i386/hvf/x86.c
@@ -61,11 +61,11 @@ bool x86_read_segment_descriptor(struct CPUState *cpu,
}
if (GDT_SEL == sel.ti) {
- base = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_BASE);
- limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_LIMIT);
+ base = rvmcs(cpu->accel->fd, VMCS_GUEST_GDTR_BASE);
+ limit = rvmcs(cpu->accel->fd, VMCS_GUEST_GDTR_LIMIT);
} else {
- base = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_BASE);
- limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_LIMIT);
+ base = rvmcs(cpu->accel->fd, VMCS_GUEST_LDTR_BASE);
+ limit = rvmcs(cpu->accel->fd, VMCS_GUEST_LDTR_LIMIT);
}
if (sel.index * 8 >= limit) {
@@ -84,11 +84,11 @@ bool x86_write_segment_descriptor(struct CPUState *cpu,
uint32_t limit;
if (GDT_SEL == sel.ti) {
- base = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_BASE);
- limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_LIMIT);
+ base = rvmcs(cpu->accel->fd, VMCS_GUEST_GDTR_BASE);
+ limit = rvmcs(cpu->accel->fd, VMCS_GUEST_GDTR_LIMIT);
} else {
- base = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_BASE);
- limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_LIMIT);
+ base = rvmcs(cpu->accel->fd, VMCS_GUEST_LDTR_BASE);
+ limit = rvmcs(cpu->accel->fd, VMCS_GUEST_LDTR_LIMIT);
}
if (sel.index * 8 >= limit) {
@@ -102,8 +102,8 @@ bool x86_write_segment_descriptor(struct CPUState *cpu,
bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc,
int gate)
{
- target_ulong base = rvmcs(cpu->hvf->fd, VMCS_GUEST_IDTR_BASE);
- uint32_t limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_IDTR_LIMIT);
+ target_ulong base = rvmcs(cpu->accel->fd, VMCS_GUEST_IDTR_BASE);
+ uint32_t limit = rvmcs(cpu->accel->fd, VMCS_GUEST_IDTR_LIMIT);
memset(idt_desc, 0, sizeof(*idt_desc));
if (gate * 8 >= limit) {
@@ -117,7 +117,7 @@ bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc,
bool x86_is_protected(struct CPUState *cpu)
{
- uint64_t cr0 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR0);
+ uint64_t cr0 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR0);
return cr0 & CR0_PE_MASK;
}
@@ -135,7 +135,7 @@ bool x86_is_v8086(struct CPUState *cpu)
bool x86_is_long_mode(struct CPUState *cpu)
{
- return rvmcs(cpu->hvf->fd, VMCS_GUEST_IA32_EFER) & MSR_EFER_LMA;
+ return rvmcs(cpu->accel->fd, VMCS_GUEST_IA32_EFER) & MSR_EFER_LMA;
}
bool x86_is_long64_mode(struct CPUState *cpu)
@@ -148,13 +148,13 @@ bool x86_is_long64_mode(struct CPUState *cpu)
bool x86_is_paging_mode(struct CPUState *cpu)
{
- uint64_t cr0 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR0);
+ uint64_t cr0 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR0);
return cr0 & CR0_PG_MASK;
}
bool x86_is_pae_enabled(struct CPUState *cpu)
{
- uint64_t cr4 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR4);
+ uint64_t cr4 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR4);
return cr4 & CR4_PAE_MASK;
}
diff --git a/target/i386/hvf/x86_descr.c b/target/i386/hvf/x86_descr.c
index a484942cfc..c2d2e9ee84 100644
--- a/target/i386/hvf/x86_descr.c
+++ b/target/i386/hvf/x86_descr.c
@@ -47,47 +47,47 @@ static const struct vmx_segment_field {
uint32_t vmx_read_segment_limit(CPUState *cpu, X86Seg seg)
{
- return (uint32_t)rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].limit);
+ return (uint32_t)rvmcs(cpu->accel->fd, vmx_segment_fields[seg].limit);
}
uint32_t vmx_read_segment_ar(CPUState *cpu, X86Seg seg)
{
- return (uint32_t)rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].ar_bytes);
+ return (uint32_t)rvmcs(cpu->accel->fd, vmx_segment_fields[seg].ar_bytes);
}
uint64_t vmx_read_segment_base(CPUState *cpu, X86Seg seg)
{
- return rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].base);
+ return rvmcs(cpu->accel->fd, vmx_segment_fields[seg].base);
}
x68_segment_selector vmx_read_segment_selector(CPUState *cpu, X86Seg seg)
{
x68_segment_selector sel;
- sel.sel = rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].selector);
+ sel.sel = rvmcs(cpu->accel->fd, vmx_segment_fields[seg].selector);
return sel;
}
void vmx_write_segment_selector(struct CPUState *cpu, x68_segment_selector selector, X86Seg seg)
{
- wvmcs(cpu->hvf->fd, vmx_segment_fields[seg].selector, selector.sel);
+ wvmcs(cpu->accel->fd, vmx_segment_fields[seg].selector, selector.sel);
}
void vmx_read_segment_descriptor(struct CPUState *cpu, struct vmx_segment *desc, X86Seg seg)
{
- desc->sel = rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].selector);
- desc->base = rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].base);
- desc->limit = rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].limit);
- desc->ar = rvmcs(cpu->hvf->fd, vmx_segment_fields[seg].ar_bytes);
+ desc->sel = rvmcs(cpu->accel->fd, vmx_segment_fields[seg].selector);
+ desc->base = rvmcs(cpu->accel->fd, vmx_segment_fields[seg].base);
+ desc->limit = rvmcs(cpu->accel->fd, vmx_segment_fields[seg].limit);
+ desc->ar = rvmcs(cpu->accel->fd, vmx_segment_fields[seg].ar_bytes);
}
void vmx_write_segment_descriptor(CPUState *cpu, struct vmx_segment *desc, X86Seg seg)
{
const struct vmx_segment_field *sf = &vmx_segment_fields[seg];
- wvmcs(cpu->hvf->fd, sf->base, desc->base);
- wvmcs(cpu->hvf->fd, sf->limit, desc->limit);
- wvmcs(cpu->hvf->fd, sf->selector, desc->sel);
- wvmcs(cpu->hvf->fd, sf->ar_bytes, desc->ar);
+ wvmcs(cpu->accel->fd, sf->base, desc->base);
+ wvmcs(cpu->accel->fd, sf->limit, desc->limit);
+ wvmcs(cpu->accel->fd, sf->selector, desc->sel);
+ wvmcs(cpu->accel->fd, sf->ar_bytes, desc->ar);
}
void x86_segment_descriptor_to_vmx(struct CPUState *cpu, x68_segment_selector selector, struct x86_segment_descriptor *desc, struct vmx_segment *vmx_desc)
diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c
index f5704f63e8..ccda568478 100644
--- a/target/i386/hvf/x86_emu.c
+++ b/target/i386/hvf/x86_emu.c
@@ -673,7 +673,7 @@ void simulate_rdmsr(struct CPUState *cpu)
switch (msr) {
case MSR_IA32_TSC:
- val = rdtscp() + rvmcs(cpu->hvf->fd, VMCS_TSC_OFFSET);
+ val = rdtscp() + rvmcs(cpu->accel->fd, VMCS_TSC_OFFSET);
break;
case MSR_IA32_APICBASE:
val = cpu_get_apic_base(X86_CPU(cpu)->apic_state);
@@ -682,16 +682,16 @@ void simulate_rdmsr(struct CPUState *cpu)
val = x86_cpu->ucode_rev;
break;
case MSR_EFER:
- val = rvmcs(cpu->hvf->fd, VMCS_GUEST_IA32_EFER);
+ val = rvmcs(cpu->accel->fd, VMCS_GUEST_IA32_EFER);
break;
case MSR_FSBASE:
- val = rvmcs(cpu->hvf->fd, VMCS_GUEST_FS_BASE);
+ val = rvmcs(cpu->accel->fd, VMCS_GUEST_FS_BASE);
break;
case MSR_GSBASE:
- val = rvmcs(cpu->hvf->fd, VMCS_GUEST_GS_BASE);
+ val = rvmcs(cpu->accel->fd, VMCS_GUEST_GS_BASE);
break;
case MSR_KERNELGSBASE:
- val = rvmcs(cpu->hvf->fd, VMCS_HOST_FS_BASE);
+ val = rvmcs(cpu->accel->fd, VMCS_HOST_FS_BASE);
break;
case MSR_STAR:
abort();
@@ -779,13 +779,13 @@ void simulate_wrmsr(struct CPUState *cpu)
cpu_set_apic_base(X86_CPU(cpu)->apic_state, data);
break;
case MSR_FSBASE:
- wvmcs(cpu->hvf->fd, VMCS_GUEST_FS_BASE, data);
+ wvmcs(cpu->accel->fd, VMCS_GUEST_FS_BASE, data);
break;
case MSR_GSBASE:
- wvmcs(cpu->hvf->fd, VMCS_GUEST_GS_BASE, data);
+ wvmcs(cpu->accel->fd, VMCS_GUEST_GS_BASE, data);
break;
case MSR_KERNELGSBASE:
- wvmcs(cpu->hvf->fd, VMCS_HOST_FS_BASE, data);
+ wvmcs(cpu->accel->fd, VMCS_HOST_FS_BASE, data);
break;
case MSR_STAR:
abort();
@@ -798,9 +798,9 @@ void simulate_wrmsr(struct CPUState *cpu)
break;
case MSR_EFER:
/*printf("new efer %llx\n", EFER(cpu));*/
- wvmcs(cpu->hvf->fd, VMCS_GUEST_IA32_EFER, data);
+ wvmcs(cpu->accel->fd, VMCS_GUEST_IA32_EFER, data);
if (data & MSR_EFER_NXE) {
- hv_vcpu_invalidate_tlb(cpu->hvf->fd);
+ hv_vcpu_invalidate_tlb(cpu->accel->fd);
}
break;
case MSR_MTRRphysBase(0):
@@ -1424,21 +1424,21 @@ void load_regs(struct CPUState *cpu)
CPUX86State *env = &x86_cpu->env;
int i = 0;
- RRX(env, R_EAX) = rreg(cpu->hvf->fd, HV_X86_RAX);
- RRX(env, R_EBX) = rreg(cpu->hvf->fd, HV_X86_RBX);
- RRX(env, R_ECX) = rreg(cpu->hvf->fd, HV_X86_RCX);
- RRX(env, R_EDX) = rreg(cpu->hvf->fd, HV_X86_RDX);
- RRX(env, R_ESI) = rreg(cpu->hvf->fd, HV_X86_RSI);
- RRX(env, R_EDI) = rreg(cpu->hvf->fd, HV_X86_RDI);
- RRX(env, R_ESP) = rreg(cpu->hvf->fd, HV_X86_RSP);
- RRX(env, R_EBP) = rreg(cpu->hvf->fd, HV_X86_RBP);
+ RRX(env, R_EAX) = rreg(cpu->accel->fd, HV_X86_RAX);
+ RRX(env, R_EBX) = rreg(cpu->accel->fd, HV_X86_RBX);
+ RRX(env, R_ECX) = rreg(cpu->accel->fd, HV_X86_RCX);
+ RRX(env, R_EDX) = rreg(cpu->accel->fd, HV_X86_RDX);
+ RRX(env, R_ESI) = rreg(cpu->accel->fd, HV_X86_RSI);
+ RRX(env, R_EDI) = rreg(cpu->accel->fd, HV_X86_RDI);
+ RRX(env, R_ESP) = rreg(cpu->accel->fd, HV_X86_RSP);
+ RRX(env, R_EBP) = rreg(cpu->accel->fd, HV_X86_RBP);
for (i = 8; i < 16; i++) {
- RRX(env, i) = rreg(cpu->hvf->fd, HV_X86_RAX + i);
+ RRX(env, i) = rreg(cpu->accel->fd, HV_X86_RAX + i);
}
- env->eflags = rreg(cpu->hvf->fd, HV_X86_RFLAGS);
+ env->eflags = rreg(cpu->accel->fd, HV_X86_RFLAGS);
rflags_to_lflags(env);
- env->eip = rreg(cpu->hvf->fd, HV_X86_RIP);
+ env->eip = rreg(cpu->accel->fd, HV_X86_RIP);
}
void store_regs(struct CPUState *cpu)
@@ -1447,20 +1447,20 @@ void store_regs(struct CPUState *cpu)
CPUX86State *env = &x86_cpu->env;
int i = 0;
- wreg(cpu->hvf->fd, HV_X86_RAX, RAX(env));
- wreg(cpu->hvf->fd, HV_X86_RBX, RBX(env));
- wreg(cpu->hvf->fd, HV_X86_RCX, RCX(env));
- wreg(cpu->hvf->fd, HV_X86_RDX, RDX(env));
- wreg(cpu->hvf->fd, HV_X86_RSI, RSI(env));
- wreg(cpu->hvf->fd, HV_X86_RDI, RDI(env));
- wreg(cpu->hvf->fd, HV_X86_RBP, RBP(env));
- wreg(cpu->hvf->fd, HV_X86_RSP, RSP(env));
+ wreg(cpu->accel->fd, HV_X86_RAX, RAX(env));
+ wreg(cpu->accel->fd, HV_X86_RBX, RBX(env));
+ wreg(cpu->accel->fd, HV_X86_RCX, RCX(env));
+ wreg(cpu->accel->fd, HV_X86_RDX, RDX(env));
+ wreg(cpu->accel->fd, HV_X86_RSI, RSI(env));
+ wreg(cpu->accel->fd, HV_X86_RDI, RDI(env));
+ wreg(cpu->accel->fd, HV_X86_RBP, RBP(env));
+ wreg(cpu->accel->fd, HV_X86_RSP, RSP(env));
for (i = 8; i < 16; i++) {
- wreg(cpu->hvf->fd, HV_X86_RAX + i, RRX(env, i));
+ wreg(cpu->accel->fd, HV_X86_RAX + i, RRX(env, i));
}
lflags_to_rflags(env);
- wreg(cpu->hvf->fd, HV_X86_RFLAGS, env->eflags);
+ wreg(cpu->accel->fd, HV_X86_RFLAGS, env->eflags);
macvm_set_rip(cpu, env->eip);
}
diff --git a/target/i386/hvf/x86_mmu.c b/target/i386/hvf/x86_mmu.c
index 96d117567e..8cd08622a1 100644
--- a/target/i386/hvf/x86_mmu.c
+++ b/target/i386/hvf/x86_mmu.c
@@ -126,7 +126,7 @@ static bool test_pt_entry(struct CPUState *cpu, struct gpt_translation *pt,
pt->err_code |= MMU_PAGE_PT;
}
- uint32_t cr0 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR0);
+ uint32_t cr0 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR0);
/* check protection */
if (cr0 & CR0_WP_MASK) {
if (pt->write_access && !pte_write_access(pte)) {
@@ -171,7 +171,7 @@ static bool walk_gpt(struct CPUState *cpu, target_ulong addr, int err_code,
{
int top_level, level;
bool is_large = false;
- target_ulong cr3 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR3);
+ target_ulong cr3 = rvmcs(cpu->accel->fd, VMCS_GUEST_CR3);
uint64_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK;
memset(pt, 0, sizeof(*pt));
diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c
index beaeec0687..f09bfbdda5 100644
--- a/target/i386/hvf/x86_task.c
+++ b/target/i386/hvf/x86_task.c
@@ -61,7 +61,7 @@ static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss)
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
- wvmcs(cpu->hvf->fd, VMCS_GUEST_CR3, tss->cr3);
+ wvmcs(cpu->accel->fd, VMCS_GUEST_CR3, tss->cr3);
env->eip = tss->eip;
env->eflags = tss->eflags | 2;
@@ -110,11 +110,11 @@ static int task_switch_32(CPUState *cpu, x68_segment_selector tss_sel, x68_segme
void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int reason, bool gate_valid, uint8_t gate, uint64_t gate_type)
{
- uint64_t rip = rreg(cpu->hvf->fd, HV_X86_RIP);
+ uint64_t rip = rreg(cpu->accel->fd, HV_X86_RIP);
if (!gate_valid || (gate_type != VMCS_INTR_T_HWEXCEPTION &&
gate_type != VMCS_INTR_T_HWINTR &&
gate_type != VMCS_INTR_T_NMI)) {
- int ins_len = rvmcs(cpu->hvf->fd, VMCS_EXIT_INSTRUCTION_LENGTH);
+ int ins_len = rvmcs(cpu->accel->fd, VMCS_EXIT_INSTRUCTION_LENGTH);
macvm_set_rip(cpu, rip + ins_len);
return;
}
@@ -173,12 +173,12 @@ void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int rea
//ret = task_switch_16(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc);
VM_PANIC("task_switch_16");
- macvm_set_cr0(cpu->hvf->fd, rvmcs(cpu->hvf->fd, VMCS_GUEST_CR0) |
+ macvm_set_cr0(cpu->accel->fd, rvmcs(cpu->accel->fd, VMCS_GUEST_CR0) |
CR0_TS_MASK);
x86_segment_descriptor_to_vmx(cpu, tss_sel, &next_tss_desc, &vmx_seg);
vmx_write_segment_descriptor(cpu, &vmx_seg, R_TR);
store_regs(cpu);
- hv_vcpu_invalidate_tlb(cpu->hvf->fd);
+ hv_vcpu_invalidate_tlb(cpu->accel->fd);
}
diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c
index 69d4fb8cf5..3b1ef5f49a 100644
--- a/target/i386/hvf/x86hvf.c
+++ b/target/i386/hvf/x86hvf.c
@@ -32,14 +32,14 @@
#include <Hypervisor/hv.h>
#include <Hypervisor/hv_vmx.h>
-void hvf_set_segment(struct CPUState *cpu, struct vmx_segment *vmx_seg,
+void hvf_set_segment(CPUState *cs, struct vmx_segment *vmx_seg,
SegmentCache *qseg, bool is_tr)
{
vmx_seg->sel = qseg->selector;
vmx_seg->base = qseg->base;
vmx_seg->limit = qseg->limit;
- if (!qseg->selector && !x86_is_real(cpu) && !is_tr) {
+ if (!qseg->selector && !x86_is_real(cs) && !is_tr) {
/* the TR register is usable after processor reset despite
* having a null selector */
vmx_seg->ar = 1 << 16;
@@ -70,279 +70,279 @@ void hvf_get_segment(SegmentCache *qseg, struct vmx_segment *vmx_seg)
(((vmx_seg->ar >> 15) & 1) << DESC_G_SHIFT);
}
-void hvf_put_xsave(CPUState *cpu_state)
+void hvf_put_xsave(CPUState *cs)
{
- void *xsave = X86_CPU(cpu_state)->env.xsave_buf;
- uint32_t xsave_len = X86_CPU(cpu_state)->env.xsave_buf_len;
+ void *xsave = X86_CPU(cs)->env.xsave_buf;
+ uint32_t xsave_len = X86_CPU(cs)->env.xsave_buf_len;
- x86_cpu_xsave_all_areas(X86_CPU(cpu_state), xsave, xsave_len);
+ x86_cpu_xsave_all_areas(X86_CPU(cs), xsave, xsave_len);
- if (hv_vcpu_write_fpstate(cpu_state->hvf->fd, xsave, xsave_len)) {
+ if (hv_vcpu_write_fpstate(cs->accel->fd, xsave, xsave_len)) {
abort();
}
}
-static void hvf_put_segments(CPUState *cpu_state)
+static void hvf_put_segments(CPUState *cs)
{
- CPUX86State *env = &X86_CPU(cpu_state)->env;
+ CPUX86State *env = &X86_CPU(cs)->env;
struct vmx_segment seg;
- wvmcs(cpu_state->hvf->fd, VMCS_GUEST_IDTR_LIMIT, env->idt.limit);
- wvmcs(cpu_state->hvf->fd, VMCS_GUEST_IDTR_BASE, env->idt.base);
+ wvmcs(cs->accel->fd, VMCS_GUEST_IDTR_LIMIT, env->idt.limit);
+ wvmcs(cs->accel->fd, VMCS_GUEST_IDTR_BASE, env->idt.base);
- wvmcs(cpu_state->hvf->fd, VMCS_GUEST_GDTR_LIMIT, env->gdt.limit);
- wvmcs(cpu_state->hvf->fd, VMCS_GUEST_GDTR_BASE, env->gdt.base);
+ wvmcs(cs->accel->fd, VMCS_GUEST_GDTR_LIMIT, env->gdt.limit);
+ wvmcs(cs->accel->fd, VMCS_GUEST_GDTR_BASE, env->gdt.base);
- /* wvmcs(cpu_state->hvf->fd, VMCS_GUEST_CR2, env->cr[2]); */
- wvmcs(cpu_state->hvf->fd, VMCS_GUEST_CR3, env->cr[3]);
- vmx_update_tpr(cpu_state);
- wvmcs(cpu_state->hvf->fd, VMCS_GUEST_IA32_EFER, env->efer);
+ /* wvmcs(cs->accel->fd, VMCS_GUEST_CR2, env->cr[2]); */
+ wvmcs(cs->accel->fd, VMCS_GUEST_CR3, env->cr[3]);
+ vmx_update_tpr(cs);
+ wvmcs(cs->accel->fd, VMCS_GUEST_IA32_EFER, env->efer);
- macvm_set_cr4(cpu_state->hvf->fd, env->cr[4]);
- macvm_set_cr0(cpu_state->hvf->fd, env->cr[0]);
+ macvm_set_cr4(cs->accel->fd, env->cr[4]);
+ macvm_set_cr0(cs->accel->fd, env->cr[0]);
- hvf_set_segment(cpu_state, &seg, &env->segs[R_CS], false);
- vmx_write_segment_descriptor(cpu_state, &seg, R_CS);
+ hvf_set_segment(cs, &seg, &env->segs[R_CS], false);
+ vmx_write_segment_descriptor(cs, &seg, R_CS);
- hvf_set_segment(cpu_state, &seg, &env->segs[R_DS], false);
- vmx_write_segment_descriptor(cpu_state, &seg, R_DS);
+ hvf_set_segment(cs, &seg, &env->segs[R_DS], false);
+ vmx_write_segment_descriptor(cs, &seg, R_DS);
- hvf_set_segment(cpu_state, &seg, &env->segs[R_ES], false);
- vmx_write_segment_descriptor(cpu_state, &seg, R_ES);
+ hvf_set_segment(cs, &seg, &env->segs[R_ES], false);
+ vmx_write_segment_descriptor(cs, &seg, R_ES);
- hvf_set_segment(cpu_state, &seg, &env->segs[R_SS], false);
- vmx_write_segment_descriptor(cpu_state, &seg, R_SS);
+ hvf_set_segment(cs, &seg, &env->segs[R_SS], false);
+ vmx_write_segment_descriptor(cs, &seg, R_SS);
- hvf_set_segment(cpu_state, &seg, &env->segs[R_FS], false);
- vmx_write_segment_descriptor(cpu_state, &seg, R_FS);
+ hvf_set_segment(cs, &seg, &env->segs[R_FS], false);
+ vmx_write_segment_descriptor(cs, &seg, R_FS);
- hvf_set_segment(cpu_state, &seg, &env->segs[R_GS], false);
- vmx_write_segment_descriptor(cpu_state, &seg, R_GS);
+ hvf_set_segment(cs, &seg, &env->segs[R_GS], false);
+ vmx_write_segment_descriptor(cs, &seg, R_GS);
- hvf_set_segment(cpu_state, &seg, &env->tr, true);
- vmx_write_segment_descriptor(cpu_state, &seg, R_TR);
+ hvf_set_segment(cs, &seg, &env->tr, true);
+ vmx_write_segment_descriptor(cs, &seg, R_TR);
- hvf_set_segment(cpu_state, &seg, &env->ldt, false);
- vmx_write_segment_descriptor(cpu_state, &seg, R_LDTR);
+ hvf_set_segment(cs, &seg, &env->ldt, false);
+ vmx_write_segment_descriptor(cs, &seg, R_LDTR);
}
-void hvf_put_msrs(CPUState *cpu_state)
+void hvf_put_msrs(CPUState *cs)
{
- CPUX86State *env = &X86_CPU(cpu_state)->env;
+ CPUX86State *env = &X86_CPU(cs)->env;
- hv_vcpu_write_msr(cpu_state->hvf->fd, MSR_IA32_SYSENTER_CS,
+ hv_vcpu_write_msr(cs->accel->fd, MSR_IA32_SYSENTER_CS,
env->sysenter_cs);
- hv_vcpu_write_msr(cpu_state->hvf->fd, MSR_IA32_SYSENTER_ESP,
+ hv_vcpu_write_msr(cs->accel->fd, MSR_IA32_SYSENTER_ESP,
env->sysenter_esp);
- hv_vcpu_write_msr(cpu_state->hvf->fd, MSR_IA32_SYSENTER_EIP,
+ hv_vcpu_write_msr(cs->accel->fd, MSR_IA32_SYSENTER_EIP,
env->sysenter_eip);
- hv_vcpu_write_msr(cpu_state->hvf->fd, MSR_STAR, env->star);
+ hv_vcpu_write_msr(cs->accel->fd, MSR_STAR, env->star);
#ifdef TARGET_X86_64
- hv_vcpu_write_msr(cpu_state->hvf->fd, MSR_CSTAR, env->cstar);
- hv_vcpu_write_msr(cpu_state->hvf->fd, MSR_KERNELGSBASE, env->kernelgsbase);
- hv_vcpu_write_msr(cpu_state->hvf->fd, MSR_FMASK, env->fmask);
- hv_vcpu_write_msr(cpu_state->hvf->fd, MSR_LSTAR, env->lstar);
+ hv_vcpu_write_msr(cs->accel->fd, MSR_CSTAR, env->cstar);
+ hv_vcpu_write_msr(cs->accel->fd, MSR_KERNELGSBASE, env->kernelgsbase);
+ hv_vcpu_write_msr(cs->accel->fd, MSR_FMASK, env->fmask);
+ hv_vcpu_write_msr(cs->accel->fd, MSR_LSTAR, env->lstar);
#endif
- hv_vcpu_write_msr(cpu_state->hvf->fd, MSR_GSBASE, env->segs[R_GS].base);
- hv_vcpu_write_msr(cpu_state->hvf->fd, MSR_FSBASE, env->segs[R_FS].base);
+ hv_vcpu_write_msr(cs->accel->fd, MSR_GSBASE, env->segs[R_GS].base);
+ hv_vcpu_write_msr(cs->accel->fd, MSR_FSBASE, env->segs[R_FS].base);
}
-void hvf_get_xsave(CPUState *cpu_state)
+void hvf_get_xsave(CPUState *cs)
{
- void *xsave = X86_CPU(cpu_state)->env.xsave_buf;
- uint32_t xsave_len = X86_CPU(cpu_state)->env.xsave_buf_len;
+ void *xsave = X86_CPU(cs)->env.xsave_buf;
+ uint32_t xsave_len = X86_CPU(cs)->env.xsave_buf_len;
- if (hv_vcpu_read_fpstate(cpu_state->hvf->fd, xsave, xsave_len)) {
+ if (hv_vcpu_read_fpstate(cs->accel->fd, xsave, xsave_len)) {
abort();
}
- x86_cpu_xrstor_all_areas(X86_CPU(cpu_state), xsave, xsave_len);
+ x86_cpu_xrstor_all_areas(X86_CPU(cs), xsave, xsave_len);
}
-static void hvf_get_segments(CPUState *cpu_state)
+static void hvf_get_segments(CPUState *cs)
{
- CPUX86State *env = &X86_CPU(cpu_state)->env;
+ CPUX86State *env = &X86_CPU(cs)->env;
struct vmx_segment seg;
env->interrupt_injected = -1;
- vmx_read_segment_descriptor(cpu_state, &seg, R_CS);
+ vmx_read_segment_descriptor(cs, &seg, R_CS);
hvf_get_segment(&env->segs[R_CS], &seg);
- vmx_read_segment_descriptor(cpu_state, &seg, R_DS);
+ vmx_read_segment_descriptor(cs, &seg, R_DS);
hvf_get_segment(&env->segs[R_DS], &seg);
- vmx_read_segment_descriptor(cpu_state, &seg, R_ES);
+ vmx_read_segment_descriptor(cs, &seg, R_ES);
hvf_get_segment(&env->segs[R_ES], &seg);
- vmx_read_segment_descriptor(cpu_state, &seg, R_FS);
+ vmx_read_segment_descriptor(cs, &seg, R_FS);
hvf_get_segment(&env->segs[R_FS], &seg);
- vmx_read_segment_descriptor(cpu_state, &seg, R_GS);
+ vmx_read_segment_descriptor(cs, &seg, R_GS);
hvf_get_segment(&env->segs[R_GS], &seg);
- vmx_read_segment_descriptor(cpu_state, &seg, R_SS);
+ vmx_read_segment_descriptor(cs, &seg, R_SS);
hvf_get_segment(&env->segs[R_SS], &seg);
- vmx_read_segment_descriptor(cpu_state, &seg, R_TR);
+ vmx_read_segment_descriptor(cs, &seg, R_TR);
hvf_get_segment(&env->tr, &seg);
- vmx_read_segment_descriptor(cpu_state, &seg, R_LDTR);
+ vmx_read_segment_descriptor(cs, &seg, R_LDTR);
hvf_get_segment(&env->ldt, &seg);
- env->idt.limit = rvmcs(cpu_state->hvf->fd, VMCS_GUEST_IDTR_LIMIT);
- env->idt.base = rvmcs(cpu_state->hvf->fd, VMCS_GUEST_IDTR_BASE);
- env->gdt.limit = rvmcs(cpu_state->hvf->fd, VMCS_GUEST_GDTR_LIMIT);
- env->gdt.base = rvmcs(cpu_state->hvf->fd, VMCS_GUEST_GDTR_BASE);
+ env->idt.limit = rvmcs(cs->accel->fd, VMCS_GUEST_IDTR_LIMIT);
+ env->idt.base = rvmcs(cs->accel->fd, VMCS_GUEST_IDTR_BASE);
+ env->gdt.limit = rvmcs(cs->accel->fd, VMCS_GUEST_GDTR_LIMIT);
+ env->gdt.base = rvmcs(cs->accel->fd, VMCS_GUEST_GDTR_BASE);
- env->cr[0] = rvmcs(cpu_state->hvf->fd, VMCS_GUEST_CR0);
+ env->cr[0] = rvmcs(cs->accel->fd, VMCS_GUEST_CR0);
env->cr[2] = 0;
- env->cr[3] = rvmcs(cpu_state->hvf->fd, VMCS_GUEST_CR3);
- env->cr[4] = rvmcs(cpu_state->hvf->fd, VMCS_GUEST_CR4);
+ env->cr[3] = rvmcs(cs->accel->fd, VMCS_GUEST_CR3);
+ env->cr[4] = rvmcs(cs->accel->fd, VMCS_GUEST_CR4);
- env->efer = rvmcs(cpu_state->hvf->fd, VMCS_GUEST_IA32_EFER);
+ env->efer = rvmcs(cs->accel->fd, VMCS_GUEST_IA32_EFER);
}
-void hvf_get_msrs(CPUState *cpu_state)
+void hvf_get_msrs(CPUState *cs)
{
- CPUX86State *env = &X86_CPU(cpu_state)->env;
+ CPUX86State *env = &X86_CPU(cs)->env;
uint64_t tmp;
- hv_vcpu_read_msr(cpu_state->hvf->fd, MSR_IA32_SYSENTER_CS, &tmp);
+ hv_vcpu_read_msr(cs->accel->fd, MSR_IA32_SYSENTER_CS, &tmp);
env->sysenter_cs = tmp;
- hv_vcpu_read_msr(cpu_state->hvf->fd, MSR_IA32_SYSENTER_ESP, &tmp);
+ hv_vcpu_read_msr(cs->accel->fd, MSR_IA32_SYSENTER_ESP, &tmp);
env->sysenter_esp = tmp;
- hv_vcpu_read_msr(cpu_state->hvf->fd, MSR_IA32_SYSENTER_EIP, &tmp);
+ hv_vcpu_read_msr(cs->accel->fd, MSR_IA32_SYSENTER_EIP, &tmp);
env->sysenter_eip = tmp;
- hv_vcpu_read_msr(cpu_state->hvf->fd, MSR_STAR, &env->star);
+ hv_vcpu_read_msr(cs->accel->fd, MSR_STAR, &env->star);
#ifdef TARGET_X86_64
- hv_vcpu_read_msr(cpu_state->hvf->fd, MSR_CSTAR, &env->cstar);
- hv_vcpu_read_msr(cpu_state->hvf->fd, MSR_KERNELGSBASE, &env->kernelgsbase);
- hv_vcpu_read_msr(cpu_state->hvf->fd, MSR_FMASK, &env->fmask);
- hv_vcpu_read_msr(cpu_state->hvf->fd, MSR_LSTAR, &env->lstar);
+ hv_vcpu_read_msr(cs->accel->fd, MSR_CSTAR, &env->cstar);
+ hv_vcpu_read_msr(cs->accel->fd, MSR_KERNELGSBASE, &env->kernelgsbase);
+ hv_vcpu_read_msr(cs->accel->fd, MSR_FMASK, &env->fmask);
+ hv_vcpu_read_msr(cs->accel->fd, MSR_LSTAR, &env->lstar);
#endif
- hv_vcpu_read_msr(cpu_state->hvf->fd, MSR_IA32_APICBASE, &tmp);
+ hv_vcpu_read_msr(cs->accel->fd, MSR_IA32_APICBASE, &tmp);
- env->tsc = rdtscp() + rvmcs(cpu_state->hvf->fd, VMCS_TSC_OFFSET);
+ env->tsc = rdtscp() + rvmcs(cs->accel->fd, VMCS_TSC_OFFSET);
}
-int hvf_put_registers(CPUState *cpu_state)
+int hvf_put_registers(CPUState *cs)
{
- X86CPU *x86cpu = X86_CPU(cpu_state);
+ X86CPU *x86cpu = X86_CPU(cs);
CPUX86State *env = &x86cpu->env;
- wreg(cpu_state->hvf->fd, HV_X86_RAX, env->regs[R_EAX]);
- wreg(cpu_state->hvf->fd, HV_X86_RBX, env->regs[R_EBX]);
- wreg(cpu_state->hvf->fd, HV_X86_RCX, env->regs[R_ECX]);
- wreg(cpu_state->hvf->fd, HV_X86_RDX, env->regs[R_EDX]);
- wreg(cpu_state->hvf->fd, HV_X86_RBP, env->regs[R_EBP]);
- wreg(cpu_state->hvf->fd, HV_X86_RSP, env->regs[R_ESP]);
- wreg(cpu_state->hvf->fd, HV_X86_RSI, env->regs[R_ESI]);
- wreg(cpu_state->hvf->fd, HV_X86_RDI, env->regs[R_EDI]);
- wreg(cpu_state->hvf->fd, HV_X86_R8, env->regs[8]);
- wreg(cpu_state->hvf->fd, HV_X86_R9, env->regs[9]);
- wreg(cpu_state->hvf->fd, HV_X86_R10, env->regs[10]);
- wreg(cpu_state->hvf->fd, HV_X86_R11, env->regs[11]);
- wreg(cpu_state->hvf->fd, HV_X86_R12, env->regs[12]);
- wreg(cpu_state->hvf->fd, HV_X86_R13, env->regs[13]);
- wreg(cpu_state->hvf->fd, HV_X86_R14, env->regs[14]);
- wreg(cpu_state->hvf->fd, HV_X86_R15, env->regs[15]);
- wreg(cpu_state->hvf->fd, HV_X86_RFLAGS, env->eflags);
- wreg(cpu_state->hvf->fd, HV_X86_RIP, env->eip);
+ wreg(cs->accel->fd, HV_X86_RAX, env->regs[R_EAX]);
+ wreg(cs->accel->fd, HV_X86_RBX, env->regs[R_EBX]);
+ wreg(cs->accel->fd, HV_X86_RCX, env->regs[R_ECX]);
+ wreg(cs->accel->fd, HV_X86_RDX, env->regs[R_EDX]);
+ wreg(cs->accel->fd, HV_X86_RBP, env->regs[R_EBP]);
+ wreg(cs->accel->fd, HV_X86_RSP, env->regs[R_ESP]);
+ wreg(cs->accel->fd, HV_X86_RSI, env->regs[R_ESI]);
+ wreg(cs->accel->fd, HV_X86_RDI, env->regs[R_EDI]);
+ wreg(cs->accel->fd, HV_X86_R8, env->regs[8]);
+ wreg(cs->accel->fd, HV_X86_R9, env->regs[9]);
+ wreg(cs->accel->fd, HV_X86_R10, env->regs[10]);
+ wreg(cs->accel->fd, HV_X86_R11, env->regs[11]);
+ wreg(cs->accel->fd, HV_X86_R12, env->regs[12]);
+ wreg(cs->accel->fd, HV_X86_R13, env->regs[13]);
+ wreg(cs->accel->fd, HV_X86_R14, env->regs[14]);
+ wreg(cs->accel->fd, HV_X86_R15, env->regs[15]);
+ wreg(cs->accel->fd, HV_X86_RFLAGS, env->eflags);
+ wreg(cs->accel->fd, HV_X86_RIP, env->eip);
- wreg(cpu_state->hvf->fd, HV_X86_XCR0, env->xcr0);
+ wreg(cs->accel->fd, HV_X86_XCR0, env->xcr0);
- hvf_put_xsave(cpu_state);
+ hvf_put_xsave(cs);
- hvf_put_segments(cpu_state);
+ hvf_put_segments(cs);
- hvf_put_msrs(cpu_state);
+ hvf_put_msrs(cs);
- wreg(cpu_state->hvf->fd, HV_X86_DR0, env->dr[0]);
- wreg(cpu_state->hvf->fd, HV_X86_DR1, env->dr[1]);
- wreg(cpu_state->hvf->fd, HV_X86_DR2, env->dr[2]);
- wreg(cpu_state->hvf->fd, HV_X86_DR3, env->dr[3]);
- wreg(cpu_state->hvf->fd, HV_X86_DR4, env->dr[4]);
- wreg(cpu_state->hvf->fd, HV_X86_DR5, env->dr[5]);
- wreg(cpu_state->hvf->fd, HV_X86_DR6, env->dr[6]);
- wreg(cpu_state->hvf->fd, HV_X86_DR7, env->dr[7]);
+ wreg(cs->accel->fd, HV_X86_DR0, env->dr[0]);
+ wreg(cs->accel->fd, HV_X86_DR1, env->dr[1]);
+ wreg(cs->accel->fd, HV_X86_DR2, env->dr[2]);
+ wreg(cs->accel->fd, HV_X86_DR3, env->dr[3]);
+ wreg(cs->accel->fd, HV_X86_DR4, env->dr[4]);
+ wreg(cs->accel->fd, HV_X86_DR5, env->dr[5]);
+ wreg(cs->accel->fd, HV_X86_DR6, env->dr[6]);
+ wreg(cs->accel->fd, HV_X86_DR7, env->dr[7]);
return 0;
}
-int hvf_get_registers(CPUState *cpu_state)
+int hvf_get_registers(CPUState *cs)
{
- X86CPU *x86cpu = X86_CPU(cpu_state);
+ X86CPU *x86cpu = X86_CPU(cs);
CPUX86State *env = &x86cpu->env;
- env->regs[R_EAX] = rreg(cpu_state->hvf->fd, HV_X86_RAX);
- env->regs[R_EBX] = rreg(cpu_state->hvf->fd, HV_X86_RBX);
- env->regs[R_ECX] = rreg(cpu_state->hvf->fd, HV_X86_RCX);
- env->regs[R_EDX] = rreg(cpu_state->hvf->fd, HV_X86_RDX);
- env->regs[R_EBP] = rreg(cpu_state->hvf->fd, HV_X86_RBP);
- env->regs[R_ESP] = rreg(cpu_state->hvf->fd, HV_X86_RSP);
- env->regs[R_ESI] = rreg(cpu_state->hvf->fd, HV_X86_RSI);
- env->regs[R_EDI] = rreg(cpu_state->hvf->fd, HV_X86_RDI);
- env->regs[8] = rreg(cpu_state->hvf->fd, HV_X86_R8);
- env->regs[9] = rreg(cpu_state->hvf->fd, HV_X86_R9);
- env->regs[10] = rreg(cpu_state->hvf->fd, HV_X86_R10);
- env->regs[11] = rreg(cpu_state->hvf->fd, HV_X86_R11);
- env->regs[12] = rreg(cpu_state->hvf->fd, HV_X86_R12);
- env->regs[13] = rreg(cpu_state->hvf->fd, HV_X86_R13);
- env->regs[14] = rreg(cpu_state->hvf->fd, HV_X86_R14);
- env->regs[15] = rreg(cpu_state->hvf->fd, HV_X86_R15);
+ env->regs[R_EAX] = rreg(cs->accel->fd, HV_X86_RAX);
+ env->regs[R_EBX] = rreg(cs->accel->fd, HV_X86_RBX);
+ env->regs[R_ECX] = rreg(cs->accel->fd, HV_X86_RCX);
+ env->regs[R_EDX] = rreg(cs->accel->fd, HV_X86_RDX);
+ env->regs[R_EBP] = rreg(cs->accel->fd, HV_X86_RBP);
+ env->regs[R_ESP] = rreg(cs->accel->fd, HV_X86_RSP);
+ env->regs[R_ESI] = rreg(cs->accel->fd, HV_X86_RSI);
+ env->regs[R_EDI] = rreg(cs->accel->fd, HV_X86_RDI);
+ env->regs[8] = rreg(cs->accel->fd, HV_X86_R8);
+ env->regs[9] = rreg(cs->accel->fd, HV_X86_R9);
+ env->regs[10] = rreg(cs->accel->fd, HV_X86_R10);
+ env->regs[11] = rreg(cs->accel->fd, HV_X86_R11);
+ env->regs[12] = rreg(cs->accel->fd, HV_X86_R12);
+ env->regs[13] = rreg(cs->accel->fd, HV_X86_R13);
+ env->regs[14] = rreg(cs->accel->fd, HV_X86_R14);
+ env->regs[15] = rreg(cs->accel->fd, HV_X86_R15);
- env->eflags = rreg(cpu_state->hvf->fd, HV_X86_RFLAGS);
- env->eip = rreg(cpu_state->hvf->fd, HV_X86_RIP);
+ env->eflags = rreg(cs->accel->fd, HV_X86_RFLAGS);
+ env->eip = rreg(cs->accel->fd, HV_X86_RIP);
- hvf_get_xsave(cpu_state);
- env->xcr0 = rreg(cpu_state->hvf->fd, HV_X86_XCR0);
+ hvf_get_xsave(cs);
+ env->xcr0 = rreg(cs->accel->fd, HV_X86_XCR0);
- hvf_get_segments(cpu_state);
- hvf_get_msrs(cpu_state);
+ hvf_get_segments(cs);
+ hvf_get_msrs(cs);
- env->dr[0] = rreg(cpu_state->hvf->fd, HV_X86_DR0);
- env->dr[1] = rreg(cpu_state->hvf->fd, HV_X86_DR1);
- env->dr[2] = rreg(cpu_state->hvf->fd, HV_X86_DR2);
- env->dr[3] = rreg(cpu_state->hvf->fd, HV_X86_DR3);
- env->dr[4] = rreg(cpu_state->hvf->fd, HV_X86_DR4);
- env->dr[5] = rreg(cpu_state->hvf->fd, HV_X86_DR5);
- env->dr[6] = rreg(cpu_state->hvf->fd, HV_X86_DR6);
- env->dr[7] = rreg(cpu_state->hvf->fd, HV_X86_DR7);
+ env->dr[0] = rreg(cs->accel->fd, HV_X86_DR0);
+ env->dr[1] = rreg(cs->accel->fd, HV_X86_DR1);
+ env->dr[2] = rreg(cs->accel->fd, HV_X86_DR2);
+ env->dr[3] = rreg(cs->accel->fd, HV_X86_DR3);
+ env->dr[4] = rreg(cs->accel->fd, HV_X86_DR4);
+ env->dr[5] = rreg(cs->accel->fd, HV_X86_DR5);
+ env->dr[6] = rreg(cs->accel->fd, HV_X86_DR6);
+ env->dr[7] = rreg(cs->accel->fd, HV_X86_DR7);
x86_update_hflags(env);
return 0;
}
-static void vmx_set_int_window_exiting(CPUState *cpu)
+static void vmx_set_int_window_exiting(CPUState *cs)
{
uint64_t val;
- val = rvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS);
- wvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS, val |
+ val = rvmcs(cs->accel->fd, VMCS_PRI_PROC_BASED_CTLS);
+ wvmcs(cs->accel->fd, VMCS_PRI_PROC_BASED_CTLS, val |
VMCS_PRI_PROC_BASED_CTLS_INT_WINDOW_EXITING);
}
-void vmx_clear_int_window_exiting(CPUState *cpu)
+void vmx_clear_int_window_exiting(CPUState *cs)
{
uint64_t val;
- val = rvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS);
- wvmcs(cpu->hvf->fd, VMCS_PRI_PROC_BASED_CTLS, val &
+ val = rvmcs(cs->accel->fd, VMCS_PRI_PROC_BASED_CTLS);
+ wvmcs(cs->accel->fd, VMCS_PRI_PROC_BASED_CTLS, val &
~VMCS_PRI_PROC_BASED_CTLS_INT_WINDOW_EXITING);
}
-bool hvf_inject_interrupts(CPUState *cpu_state)
+bool hvf_inject_interrupts(CPUState *cs)
{
- X86CPU *x86cpu = X86_CPU(cpu_state);
+ X86CPU *x86cpu = X86_CPU(cs);
CPUX86State *env = &x86cpu->env;
uint8_t vector;
@@ -372,89 +372,89 @@ bool hvf_inject_interrupts(CPUState *cpu_state)
uint64_t info = 0;
if (have_event) {
info = vector | intr_type | VMCS_INTR_VALID;
- uint64_t reason = rvmcs(cpu_state->hvf->fd, VMCS_EXIT_REASON);
+ uint64_t reason = rvmcs(cs->accel->fd, VMCS_EXIT_REASON);
if (env->nmi_injected && reason != EXIT_REASON_TASK_SWITCH) {
- vmx_clear_nmi_blocking(cpu_state);
+ vmx_clear_nmi_blocking(cs);
}
if (!(env->hflags2 & HF2_NMI_MASK) || intr_type != VMCS_INTR_T_NMI) {
info &= ~(1 << 12); /* clear undefined bit */
if (intr_type == VMCS_INTR_T_SWINTR ||
intr_type == VMCS_INTR_T_SWEXCEPTION) {
- wvmcs(cpu_state->hvf->fd, VMCS_ENTRY_INST_LENGTH, env->ins_len);
+ wvmcs(cs->accel->fd, VMCS_ENTRY_INST_LENGTH, env->ins_len);
}
if (env->has_error_code) {
- wvmcs(cpu_state->hvf->fd, VMCS_ENTRY_EXCEPTION_ERROR,
+ wvmcs(cs->accel->fd, VMCS_ENTRY_EXCEPTION_ERROR,
env->error_code);
/* Indicate that VMCS_ENTRY_EXCEPTION_ERROR is valid */
info |= VMCS_INTR_DEL_ERRCODE;
}
/*printf("reinject %lx err %d\n", info, err);*/
- wvmcs(cpu_state->hvf->fd, VMCS_ENTRY_INTR_INFO, info);
+ wvmcs(cs->accel->fd, VMCS_ENTRY_INTR_INFO, info);
};
}
- if (cpu_state->interrupt_request & CPU_INTERRUPT_NMI) {
+ if (cs->interrupt_request & CPU_INTERRUPT_NMI) {
if (!(env->hflags2 & HF2_NMI_MASK) && !(info & VMCS_INTR_VALID)) {
- cpu_state->interrupt_request &= ~CPU_INTERRUPT_NMI;
+ cs->interrupt_request &= ~CPU_INTERRUPT_NMI;
info = VMCS_INTR_VALID | VMCS_INTR_T_NMI | EXCP02_NMI;
- wvmcs(cpu_state->hvf->fd, VMCS_ENTRY_INTR_INFO, info);
+ wvmcs(cs->accel->fd, VMCS_ENTRY_INTR_INFO, info);
} else {
- vmx_set_nmi_window_exiting(cpu_state);
+ vmx_set_nmi_window_exiting(cs);
}
}
if (!(env->hflags & HF_INHIBIT_IRQ_MASK) &&
- (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) &&
+ (cs->interrupt_request & CPU_INTERRUPT_HARD) &&
(env->eflags & IF_MASK) && !(info & VMCS_INTR_VALID)) {
int line = cpu_get_pic_interrupt(&x86cpu->env);
- cpu_state->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
if (line >= 0) {
- wvmcs(cpu_state->hvf->fd, VMCS_ENTRY_INTR_INFO, line |
+ wvmcs(cs->accel->fd, VMCS_ENTRY_INTR_INFO, line |
VMCS_INTR_VALID | VMCS_INTR_T_HWINTR);
}
}
- if (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) {
- vmx_set_int_window_exiting(cpu_state);
+ if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
+ vmx_set_int_window_exiting(cs);
}
- return (cpu_state->interrupt_request
+ return (cs->interrupt_request
& (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR));
}
-int hvf_process_events(CPUState *cpu_state)
+int hvf_process_events(CPUState *cs)
{
- X86CPU *cpu = X86_CPU(cpu_state);
+ X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
- if (!cpu_state->vcpu_dirty) {
+ if (!cs->vcpu_dirty) {
/* light weight sync for CPU_INTERRUPT_HARD and IF_MASK */
- env->eflags = rreg(cpu_state->hvf->fd, HV_X86_RFLAGS);
+ env->eflags = rreg(cs->accel->fd, HV_X86_RFLAGS);
}
- if (cpu_state->interrupt_request & CPU_INTERRUPT_INIT) {
- cpu_synchronize_state(cpu_state);
+ if (cs->interrupt_request & CPU_INTERRUPT_INIT) {
+ cpu_synchronize_state(cs);
do_cpu_init(cpu);
}
- if (cpu_state->interrupt_request & CPU_INTERRUPT_POLL) {
- cpu_state->interrupt_request &= ~CPU_INTERRUPT_POLL;
+ if (cs->interrupt_request & CPU_INTERRUPT_POLL) {
+ cs->interrupt_request &= ~CPU_INTERRUPT_POLL;
apic_poll_irq(cpu->apic_state);
}
- if (((cpu_state->interrupt_request & CPU_INTERRUPT_HARD) &&
+ if (((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
(env->eflags & IF_MASK)) ||
- (cpu_state->interrupt_request & CPU_INTERRUPT_NMI)) {
- cpu_state->halted = 0;
+ (cs->interrupt_request & CPU_INTERRUPT_NMI)) {
+ cs->halted = 0;
}
- if (cpu_state->interrupt_request & CPU_INTERRUPT_SIPI) {
- cpu_synchronize_state(cpu_state);
+ if (cs->interrupt_request & CPU_INTERRUPT_SIPI) {
+ cpu_synchronize_state(cs);
do_cpu_sipi(cpu);
}
- if (cpu_state->interrupt_request & CPU_INTERRUPT_TPR) {
- cpu_state->interrupt_request &= ~CPU_INTERRUPT_TPR;
- cpu_synchronize_state(cpu_state);
+ if (cs->interrupt_request & CPU_INTERRUPT_TPR) {
+ cs->interrupt_request &= ~CPU_INTERRUPT_TPR;
+ cpu_synchronize_state(cs);
apic_handle_tpr_access_report(cpu->apic_state, env->eip,
env->tpr_access_type);
}
- return cpu_state->halted;
+ return cs->halted;
}
diff --git a/target/i386/hvf/x86hvf.h b/target/i386/hvf/x86hvf.h
index db6003d6bd..423a89b6ad 100644
--- a/target/i386/hvf/x86hvf.h
+++ b/target/i386/hvf/x86hvf.h
@@ -20,15 +20,15 @@
#include "cpu.h"
#include "x86_descr.h"
-int hvf_process_events(CPUState *);
-bool hvf_inject_interrupts(CPUState *);
-void hvf_set_segment(struct CPUState *cpu, struct vmx_segment *vmx_seg,
+int hvf_process_events(CPUState *cs);
+bool hvf_inject_interrupts(CPUState *cs);
+void hvf_set_segment(CPUState *cs, struct vmx_segment *vmx_seg,
SegmentCache *qseg, bool is_tr);
void hvf_get_segment(SegmentCache *qseg, struct vmx_segment *vmx_seg);
-void hvf_put_xsave(CPUState *cpu_state);
-void hvf_put_msrs(CPUState *cpu_state);
-void hvf_get_xsave(CPUState *cpu_state);
-void hvf_get_msrs(CPUState *cpu_state);
-void vmx_clear_int_window_exiting(CPUState *cpu);
-void vmx_update_tpr(CPUState *cpu);
+void hvf_put_xsave(CPUState *cs);
+void hvf_put_msrs(CPUState *cs);
+void hvf_get_xsave(CPUState *cs);
+void hvf_get_msrs(CPUState *cs);
+void vmx_clear_int_window_exiting(CPUState *cs);
+void vmx_update_tpr(CPUState *cs);
#endif
diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c
index b75738ee9c..066a173d26 100644
--- a/target/i386/nvmm/nvmm-all.c
+++ b/target/i386/nvmm/nvmm-all.c
@@ -26,7 +26,7 @@
#include <nvmm.h>
-struct qemu_vcpu {
+struct AccelCPUState {
struct nvmm_vcpu vcpu;
uint8_t tpr;
bool stop;
@@ -49,12 +49,6 @@ struct qemu_machine {
static bool nvmm_allowed;
static struct qemu_machine qemu_mach;
-static struct qemu_vcpu *
-get_qemu_vcpu(CPUState *cpu)
-{
- return (struct qemu_vcpu *)cpu->hax_vcpu;
-}
-
static struct nvmm_machine *
get_nvmm_mach(void)
{
@@ -86,7 +80,7 @@ nvmm_set_registers(CPUState *cpu)
{
CPUX86State *env = cpu->env_ptr;
struct nvmm_machine *mach = get_nvmm_mach();
- struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu);
+ AccelCPUState *qcpu = cpu->accel;
struct nvmm_vcpu *vcpu = &qcpu->vcpu;
struct nvmm_x64_state *state = vcpu->state;
uint64_t bitmap;
@@ -223,7 +217,7 @@ nvmm_get_registers(CPUState *cpu)
{
CPUX86State *env = cpu->env_ptr;
struct nvmm_machine *mach = get_nvmm_mach();
- struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu);
+ AccelCPUState *qcpu = cpu->accel;
struct nvmm_vcpu *vcpu = &qcpu->vcpu;
X86CPU *x86_cpu = X86_CPU(cpu);
struct nvmm_x64_state *state = vcpu->state;
@@ -347,7 +341,7 @@ static bool
nvmm_can_take_int(CPUState *cpu)
{
CPUX86State *env = cpu->env_ptr;
- struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu);
+ AccelCPUState *qcpu = cpu->accel;
struct nvmm_vcpu *vcpu = &qcpu->vcpu;
struct nvmm_machine *mach = get_nvmm_mach();
@@ -372,7 +366,7 @@ nvmm_can_take_int(CPUState *cpu)
static bool
nvmm_can_take_nmi(CPUState *cpu)
{
- struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu);
+ AccelCPUState *qcpu = cpu->accel;
/*
* Contrary to INTs, NMIs always schedule an exit when they are
@@ -395,7 +389,7 @@ nvmm_vcpu_pre_run(CPUState *cpu)
{
CPUX86State *env = cpu->env_ptr;
struct nvmm_machine *mach = get_nvmm_mach();
- struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu);
+ AccelCPUState *qcpu = cpu->accel;
struct nvmm_vcpu *vcpu = &qcpu->vcpu;
X86CPU *x86_cpu = X86_CPU(cpu);
struct nvmm_x64_state *state = vcpu->state;
@@ -478,7 +472,7 @@ nvmm_vcpu_pre_run(CPUState *cpu)
static void
nvmm_vcpu_post_run(CPUState *cpu, struct nvmm_vcpu_exit *exit)
{
- struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu);
+ AccelCPUState *qcpu = cpu->accel;
CPUX86State *env = cpu->env_ptr;
X86CPU *x86_cpu = X86_CPU(cpu);
uint64_t tpr;
@@ -565,7 +559,7 @@ static int
nvmm_handle_rdmsr(struct nvmm_machine *mach, CPUState *cpu,
struct nvmm_vcpu_exit *exit)
{
- struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu);
+ AccelCPUState *qcpu = cpu->accel;
struct nvmm_vcpu *vcpu = &qcpu->vcpu;
X86CPU *x86_cpu = X86_CPU(cpu);
struct nvmm_x64_state *state = vcpu->state;
@@ -610,7 +604,7 @@ static int
nvmm_handle_wrmsr(struct nvmm_machine *mach, CPUState *cpu,
struct nvmm_vcpu_exit *exit)
{
- struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu);
+ AccelCPUState *qcpu = cpu->accel;
struct nvmm_vcpu *vcpu = &qcpu->vcpu;
X86CPU *x86_cpu = X86_CPU(cpu);
struct nvmm_x64_state *state = vcpu->state;
@@ -686,7 +680,7 @@ nvmm_vcpu_loop(CPUState *cpu)
{
CPUX86State *env = cpu->env_ptr;
struct nvmm_machine *mach = get_nvmm_mach();
- struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu);
+ AccelCPUState *qcpu = cpu->accel;
struct nvmm_vcpu *vcpu = &qcpu->vcpu;
X86CPU *x86_cpu = X86_CPU(cpu);
struct nvmm_vcpu_exit *exit = vcpu->exit;
@@ -892,7 +886,7 @@ static void
nvmm_ipi_signal(int sigcpu)
{
if (current_cpu) {
- struct qemu_vcpu *qcpu = get_qemu_vcpu(current_cpu);
+ AccelCPUState *qcpu = current_cpu->accel;
#if NVMM_USER_VERSION >= 2
struct nvmm_vcpu *vcpu = &qcpu->vcpu;
nvmm_vcpu_stop(vcpu);
@@ -926,7 +920,7 @@ nvmm_init_vcpu(CPUState *cpu)
struct nvmm_vcpu_conf_cpuid cpuid;
struct nvmm_vcpu_conf_tpr tpr;
Error *local_error = NULL;
- struct qemu_vcpu *qcpu;
+ AccelCPUState *qcpu;
int ret, err;
nvmm_init_cpu_signals();
@@ -942,11 +936,7 @@ nvmm_init_vcpu(CPUState *cpu)
}
}
- qcpu = g_malloc0(sizeof(*qcpu));
- if (qcpu == NULL) {
- error_report("NVMM: Failed to allocate VCPU context.");
- return -ENOMEM;
- }
+ qcpu = g_new0(AccelCPUState, 1);
ret = nvmm_vcpu_create(mach, cpu->cpu_index, &qcpu->vcpu);
if (ret == -1) {
@@ -995,7 +985,7 @@ nvmm_init_vcpu(CPUState *cpu)
}
cpu->vcpu_dirty = true;
- cpu->hax_vcpu = (struct hax_vcpu_state *)qcpu;
+ cpu->accel = qcpu;
return 0;
}
@@ -1027,10 +1017,10 @@ void
nvmm_destroy_vcpu(CPUState *cpu)
{
struct nvmm_machine *mach = get_nvmm_mach();
- struct qemu_vcpu *qcpu = get_qemu_vcpu(cpu);
+ AccelCPUState *qcpu = cpu->accel;
nvmm_vcpu_destroy(mach, &qcpu->vcpu);
- g_free(cpu->hax_vcpu);
+ g_free(cpu->accel);
}
/* -------------------------------------------------------------------------- */
@@ -1138,7 +1128,7 @@ static MemoryListener nvmm_memory_listener = {
.region_add = nvmm_region_add,
.region_del = nvmm_region_del,
.log_sync = nvmm_log_sync,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
};
static void
diff --git a/target/i386/whpx/whpx-accel-ops.c b/target/i386/whpx/whpx-accel-ops.c
index e8dc4b3a47..67cad86720 100644
--- a/target/i386/whpx/whpx-accel-ops.c
+++ b/target/i386/whpx/whpx-accel-ops.c
@@ -71,9 +71,6 @@ static void whpx_start_vcpu_thread(CPUState *cpu)
cpu->cpu_index);
qemu_thread_create(cpu->thread, thread_name, whpx_cpu_thread_fn,
cpu, QEMU_THREAD_JOINABLE);
-#ifdef _WIN32
- cpu->hThread = qemu_thread_get_handle(cpu->thread);
-#endif
}
static void whpx_kick_vcpu_thread(CPUState *cpu)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 52af81683c..3de0dc1d46 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -31,8 +31,8 @@
#include "whpx-internal.h"
#include "whpx-accel-ops.h"
-#include <WinHvPlatform.h>
-#include <WinHvEmulation.h>
+#include <winhvplatform.h>
+#include <winhvemulation.h>
#define HYPERV_APIC_BUS_FREQUENCY (200000000ULL)
@@ -229,7 +229,7 @@ typedef enum WhpxStepMode {
WHPX_STEP_EXCLUSIVE,
} WhpxStepMode;
-struct whpx_vcpu {
+struct AccelCPUState {
WHV_EMULATOR_HANDLE emulator;
bool window_registered;
bool interruptable;
@@ -256,15 +256,6 @@ static bool whpx_has_xsave(void)
return whpx_xsave_cap.XsaveSupport;
}
-/*
- * VP support
- */
-
-static struct whpx_vcpu *get_whpx_vcpu(CPUState *cpu)
-{
- return (struct whpx_vcpu *)cpu->hax_vcpu;
-}
-
static WHV_X64_SEGMENT_REGISTER whpx_seg_q2h(const SegmentCache *qs, int v86,
int r86)
{
@@ -390,7 +381,7 @@ static uint64_t whpx_cr8_to_apic_tpr(uint64_t cr8)
static void whpx_set_registers(CPUState *cpu, int level)
{
struct whpx_state *whpx = &whpx_global;
- struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
+ AccelCPUState *vcpu = cpu->accel;
CPUX86State *env = cpu->env_ptr;
X86CPU *x86_cpu = X86_CPU(cpu);
struct whpx_register_set vcxt;
@@ -609,7 +600,7 @@ static void whpx_get_xcrs(CPUState *cpu)
static void whpx_get_registers(CPUState *cpu)
{
struct whpx_state *whpx = &whpx_global;
- struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
+ AccelCPUState *vcpu = cpu->accel;
CPUX86State *env = cpu->env_ptr;
X86CPU *x86_cpu = X86_CPU(cpu);
struct whpx_register_set vcxt;
@@ -892,7 +883,7 @@ static const WHV_EMULATOR_CALLBACKS whpx_emu_callbacks = {
static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx)
{
HRESULT hr;
- struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
+ AccelCPUState *vcpu = cpu->accel;
WHV_EMULATOR_STATUS emu_status;
hr = whp_dispatch.WHvEmulatorTryMmioEmulation(
@@ -917,7 +908,7 @@ static int whpx_handle_portio(CPUState *cpu,
WHV_X64_IO_PORT_ACCESS_CONTEXT *ctx)
{
HRESULT hr;
- struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
+ AccelCPUState *vcpu = cpu->accel;
WHV_EMULATOR_STATUS emu_status;
hr = whp_dispatch.WHvEmulatorTryIoEmulation(
@@ -1417,7 +1408,7 @@ static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid)
* of QEMU, nor this port by calling WHvSetVirtualProcessorRegisters().
* This is the most common case.
*/
- struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
+ AccelCPUState *vcpu = cpu->accel;
return vcpu->exit_ctx.VpContext.Rip;
} else {
/*
@@ -1468,7 +1459,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);
+ AccelCPUState *vcpu = cpu->accel;
CPUX86State *env = cpu->env_ptr;
X86CPU *x86_cpu = X86_CPU(cpu);
int irq;
@@ -1590,7 +1581,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);
+ AccelCPUState *vcpu = cpu->accel;
CPUX86State *env = cpu->env_ptr;
X86CPU *x86_cpu = X86_CPU(cpu);
@@ -1617,7 +1608,7 @@ static void whpx_vcpu_process_async_events(CPUState *cpu)
{
CPUX86State *env = cpu->env_ptr;
X86CPU *x86_cpu = X86_CPU(cpu);
- struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
+ AccelCPUState *vcpu = cpu->accel;
if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) &&
!(env->hflags & HF_SMM_MASK)) {
@@ -1656,7 +1647,7 @@ static int whpx_vcpu_run(CPUState *cpu)
{
HRESULT hr;
struct whpx_state *whpx = &whpx_global;
- struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
+ AccelCPUState *vcpu = cpu->accel;
struct whpx_breakpoint *stepped_over_bp = NULL;
WhpxStepMode exclusive_step_mode = WHPX_STEP_NONE;
int ret;
@@ -2154,7 +2145,7 @@ int whpx_init_vcpu(CPUState *cpu)
{
HRESULT hr;
struct whpx_state *whpx = &whpx_global;
- struct whpx_vcpu *vcpu = NULL;
+ AccelCPUState *vcpu = NULL;
Error *local_error = NULL;
CPUX86State *env = cpu->env_ptr;
X86CPU *x86_cpu = X86_CPU(cpu);
@@ -2177,13 +2168,7 @@ int whpx_init_vcpu(CPUState *cpu)
}
}
- vcpu = g_new0(struct whpx_vcpu, 1);
-
- if (!vcpu) {
- error_report("WHPX: Failed to allocte VCPU context.");
- ret = -ENOMEM;
- goto error;
- }
+ vcpu = g_new0(AccelCPUState, 1);
hr = whp_dispatch.WHvEmulatorCreateEmulator(
&whpx_emu_callbacks,
@@ -2258,7 +2243,7 @@ int whpx_init_vcpu(CPUState *cpu)
vcpu->interruptable = true;
cpu->vcpu_dirty = true;
- cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu;
+ cpu->accel = vcpu;
max_vcpu_index = max(max_vcpu_index, cpu->cpu_index);
qemu_add_vm_change_state_handler(whpx_cpu_update_state, cpu->env_ptr);
@@ -2296,11 +2281,11 @@ int whpx_vcpu_exec(CPUState *cpu)
void whpx_destroy_vcpu(CPUState *cpu)
{
struct whpx_state *whpx = &whpx_global;
- struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
+ AccelCPUState *vcpu = cpu->accel;
whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
- g_free(cpu->hax_vcpu);
+ g_free(cpu->accel);
return;
}
@@ -2427,7 +2412,7 @@ static MemoryListener whpx_memory_listener = {
.region_add = whpx_region_add,
.region_del = whpx_region_del,
.log_sync = whpx_log_sync,
- .priority = 10,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
};
static void whpx_memory_init(void)
@@ -2613,8 +2598,8 @@ static int whpx_accel_init(MachineState *ms)
sizeof(WHV_PARTITION_PROPERTY));
if (FAILED(hr)) {
- error_report("WHPX: Failed to set partition core count to %d,"
- " hr=%08lx", ms->smp.cores, hr);
+ error_report("WHPX: Failed to set partition processor count to %u,"
+ " hr=%08lx", prop.ProcessorCount, hr);
ret = -EINVAL;
goto error;
}
diff --git a/target/i386/whpx/whpx-internal.h b/target/i386/whpx/whpx-internal.h
index 06429d8ccd..6633e9c4ca 100644
--- a/target/i386/whpx/whpx-internal.h
+++ b/target/i386/whpx/whpx-internal.h
@@ -2,8 +2,8 @@
#define TARGET_I386_WHPX_INTERNAL_H
#include <windows.h>
-#include <WinHvPlatform.h>
-#include <WinHvEmulation.h>
+#include <winhvplatform.h>
+#include <winhvemulation.h>
typedef enum WhpxBreakpointState {
WHPX_BP_CLEARED = 0,
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 94497aa115..af12c93ebc 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1149,8 +1149,10 @@ struct CPUArchState {
int nb_pids; /* Number of available PID registers */
int tlb_type; /* Type of TLB we're dealing with */
ppc_tlb_t tlb; /* TLB is optional. Allocate them only if needed */
+#ifdef CONFIG_KVM
bool tlb_dirty; /* Set to non-zero when modifying TLB */
bool kvm_sw_tlb; /* non-zero if KVM SW TLB API is active */
+#endif /* CONFIG_KVM */
uint32_t tlb_need_flush; /* Delayed flush needed */
#define TLB_NEED_LOCAL_FLUSH 0x1
#define TLB_NEED_GLOBAL_FLUSH 0x2
diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index ae1db6e348..8c000e250d 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -930,10 +930,12 @@ static void mmubooke_dump_mmu(CPUPPCState *env)
ppcemb_tlb_t *entry;
int i;
+#ifdef CONFIG_KVM
if (kvm_enabled() && !env->kvm_sw_tlb) {
qemu_printf("Cannot access KVM TLB\n");
return;
}
+#endif
qemu_printf("\nTLB:\n");
qemu_printf("Effective Physical Size PID Prot "
@@ -1021,10 +1023,12 @@ static void mmubooke206_dump_mmu(CPUPPCState *env)
int offset = 0;
int i;
+#ifdef CONFIG_KVM
if (kvm_enabled() && !env->kvm_sw_tlb) {
qemu_printf("Cannot access KVM TLB\n");
return;
}
+#endif
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
int size = booke206_tlb_size(env, i);
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 881bddf393..4035fe0e62 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -584,7 +584,7 @@ static void riscv_host_cpu_init(Object *obj)
#endif
riscv_cpu_add_user_properties(obj);
}
-#endif
+#endif /* CONFIG_KVM */
static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model)
{
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 7bff1d47f6..7adb8706ac 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -363,12 +363,14 @@ struct CPUArchState {
hwaddr kernel_addr;
hwaddr fdt_addr;
+#ifdef CONFIG_KVM
/* kvm timer */
bool kvm_timer_dirty;
uint64_t kvm_timer_time;
uint64_t kvm_timer_compare;
uint64_t kvm_timer_state;
uint64_t kvm_timer_frequency;
+#endif /* CONFIG_KVM */
};
/*
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 3ce2970785..c7c862cdd3 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -194,12 +194,13 @@ static const VMStateDescription vmstate_rv128 = {
}
};
+#ifdef CONFIG_KVM
static bool kvmtimer_needed(void *opaque)
{
return kvm_enabled();
}
-static int cpu_post_load(void *opaque, int version_id)
+static int cpu_kvmtimer_post_load(void *opaque, int version_id)
{
RISCVCPU *cpu = opaque;
CPURISCVState *env = &cpu->env;
@@ -213,7 +214,7 @@ static const VMStateDescription vmstate_kvmtimer = {
.version_id = 1,
.minimum_version_id = 1,
.needed = kvmtimer_needed,
- .post_load = cpu_post_load,
+ .post_load = cpu_kvmtimer_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT64(env.kvm_timer_time, RISCVCPU),
VMSTATE_UINT64(env.kvm_timer_compare, RISCVCPU),
@@ -221,6 +222,7 @@ static const VMStateDescription vmstate_kvmtimer = {
VMSTATE_END_OF_LIST()
}
};
+#endif
static bool debug_needed(void *opaque)
{
@@ -409,7 +411,9 @@ const VMStateDescription vmstate_riscv_cpu = {
&vmstate_vector,
&vmstate_pointermasking,
&vmstate_rv128,
+#ifdef CONFIG_KVM
&vmstate_kvmtimer,
+#endif
&vmstate_envcfg,
&vmstate_debug,
&vmstate_smstateen,
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index bad2ec90a0..bd877a5e4a 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -37,9 +37,12 @@
#include "exec/helper-info.c.inc"
#undef HELPER_H
-#define DYNAMIC_PC 1 /* dynamic pc value */
-#define JUMP_PC 2 /* dynamic pc value which takes only two values
- according to jump_pc[T2] */
+/* Dynamic PC, must exit to main loop. */
+#define DYNAMIC_PC 1
+/* Dynamic PC, one of two values according to jump_pc[T2]. */
+#define JUMP_PC 2
+/* Dynamic PC, may lookup next TB. */
+#define DYNAMIC_PC_LOOKUP 3
#define DISAS_EXIT DISAS_TARGET_0
@@ -125,7 +128,7 @@ static int sign_extend(int x, int len)
#define IS_IMM (insn & (1<<13))
-static inline void gen_update_fprs_dirty(DisasContext *dc, int rd)
+static void gen_update_fprs_dirty(DisasContext *dc, int rd)
{
#if defined(TARGET_SPARC64)
int bit = (rd < 32) ? 1 : 2;
@@ -264,7 +267,7 @@ static void gen_move_Q(DisasContext *dc, unsigned int rd, unsigned int rs)
#endif
#endif
-static inline void gen_address_mask(DisasContext *dc, TCGv addr)
+static void gen_address_mask(DisasContext *dc, TCGv addr)
{
#ifdef TARGET_SPARC64
if (AM_CHECK(dc))
@@ -272,7 +275,7 @@ static inline void gen_address_mask(DisasContext *dc, TCGv addr)
#endif
}
-static inline TCGv gen_load_gpr(DisasContext *dc, int reg)
+static TCGv gen_load_gpr(DisasContext *dc, int reg)
{
if (reg > 0) {
assert(reg < 32);
@@ -284,7 +287,7 @@ static inline TCGv gen_load_gpr(DisasContext *dc, int reg)
}
}
-static inline void gen_store_gpr(DisasContext *dc, int reg, TCGv v)
+static void gen_store_gpr(DisasContext *dc, int reg, TCGv v)
{
if (reg > 0) {
assert(reg < 32);
@@ -292,7 +295,7 @@ static inline void gen_store_gpr(DisasContext *dc, int reg, TCGv v)
}
}
-static inline TCGv gen_dest_gpr(DisasContext *dc, int reg)
+static TCGv gen_dest_gpr(DisasContext *dc, int reg)
{
if (reg > 0) {
assert(reg < 32);
@@ -318,39 +321,39 @@ static void gen_goto_tb(DisasContext *s, int tb_num,
tcg_gen_movi_tl(cpu_npc, npc);
tcg_gen_exit_tb(s->base.tb, tb_num);
} else {
- /* jump to another page: currently not optimized */
+ /* jump to another page: we can use an indirect jump */
tcg_gen_movi_tl(cpu_pc, pc);
tcg_gen_movi_tl(cpu_npc, npc);
- tcg_gen_exit_tb(NULL, 0);
+ tcg_gen_lookup_and_goto_ptr();
}
}
// XXX suboptimal
-static inline void gen_mov_reg_N(TCGv reg, TCGv_i32 src)
+static void gen_mov_reg_N(TCGv reg, TCGv_i32 src)
{
tcg_gen_extu_i32_tl(reg, src);
tcg_gen_extract_tl(reg, reg, PSR_NEG_SHIFT, 1);
}
-static inline void gen_mov_reg_Z(TCGv reg, TCGv_i32 src)
+static void gen_mov_reg_Z(TCGv reg, TCGv_i32 src)
{
tcg_gen_extu_i32_tl(reg, src);
tcg_gen_extract_tl(reg, reg, PSR_ZERO_SHIFT, 1);
}
-static inline void gen_mov_reg_V(TCGv reg, TCGv_i32 src)
+static void gen_mov_reg_V(TCGv reg, TCGv_i32 src)
{
tcg_gen_extu_i32_tl(reg, src);
tcg_gen_extract_tl(reg, reg, PSR_OVF_SHIFT, 1);
}
-static inline void gen_mov_reg_C(TCGv reg, TCGv_i32 src)
+static void gen_mov_reg_C(TCGv reg, TCGv_i32 src)
{
tcg_gen_extu_i32_tl(reg, src);
tcg_gen_extract_tl(reg, reg, PSR_CARRY_SHIFT, 1);
}
-static inline void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2)
+static void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2)
{
tcg_gen_mov_tl(cpu_cc_src, src1);
tcg_gen_mov_tl(cpu_cc_src2, src2);
@@ -465,7 +468,7 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
}
}
-static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
+static void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
{
tcg_gen_mov_tl(cpu_cc_src, src1);
tcg_gen_mov_tl(cpu_cc_src2, src2);
@@ -538,7 +541,7 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1,
}
}
-static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
+static void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
{
TCGv r_temp, zero, t0;
@@ -577,7 +580,7 @@ static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2)
tcg_gen_mov_tl(dst, cpu_cc_dst);
}
-static inline void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext)
+static void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext)
{
#if TARGET_LONG_BITS == 32
if (sign_ext) {
@@ -602,32 +605,32 @@ static inline void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext)
#endif
}
-static inline void gen_op_umul(TCGv dst, TCGv src1, TCGv src2)
+static void gen_op_umul(TCGv dst, TCGv src1, TCGv src2)
{
/* zero-extend truncated operands before multiplication */
gen_op_multiply(dst, src1, src2, 0);
}
-static inline void gen_op_smul(TCGv dst, TCGv src1, TCGv src2)
+static void gen_op_smul(TCGv dst, TCGv src1, TCGv src2)
{
/* sign-extend truncated operands before multiplication */
gen_op_multiply(dst, src1, src2, 1);
}
// 1
-static inline void gen_op_eval_ba(TCGv dst)
+static void gen_op_eval_ba(TCGv dst)
{
tcg_gen_movi_tl(dst, 1);
}
// Z
-static inline void gen_op_eval_be(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_be(TCGv dst, TCGv_i32 src)
{
gen_mov_reg_Z(dst, src);
}
// Z | (N ^ V)
-static inline void gen_op_eval_ble(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_ble(TCGv dst, TCGv_i32 src)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_N(t0, src);
@@ -638,7 +641,7 @@ static inline void gen_op_eval_ble(TCGv dst, TCGv_i32 src)
}
// N ^ V
-static inline void gen_op_eval_bl(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bl(TCGv dst, TCGv_i32 src)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_V(t0, src);
@@ -647,7 +650,7 @@ static inline void gen_op_eval_bl(TCGv dst, TCGv_i32 src)
}
// C | Z
-static inline void gen_op_eval_bleu(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bleu(TCGv dst, TCGv_i32 src)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_Z(t0, src);
@@ -656,73 +659,73 @@ static inline void gen_op_eval_bleu(TCGv dst, TCGv_i32 src)
}
// C
-static inline void gen_op_eval_bcs(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bcs(TCGv dst, TCGv_i32 src)
{
gen_mov_reg_C(dst, src);
}
// V
-static inline void gen_op_eval_bvs(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bvs(TCGv dst, TCGv_i32 src)
{
gen_mov_reg_V(dst, src);
}
// 0
-static inline void gen_op_eval_bn(TCGv dst)
+static void gen_op_eval_bn(TCGv dst)
{
tcg_gen_movi_tl(dst, 0);
}
// N
-static inline void gen_op_eval_bneg(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bneg(TCGv dst, TCGv_i32 src)
{
gen_mov_reg_N(dst, src);
}
// !Z
-static inline void gen_op_eval_bne(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bne(TCGv dst, TCGv_i32 src)
{
gen_mov_reg_Z(dst, src);
tcg_gen_xori_tl(dst, dst, 0x1);
}
// !(Z | (N ^ V))
-static inline void gen_op_eval_bg(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bg(TCGv dst, TCGv_i32 src)
{
gen_op_eval_ble(dst, src);
tcg_gen_xori_tl(dst, dst, 0x1);
}
// !(N ^ V)
-static inline void gen_op_eval_bge(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bge(TCGv dst, TCGv_i32 src)
{
gen_op_eval_bl(dst, src);
tcg_gen_xori_tl(dst, dst, 0x1);
}
// !(C | Z)
-static inline void gen_op_eval_bgu(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bgu(TCGv dst, TCGv_i32 src)
{
gen_op_eval_bleu(dst, src);
tcg_gen_xori_tl(dst, dst, 0x1);
}
// !C
-static inline void gen_op_eval_bcc(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bcc(TCGv dst, TCGv_i32 src)
{
gen_mov_reg_C(dst, src);
tcg_gen_xori_tl(dst, dst, 0x1);
}
// !N
-static inline void gen_op_eval_bpos(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bpos(TCGv dst, TCGv_i32 src)
{
gen_mov_reg_N(dst, src);
tcg_gen_xori_tl(dst, dst, 0x1);
}
// !V
-static inline void gen_op_eval_bvc(TCGv dst, TCGv_i32 src)
+static void gen_op_eval_bvc(TCGv dst, TCGv_i32 src)
{
gen_mov_reg_V(dst, src);
tcg_gen_xori_tl(dst, dst, 0x1);
@@ -735,23 +738,21 @@ static inline void gen_op_eval_bvc(TCGv dst, TCGv_i32 src)
2 >
3 unordered
*/
-static inline void gen_mov_reg_FCC0(TCGv reg, TCGv src,
+static void gen_mov_reg_FCC0(TCGv reg, TCGv src,
unsigned int fcc_offset)
{
tcg_gen_shri_tl(reg, src, FSR_FCC0_SHIFT + fcc_offset);
tcg_gen_andi_tl(reg, reg, 0x1);
}
-static inline void gen_mov_reg_FCC1(TCGv reg, TCGv src,
- unsigned int fcc_offset)
+static void gen_mov_reg_FCC1(TCGv reg, TCGv src, unsigned int fcc_offset)
{
tcg_gen_shri_tl(reg, src, FSR_FCC1_SHIFT + fcc_offset);
tcg_gen_andi_tl(reg, reg, 0x1);
}
// !0: FCC0 | FCC1
-static inline void gen_op_eval_fbne(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbne(TCGv dst, TCGv src, unsigned int fcc_offset)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_FCC0(dst, src, fcc_offset);
@@ -760,8 +761,7 @@ static inline void gen_op_eval_fbne(TCGv dst, TCGv src,
}
// 1 or 2: FCC0 ^ FCC1
-static inline void gen_op_eval_fblg(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fblg(TCGv dst, TCGv src, unsigned int fcc_offset)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_FCC0(dst, src, fcc_offset);
@@ -770,15 +770,13 @@ static inline void gen_op_eval_fblg(TCGv dst, TCGv src,
}
// 1 or 3: FCC0
-static inline void gen_op_eval_fbul(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbul(TCGv dst, TCGv src, unsigned int fcc_offset)
{
gen_mov_reg_FCC0(dst, src, fcc_offset);
}
// 1: FCC0 & !FCC1
-static inline void gen_op_eval_fbl(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbl(TCGv dst, TCGv src, unsigned int fcc_offset)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_FCC0(dst, src, fcc_offset);
@@ -787,15 +785,13 @@ static inline void gen_op_eval_fbl(TCGv dst, TCGv src,
}
// 2 or 3: FCC1
-static inline void gen_op_eval_fbug(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbug(TCGv dst, TCGv src, unsigned int fcc_offset)
{
gen_mov_reg_FCC1(dst, src, fcc_offset);
}
// 2: !FCC0 & FCC1
-static inline void gen_op_eval_fbg(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbg(TCGv dst, TCGv src, unsigned int fcc_offset)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_FCC0(dst, src, fcc_offset);
@@ -804,8 +800,7 @@ static inline void gen_op_eval_fbg(TCGv dst, TCGv src,
}
// 3: FCC0 & FCC1
-static inline void gen_op_eval_fbu(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbu(TCGv dst, TCGv src, unsigned int fcc_offset)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_FCC0(dst, src, fcc_offset);
@@ -814,8 +809,7 @@ static inline void gen_op_eval_fbu(TCGv dst, TCGv src,
}
// 0: !(FCC0 | FCC1)
-static inline void gen_op_eval_fbe(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbe(TCGv dst, TCGv src, unsigned int fcc_offset)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_FCC0(dst, src, fcc_offset);
@@ -825,8 +819,7 @@ static inline void gen_op_eval_fbe(TCGv dst, TCGv src,
}
// 0 or 3: !(FCC0 ^ FCC1)
-static inline void gen_op_eval_fbue(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbue(TCGv dst, TCGv src, unsigned int fcc_offset)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_FCC0(dst, src, fcc_offset);
@@ -836,16 +829,14 @@ static inline void gen_op_eval_fbue(TCGv dst, TCGv src,
}
// 0 or 2: !FCC0
-static inline void gen_op_eval_fbge(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbge(TCGv dst, TCGv src, unsigned int fcc_offset)
{
gen_mov_reg_FCC0(dst, src, fcc_offset);
tcg_gen_xori_tl(dst, dst, 0x1);
}
// !1: !(FCC0 & !FCC1)
-static inline void gen_op_eval_fbuge(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbuge(TCGv dst, TCGv src, unsigned int fcc_offset)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_FCC0(dst, src, fcc_offset);
@@ -855,16 +846,14 @@ static inline void gen_op_eval_fbuge(TCGv dst, TCGv src,
}
// 0 or 1: !FCC1
-static inline void gen_op_eval_fble(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fble(TCGv dst, TCGv src, unsigned int fcc_offset)
{
gen_mov_reg_FCC1(dst, src, fcc_offset);
tcg_gen_xori_tl(dst, dst, 0x1);
}
// !2: !(!FCC0 & FCC1)
-static inline void gen_op_eval_fbule(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbule(TCGv dst, TCGv src, unsigned int fcc_offset)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_FCC0(dst, src, fcc_offset);
@@ -874,8 +863,7 @@ static inline void gen_op_eval_fbule(TCGv dst, TCGv src,
}
// !3: !(FCC0 & FCC1)
-static inline void gen_op_eval_fbo(TCGv dst, TCGv src,
- unsigned int fcc_offset)
+static void gen_op_eval_fbo(TCGv dst, TCGv src, unsigned int fcc_offset)
{
TCGv t0 = tcg_temp_new();
gen_mov_reg_FCC0(dst, src, fcc_offset);
@@ -884,8 +872,8 @@ static inline void gen_op_eval_fbo(TCGv dst, TCGv src,
tcg_gen_xori_tl(dst, dst, 0x1);
}
-static inline void gen_branch2(DisasContext *dc, target_ulong pc1,
- target_ulong pc2, TCGv r_cond)
+static void gen_branch2(DisasContext *dc, target_ulong pc1,
+ target_ulong pc2, TCGv r_cond)
{
TCGLabel *l1 = gen_new_label();
@@ -916,26 +904,29 @@ static void gen_branch_n(DisasContext *dc, target_ulong pc1)
{
target_ulong npc = dc->npc;
- if (likely(npc != DYNAMIC_PC)) {
+ if (npc & 3) {
+ switch (npc) {
+ case DYNAMIC_PC:
+ case DYNAMIC_PC_LOOKUP:
+ tcg_gen_mov_tl(cpu_pc, cpu_npc);
+ tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
+ tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc,
+ cpu_cond, tcg_constant_tl(0),
+ tcg_constant_tl(pc1), cpu_npc);
+ dc->pc = npc;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ } else {
dc->pc = npc;
dc->jump_pc[0] = pc1;
dc->jump_pc[1] = npc + 4;
dc->npc = JUMP_PC;
- } else {
- TCGv t, z;
-
- tcg_gen_mov_tl(cpu_pc, cpu_npc);
-
- tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
- t = tcg_constant_tl(pc1);
- z = tcg_constant_tl(0);
- tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc, cpu_cond, z, t, cpu_npc);
-
- dc->pc = DYNAMIC_PC;
}
}
-static inline void gen_generic_branch(DisasContext *dc)
+static void gen_generic_branch(DisasContext *dc)
{
TCGv npc0 = tcg_constant_tl(dc->jump_pc[0]);
TCGv npc1 = tcg_constant_tl(dc->jump_pc[1]);
@@ -946,25 +937,34 @@ static inline void gen_generic_branch(DisasContext *dc)
/* call this function before using the condition register as it may
have been set for a jump */
-static inline void flush_cond(DisasContext *dc)
+static void flush_cond(DisasContext *dc)
{
if (dc->npc == JUMP_PC) {
gen_generic_branch(dc);
- dc->npc = DYNAMIC_PC;
+ dc->npc = DYNAMIC_PC_LOOKUP;
}
}
-static inline void save_npc(DisasContext *dc)
+static void save_npc(DisasContext *dc)
{
- if (dc->npc == JUMP_PC) {
- gen_generic_branch(dc);
- dc->npc = DYNAMIC_PC;
- } else if (dc->npc != DYNAMIC_PC) {
+ if (dc->npc & 3) {
+ switch (dc->npc) {
+ case JUMP_PC:
+ gen_generic_branch(dc);
+ dc->npc = DYNAMIC_PC_LOOKUP;
+ break;
+ case DYNAMIC_PC:
+ case DYNAMIC_PC_LOOKUP:
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ } else {
tcg_gen_movi_tl(cpu_npc, dc->npc);
}
}
-static inline void update_psr(DisasContext *dc)
+static void update_psr(DisasContext *dc)
{
if (dc->cc_op != CC_OP_FLAGS) {
dc->cc_op = CC_OP_FLAGS;
@@ -972,7 +972,7 @@ static inline void update_psr(DisasContext *dc)
}
}
-static inline void save_state(DisasContext *dc)
+static void save_state(DisasContext *dc)
{
tcg_gen_movi_tl(cpu_pc, dc->pc);
save_npc(dc);
@@ -990,21 +990,29 @@ static void gen_check_align(TCGv addr, int mask)
gen_helper_check_align(cpu_env, addr, tcg_constant_i32(mask));
}
-static inline void gen_mov_pc_npc(DisasContext *dc)
+static void gen_mov_pc_npc(DisasContext *dc)
{
- if (dc->npc == JUMP_PC) {
- gen_generic_branch(dc);
- tcg_gen_mov_tl(cpu_pc, cpu_npc);
- dc->pc = DYNAMIC_PC;
- } else if (dc->npc == DYNAMIC_PC) {
- tcg_gen_mov_tl(cpu_pc, cpu_npc);
- dc->pc = DYNAMIC_PC;
+ if (dc->npc & 3) {
+ switch (dc->npc) {
+ case JUMP_PC:
+ gen_generic_branch(dc);
+ tcg_gen_mov_tl(cpu_pc, cpu_npc);
+ dc->pc = DYNAMIC_PC_LOOKUP;
+ break;
+ case DYNAMIC_PC:
+ case DYNAMIC_PC_LOOKUP:
+ tcg_gen_mov_tl(cpu_pc, cpu_npc);
+ dc->pc = dc->npc;
+ break;
+ default:
+ g_assert_not_reached();
+ }
} else {
dc->pc = dc->npc;
}
}
-static inline void gen_op_next_insn(void)
+static void gen_op_next_insn(void)
{
tcg_gen_mov_tl(cpu_pc, cpu_npc);
tcg_gen_addi_tl(cpu_npc, cpu_npc, 4);
@@ -1305,7 +1313,7 @@ static void gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src)
cmp->c2 = tcg_constant_tl(0);
}
-static inline void gen_cond_reg(TCGv r_dst, int cond, TCGv r_src)
+static void gen_cond_reg(TCGv r_dst, int cond, TCGv r_src)
{
DisasCompare cmp;
gen_compare_reg(&cmp, cond, r_src);
@@ -1414,7 +1422,7 @@ static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn,
}
}
-static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
+static void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
{
switch (fccno) {
case 0:
@@ -1432,7 +1440,7 @@ static inline void gen_op_fcmps(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
}
}
-static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
+static void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
{
switch (fccno) {
case 0:
@@ -1450,7 +1458,7 @@ static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
}
}
-static inline void gen_op_fcmpq(int fccno)
+static void gen_op_fcmpq(int fccno)
{
switch (fccno) {
case 0:
@@ -1468,7 +1476,7 @@ static inline void gen_op_fcmpq(int fccno)
}
}
-static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
+static void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
{
switch (fccno) {
case 0:
@@ -1486,7 +1494,7 @@ static inline void gen_op_fcmpes(int fccno, TCGv_i32 r_rs1, TCGv_i32 r_rs2)
}
}
-static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
+static void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
{
switch (fccno) {
case 0:
@@ -1504,7 +1512,7 @@ static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
}
}
-static inline void gen_op_fcmpeq(int fccno)
+static void gen_op_fcmpeq(int fccno)
{
switch (fccno) {
case 0:
@@ -1524,32 +1532,32 @@ static inline void gen_op_fcmpeq(int fccno)
#else
-static inline void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
+static void gen_op_fcmps(int fccno, TCGv r_rs1, TCGv r_rs2)
{
gen_helper_fcmps(cpu_fsr, cpu_env, r_rs1, r_rs2);
}
-static inline void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
+static void gen_op_fcmpd(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
{
gen_helper_fcmpd(cpu_fsr, cpu_env, r_rs1, r_rs2);
}
-static inline void gen_op_fcmpq(int fccno)
+static void gen_op_fcmpq(int fccno)
{
gen_helper_fcmpq(cpu_fsr, cpu_env);
}
-static inline void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
+static void gen_op_fcmpes(int fccno, TCGv r_rs1, TCGv r_rs2)
{
gen_helper_fcmpes(cpu_fsr, cpu_env, r_rs1, r_rs2);
}
-static inline void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
+static void gen_op_fcmped(int fccno, TCGv_i64 r_rs1, TCGv_i64 r_rs2)
{
gen_helper_fcmped(cpu_fsr, cpu_env, r_rs1, r_rs2);
}
-static inline void gen_op_fcmpeq(int fccno)
+static void gen_op_fcmpeq(int fccno)
{
gen_helper_fcmpeq(cpu_fsr, cpu_env);
}
@@ -1573,12 +1581,12 @@ static int gen_trap_ifnofpu(DisasContext *dc)
return 0;
}
-static inline void gen_op_clear_ieee_excp_and_FTT(void)
+static void gen_op_clear_ieee_excp_and_FTT(void)
{
tcg_gen_andi_tl(cpu_fsr, cpu_fsr, FSR_FTT_CEXC_NMASK);
}
-static inline void gen_fop_FF(DisasContext *dc, int rd, int rs,
+static void gen_fop_FF(DisasContext *dc, int rd, int rs,
void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i32))
{
TCGv_i32 dst, src;
@@ -1592,8 +1600,8 @@ static inline void gen_fop_FF(DisasContext *dc, int rd, int rs,
gen_store_fpr_F(dc, rd, dst);
}
-static inline void gen_ne_fop_FF(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_i32, TCGv_i32))
+static void gen_ne_fop_FF(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_i32, TCGv_i32))
{
TCGv_i32 dst, src;
@@ -1605,7 +1613,7 @@ static inline void gen_ne_fop_FF(DisasContext *dc, int rd, int rs,
gen_store_fpr_F(dc, rd, dst);
}
-static inline void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
+static void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32))
{
TCGv_i32 dst, src1, src2;
@@ -1621,8 +1629,8 @@ static inline void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
}
#ifdef TARGET_SPARC64
-static inline void gen_ne_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
- void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32))
+static void gen_ne_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
+ void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32))
{
TCGv_i32 dst, src1, src2;
@@ -1636,8 +1644,8 @@ static inline void gen_ne_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2,
}
#endif
-static inline void gen_fop_DD(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i64))
+static void gen_fop_DD(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i64))
{
TCGv_i64 dst, src;
@@ -1651,8 +1659,8 @@ static inline void gen_fop_DD(DisasContext *dc, int rd, int rs,
}
#ifdef TARGET_SPARC64
-static inline void gen_ne_fop_DD(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_i64, TCGv_i64))
+static void gen_ne_fop_DD(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_i64, TCGv_i64))
{
TCGv_i64 dst, src;
@@ -1665,7 +1673,7 @@ static inline void gen_ne_fop_DD(DisasContext *dc, int rd, int rs,
}
#endif
-static inline void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
+static void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64))
{
TCGv_i64 dst, src1, src2;
@@ -1681,8 +1689,8 @@ static inline void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
}
#ifdef TARGET_SPARC64
-static inline void gen_ne_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
- void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64))
+static void gen_ne_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
+ void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64))
{
TCGv_i64 dst, src1, src2;
@@ -1695,8 +1703,8 @@ static inline void gen_ne_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
gen_store_fpr_D(dc, rd, dst);
}
-static inline void gen_gsr_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
- void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
+static void gen_gsr_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
+ void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
{
TCGv_i64 dst, src1, src2;
@@ -1709,8 +1717,8 @@ static inline void gen_gsr_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2,
gen_store_fpr_D(dc, rd, dst);
}
-static inline void gen_ne_fop_DDDD(DisasContext *dc, int rd, int rs1, int rs2,
- void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
+static void gen_ne_fop_DDDD(DisasContext *dc, int rd, int rs1, int rs2,
+ void (*gen)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
{
TCGv_i64 dst, src0, src1, src2;
@@ -1725,8 +1733,8 @@ static inline void gen_ne_fop_DDDD(DisasContext *dc, int rd, int rs1, int rs2,
}
#endif
-static inline void gen_fop_QQ(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_ptr))
+static void gen_fop_QQ(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_ptr))
{
gen_op_load_fpr_QT1(QFPREG(rs));
@@ -1738,8 +1746,8 @@ static inline void gen_fop_QQ(DisasContext *dc, int rd, int rs,
}
#ifdef TARGET_SPARC64
-static inline void gen_ne_fop_QQ(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_ptr))
+static void gen_ne_fop_QQ(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_ptr))
{
gen_op_load_fpr_QT1(QFPREG(rs));
@@ -1750,8 +1758,8 @@ static inline void gen_ne_fop_QQ(DisasContext *dc, int rd, int rs,
}
#endif
-static inline void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2,
- void (*gen)(TCGv_ptr))
+static void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2,
+ void (*gen)(TCGv_ptr))
{
gen_op_load_fpr_QT0(QFPREG(rs1));
gen_op_load_fpr_QT1(QFPREG(rs2));
@@ -1763,7 +1771,7 @@ static inline void gen_fop_QQQ(DisasContext *dc, int rd, int rs1, int rs2,
gen_update_fprs_dirty(dc, QFPREG(rd));
}
-static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2,
+static void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2,
void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32, TCGv_i32))
{
TCGv_i64 dst;
@@ -1779,8 +1787,8 @@ static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2,
gen_store_fpr_D(dc, rd, dst);
}
-static inline void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2,
- void (*gen)(TCGv_ptr, TCGv_i64, TCGv_i64))
+static void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2,
+ void (*gen)(TCGv_ptr, TCGv_i64, TCGv_i64))
{
TCGv_i64 src1, src2;
@@ -1795,8 +1803,8 @@ static inline void gen_fop_QDD(DisasContext *dc, int rd, int rs1, int rs2,
}
#ifdef TARGET_SPARC64
-static inline void gen_fop_DF(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32))
+static void gen_fop_DF(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32))
{
TCGv_i64 dst;
TCGv_i32 src;
@@ -1811,8 +1819,8 @@ static inline void gen_fop_DF(DisasContext *dc, int rd, int rs,
}
#endif
-static inline void gen_ne_fop_DF(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32))
+static void gen_ne_fop_DF(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_i64, TCGv_ptr, TCGv_i32))
{
TCGv_i64 dst;
TCGv_i32 src;
@@ -1825,8 +1833,8 @@ static inline void gen_ne_fop_DF(DisasContext *dc, int rd, int rs,
gen_store_fpr_D(dc, rd, dst);
}
-static inline void gen_fop_FD(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i64))
+static void gen_fop_FD(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_i32, TCGv_ptr, TCGv_i64))
{
TCGv_i32 dst;
TCGv_i64 src;
@@ -1840,8 +1848,8 @@ static inline void gen_fop_FD(DisasContext *dc, int rd, int rs,
gen_store_fpr_F(dc, rd, dst);
}
-static inline void gen_fop_FQ(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_i32, TCGv_ptr))
+static void gen_fop_FQ(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_i32, TCGv_ptr))
{
TCGv_i32 dst;
@@ -1854,8 +1862,8 @@ static inline void gen_fop_FQ(DisasContext *dc, int rd, int rs,
gen_store_fpr_F(dc, rd, dst);
}
-static inline void gen_fop_DQ(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_i64, TCGv_ptr))
+static void gen_fop_DQ(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_i64, TCGv_ptr))
{
TCGv_i64 dst;
@@ -1868,8 +1876,8 @@ static inline void gen_fop_DQ(DisasContext *dc, int rd, int rs,
gen_store_fpr_D(dc, rd, dst);
}
-static inline void gen_ne_fop_QF(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_ptr, TCGv_i32))
+static void gen_ne_fop_QF(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_ptr, TCGv_i32))
{
TCGv_i32 src;
@@ -1881,8 +1889,8 @@ static inline void gen_ne_fop_QF(DisasContext *dc, int rd, int rs,
gen_update_fprs_dirty(dc, QFPREG(rd));
}
-static inline void gen_ne_fop_QD(DisasContext *dc, int rd, int rs,
- void (*gen)(TCGv_ptr, TCGv_i64))
+static void gen_ne_fop_QD(DisasContext *dc, int rd, int rs,
+ void (*gen)(TCGv_ptr, TCGv_i64))
{
TCGv_i64 src;
@@ -2813,7 +2821,7 @@ static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
}
#ifndef CONFIG_USER_ONLY
-static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_env cpu_env)
+static void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_env cpu_env)
{
TCGv_i32 r_tl = tcg_temp_new_i32();
@@ -4139,10 +4147,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xff);
tcg_gen_st32_tl(cpu_tmp0, cpu_env,
offsetof(CPUSPARCState, asi));
- /* End TB to notice changed ASI. */
+ /*
+ * End TB to notice changed ASI.
+ * TODO: Could notice src1 = %g0 and IS_IMM,
+ * update DisasContext and not exit the TB.
+ */
save_state(dc);
gen_op_next_insn();
- tcg_gen_exit_tb(NULL, 0);
+ tcg_gen_lookup_and_goto_ptr();
dc->base.is_jmp = DISAS_NORETURN;
break;
case 0x6: /* V9 wrfprs */
@@ -5021,7 +5033,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
gen_mov_pc_npc(dc);
gen_check_align(cpu_tmp0, 3);
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
- dc->npc = DYNAMIC_PC;
+ dc->npc = DYNAMIC_PC_LOOKUP;
goto jmp_insn;
#endif
} else {
@@ -5050,7 +5062,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
gen_check_align(cpu_tmp0, 3);
gen_address_mask(dc, cpu_tmp0);
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
- dc->npc = DYNAMIC_PC;
+ dc->npc = DYNAMIC_PC_LOOKUP;
}
goto jmp_insn;
#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
@@ -5516,13 +5528,21 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
break;
}
/* default case for non jump instructions */
- if (dc->npc == DYNAMIC_PC) {
- dc->pc = DYNAMIC_PC;
- gen_op_next_insn();
- } else if (dc->npc == JUMP_PC) {
- /* we can do a static jump */
- gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1], cpu_cond);
- dc->base.is_jmp = DISAS_NORETURN;
+ if (dc->npc & 3) {
+ switch (dc->npc) {
+ case DYNAMIC_PC:
+ case DYNAMIC_PC_LOOKUP:
+ dc->pc = dc->npc;
+ gen_op_next_insn();
+ break;
+ case JUMP_PC:
+ /* we can do a static jump */
+ gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1], cpu_cond);
+ dc->base.is_jmp = DISAS_NORETURN;
+ break;
+ default:
+ g_assert_not_reached();
+ }
} else {
dc->pc = dc->npc;
dc->npc = dc->npc + 4;
@@ -5593,13 +5613,23 @@ static void sparc_tr_tb_start(DisasContextBase *db, CPUState *cs)
static void sparc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
+ target_ulong npc = dc->npc;
- if (dc->npc & JUMP_PC) {
- assert(dc->jump_pc[1] == dc->pc + 4);
- tcg_gen_insn_start(dc->pc, dc->jump_pc[0] | JUMP_PC);
- } else {
- tcg_gen_insn_start(dc->pc, dc->npc);
+ if (npc & 3) {
+ switch (npc) {
+ case JUMP_PC:
+ assert(dc->jump_pc[1] == dc->pc + 4);
+ npc = dc->jump_pc[0] | JUMP_PC;
+ break;
+ case DYNAMIC_PC:
+ case DYNAMIC_PC_LOOKUP:
+ npc = DYNAMIC_PC;
+ break;
+ default:
+ g_assert_not_reached();
+ }
}
+ tcg_gen_insn_start(dc->pc, npc);
}
static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
@@ -5623,19 +5653,37 @@ static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
+ bool may_lookup;
switch (dc->base.is_jmp) {
case DISAS_NEXT:
case DISAS_TOO_MANY:
- if (dc->pc != DYNAMIC_PC &&
- (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
+ if (((dc->pc | dc->npc) & 3) == 0) {
/* static PC and NPC: we can use direct chaining */
gen_goto_tb(dc, 0, dc->pc, dc->npc);
- } else {
- if (dc->pc != DYNAMIC_PC) {
- tcg_gen_movi_tl(cpu_pc, dc->pc);
+ break;
+ }
+
+ if (dc->pc & 3) {
+ switch (dc->pc) {
+ case DYNAMIC_PC_LOOKUP:
+ may_lookup = true;
+ break;
+ case DYNAMIC_PC:
+ may_lookup = false;
+ break;
+ default:
+ g_assert_not_reached();
}
- save_npc(dc);
+ } else {
+ tcg_gen_movi_tl(cpu_pc, dc->pc);
+ may_lookup = true;
+ }
+
+ save_npc(dc);
+ if (may_lookup) {
+ tcg_gen_lookup_and_goto_ptr();
+ } else {
tcg_gen_exit_tb(NULL, 0);
}
break;
diff --git a/tests/qemu-iotests/tests/iothreads-commit-active b/tests/qemu-iotests/tests/iothreads-commit-active
new file mode 100755
index 0000000000..4010a4871f
--- /dev/null
+++ b/tests/qemu-iotests/tests/iothreads-commit-active
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+# group: rw quick auto
+#
+# Copyright (C) 2023 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+
+import asyncio
+import iotests
+
+iotests.script_initialize(supported_fmts=['qcow2'],
+ supported_platforms=['linux'])
+iotests.verify_virtio_scsi_pci_or_ccw()
+
+with iotests.FilePath('disk0.img') as img_path, \
+ iotests.FilePath('disk0-snap.img') as snap_path, \
+ iotests.FilePath('mirror-src.img') as src_path, \
+ iotests.FilePath('mirror-dst.img') as dst_path, \
+ iotests.VM() as vm:
+
+ img_size = '10M'
+ iotests.qemu_img_create('-f', iotests.imgfmt, img_path, img_size)
+ iotests.qemu_img_create('-f', iotests.imgfmt, '-b', img_path,
+ '-F', iotests.imgfmt, snap_path)
+ iotests.qemu_img_create('-f', iotests.imgfmt, src_path, img_size)
+ iotests.qemu_img_create('-f', iotests.imgfmt, dst_path, img_size)
+
+ iotests.qemu_io_log('-c', 'write 0 64k', img_path)
+ iotests.qemu_io_log('-c', 'write 1M 64k', snap_path)
+ iotests.qemu_io_log('-c', 'write 3M 64k', snap_path)
+
+ iotests.qemu_io_log('-c', f'write 0 {img_size}', src_path)
+
+ iotests.log('Launching VM...')
+ vm.add_object('iothread,id=iothread0')
+ vm.add_object('throttle-group,x-bps-write=1048576,id=tg0')
+ vm.add_blockdev(f'file,node-name=disk0-file,filename={img_path}')
+ vm.add_blockdev('qcow2,node-name=disk0-fmt,file=disk0-file')
+ vm.add_drive(snap_path, 'backing=disk0-fmt,node-name=disk0',
+ interface='none')
+ vm.add_device('virtio-scsi,iothread=iothread0')
+ vm.add_device('scsi-hd,drive=drive0')
+
+ vm.add_blockdev(f'file,filename={src_path},node-name=mirror-src-file')
+ vm.add_blockdev('qcow2,file=mirror-src-file,node-name=mirror-src')
+ vm.add_blockdev(f'file,filename={dst_path},node-name=mirror-dst-file')
+ vm.add_blockdev('qcow2,file=mirror-dst-file,node-name=mirror-dst-fmt')
+ vm.add_blockdev('throttle,throttle-group=tg0,file=mirror-dst-fmt,'
+ 'node-name=mirror-dst')
+ vm.add_device('scsi-hd,drive=mirror-src')
+
+ vm.launch()
+
+ # The background I/O is created on unrelated nodes (so that they won't be
+ # drained together with the other ones), but on the same iothread
+ iotests.log('Creating some background I/O...')
+ iotests.log(vm.qmp('blockdev-mirror', job_id='job0', sync='full',
+ device='mirror-src', target='mirror-dst',
+ auto_dismiss=False))
+
+ iotests.log('Starting active commit...')
+ iotests.log(vm.qmp('block-commit', device='disk0', job_id='job1',
+ auto_dismiss=False))
+
+ # Should succeed and not time out
+ try:
+ vm.run_job('job1', wait=5.0)
+ vm.shutdown()
+ except asyncio.TimeoutError:
+ # VM may be stuck, kill it
+ vm.kill()
+ raise
diff --git a/tests/qemu-iotests/tests/iothreads-commit-active.out b/tests/qemu-iotests/tests/iothreads-commit-active.out
new file mode 100644
index 0000000000..4afd50b8d3
--- /dev/null
+++ b/tests/qemu-iotests/tests/iothreads-commit-active.out
@@ -0,0 +1,23 @@
+wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+wrote 65536/65536 bytes at offset 1048576
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+wrote 65536/65536 bytes at offset 3145728
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+wrote 10485760/10485760 bytes at offset 0
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+Launching VM...
+Creating some background I/O...
+{"return": {}}
+Starting active commit...
+{"return": {}}
+{"execute": "job-complete", "arguments": {"id": "job1"}}
+{"return": {}}
+{"data": {"device": "job1", "len": 131072, "offset": 131072, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "job1", "len": 131072, "offset": 131072, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"execute": "job-dismiss", "arguments": {"id": "job1"}}
+{"return": {}}
diff --git a/tests/qtest/dbus-display-test.c b/tests/qtest/dbus-display-test.c
index fef025ac6f..21edaa1e32 100644
--- a/tests/qtest/dbus-display-test.c
+++ b/tests/qtest/dbus-display-test.c
@@ -1,4 +1,5 @@
#include "qemu/osdep.h"
+#include "qemu/sockets.h"
#include "qemu/dbus.h"
#include "qemu/sockets.h"
#include <gio/gio.h>
@@ -14,7 +15,11 @@ test_dbus_p2p_from_fd(int fd)
g_autoptr(GSocketConnection) socketc = NULL;
GDBusConnection *conn;
+#ifdef WIN32
+ socket = g_socket_new_from_fd(_get_osfhandle(fd), &err);
+#else
socket = g_socket_new_from_fd(fd, &err);
+#endif
g_assert_no_error(err);
socketc = g_socket_connection_factory_create_connection(socket);
@@ -126,7 +131,10 @@ test_dbus_console_registered(GObject *source_object,
qemu_dbus_display1_console_call_register_listener_finish(
QEMU_DBUS_DISPLAY1_CONSOLE(source_object),
- NULL, res, &err);
+#ifndef WIN32
+ NULL,
+#endif
+ res, &err);
g_assert_no_error(err);
test->listener_conn = g_thread_join(test->thread);
@@ -145,17 +153,25 @@ test_dbus_display_console(void)
g_autoptr(GError) err = NULL;
g_autoptr(GDBusConnection) conn = NULL;
g_autoptr(QemuDBusDisplay1ConsoleProxy) console = NULL;
- g_autoptr(GUnixFDList) fd_list = NULL;
g_autoptr(GMainLoop) loop = NULL;
QTestState *qts = NULL;
- int pair[2], idx;
+ int pair[2];
TestDBusConsoleRegister test;
+#ifdef WIN32
+ WSAPROTOCOL_INFOW info;
+ g_autoptr(GVariant) listener = NULL;
+#else
+ g_autoptr(GUnixFDList) fd_list = NULL;
+ int idx;
+#endif
test_setup(&qts, &conn);
g_assert_cmpint(qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0);
+#ifndef WIN32
fd_list = g_unix_fd_list_new();
idx = g_unix_fd_list_append(fd_list, pair[1], NULL);
+#endif
console = QEMU_DBUS_DISPLAY1_CONSOLE_PROXY(
qemu_dbus_display1_console_proxy_new_sync(
@@ -171,12 +187,33 @@ test_dbus_display_console(void)
test.thread = g_thread_new(NULL, test_dbus_p2p_server_setup_thread,
GINT_TO_POINTER(pair[0]));
+#ifdef WIN32
+ if (WSADuplicateSocketW(_get_osfhandle(pair[1]),
+ GetProcessId((HANDLE) qtest_pid(qts)),
+ &info) == SOCKET_ERROR)
+ {
+ g_autofree char *emsg = g_win32_error_message(WSAGetLastError());
+ g_error("WSADuplicateSocket failed: %s", emsg);
+ }
+ close(pair[1]);
+ listener = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
+ &info,
+ sizeof(info),
+ 1);
+#endif
+
qemu_dbus_display1_console_call_register_listener(
QEMU_DBUS_DISPLAY1_CONSOLE(console),
+#ifdef WIN32
+ listener,
+#else
g_variant_new_handle(idx),
+#endif
G_DBUS_CALL_FLAGS_NONE,
-1,
+#ifndef WIN32
fd_list,
+#endif
NULL,
test_dbus_console_registered,
&test);
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index de03ef5f60..79152f0ec3 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -142,6 +142,11 @@ static int socket_accept(int sock)
return ret;
}
+pid_t qtest_pid(QTestState *s)
+{
+ return s->qemu_pid;
+}
+
bool qtest_probe_child(QTestState *s)
{
pid_t pid = s->qemu_pid;
diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index a12acf7fa9..913acc3d5c 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -985,4 +985,13 @@ void qtest_qom_set_bool(QTestState *s, const char *path, const char *property,
* Returns: Value retrieved from property.
*/
bool qtest_qom_get_bool(QTestState *s, const char *path, const char *property);
+
+/**
+ * qtest_pid:
+ * @s: QTestState instance to operate on.
+ *
+ * Returns: the PID of the QEMU process, or <= 0
+ */
+pid_t qtest_pid(QTestState *s);
+
#endif
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 5fa6833ad7..74630f6672 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -104,7 +104,7 @@ qtests_i386 = \
'numa-test'
]
-if dbus_display and targetos != 'windows'
+if dbus_display
qtests_i386 += ['dbus-display-test']
endif
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
index f081c09729..d727a5fee8 100644
--- a/tests/unit/test-block-iothread.c
+++ b/tests/unit/test-block-iothread.c
@@ -825,6 +825,7 @@ static void test_attach_second_node(void)
BlockDriverState *bs, *filter;
QDict *options;
+ aio_context_acquire(main_ctx);
blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
blk_insert_bs(blk, bs, &error_abort);
@@ -833,7 +834,6 @@ static void test_attach_second_node(void)
qdict_put_str(options, "driver", "raw");
qdict_put_str(options, "file", "base");
- aio_context_acquire(main_ctx);
filter = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
aio_context_release(main_ctx);
@@ -857,9 +857,11 @@ static void test_attach_preserve_blk_ctx(void)
{
IOThread *iothread = iothread_new();
AioContext *ctx = iothread_get_aio_context(iothread);
+ AioContext *main_ctx = qemu_get_aio_context();
BlockBackend *blk;
BlockDriverState *bs;
+ aio_context_acquire(main_ctx);
blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
@@ -868,6 +870,7 @@ static void test_attach_preserve_blk_ctx(void)
blk_insert_bs(blk, bs, &error_abort);
g_assert(blk_get_aio_context(blk) == ctx);
g_assert(bdrv_get_aio_context(bs) == ctx);
+ aio_context_release(main_ctx);
/* Remove the node again */
aio_context_acquire(ctx);
@@ -877,7 +880,9 @@ static void test_attach_preserve_blk_ctx(void)
g_assert(bdrv_get_aio_context(bs) == qemu_get_aio_context());
/* Re-attach the node */
+ aio_context_acquire(main_ctx);
blk_insert_bs(blk, bs, &error_abort);
+ aio_context_release(main_ctx);
g_assert(blk_get_aio_context(blk) == ctx);
g_assert(bdrv_get_aio_context(bs) == ctx);
diff --git a/ui/console.c b/ui/console.c
index e173731e20..c1544e0fb8 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1223,7 +1223,8 @@ static void displaychangelistener_display_console(DisplayChangeListener *dcl,
con->scanout.texture.x,
con->scanout.texture.y,
con->scanout.texture.width,
- con->scanout.texture.height);
+ con->scanout.texture.height,
+ con->scanout.texture.d3d_tex2d);
}
}
@@ -1513,18 +1514,59 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
return s;
}
+#ifdef WIN32
+void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
+ HANDLE h, uint32_t offset)
+{
+ assert(!surface->handle);
+
+ surface->handle = h;
+ surface->handle_offset = offset;
+}
+
+static void
+win32_pixman_image_destroy(pixman_image_t *image, void *data)
+{
+ DisplaySurface *surface = data;
+
+ if (!surface->handle) {
+ return;
+ }
+
+ assert(surface->handle_offset == 0);
+
+ qemu_win32_map_free(
+ pixman_image_get_data(surface->image),
+ surface->handle,
+ &error_warn
+ );
+}
+#endif
+
DisplaySurface *qemu_create_displaysurface(int width, int height)
{
- DisplaySurface *surface = g_new0(DisplaySurface, 1);
+ DisplaySurface *surface;
+ void *bits = NULL;
+#ifdef WIN32
+ HANDLE handle = NULL;
+#endif
- trace_displaysurface_create(surface, width, height);
- surface->format = PIXMAN_x8r8g8b8;
- surface->image = pixman_image_create_bits(surface->format,
- width, height,
- NULL, width * 4);
- assert(surface->image != NULL);
+ trace_displaysurface_create(width, height);
+
+#ifdef WIN32
+ bits = qemu_win32_map_alloc(width * height * 4, &handle, &error_abort);
+#endif
+
+ surface = qemu_create_displaysurface_from(
+ width, height,
+ PIXMAN_x8r8g8b8,
+ width * 4, bits
+ );
surface->flags = QEMU_ALLOCATED_FLAG;
+#ifdef WIN32
+ qemu_displaysurface_win32_set_handle(surface, handle, 0);
+#endif
return surface;
}
@@ -1540,6 +1582,10 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
width, height,
(void *)data, linesize);
assert(surface->image != NULL);
+#ifdef WIN32
+ pixman_image_set_destroy_function(surface->image,
+ win32_pixman_image_destroy, surface);
+#endif
return surface;
}
@@ -1635,6 +1681,71 @@ static bool console_compatible_with(QemuConsole *con,
return true;
}
+void console_handle_touch_event(QemuConsole *con,
+ struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
+ uint64_t num_slot,
+ int width, int height,
+ double x, double y,
+ InputMultiTouchType type,
+ Error **errp)
+{
+ struct touch_slot *slot;
+ bool needs_sync = false;
+ int update;
+ int i;
+
+ if (num_slot >= INPUT_EVENT_SLOTS_MAX) {
+ error_setg(errp,
+ "Unexpected touch slot number: % " PRId64" >= %d",
+ num_slot, INPUT_EVENT_SLOTS_MAX);
+ return;
+ }
+
+ slot = &touch_slots[num_slot];
+ slot->x = x;
+ slot->y = y;
+
+ if (type == INPUT_MULTI_TOUCH_TYPE_BEGIN) {
+ slot->tracking_id = num_slot;
+ }
+
+ for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) {
+ if (i == num_slot) {
+ update = type;
+ } else {
+ update = INPUT_MULTI_TOUCH_TYPE_UPDATE;
+ }
+
+ slot = &touch_slots[i];
+
+ if (slot->tracking_id == -1) {
+ continue;
+ }
+
+ if (update == INPUT_MULTI_TOUCH_TYPE_END) {
+ slot->tracking_id = -1;
+ qemu_input_queue_mtt(con, update, i, slot->tracking_id);
+ needs_sync = true;
+ } else {
+ qemu_input_queue_mtt(con, update, i, slot->tracking_id);
+ qemu_input_queue_btn(con, INPUT_BUTTON_TOUCH, true);
+ qemu_input_queue_mtt_abs(con,
+ INPUT_AXIS_X, (int) slot->x,
+ 0, width,
+ i, slot->tracking_id);
+ qemu_input_queue_mtt_abs(con,
+ INPUT_AXIS_Y, (int) slot->y,
+ 0, height,
+ i, slot->tracking_id);
+ needs_sync = true;
+ }
+ }
+
+ if (needs_sync) {
+ qemu_input_event_sync();
+ }
+}
+
void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)
{
/* display has opengl support */
@@ -2005,7 +2116,8 @@ void dpy_gl_scanout_texture(QemuConsole *con,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t width, uint32_t height)
+ uint32_t width, uint32_t height,
+ void *d3d_tex2d)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -2013,7 +2125,7 @@ void dpy_gl_scanout_texture(QemuConsole *con,
con->scanout.kind = SCANOUT_TEXTURE;
con->scanout.texture = (ScanoutTexture) {
backing_id, backing_y_0_top, backing_width, backing_height,
- x, y, width, height
+ x, y, width, height, d3d_tex2d,
};
QLIST_FOREACH(dcl, &s->listeners, next) {
if (con != (dcl->con ? dcl->con : active_console)) {
@@ -2023,7 +2135,8 @@ void dpy_gl_scanout_texture(QemuConsole *con,
dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
backing_y_0_top,
backing_width, backing_height,
- x, y, width, height);
+ x, y, width, height,
+ d3d_tex2d);
}
}
}
@@ -2306,7 +2419,7 @@ QEMUCursor *qemu_console_get_cursor(QemuConsole *con)
if (con == NULL) {
con = active_console;
}
- return con->cursor;
+ return con ? con->cursor : NULL;
}
bool qemu_console_is_visible(QemuConsole *con)
diff --git a/ui/dbus-chardev.c b/ui/dbus-chardev.c
index 940ef937cd..1d3a7122a1 100644
--- a/ui/dbus-chardev.c
+++ b/ui/dbus-chardev.c
@@ -27,7 +27,9 @@
#include "qemu/config-file.h"
#include "qemu/option.h"
+#ifdef G_OS_UNIX
#include <gio/gunixfdlist.h>
+#endif
#include "dbus.h"
@@ -112,13 +114,20 @@ static gboolean
dbus_chr_register(
DBusChardev *dc,
GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
GUnixFDList *fd_list,
+#endif
GVariant *arg_stream,
QemuDBusDisplay1Chardev *object)
{
g_autoptr(GError) err = NULL;
int fd;
+#ifdef G_OS_WIN32
+ if (!dbus_win32_import_socket(invocation, arg_stream, &fd)) {
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+#else
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_stream), &err);
if (err) {
g_dbus_method_invocation_return_error(
@@ -128,13 +137,18 @@ dbus_chr_register(
"Couldn't get peer FD: %s", err->message);
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#endif
if (qemu_chr_add_client(CHARDEV(dc), fd) < 0) {
g_dbus_method_invocation_return_error(invocation,
DBUS_DISPLAY_ERROR,
DBUS_DISPLAY_ERROR_FAILED,
"Couldn't register FD!");
+#ifdef G_OS_WIN32
+ closesocket(fd);
+#else
close(fd);
+#endif
return DBUS_METHOD_INVOCATION_HANDLED;
}
@@ -142,7 +156,11 @@ dbus_chr_register(
"owner", g_dbus_method_invocation_get_sender(invocation),
NULL);
- qemu_dbus_display1_chardev_complete_register(object, invocation, NULL);
+ qemu_dbus_display1_chardev_complete_register(object, invocation
+#ifndef G_OS_WIN32
+ , NULL
+#endif
+ );
return DBUS_METHOD_INVOCATION_HANDLED;
}
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index f77bc49d2e..e19774f985 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -28,10 +28,14 @@
#include "ui/kbd-state.h"
#include "trace.h"
+#ifdef G_OS_UNIX
#include <gio/gunixfdlist.h>
+#endif
#include "dbus.h"
+static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX];
+
struct _DBusDisplayConsole {
GDBusObjectSkeleton parent_instance;
DisplayChangeListener dcl;
@@ -44,6 +48,7 @@ struct _DBusDisplayConsole {
QKbdState *kbd;
QemuDBusDisplay1Mouse *iface_mouse;
+ QemuDBusDisplay1MultiTouch *iface_touch;
gboolean last_set;
guint last_x;
guint last_y;
@@ -93,7 +98,8 @@ dbus_gl_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h)
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d)
{
DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl);
@@ -204,10 +210,47 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc,
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#ifdef G_OS_WIN32
+bool
+dbus_win32_import_socket(GDBusMethodInvocation *invocation,
+ GVariant *arg_listener, int *socket)
+{
+ gsize n;
+ WSAPROTOCOL_INFOW *info = (void *)g_variant_get_fixed_array(arg_listener, &n, 1);
+
+ if (!info || n != sizeof(*info)) {
+ g_dbus_method_invocation_return_error(
+ invocation,
+ DBUS_DISPLAY_ERROR,
+ DBUS_DISPLAY_ERROR_FAILED,
+ "Failed to get socket infos");
+ return false;
+ }
+
+ *socket = WSASocketW(FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ info, 0, 0);
+ if (*socket == INVALID_SOCKET) {
+ g_autofree gchar *emsg = g_win32_error_message(WSAGetLastError());
+ g_dbus_method_invocation_return_error(
+ invocation,
+ DBUS_DISPLAY_ERROR,
+ DBUS_DISPLAY_ERROR_FAILED,
+ "Couldn't create socket: %s", emsg);
+ return false;
+ }
+
+ return true;
+}
+#endif
+
static gboolean
dbus_console_register_listener(DBusDisplayConsole *ddc,
GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
GUnixFDList *fd_list,
+#endif
GVariant *arg_listener)
{
const char *sender = g_dbus_method_invocation_get_sender(invocation);
@@ -229,6 +272,11 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#ifdef G_OS_WIN32
+ if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+#else
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
if (err) {
g_dbus_method_invocation_return_error(
@@ -238,6 +286,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
"Couldn't get peer fd: %s", err->message);
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#endif
socket = g_socket_new_from_fd(fd, &err);
if (err) {
@@ -246,13 +295,21 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
DBUS_DISPLAY_ERROR,
DBUS_DISPLAY_ERROR_FAILED,
"Couldn't make a socket: %s", err->message);
+#ifdef G_OS_WIN32
+ closesocket(fd);
+#else
close(fd);
+#endif
return DBUS_METHOD_INVOCATION_HANDLED;
}
socket_conn = g_socket_connection_factory_create_connection(socket);
qemu_dbus_display1_console_complete_register_listener(
- ddc->iface, invocation, NULL);
+ ddc->iface, invocation
+#ifdef G_OS_UNIX
+ , NULL
+#endif
+ );
listener_conn = g_dbus_connection_new_sync(
G_IO_STREAM(socket_conn),
@@ -346,6 +403,46 @@ dbus_mouse_rel_motion(DBusDisplayConsole *ddc,
}
static gboolean
+dbus_touch_send_event(DBusDisplayConsole *ddc,
+ GDBusMethodInvocation *invocation,
+ guint kind, uint64_t num_slot,
+ double x, double y)
+{
+ Error *error = NULL;
+ int width, height;
+ trace_dbus_touch_send_event(kind, num_slot, x, y);
+
+ if (kind != INPUT_MULTI_TOUCH_TYPE_BEGIN &&
+ kind != INPUT_MULTI_TOUCH_TYPE_UPDATE &&
+ kind != INPUT_MULTI_TOUCH_TYPE_CANCEL &&
+ kind != INPUT_MULTI_TOUCH_TYPE_END)
+ {
+ g_dbus_method_invocation_return_error(
+ invocation, DBUS_DISPLAY_ERROR,
+ DBUS_DISPLAY_ERROR_INVALID,
+ "Invalid touch event kind");
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+ width = qemu_console_get_width(ddc->dcl.con, 0);
+ height = qemu_console_get_height(ddc->dcl.con, 0);
+
+ console_handle_touch_event(ddc->dcl.con, touch_slots,
+ num_slot, width, height,
+ x, y, kind, &error);
+ if (error != NULL) {
+ g_dbus_method_invocation_return_error(
+ invocation, DBUS_DISPLAY_ERROR,
+ DBUS_DISPLAY_ERROR_INVALID,
+ error_get_pretty(error), NULL);
+ error_free(error);
+ } else {
+ qemu_dbus_display1_multi_touch_complete_send_event(ddc->iface_touch,
+ invocation);
+ }
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
dbus_mouse_set_pos(DBusDisplayConsole *ddc,
GDBusMethodInvocation *invocation,
guint x, guint y)
@@ -440,7 +537,13 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
g_autofree char *label = NULL;
char device_addr[256] = "";
DBusDisplayConsole *ddc;
- int idx;
+ int idx, i;
+ const char *interfaces[] = {
+ "org.qemu.Display1.Keyboard",
+ "org.qemu.Display1.Mouse",
+ "org.qemu.Display1.MultiTouch",
+ NULL
+ };
assert(display);
assert(con);
@@ -465,6 +568,7 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
"width", qemu_console_get_width(con, 0),
"height", qemu_console_get_height(con, 0),
"device-address", device_addr,
+ "interfaces", interfaces,
NULL);
g_object_connect(ddc->iface,
"swapped-signal::handle-register-listener",
@@ -495,6 +599,20 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
G_DBUS_INTERFACE_SKELETON(ddc->iface_mouse));
+ ddc->iface_touch = qemu_dbus_display1_multi_touch_skeleton_new();
+ g_object_connect(ddc->iface_touch,
+ "swapped-signal::handle-send-event", dbus_touch_send_event, ddc,
+ NULL);
+ qemu_dbus_display1_multi_touch_set_max_slots(ddc->iface_touch,
+ INPUT_EVENT_SLOTS_MAX);
+ g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
+ G_DBUS_INTERFACE_SKELETON(ddc->iface_touch));
+
+ for (i = 0; i < INPUT_EVENT_SLOTS_MAX; i++) {
+ struct touch_slot *slot = &touch_slots[i];
+ slot->tracking_id = -1;
+ }
+
register_displaychangelistener(&ddc->dcl);
ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change;
qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier);
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
index c3b2293376..f0e2fac212 100644
--- a/ui/dbus-display1.xml
+++ b/ui/dbus-display1.xml
@@ -26,6 +26,20 @@
The list of consoles available on ``/org/qemu/Display1/Console_$id``.
-->
<property name="ConsoleIDs" type="au" access="read"/>
+
+ <!--
+ Interfaces:
+
+ This property lists extra interfaces provided by the
+ /org/qemu/Display1/VM object, and can be used to detect
+ the capabilities with which they are communicating.
+
+ Unlike the standard D-Bus Introspectable interface, querying this
+ property does not require parsing XML.
+
+ (earlier version of the display interface do not provide this property)
+ -->
+ <property name="Interfaces" type="as" access="read"/>
</interface>
<!--
@@ -39,8 +53,9 @@
"Text" (see :dbus:prop:`Type` and other properties).
Interactions with a console may be done with
- :dbus:iface:`org.qemu.Display1.Keyboard` and
- :dbus:iface:`org.qemu.Display1.Mouse` interfaces when available.
+ :dbus:iface:`org.qemu.Display1.Keyboard`,
+ :dbus:iface:`org.qemu.Display1.Mouse` and
+ :dbus:iface:`org.qemu.Display1.MultiTouch` interfaces when available.
-->
<interface name="org.qemu.Display1.Console">
<!--
@@ -56,7 +71,13 @@
:dbus:iface:`org.qemu.Display1.Listener` interface.
-->
<method name="RegisterListener">
+ <?if $(env.TARGETOS) == windows?>
+ <arg type="ay" name="listener" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <?else?>
<arg type="h" name="listener" direction="in"/>
+ <?endif?>
</method>
<!--
@@ -120,12 +141,27 @@
The device address (ex: "pci/0000/02.0").
-->
<property name="DeviceAddress" type="s" access="read"/>
+
+ <!--
+ Interfaces:
+
+ This property lists extra interfaces provided by the
+ ``/org/qemu/Display1/Console_$id`` object, and can be used to detect the
+ capabilities with which they are communicating.
+
+ Unlike the standard D-Bus Introspectable interface, querying this
+ property does not require parsing XML.
+
+ (earlier version of the display interface do not provide this property)
+ -->
+ <property name="Interfaces" type="as" access="read"/>
</interface>
<!--
org.qemu.Display1.Keyboard:
- This interface in implemented on ``/org/qemu/Display1/Console_$id`` (see
+ This interface is optionally implemented on
+ ``/org/qemu/Display1/Console_$id`` (see
:dbus:iface:`~org.qemu.Display1.Console`).
-->
<interface name="org.qemu.Display1.Keyboard">
@@ -164,7 +200,8 @@
<!--
org.qemu.Display1.Mouse:
- This interface in implemented on ``/org/qemu/Display1/Console_$id`` (see
+ This interface is optionally implemented on
+ ``/org/qemu/Display1/Console_$id`` (see
:dbus:iface:`~org.qemu.Display1.Console` documentation).
.. _dbus-button-values:
@@ -237,6 +274,46 @@
</interface>
<!--
+ org.qemu.Display1.MultiTouch:
+
+ This interface in implemented on ``/org/qemu/Display1/Console_$id`` (see
+ :dbus:iface:`~org.qemu.Display1.Console` documentation).
+
+ .. _dbus-kind-values:
+
+ **Kind values**::
+
+ Begin = 0
+ Update = 1
+ End = 2
+ Cancel = 3
+ -->
+ <interface name="org.qemu.Display1.MultiTouch">
+ <!--
+ SendEvent:
+ @kind: The touch event kind
+ @num_slot: The slot number.
+ @x: The x coordinates.
+ @y: The y coordinates.
+
+ Send a touch gesture event.
+ -->
+ <method name="SendEvent">
+ <arg type="u" name="kind" direction="in"/>
+ <arg type="t" name="num_slot" direction="in"/>
+ <arg type="d" name="x" direction="in"/>
+ <arg type="d" name="y" direction="in"/>
+ </method>
+
+ <!--
+ MaxSlots:
+
+ The maximum number of slots.
+ -->
+ <property name="MaxSlots" type="i" access="read"/>
+ </interface>
+
+ <!--
org.qemu.Display1.Listener:
This client-side interface must be available on
@@ -293,6 +370,7 @@
</arg>
</method>
+ <?if $(env.TARGETOS) != windows?>
<!--
ScanoutDMABUF:
@dmabuf: the DMABUF file descriptor.
@@ -331,6 +409,7 @@
<arg type="i" name="width" direction="in"/>
<arg type="i" name="height" direction="in"/>
</method>
+ <?endif?>
<!--
Disable:
@@ -374,6 +453,116 @@
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
</arg>
</method>
+
+ <!--
+ Interfaces:
+
+ This property lists extra interfaces provided by the
+ /org/qemu/Display1/Listener object, and can be used to detect
+ the capabilities with which they are communicating.
+
+ Unlike the standard D-Bus Introspectable interface, querying this
+ property does not require parsing XML.
+
+ (earlier version of the display interface do not provide this property)
+ -->
+ <property name="Interfaces" type="as" access="read"/>
+ </interface>
+
+ <!--
+ org.qemu.Display1.Listener.Win32.Map:
+
+ This optional client-side interface can complement
+ org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for Windows
+ specific shared memory scanouts.
+ -->
+ <interface name="org.qemu.Display1.Listener.Win32.Map">
+ <!--
+ ScanoutMap:
+ @handle: the shared map handle value.
+ @offset: mapping offset.
+ @width: display width, in pixels.
+ @height: display height, in pixels.
+ @stride: stride, in bytes.
+ @pixman_format: image format (ex: ``PIXMAN_X8R8G8B8``).
+
+ Resize and update the display content with a shared map.
+ -->
+ <method name="ScanoutMap">
+ <arg type="t" name="handle" direction="in"/>
+ <arg type="u" name="offset" direction="in"/>
+ <arg type="u" name="width" direction="in"/>
+ <arg type="u" name="height" direction="in"/>
+ <arg type="u" name="stride" direction="in"/>
+ <arg type="u" name="pixman_format" direction="in"/>
+ </method>
+
+ <!--
+ UpdateMap:
+ @x: the X update position, in pixels.
+ @y: the Y update position, in pixels.
+ @width: the update width, in pixels.
+ @height: the update height, in pixels.
+
+ Update the display content with the current shared map and the given region.
+ -->
+ <method name="UpdateMap">
+ <arg type="i" name="x" direction="in"/>
+ <arg type="i" name="y" direction="in"/>
+ <arg type="i" name="width" direction="in"/>
+ <arg type="i" name="height" direction="in"/>
+ </method>
+ </interface>
+
+ <!--
+ org.qemu.Display1.Listener.Win32.D3d11:
+
+ This optional client-side interface can complement
+ org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for Windows
+ specific Direct3D texture sharing of the scanouts.
+ -->
+ <interface name="org.qemu.Display1.Listener.Win32.D3d11">
+ <!--
+ ScanoutTexture2d:
+ @handle: the NT handle for the shared texture (to be opened back with ID3D11Device1::OpenSharedResource1).
+ @texture_width: texture width, in pixels.
+ @texture_height: texture height, in pixels.
+ @y0_top: whether Y position 0 is the top or not.
+ @x: the X scanout position, in pixels.
+ @y: the Y scanout position, in pixels.
+ @width: the scanout width, in pixels.
+ @height: the scanout height, in pixels.
+
+ Resize and update the display content with a Direct3D 11 2D texture.
+ You must acquire and release the associated KeyedMutex 0 during rendering.
+ -->
+ <method name="ScanoutTexture2d">
+ <arg type="t" name="handle" direction="in"/>
+ <arg type="u" name="texture_width" direction="in"/>
+ <arg type="u" name="texture_height" direction="in"/>
+ <arg type="b" name="y0_top" direction="in"/>
+ <arg type="u" name="x" direction="in"/>
+ <arg type="u" name="y" direction="in"/>
+ <arg type="u" name="width" direction="in"/>
+ <arg type="u" name="height" direction="in"/>
+ </method>
+
+ <!--
+ UpdateTexture2d:
+ @x: the X update position, in pixels.
+ @y: the Y update position, in pixels.
+ @width: the update width, in pixels.
+ @height: the update height, in pixels.
+
+ Update the display content with the current Direct3D 2D texture and the given region.
+ You must acquire and release the associated KeyedMutex 0 during rendering.
+ -->
+ <method name="UpdateTexture2d">
+ <arg type="i" name="x" direction="in"/>
+ <arg type="i" name="y" direction="in"/>
+ <arg type="i" name="width" direction="in"/>
+ <arg type="i" name="height" direction="in"/>
+ </method>
</interface>
<!--
@@ -471,6 +660,20 @@
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
</arg>
</method>
+
+ <!--
+ Interfaces:
+
+ This property lists extra interfaces provided by the
+ /org/qemu/Display1/Clipboard object, and can be used to detect
+ the capabilities with which they are communicating.
+
+ Unlike the standard D-Bus Introspectable interface, querying this
+ property does not require parsing XML.
+
+ (earlier version of the display interface do not provide this property)
+ -->
+ <property name="Interfaces" type="as" access="read"/>
</interface>
<!--
@@ -491,7 +694,13 @@
:dbus:iface:`org.qemu.Display1.AudioOutListener` interface.
-->
<method name="RegisterOutListener">
+ <?if $(env.TARGETOS) == windows?>
+ <arg type="ay" name="listener" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <?else?>
<arg type="h" name="listener" direction="in"/>
+ <?endif?>
</method>
<!--
@@ -506,8 +715,28 @@
:dbus:iface:`org.qemu.Display1.AudioInListener` interface.
-->
<method name="RegisterInListener">
+ <?if $(env.TARGETOS) == windows?>
+ <arg type="ay" name="listener" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <?else?>
<arg type="h" name="listener" direction="in"/>
+ <?endif?>
</method>
+
+ <!--
+ Interfaces:
+
+ This property lists extra interfaces provided by the
+ /org/qemu/Display1/Audio object, and can be used to detect
+ the capabilities with which they are communicating.
+
+ Unlike the standard D-Bus Introspectable interface, querying this
+ property does not require parsing XML.
+
+ (earlier version of the display interface do not provide this property)
+ -->
+ <property name="Interfaces" type="as" access="read"/>
</interface>
<!--
@@ -594,6 +823,20 @@
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
</arg>
</method>
+
+ <!--
+ Interfaces:
+
+ This property lists extra interfaces provided by the
+ /org/qemu/Display1/AudioOutListener object, and can be used to detect
+ the capabilities with which they are communicating.
+
+ Unlike the standard D-Bus Introspectable interface, querying this
+ property does not require parsing XML.
+
+ (earlier version of the display interface do not provide this property)
+ -->
+ <property name="Interfaces" type="as" access="read"/>
</interface>
<!--
@@ -682,6 +925,20 @@
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
</arg>
</method>
+
+ <!--
+ Interfaces:
+
+ This property lists extra interfaces provided by the
+ /org/qemu/Display1/AudioInListener object, and can be used to detect
+ the capabilities with which they are communicating.
+
+ Unlike the standard D-Bus Introspectable interface, querying this
+ property does not require parsing XML.
+
+ (earlier version of the display interface do not provide this property)
+ -->
+ <property name="Interfaces" type="as" access="read"/>
</interface>
<!--
@@ -719,7 +976,13 @@
The current handler, if any, will be replaced.
-->
<method name="Register">
+ <?if $(env.TARGETOS) == windows?>
+ <arg type="ay" name="listener" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <?else?>
<arg type="h" name="stream" direction="in"/>
+ <?endif?>
</method>
<!--
@@ -757,5 +1020,19 @@
The D-Bus unique name of the registered handler.
-->
<property name="Owner" type="s" access="read"/>
+
+ <!--
+ Interfaces:
+
+ This property lists extra interfaces provided by the
+ ``/org/qemu/Display1/Chardev_$i`` object, and can be used to detect
+ the capabilities with which they are communicating.
+
+ Unlike the standard D-Bus Introspectable interface, querying this
+ property does not require parsing XML.
+
+ (earlier version of the display interface do not provide this property)
+ -->
+ <property name="Interfaces" type="as" access="read"/>
</interface>
</node>
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 23034eebf9..e10162b279 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -23,9 +23,16 @@
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
+#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "dbus.h"
+#ifdef G_OS_UNIX
#include <gio/gunixfdlist.h>
+#endif
+#ifdef WIN32
+#include <d3d11.h>
+#include <dxgi1_2.h>
+#endif
#ifdef CONFIG_OPENGL
#include "ui/shader.h"
@@ -34,6 +41,15 @@
#endif
#include "trace.h"
+static void dbus_gfx_switch(DisplayChangeListener *dcl,
+ struct DisplaySurface *new_surface);
+
+enum share_kind {
+ SHARE_KIND_NONE,
+ SHARE_KIND_MAPPED,
+ SHARE_KIND_D3DTEX,
+};
+
struct _DBusDisplayListener {
GObject parent;
@@ -45,21 +61,142 @@ struct _DBusDisplayListener {
DisplayChangeListener dcl;
DisplaySurface *ds;
+ enum share_kind ds_share;
+
int gl_updates;
+
+ bool ds_mapped;
+ bool can_share_map;
+
+#ifdef WIN32
+ QemuDBusDisplay1ListenerWin32Map *map_proxy;
+ QemuDBusDisplay1ListenerWin32D3d11 *d3d11_proxy;
+ HANDLE peer_process;
+ ID3D11Texture2D *d3d_texture;
+#ifdef CONFIG_OPENGL
+ egl_fb fb;
+#endif
+#endif
};
G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+static void dbus_gfx_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h);
+
+#ifdef CONFIG_OPENGL
+static void dbus_scanout_disable(DisplayChangeListener *dcl)
+{
+ DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+
+ qemu_dbus_display1_listener_call_disable(
+ ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+}
+
+#ifdef WIN32
+static bool d3d_texture2d_share(ID3D11Texture2D *d3d_texture,
+ HANDLE *handle, Error **errp)
+{
+ IDXGIResource1 *dxgiResource = NULL;
+ HRESULT hr;
+
+ hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
+ &IID_IDXGIResource1,
+ (void **)&dxgiResource);
+ if (FAILED(hr)) {
+ goto fail;
+ }
+
+ hr = dxgiResource->lpVtbl->CreateSharedHandle(
+ dxgiResource,
+ NULL,
+ DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
+ NULL,
+ handle
+ );
+
+ dxgiResource->lpVtbl->Release(dxgiResource);
+
+ if (SUCCEEDED(hr)) {
+ return true;
+ }
+
+fail:
+ error_setg_win32(errp, GetLastError(), "failed to create shared handle");
+ return false;
+}
+
+static bool d3d_texture2d_acquire0(ID3D11Texture2D *d3d_texture, Error **errp)
+{
+ IDXGIKeyedMutex *dxgiMutex = NULL;
+ HRESULT hr;
+
+ hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
+ &IID_IDXGIKeyedMutex,
+ (void **)&dxgiMutex);
+ if (FAILED(hr)) {
+ goto fail;
+ }
+
+ hr = dxgiMutex->lpVtbl->AcquireSync(dxgiMutex, 0, INFINITE);
+
+ dxgiMutex->lpVtbl->Release(dxgiMutex);
+
+ if (SUCCEEDED(hr)) {
+ return true;
+ }
+
+fail:
+ error_setg_win32(errp, GetLastError(), "failed to acquire texture mutex");
+ return false;
+}
+
+static bool d3d_texture2d_release0(ID3D11Texture2D *d3d_texture, Error **errp)
+{
+ IDXGIKeyedMutex *dxgiMutex = NULL;
+ HRESULT hr;
+
+ hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
+ &IID_IDXGIKeyedMutex,
+ (void **)&dxgiMutex);
+ if (FAILED(hr)) {
+ goto fail;
+ }
+
+ hr = dxgiMutex->lpVtbl->ReleaseSync(dxgiMutex, 0);
+
+ dxgiMutex->lpVtbl->Release(dxgiMutex);
+
+ if (SUCCEEDED(hr)) {
+ return true;
+ }
+
+fail:
+ error_setg_win32(errp, GetLastError(), "failed to release texture mutex");
+ return false;
+}
+#endif /* WIN32 */
+
static void dbus_update_gl_cb(GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
+ GAsyncResult *res,
+ gpointer user_data)
{
g_autoptr(GError) err = NULL;
DBusDisplayListener *ddl = user_data;
+ bool success;
+
+#ifdef CONFIG_GBM
+ success = qemu_dbus_display1_listener_call_update_dmabuf_finish(
+ ddl->proxy, res, &err);
+#endif
+
+#ifdef WIN32
+ success = qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
+ ddl->d3d11_proxy, res, &err);
+ d3d_texture2d_acquire0(ddl->d3d_texture, &error_warn);
+#endif
- if (!qemu_dbus_display1_listener_call_update_dmabuf_finish(ddl->proxy,
- res, &err)) {
+ if (!success) {
error_report("Failed to call update: %s", err->message);
}
@@ -67,28 +204,54 @@ static void dbus_update_gl_cb(GObject *source_object,
g_object_unref(ddl);
}
-static void dbus_call_update_gl(DBusDisplayListener *ddl,
+static void dbus_call_update_gl(DisplayChangeListener *dcl,
int x, int y, int w, int h)
{
- graphic_hw_gl_block(ddl->dcl.con, true);
+ DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+
+ trace_dbus_update_gl(x, y, w, h);
+
glFlush();
+#ifdef CONFIG_GBM
+ graphic_hw_gl_block(ddl->dcl.con, true);
qemu_dbus_display1_listener_call_update_dmabuf(ddl->proxy,
x, y, w, h,
G_DBUS_CALL_FLAGS_NONE,
DBUS_DEFAULT_TIMEOUT, NULL,
dbus_update_gl_cb,
g_object_ref(ddl));
-}
-
-static void dbus_scanout_disable(DisplayChangeListener *dcl)
-{
- DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+#endif
- ddl->ds = NULL;
- qemu_dbus_display1_listener_call_disable(
- ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+#ifdef WIN32
+ switch (ddl->ds_share) {
+ case SHARE_KIND_MAPPED:
+ egl_fb_read_rect(ddl->ds, &ddl->fb, x, y, w, h);
+ dbus_gfx_update(dcl, x, y, w, h);
+ break;
+ case SHARE_KIND_D3DTEX:
+ Error *err = NULL;
+ assert(ddl->d3d_texture);
+
+ graphic_hw_gl_block(ddl->dcl.con, true);
+ if (!d3d_texture2d_release0(ddl->d3d_texture, &err)) {
+ error_report_err(err);
+ return;
+ }
+ qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d(
+ ddl->d3d11_proxy,
+ x, y, w, h,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_DEFAULT_TIMEOUT, NULL,
+ dbus_update_gl_cb,
+ g_object_ref(ddl));
+ break;
+ default:
+ g_warn_if_reached();
+ }
+#endif
}
+#ifdef CONFIG_GBM
static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
QemuDmaBuf *dmabuf)
{
@@ -117,15 +280,136 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
fd_list,
NULL, NULL, NULL);
}
+#endif /* GBM */
+#endif /* OPENGL */
+
+#ifdef WIN32
+static bool dbus_scanout_map(DBusDisplayListener *ddl)
+{
+ g_autoptr(GError) err = NULL;
+ BOOL success;
+ HANDLE target_handle;
+
+ if (ddl->ds_share == SHARE_KIND_MAPPED) {
+ return true;
+ }
+
+ if (!ddl->can_share_map || !ddl->ds->handle) {
+ return false;
+ }
+
+ success = DuplicateHandle(
+ GetCurrentProcess(),
+ ddl->ds->handle,
+ ddl->peer_process,
+ &target_handle,
+ FILE_MAP_READ | SECTION_QUERY,
+ FALSE, 0);
+ if (!success) {
+ g_autofree char *msg = g_win32_error_message(GetLastError());
+ g_debug("Failed to DuplicateHandle: %s", msg);
+ ddl->can_share_map = false;
+ return false;
+ }
+
+ if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
+ ddl->map_proxy,
+ GPOINTER_TO_UINT(target_handle),
+ ddl->ds->handle_offset,
+ surface_width(ddl->ds),
+ surface_height(ddl->ds),
+ surface_stride(ddl->ds),
+ surface_format(ddl->ds),
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_DEFAULT_TIMEOUT,
+ NULL,
+ &err)) {
+ g_debug("Failed to call ScanoutMap: %s", err->message);
+ ddl->can_share_map = false;
+ return false;
+ }
+
+ ddl->ds_share = SHARE_KIND_MAPPED;
+
+ return true;
+}
+
+static bool
+dbus_scanout_share_d3d_texture(
+ DBusDisplayListener *ddl,
+ ID3D11Texture2D *tex,
+ bool backing_y_0_top,
+ uint32_t backing_width,
+ uint32_t backing_height,
+ uint32_t x, uint32_t y,
+ uint32_t w, uint32_t h)
+{
+ Error *err = NULL;
+ BOOL success;
+ HANDLE share_handle, target_handle;
+
+ if (!d3d_texture2d_release0(tex, &err)) {
+ error_report_err(err);
+ return false;
+ }
+
+ if (!d3d_texture2d_share(tex, &share_handle, &err)) {
+ error_report_err(err);
+ return false;
+ }
+
+ success = DuplicateHandle(
+ GetCurrentProcess(),
+ share_handle,
+ ddl->peer_process,
+ &target_handle,
+ 0,
+ FALSE, DUPLICATE_SAME_ACCESS);
+ if (!success) {
+ g_autofree char *msg = g_win32_error_message(GetLastError());
+ g_debug("Failed to DuplicateHandle: %s", msg);
+ CloseHandle(share_handle);
+ return false;
+ }
+
+ qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
+ ddl->d3d11_proxy,
+ GPOINTER_TO_INT(target_handle),
+ backing_width,
+ backing_height,
+ backing_y_0_top,
+ x, y, w, h,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, NULL, NULL);
+
+ CloseHandle(share_handle);
+
+ if (!d3d_texture2d_acquire0(tex, &err)) {
+ error_report_err(err);
+ return false;
+ }
+
+ ddl->d3d_texture = tex;
+ ddl->ds_share = SHARE_KIND_D3DTEX;
+
+ return true;
+}
+#endif
+#ifdef CONFIG_OPENGL
static void dbus_scanout_texture(DisplayChangeListener *dcl,
uint32_t tex_id,
bool backing_y_0_top,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h)
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d)
{
+ trace_dbus_scanout_texture(tex_id, backing_y_0_top,
+ backing_width, backing_height, x, y, w, h);
+#ifdef CONFIG_GBM
QemuDmaBuf dmabuf = {
.width = backing_width,
.height = backing_height,
@@ -148,8 +432,26 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
dbus_scanout_dmabuf(dcl, &dmabuf);
close(dmabuf.fd);
+#endif
+
+#ifdef WIN32
+ DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+
+ /* there must be a matching gfx_switch before */
+ assert(surface_width(ddl->ds) == w);
+ assert(surface_height(ddl->ds) == h);
+
+ if (d3d_tex2d) {
+ dbus_scanout_share_d3d_texture(ddl, d3d_tex2d, backing_y_0_top,
+ backing_width, backing_height, x, y, w, h);
+ } else {
+ dbus_scanout_map(ddl);
+ egl_fb_setup_for_tex(&ddl->fb, backing_width, backing_height, tex_id, false);
+ }
+#endif
}
+#ifdef CONFIG_GBM
static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
QemuDmaBuf *dmabuf, bool have_hot,
uint32_t hot_x, uint32_t hot_y)
@@ -196,7 +498,14 @@ static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
NULL);
}
-static void dbus_cursor_position(DisplayChangeListener *dcl,
+static void dbus_release_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf)
+{
+ dbus_scanout_disable(dcl);
+}
+#endif /* GBM */
+
+static void dbus_gl_cursor_position(DisplayChangeListener *dcl,
uint32_t pos_x, uint32_t pos_y)
{
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
@@ -206,19 +515,11 @@ static void dbus_cursor_position(DisplayChangeListener *dcl,
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
}
-static void dbus_release_dmabuf(DisplayChangeListener *dcl,
- QemuDmaBuf *dmabuf)
-{
- dbus_scanout_disable(dcl);
-}
-
static void dbus_scanout_update(DisplayChangeListener *dcl,
uint32_t x, uint32_t y,
uint32_t w, uint32_t h)
{
- DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
-
- dbus_call_update_gl(ddl, x, y, w, h);
+ dbus_call_update_gl(dcl, x, y, w, h);
}
static void dbus_gl_refresh(DisplayChangeListener *dcl)
@@ -232,19 +533,19 @@ static void dbus_gl_refresh(DisplayChangeListener *dcl)
}
if (ddl->gl_updates) {
- dbus_call_update_gl(ddl, 0, 0,
+ dbus_call_update_gl(dcl, 0, 0,
surface_width(ddl->ds), surface_height(ddl->ds));
ddl->gl_updates = 0;
}
}
-#endif
+#endif /* OPENGL */
static void dbus_refresh(DisplayChangeListener *dcl)
{
graphic_hw_update(dcl->con);
}
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+#ifdef CONFIG_OPENGL
static void dbus_gl_gfx_update(DisplayChangeListener *dcl,
int x, int y, int w, int h)
{
@@ -263,10 +564,20 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
size_t stride;
assert(ddl->ds);
- stride = w * DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl->ds)), 8);
trace_dbus_update(x, y, w, h);
+#ifdef WIN32
+ if (dbus_scanout_map(ddl)) {
+ qemu_dbus_display1_listener_win32_map_call_update_map(
+ ddl->map_proxy,
+ x, y, w, h,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
+ return;
+ }
+#endif
+
if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) {
v_data = g_variant_new_from_data(
G_VARIANT_TYPE("ay"),
@@ -288,6 +599,7 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
}
/* make a copy, since gvariant only handles linear data */
+ stride = w * DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl->ds)), 8);
img = pixman_image_create_bits(surface_format(ddl->ds),
w, h, NULL, stride);
pixman_image_composite(PIXMAN_OP_SRC, ddl->ds->image, NULL, img,
@@ -307,20 +619,23 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
}
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+#ifdef CONFIG_OPENGL
static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface)
{
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+ trace_dbus_gl_gfx_switch(new_surface);
+
ddl->ds = new_surface;
+ ddl->ds_share = SHARE_KIND_NONE;
if (ddl->ds) {
int width = surface_width(ddl->ds);
int height = surface_height(ddl->ds);
/* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */
dbus_scanout_texture(&ddl->dcl, ddl->ds->texture, false,
- width, height, 0, 0, width, height);
+ width, height, 0, 0, width, height, NULL);
}
}
#endif
@@ -331,10 +646,7 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl,
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
ddl->ds = new_surface;
- if (!ddl->ds) {
- /* why not call disable instead? */
- return;
- }
+ ddl->ds_share = SHARE_KIND_NONE;
}
static void dbus_mouse_set(DisplayChangeListener *dcl,
@@ -374,7 +686,7 @@ static void dbus_cursor_define(DisplayChangeListener *dcl,
NULL);
}
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+#ifdef CONFIG_OPENGL
const DisplayChangeListenerOps dbus_gl_dcl_ops = {
.dpy_name = "dbus-gl",
.dpy_gfx_update = dbus_gl_gfx_update,
@@ -386,10 +698,12 @@ const DisplayChangeListenerOps dbus_gl_dcl_ops = {
.dpy_gl_scanout_disable = dbus_scanout_disable,
.dpy_gl_scanout_texture = dbus_scanout_texture,
+#ifdef CONFIG_GBM
.dpy_gl_scanout_dmabuf = dbus_scanout_dmabuf,
.dpy_gl_cursor_dmabuf = dbus_cursor_dmabuf,
- .dpy_gl_cursor_position = dbus_cursor_position,
.dpy_gl_release_dmabuf = dbus_release_dmabuf,
+#endif
+ .dpy_gl_cursor_position = dbus_gl_cursor_position,
.dpy_gl_update = dbus_scanout_update,
};
#endif
@@ -412,6 +726,14 @@ dbus_display_listener_dispose(GObject *object)
g_clear_object(&ddl->conn);
g_clear_pointer(&ddl->bus_name, g_free);
g_clear_object(&ddl->proxy);
+#ifdef WIN32
+ g_clear_object(&ddl->map_proxy);
+ g_clear_object(&ddl->d3d11_proxy);
+ g_clear_pointer(&ddl->peer_process, CloseHandle);
+#ifdef CONFIG_OPENGL
+ egl_fb_destroy(&ddl->fb);
+#endif
+#endif
G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object);
}
@@ -422,7 +744,7 @@ dbus_display_listener_constructed(GObject *object)
DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
ddl->dcl.ops = &dbus_dcl_ops;
-#if defined(CONFIG_OPENGL) && defined(CONFIG_GBM)
+#ifdef CONFIG_OPENGL
if (display_opengl) {
ddl->dcl.ops = &dbus_gl_dcl_ops;
}
@@ -457,6 +779,130 @@ dbus_display_listener_get_console(DBusDisplayListener *ddl)
return ddl->console;
}
+#ifdef WIN32
+static bool
+dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
+{
+ QemuDBusDisplay1Listener *l = QEMU_DBUS_DISPLAY1_LISTENER(ddl->proxy);
+ bool implements;
+
+ implements = g_strv_contains(qemu_dbus_display1_listener_get_interfaces(l), iface);
+ if (!implements) {
+ g_debug("Display listener does not implement: `%s`", iface);
+ }
+
+ return implements;
+}
+
+static bool
+dbus_display_listener_setup_peer_process(DBusDisplayListener *ddl)
+{
+ g_autoptr(GError) err = NULL;
+ GDBusConnection *conn;
+ GIOStream *stream;
+ GSocket *sock;
+ g_autoptr(GCredentials) creds = NULL;
+ DWORD *pid;
+
+ if (ddl->peer_process) {
+ return true;
+ }
+
+ conn = g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy));
+ stream = g_dbus_connection_get_stream(conn);
+
+ if (!G_IS_UNIX_CONNECTION(stream)) {
+ return false;
+ }
+
+ sock = g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream));
+ creds = g_socket_get_credentials(sock, &err);
+
+ if (!creds) {
+ g_debug("Failed to get peer credentials: %s", err->message);
+ return false;
+ }
+
+ pid = g_credentials_get_native(creds, G_CREDENTIALS_TYPE_WIN32_PID);
+
+ if (pid == NULL) {
+ g_debug("Failed to get peer PID");
+ return false;
+ }
+
+ ddl->peer_process = OpenProcess(
+ PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
+ false, *pid);
+
+ if (!ddl->peer_process) {
+ g_autofree char *msg = g_win32_error_message(GetLastError());
+ g_debug("Failed to OpenProcess: %s", msg);
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+static void
+dbus_display_listener_setup_d3d11(DBusDisplayListener *ddl)
+{
+#ifdef WIN32
+ g_autoptr(GError) err = NULL;
+
+ if (!dbus_display_listener_implements(ddl,
+ "org.qemu.Display1.Listener.Win32.D3d11")) {
+ return;
+ }
+
+ if (!dbus_display_listener_setup_peer_process(ddl)) {
+ return;
+ }
+
+ ddl->d3d11_proxy =
+ qemu_dbus_display1_listener_win32_d3d11_proxy_new_sync(ddl->conn,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ NULL,
+ "/org/qemu/Display1/Listener",
+ NULL,
+ &err);
+ if (!ddl->d3d11_proxy) {
+ g_debug("Failed to setup win32 d3d11 proxy: %s", err->message);
+ return;
+ }
+#endif
+}
+
+static void
+dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
+{
+#ifdef WIN32
+ g_autoptr(GError) err = NULL;
+
+ if (!dbus_display_listener_implements(ddl, "org.qemu.Display1.Listener.Win32.Map")) {
+ return;
+ }
+
+ if (!dbus_display_listener_setup_peer_process(ddl)) {
+ return;
+ }
+
+ ddl->map_proxy =
+ qemu_dbus_display1_listener_win32_map_proxy_new_sync(ddl->conn,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ NULL,
+ "/org/qemu/Display1/Listener",
+ NULL,
+ &err);
+ if (!ddl->map_proxy) {
+ g_debug("Failed to setup win32 map proxy: %s", err->message);
+ return;
+ }
+
+ ddl->can_share_map = true;
+#endif
+}
+
DBusDisplayListener *
dbus_display_listener_new(const char *bus_name,
GDBusConnection *conn,
@@ -485,6 +931,9 @@ dbus_display_listener_new(const char *bus_name,
ddl->conn = conn;
ddl->console = console;
+ dbus_display_listener_setup_shared_map(ddl);
+ dbus_display_listener_setup_d3d11(ddl);
+
con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
assert(con);
ddl->dcl.con = con;
diff --git a/ui/dbus.c b/ui/dbus.c
index b9e9698503..32f1bbe81a 100644
--- a/ui/dbus.c
+++ b/ui/dbus.c
@@ -47,10 +47,8 @@ static DBusDisplay *dbus_display;
static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc,
QEMUGLParams *params)
{
-#ifdef CONFIG_GBM
eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
qemu_egl_rn_ctx);
-#endif
return qemu_egl_create_context(dgc, params);
}
@@ -59,9 +57,7 @@ dbus_is_compatible_dcl(DisplayGLCtx *dgc,
DisplayChangeListener *dcl)
{
return
-#ifdef CONFIG_GBM
dcl->ops == &dbus_gl_dcl_ops ||
-#endif
dcl->ops == &dbus_console_dcl_ops;
}
diff --git a/ui/dbus.h b/ui/dbus.h
index 9c149e7b41..1e8c24a48e 100644
--- a/ui/dbus.h
+++ b/ui/dbus.h
@@ -62,6 +62,12 @@ struct DBusDisplay {
Notifier notifier;
};
+#ifdef WIN32
+bool
+dbus_win32_import_socket(GDBusMethodInvocation *invocation,
+ GVariant *arg_listener, int *socket);
+#endif
+
#define TYPE_DBUS_DISPLAY "dbus-display"
OBJECT_DECLARE_SIMPLE_TYPE(DBusDisplay, DBUS_DISPLAY)
diff --git a/ui/egl-context.c b/ui/egl-context.c
index eb5f520fc4..9e0df466f3 100644
--- a/ui/egl-context.c
+++ b/ui/egl-context.c
@@ -1,4 +1,5 @@
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
#include "ui/egl-context.h"
QEMUGLContext qemu_egl_create_context(DisplayGLCtx *dgc,
@@ -32,6 +33,11 @@ void qemu_egl_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx)
int qemu_egl_make_context_current(DisplayGLCtx *dgc,
QEMUGLContext ctx)
{
- return eglMakeCurrent(qemu_egl_display,
- EGL_NO_SURFACE, EGL_NO_SURFACE, ctx);
+ if (!eglMakeCurrent(qemu_egl_display,
+ EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
+ error_report("egl: eglMakeCurrent failed: %s", qemu_egl_get_error_string());
+ return -1;
+ }
+
+ return 0;
}
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index ef70e6a18e..d5637dadb2 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -61,7 +61,8 @@ static void egl_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h)
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d)
{
egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
@@ -79,6 +80,8 @@ static void egl_scanout_texture(DisplayChangeListener *dcl,
}
}
+#ifdef CONFIG_GBM
+
static void egl_scanout_dmabuf(DisplayChangeListener *dcl,
QemuDmaBuf *dmabuf)
{
@@ -89,7 +92,7 @@ static void egl_scanout_dmabuf(DisplayChangeListener *dcl,
egl_scanout_texture(dcl, dmabuf->texture,
false, dmabuf->width, dmabuf->height,
- 0, 0, dmabuf->width, dmabuf->height);
+ 0, 0, dmabuf->width, dmabuf->height, NULL);
}
static void egl_cursor_dmabuf(DisplayChangeListener *dcl,
@@ -110,6 +113,14 @@ static void egl_cursor_dmabuf(DisplayChangeListener *dcl,
}
}
+static void egl_release_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf)
+{
+ egl_dmabuf_release_texture(dmabuf);
+}
+
+#endif
+
static void egl_cursor_position(DisplayChangeListener *dcl,
uint32_t pos_x, uint32_t pos_y)
{
@@ -119,12 +130,6 @@ static void egl_cursor_position(DisplayChangeListener *dcl,
edpy->pos_y = pos_y;
}
-static void egl_release_dmabuf(DisplayChangeListener *dcl,
- QemuDmaBuf *dmabuf)
-{
- egl_dmabuf_release_texture(dmabuf);
-}
-
static void egl_scanout_flush(DisplayChangeListener *dcl,
uint32_t x, uint32_t y,
uint32_t w, uint32_t h)
@@ -160,10 +165,12 @@ static const DisplayChangeListenerOps egl_ops = {
.dpy_gl_scanout_disable = egl_scanout_disable,
.dpy_gl_scanout_texture = egl_scanout_texture,
+#ifdef CONFIG_GBM
.dpy_gl_scanout_dmabuf = egl_scanout_dmabuf,
.dpy_gl_cursor_dmabuf = egl_cursor_dmabuf,
- .dpy_gl_cursor_position = egl_cursor_position,
.dpy_gl_release_dmabuf = egl_release_dmabuf,
+#endif
+ .dpy_gl_cursor_position = egl_cursor_position,
.dpy_gl_update = egl_scanout_flush,
};
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 4203163ace..8f9fbf583e 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -15,21 +15,23 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
+
#include "qemu/drm.h"
#include "qemu/error-report.h"
#include "ui/console.h"
#include "ui/egl-helpers.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
+#include "trace.h"
EGLDisplay *qemu_egl_display;
EGLConfig qemu_egl_config;
DisplayGLMode qemu_egl_mode;
+bool qemu_egl_angle_d3d;
/* ------------------------------------------------------------------ */
-#if defined(CONFIG_X11) || defined(CONFIG_GBM)
-static const char *egl_get_error_string(void)
+const char *qemu_egl_get_error_string(void)
{
EGLint error = eglGetError();
@@ -68,7 +70,6 @@ static const char *egl_get_error_string(void)
return "Unknown EGL error";
}
}
-#endif
static void egl_fb_delete_texture(egl_fb *fb)
{
@@ -171,6 +172,20 @@ void egl_fb_read(DisplaySurface *dst, egl_fb *src)
GL_BGRA, GL_UNSIGNED_BYTE, surface_data(dst));
}
+void egl_fb_read_rect(DisplaySurface *dst, egl_fb *src, int x, int y, int w, int h)
+{
+ assert(surface_width(dst) == src->width);
+ assert(surface_height(dst) == src->height);
+ assert(surface_format(dst) == PIXMAN_x8r8g8b8);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glPixelStorei(GL_PACK_ROW_LENGTH, surface_stride(dst) / 4);
+ glReadPixels(x, y, w, h,
+ GL_BGRA, GL_UNSIGNED_BYTE, surface_data(dst) + x * 4);
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+}
+
void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip)
{
glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer);
@@ -201,11 +216,12 @@ void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip,
/* ---------------------------------------------------------------------- */
+EGLContext qemu_egl_rn_ctx;
+
#ifdef CONFIG_GBM
int qemu_egl_rn_fd;
struct gbm_device *qemu_egl_rn_gbm_dev;
-EGLContext qemu_egl_rn_ctx;
int egl_rendernode_init(const char *rendernode, DisplayGLMode mode)
{
@@ -402,7 +418,7 @@ EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, EGLNativeWindowType win)
/* ---------------------------------------------------------------------- */
-#if defined(CONFIG_X11) || defined(CONFIG_GBM)
+#if defined(CONFIG_X11) || defined(CONFIG_GBM) || defined(WIN32)
/*
* Taken from glamor_egl.h from the Xorg xserver, which is MIT licensed
@@ -439,10 +455,8 @@ static EGLDisplay qemu_egl_get_display(EGLNativeDisplayType native,
/* In practise any EGL 1.5 implementation would support the EXT extension */
if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) {
- PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT =
- (void *) eglGetProcAddress("eglGetPlatformDisplayEXT");
- if (getPlatformDisplayEXT && platform != 0) {
- dpy = getPlatformDisplayEXT(platform, native, NULL);
+ if (platform != 0) {
+ dpy = eglGetPlatformDisplayEXT(platform, native, NULL);
}
}
@@ -482,20 +496,20 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
qemu_egl_display = qemu_egl_get_display(dpy, platform);
if (qemu_egl_display == EGL_NO_DISPLAY) {
- error_report("egl: eglGetDisplay failed: %s", egl_get_error_string());
+ error_report("egl: eglGetDisplay failed: %s", qemu_egl_get_error_string());
return -1;
}
b = eglInitialize(qemu_egl_display, &major, &minor);
if (b == EGL_FALSE) {
- error_report("egl: eglInitialize failed: %s", egl_get_error_string());
+ error_report("egl: eglInitialize failed: %s", qemu_egl_get_error_string());
return -1;
}
b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API);
if (b == EGL_FALSE) {
error_report("egl: eglBindAPI failed (%s mode): %s",
- gles ? "gles" : "core", egl_get_error_string());
+ gles ? "gles" : "core", qemu_egl_get_error_string());
return -1;
}
@@ -504,7 +518,7 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
&qemu_egl_config, 1, &n);
if (b == EGL_FALSE || n != 1) {
error_report("egl: eglChooseConfig failed (%s mode): %s",
- gles ? "gles" : "core", egl_get_error_string());
+ gles ? "gles" : "core", qemu_egl_get_error_string());
return -1;
}
@@ -512,6 +526,9 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
return 0;
}
+#endif
+
+#if defined(CONFIG_X11) || defined(CONFIG_GBM)
int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy, DisplayGLMode mode)
{
#ifdef EGL_KHR_platform_x11
@@ -529,7 +546,45 @@ int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode)
return qemu_egl_init_dpy(dpy, 0, mode);
#endif
}
+#endif
+
+
+#ifdef WIN32
+int qemu_egl_init_dpy_win32(EGLNativeDisplayType dpy, DisplayGLMode mode)
+{
+ /* prefer GL ES, as that's what ANGLE supports */
+ if (mode == DISPLAYGL_MODE_ON) {
+ mode = DISPLAYGL_MODE_ES;
+ }
+
+ if (qemu_egl_init_dpy(dpy, 0, mode) < 0) {
+ return -1;
+ }
+
+#ifdef EGL_D3D11_DEVICE_ANGLE
+ if (epoxy_has_egl_extension(qemu_egl_display, "EGL_EXT_device_query")) {
+ EGLDeviceEXT device;
+ void *d3d11_device;
+ if (!eglQueryDisplayAttribEXT(qemu_egl_display,
+ EGL_DEVICE_EXT,
+ (EGLAttrib *)&device)) {
+ return 0;
+ }
+
+ if (!eglQueryDeviceAttribEXT(device,
+ EGL_D3D11_DEVICE_ANGLE,
+ (EGLAttrib *)&d3d11_device)) {
+ return 0;
+ }
+
+ trace_egl_init_d3d11_device(device);
+ qemu_egl_angle_d3d = device != NULL;
+ }
+#endif
+
+ return 0;
+}
#endif
bool qemu_egl_has_dmabuf(void)
@@ -581,15 +636,28 @@ bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp)
return false;
}
-#ifdef CONFIG_GBM
+#ifdef WIN32
+ if (qemu_egl_init_dpy_win32(EGL_DEFAULT_DISPLAY, mode) < 0) {
+ error_setg(errp, "egl: init failed");
+ return false;
+ }
+ qemu_egl_rn_ctx = qemu_egl_init_ctx();
+ if (!qemu_egl_rn_ctx) {
+ error_setg(errp, "egl: egl_init_ctx failed");
+ return false;
+ }
+#elif defined(CONFIG_GBM)
if (egl_rendernode_init(rendernode, mode) < 0) {
error_setg(errp, "egl: render node init failed");
return false;
}
+#endif
+
+ if (!qemu_egl_rn_ctx) {
+ error_setg(errp, "egl: not available on this platform");
+ return false;
+ }
+
display_opengl = 1;
return true;
-#else
- error_setg(errp, "egl: not available on this platform");
- return false;
-#endif
}
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 19130041bc..d59b8cd7d7 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
+#include "qemu/error-report.h"
#include "trace.h"
@@ -223,7 +224,8 @@ void gd_egl_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_id, bool backing_y_0_top,
uint32_t backing_width, uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h)
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d)
{
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
@@ -257,7 +259,8 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
gd_egl_scanout_texture(dcl, dmabuf->texture,
dmabuf->y0_top, dmabuf->width, dmabuf->height,
- 0, 0, dmabuf->width, dmabuf->height);
+ dmabuf->x, dmabuf->y, dmabuf->scanout_width,
+ dmabuf->scanout_height, NULL);
if (dmabuf->allow_fences) {
vc->gfx.guest_fb.dmabuf = dmabuf;
@@ -368,6 +371,11 @@ int gd_egl_make_current(DisplayGLCtx *dgc,
{
VirtualConsole *vc = container_of(dgc, VirtualConsole, gfx.dgc);
- return eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
- vc->gfx.esurface, ctx);
+ if (!eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
+ vc->gfx.esurface, ctx)) {
+ error_report("egl: eglMakeCurrent failed: %s", qemu_egl_get_error_string());
+ return -1;
+ }
+
+ return 0;
}
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index c384a1516b..7367dfd793 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -244,7 +244,8 @@ void gd_gl_area_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h)
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d)
{
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
@@ -299,7 +300,8 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
gd_gl_area_scanout_texture(dcl, dmabuf->texture,
dmabuf->y0_top, dmabuf->width, dmabuf->height,
- 0, 0, dmabuf->width, dmabuf->height);
+ dmabuf->x, dmabuf->y, dmabuf->scanout_width,
+ dmabuf->scanout_height, NULL);
if (dmabuf->allow_fences) {
vc->gfx.guest_fb.dmabuf = dmabuf;
diff --git a/ui/gtk.c b/ui/gtk.c
index e50f950f2b..8ba41c8f13 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -130,11 +130,6 @@ typedef struct VCChardev VCChardev;
DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
TYPE_CHARDEV_VC)
-struct touch_slot {
- int x;
- int y;
- int tracking_id;
-};
static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX];
bool gtk_use_gl_area;
@@ -588,7 +583,12 @@ static void gd_gl_release_dmabuf(DisplayChangeListener *dcl,
QemuDmaBuf *dmabuf)
{
#ifdef CONFIG_GBM
+ VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
egl_dmabuf_release_texture(dmabuf);
+ if (vc->gfx.guest_fb.dmabuf == dmabuf) {
+ vc->gfx.guest_fb.dmabuf = NULL;
+ }
#endif
}
@@ -1068,27 +1068,12 @@ static gboolean gd_touch_event(GtkWidget *widget, GdkEventTouch *touch,
void *opaque)
{
VirtualConsole *vc = opaque;
- struct touch_slot *slot;
uint64_t num_slot = GPOINTER_TO_UINT(touch->sequence);
- bool needs_sync = false;
- int update;
int type = -1;
- int i;
-
- if (num_slot >= INPUT_EVENT_SLOTS_MAX) {
- warn_report("gtk: unexpected touch slot number: % " PRId64" >= %d\n",
- num_slot, INPUT_EVENT_SLOTS_MAX);
- return FALSE;
- }
-
- slot = &touch_slots[num_slot];
- slot->x = touch->x;
- slot->y = touch->y;
switch (touch->type) {
case GDK_TOUCH_BEGIN:
type = INPUT_MULTI_TOUCH_TYPE_BEGIN;
- slot->tracking_id = num_slot;
break;
case GDK_TOUCH_UPDATE:
type = INPUT_MULTI_TOUCH_TYPE_UPDATE;
@@ -1099,44 +1084,13 @@ static gboolean gd_touch_event(GtkWidget *widget, GdkEventTouch *touch,
break;
default:
warn_report("gtk: unexpected touch event type\n");
+ return FALSE;
}
- for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) {
- if (i == num_slot) {
- update = type;
- } else {
- update = INPUT_MULTI_TOUCH_TYPE_UPDATE;
- }
-
- slot = &touch_slots[i];
-
- if (slot->tracking_id == -1) {
- continue;
- }
-
- if (update == INPUT_MULTI_TOUCH_TYPE_END) {
- slot->tracking_id = -1;
- qemu_input_queue_mtt(vc->gfx.dcl.con, update, i, slot->tracking_id);
- needs_sync = true;
- } else {
- qemu_input_queue_mtt(vc->gfx.dcl.con, update, i, slot->tracking_id);
- qemu_input_queue_btn(vc->gfx.dcl.con, INPUT_BUTTON_TOUCH, true);
- qemu_input_queue_mtt_abs(vc->gfx.dcl.con,
- INPUT_AXIS_X, (int) slot->x,
- 0, surface_width(vc->gfx.ds),
- i, slot->tracking_id);
- qemu_input_queue_mtt_abs(vc->gfx.dcl.con,
- INPUT_AXIS_Y, (int) slot->y,
- 0, surface_height(vc->gfx.ds),
- i, slot->tracking_id);
- needs_sync = true;
- }
- }
-
- if (needs_sync) {
- qemu_input_event_sync();
- }
-
+ console_handle_touch_event(vc->gfx.dcl.con, touch_slots,
+ num_slot, surface_width(vc->gfx.ds),
+ surface_height(vc->gfx.ds), touch->x,
+ touch->y, type, &error_warn);
return TRUE;
}
diff --git a/ui/meson.build b/ui/meson.build
index a5506ac8ad..d81609fb0e 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -65,18 +65,25 @@ if opengl.found()
ui_modules += {'opengl' : opengl_ss}
endif
-if opengl.found() and gbm.found()
+if opengl.found()
egl_headless_ss = ss.source_set()
- egl_headless_ss.add(when: [opengl, gbm, pixman],
- if_true: files('egl-headless.c'))
+ egl_headless_ss.add(when: [opengl, pixman],
+ if_true: [files('egl-headless.c'), gbm])
ui_modules += {'egl-headless' : egl_headless_ss}
endif
if dbus_display
dbus_ss = ss.source_set()
+ env = environment()
+ env.set('TARGETOS', targetos)
+ xml = custom_target('dbus-display preprocess',
+ input: 'dbus-display1.xml',
+ output: 'dbus-display1.xml',
+ env: env,
+ command: [xml_pp, '@INPUT@', '@OUTPUT@'])
dbus_display1 = custom_target('dbus-display gdbus-codegen',
output: ['dbus-display1.h', 'dbus-display1.c'],
- input: files('dbus-display1.xml'),
+ input: xml,
command: [gdbus_codegen, '@INPUT@',
'--glib-min-required', '2.64',
'--output-directory', meson.current_build_dir(),
diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c
index 3ab7e2e958..e4f024a85e 100644
--- a/ui/qemu-pixman.c
+++ b/ui/qemu-pixman.c
@@ -6,6 +6,7 @@
#include "qemu/osdep.h"
#include "ui/console.h"
#include "standard-headers/drm/drm_fourcc.h"
+#include "trace.h"
PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format)
{
diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
index bbfa70eac3..28d796607c 100644
--- a/ui/sdl2-gl.c
+++ b/ui/sdl2-gl.c
@@ -205,7 +205,8 @@ void sdl2_gl_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h)
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d)
{
struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 9d703200bf..0d91b555e3 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -113,11 +113,11 @@ void sdl2_window_create(struct sdl2_console *scon)
SDL_SetHint(SDL_HINT_RENDER_DRIVER, driver);
SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
- }
- scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);
- if (scon->opengl) {
scon->winctx = SDL_GL_CreateContext(scon->real_window);
+ } else {
+ /* The SDL renderer is only used by sdl2-2D, when OpenGL is disabled */
+ scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);
}
sdl_update_caption(scon);
}
@@ -128,10 +128,14 @@ void sdl2_window_destroy(struct sdl2_console *scon)
return;
}
- SDL_GL_DeleteContext(scon->winctx);
- scon->winctx = NULL;
- SDL_DestroyRenderer(scon->real_renderer);
- scon->real_renderer = NULL;
+ if (scon->winctx) {
+ SDL_GL_DeleteContext(scon->winctx);
+ scon->winctx = NULL;
+ }
+ if (scon->real_renderer) {
+ SDL_DestroyRenderer(scon->real_renderer);
+ scon->real_renderer = NULL;
+ }
SDL_DestroyWindow(scon->real_window);
scon->real_window = NULL;
}
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 5bee19a7f9..3f3f8013d8 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -935,7 +935,8 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
uint32_t backing_width,
uint32_t backing_height,
uint32_t x, uint32_t y,
- uint32_t w, uint32_t h)
+ uint32_t w, uint32_t h,
+ void *d3d_tex2d)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
EGLint stride = 0, fourcc = 0;
diff --git a/ui/trace-events b/ui/trace-events
index 6747361745..76b19a2995 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -9,7 +9,7 @@ console_putchar_unhandled(int ch) "unhandled escape character '%c'"
console_txt_new(int w, int h) "%dx%d"
console_select(int nr) "%d"
console_refresh(int interval) "interval %d ms"
-displaysurface_create(void *display_surface, int w, int h) "surface=%p, %dx%d"
+displaysurface_create(int w, int h) "%dx%d"
displaysurface_create_from(void *display_surface, int w, int h, uint32_t format) "surface=%p, %dx%d, format 0x%x"
displaysurface_create_pixman(void *display_surface) "surface=%p"
displaysurface_free(void *display_surface) "surface=%p"
@@ -154,7 +154,14 @@ dbus_mouse_press(unsigned int button) "button %u"
dbus_mouse_release(unsigned int button) "button %u"
dbus_mouse_set_pos(unsigned int x, unsigned int y) "x=%u, y=%u"
dbus_mouse_rel_motion(int dx, int dy) "dx=%d, dy=%d"
+dbus_touch_send_event(unsigned int kind, uint32_t num_slot, uint32_t x, uint32_t y) "kind=%u, num_slot=%u, x=%d, y=%d"
dbus_update(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
+dbus_update_gl(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
dbus_clipboard_grab_failed(void) ""
dbus_clipboard_register(const char *bus_name) "peer %s"
dbus_clipboard_unregister(const char *bus_name) "peer %s"
+dbus_scanout_texture(uint32_t tex_id, bool backing_y_0_top, uint32_t backing_width, uint32_t backing_height, uint32_t x, uint32_t y, uint32_t w, uint32_t h) "tex_id:%u y0top:%d back:%ux%u %u+%u-%ux%u"
+dbus_gl_gfx_switch(void *p) "surf: %p"
+
+# egl-helpers.c
+egl_init_d3d11_device(void *p) "d3d device: %p"
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index fafbab80b4..429542face 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -835,3 +835,36 @@ int qemu_msync(void *addr, size_t length, int fd)
*/
return qemu_fdatasync(fd);
}
+
+void *qemu_win32_map_alloc(size_t size, HANDLE *h, Error **errp)
+{
+ void *bits;
+
+ trace_win32_map_alloc(size);
+
+ *h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
+ size, NULL);
+ if (*h == NULL) {
+ error_setg_win32(errp, GetLastError(), "Failed to CreateFileMapping");
+ return NULL;
+ }
+
+ bits = MapViewOfFile(*h, FILE_MAP_ALL_ACCESS, 0, 0, size);
+ if (bits == NULL) {
+ error_setg_win32(errp, GetLastError(), "Failed to MapViewOfFile");
+ CloseHandle(*h);
+ return NULL;
+ }
+
+ return bits;
+}
+
+void qemu_win32_map_free(void *ptr, HANDLE h, Error **errp)
+{
+ trace_win32_map_free(ptr, h);
+
+ if (UnmapViewOfFile(ptr) == 0) {
+ error_setg_win32(errp, GetLastError(), "Failed to UnmapViewOfFile");
+ }
+ CloseHandle(h);
+}
diff --git a/util/trace-events b/util/trace-events
index 3f7e766683..49a4962e18 100644
--- a/util/trace-events
+++ b/util/trace-events
@@ -52,6 +52,10 @@ qemu_anon_ram_alloc(size_t size, void *ptr) "size %zu ptr %p"
qemu_vfree(void *ptr) "ptr %p"
qemu_anon_ram_free(void *ptr, size_t size) "ptr %p size %zu"
+# oslib-win32.c
+win32_map_alloc(size_t size) "size:%zd"
+win32_map_free(void *ptr, void *h) "ptr:%p handle:%p"
+
# hbitmap.c
hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx"
hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64