[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v11 16/59] i386/xen: manage and save/restore Xen guest long_mode
From: |
David Woodhouse |
Subject: |
[PATCH v11 16/59] i386/xen: manage and save/restore Xen guest long_mode setting |
Date: |
Thu, 16 Feb 2023 06:24:01 +0000 |
From: David Woodhouse <dwmw@amazon.co.uk>
Xen will "latch" the guest's 32-bit or 64-bit ("long mode") setting when
the guest writes the MSR to fill in the hypercall page, or when the guest
sets the event channel callback in HVM_PARAM_CALLBACK_IRQ.
KVM handles the former and sets the kernel's long_mode flag accordingly.
The latter will be handled in userspace. Keep them in sync by noticing
when a hypercall is made in a mode that doesn't match qemu's idea of
the guest mode, and resyncing from the kernel. Do that same sync right
before serialization too, in case the guest has set the hypercall page
but hasn't yet made a system call.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
---
hw/i386/kvm/xen_overlay.c | 62 +++++++++++++++++++++++++++++++++++++++
hw/i386/kvm/xen_overlay.h | 4 +++
target/i386/kvm/xen-emu.c | 12 ++++++++
3 files changed, 78 insertions(+)
diff --git a/hw/i386/kvm/xen_overlay.c b/hw/i386/kvm/xen_overlay.c
index a2441e2b4e..8685d87959 100644
--- a/hw/i386/kvm/xen_overlay.c
+++ b/hw/i386/kvm/xen_overlay.c
@@ -44,6 +44,7 @@ struct XenOverlayState {
MemoryRegion shinfo_mem;
void *shinfo_ptr;
uint64_t shinfo_gpa;
+ bool long_mode;
};
struct XenOverlayState *xen_overlay_singleton;
@@ -96,9 +97,21 @@ static void xen_overlay_realize(DeviceState *dev, Error
**errp)
s->shinfo_ptr = memory_region_get_ram_ptr(&s->shinfo_mem);
s->shinfo_gpa = INVALID_GPA;
+ s->long_mode = false;
memset(s->shinfo_ptr, 0, XEN_PAGE_SIZE);
}
+static int xen_overlay_pre_save(void *opaque)
+{
+ /*
+ * Fetch the kernel's idea of long_mode to avoid the race condition
+ * where the guest has set the hypercall page up in 64-bit mode but
+ * not yet made a hypercall by the time migration happens, so qemu
+ * hasn't yet noticed.
+ */
+ return xen_sync_long_mode();
+}
+
static int xen_overlay_post_load(void *opaque, int version_id)
{
XenOverlayState *s = opaque;
@@ -107,6 +120,9 @@ static int xen_overlay_post_load(void *opaque, int
version_id)
xen_overlay_do_map_page(&s->shinfo_mem, s->shinfo_gpa);
xen_overlay_set_be_shinfo(s->shinfo_gpa >> XEN_PAGE_SHIFT);
}
+ if (s->long_mode) {
+ xen_set_long_mode(true);
+ }
return 0;
}
@@ -121,9 +137,11 @@ static const VMStateDescription xen_overlay_vmstate = {
.version_id = 1,
.minimum_version_id = 1,
.needed = xen_overlay_is_needed,
+ .pre_save = xen_overlay_pre_save,
.post_load = xen_overlay_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT64(shinfo_gpa, XenOverlayState),
+ VMSTATE_BOOL(long_mode, XenOverlayState),
VMSTATE_END_OF_LIST()
}
};
@@ -208,3 +226,47 @@ void *xen_overlay_get_shinfo_ptr(void)
return s->shinfo_ptr;
}
+
+int xen_sync_long_mode(void)
+{
+ int ret;
+ struct kvm_xen_hvm_attr xa = {
+ .type = KVM_XEN_ATTR_TYPE_LONG_MODE,
+ };
+
+ if (!xen_overlay_singleton) {
+ return -ENOENT;
+ }
+
+ ret = kvm_vm_ioctl(kvm_state, KVM_XEN_HVM_GET_ATTR, &xa);
+ if (!ret) {
+ xen_overlay_singleton->long_mode = xa.u.long_mode;
+ }
+
+ return ret;
+}
+
+int xen_set_long_mode(bool long_mode)
+{
+ int ret;
+ struct kvm_xen_hvm_attr xa = {
+ .type = KVM_XEN_ATTR_TYPE_LONG_MODE,
+ .u.long_mode = long_mode,
+ };
+
+ if (!xen_overlay_singleton) {
+ return -ENOENT;
+ }
+
+ ret = kvm_vm_ioctl(kvm_state, KVM_XEN_HVM_SET_ATTR, &xa);
+ if (!ret) {
+ xen_overlay_singleton->long_mode = xa.u.long_mode;
+ }
+
+ return ret;
+}
+
+bool xen_is_long_mode(void)
+{
+ return xen_overlay_singleton && xen_overlay_singleton->long_mode;
+}
diff --git a/hw/i386/kvm/xen_overlay.h b/hw/i386/kvm/xen_overlay.h
index 00cff05bb0..5c46a0b036 100644
--- a/hw/i386/kvm/xen_overlay.h
+++ b/hw/i386/kvm/xen_overlay.h
@@ -17,4 +17,8 @@ void xen_overlay_create(void);
int xen_overlay_map_shinfo_page(uint64_t gpa);
void *xen_overlay_get_shinfo_ptr(void);
+int xen_sync_long_mode(void);
+int xen_set_long_mode(bool long_mode);
+bool xen_is_long_mode(void);
+
#endif /* QEMU_XEN_OVERLAY_H */
diff --git a/target/i386/kvm/xen-emu.c b/target/i386/kvm/xen-emu.c
index ebea27caf6..be6d85f2cb 100644
--- a/target/i386/kvm/xen-emu.c
+++ b/target/i386/kvm/xen-emu.c
@@ -20,6 +20,8 @@
#include "trace.h"
#include "sysemu/runstate.h"
+#include "hw/i386/kvm/xen_overlay.h"
+
#include "hw/xen/interface/version.h"
#include "hw/xen/interface/sched.h"
@@ -282,6 +284,16 @@ int kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit
*exit)
return -1;
}
+ /*
+ * The kernel latches the guest 32/64 mode when the MSR is used to fill
+ * the hypercall page. So if we see a hypercall in a mode that doesn't
+ * match our own idea of the guest mode, fetch the kernel's idea of the
+ * "long mode" to remain in sync.
+ */
+ if (exit->u.hcall.longmode != xen_is_long_mode()) {
+ xen_sync_long_mode();
+ }
+
if (!do_kvm_xen_handle_exit(cpu, exit)) {
/*
* Some hypercalls will be deliberately "implemented" by returning
--
2.39.0
- [PATCH v11 02/59] xen: add CONFIG_XEN_BUS and CONFIG_XEN_EMU options for Xen emulation, (continued)
- [PATCH v11 02/59] xen: add CONFIG_XEN_BUS and CONFIG_XEN_EMU options for Xen emulation, David Woodhouse, 2023/02/16
- [PATCH v11 14/59] xen: Permit --xen-domid argument when accel is KVM, David Woodhouse, 2023/02/16
- [PATCH v11 20/59] i386/xen: implement HYPERVISOR_vcpu_op, David Woodhouse, 2023/02/16
- [PATCH v11 41/59] hw/xen: Support HVM_PARAM_CALLBACK_TYPE_PCI_INTX callback, David Woodhouse, 2023/02/16
- [PATCH v11 34/59] hw/xen: Implement EVTCHNOP_send, David Woodhouse, 2023/02/16
- [PATCH v11 05/59] i386/kvm: handle Xen HVM cpuid leaves, David Woodhouse, 2023/02/16
- [PATCH v11 09/59] i386/xen: handle guest hypercalls, David Woodhouse, 2023/02/16
- [PATCH v11 13/59] hw/xen: Add xen_overlay device for emulating shared xenheap pages, David Woodhouse, 2023/02/16
- [PATCH v11 56/59] hw/xen: Support GSI mapping to PIRQ, David Woodhouse, 2023/02/16
- [PATCH v11 22/59] i386/xen: handle VCPUOP_register_vcpu_time_info, David Woodhouse, 2023/02/16
- [PATCH v11 16/59] i386/xen: manage and save/restore Xen guest long_mode setting,
David Woodhouse <=
- [PATCH v11 35/59] hw/xen: Implement EVTCHNOP_alloc_unbound, David Woodhouse, 2023/02/16
- [PATCH v11 53/59] hw/xen: Automatically add xen-platform PCI device for emulated Xen guests, David Woodhouse, 2023/02/16
- [PATCH v11 37/59] hw/xen: Implement EVTCHNOP_bind_vcpu, David Woodhouse, 2023/02/16
- [PATCH v11 38/59] hw/xen: Implement EVTCHNOP_reset, David Woodhouse, 2023/02/16
- [PATCH v11 11/59] i386/xen: implement HYPERVISOR_sched_op, SCHEDOP_shutdown, David Woodhouse, 2023/02/16
- [PATCH v11 25/59] i386/xen: implement HVMOP_set_evtchn_upcall_vector, David Woodhouse, 2023/02/16
- [PATCH v11 58/59] kvm/i386: Add xen-evtchn-max-pirq property, David Woodhouse, 2023/02/16
- [PATCH v11 04/59] i386/kvm: Add xen-version KVM accelerator property and init KVM Xen support, David Woodhouse, 2023/02/16
- [PATCH v11 07/59] xen-platform: exclude vfio-pci from the PCI platform unplug, David Woodhouse, 2023/02/16
- [PATCH v11 48/59] i386/xen: Reserve Xen special pages for console, xenstore rings, David Woodhouse, 2023/02/16