[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH v3 13/38] i386/xen: manage and save/restore Xen guest long_mo
From: |
David Woodhouse |
Subject: |
[RFC PATCH v3 13/38] i386/xen: manage and save/restore Xen guest long_mode setting |
Date: |
Fri, 16 Dec 2022 00:40:52 +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>
---
hw/i386/kvm/xen_overlay.c | 63 +++++++++++++++++++++++++++++++++++++++
hw/i386/kvm/xen_overlay.h | 4 +++
target/i386/kvm/xen-emu.c | 10 ++++++-
3 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/hw/i386/kvm/xen_overlay.c b/hw/i386/kvm/xen_overlay.c
index 2ae54e1a88..a0ddbda91c 100644
--- a/hw/i386/kvm/xen_overlay.c
+++ b/hw/i386/kvm/xen_overlay.c
@@ -47,6 +47,7 @@ struct XenOverlayState {
MemoryRegion shinfo_mem;
void *shinfo_ptr;
uint64_t shinfo_gpa;
+ bool long_mode;
};
struct XenOverlayState *xen_overlay_singleton;
@@ -64,9 +65,19 @@ static void xen_overlay_realize(DeviceState *dev, Error
**errp)
memory_region_set_enabled(&s->shinfo_mem, true);
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;
@@ -74,6 +85,9 @@ static int xen_overlay_post_load(void *opaque, int version_id)
if (s->shinfo_gpa != INVALID_GPA) {
xen_overlay_map_page_locked(XENMAPSPACE_shared_info, 0, s->shinfo_gpa);
}
+ if (s->long_mode) {
+ xen_set_long_mode(true);
+ }
return 0;
}
@@ -88,9 +102,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()
}
};
@@ -196,3 +212,50 @@ void *xen_overlay_page_ptr(uint32_t space, uint64_t idx)
return xen_overlay_singleton->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)
+{
+ if (xen_overlay_singleton) {
+ return xen_overlay_singleton->long_mode;
+ }
+ return false;
+}
diff --git a/hw/i386/kvm/xen_overlay.h b/hw/i386/kvm/xen_overlay.h
index afc63991ea..ed8f0ef0e7 100644
--- a/hw/i386/kvm/xen_overlay.h
+++ b/hw/i386/kvm/xen_overlay.h
@@ -12,3 +12,7 @@
void xen_overlay_create(void);
int xen_overlay_map_page(uint32_t space, uint64_t idx, uint64_t gpa);
void *xen_overlay_page_ptr(uint32_t space, uint64_t idx);
+
+int xen_sync_long_mode(void);
+int xen_set_long_mode(bool long_mode);
+bool xen_is_long_mode(void);
diff --git a/target/i386/kvm/xen-emu.c b/target/i386/kvm/xen-emu.c
index 9026fd3eb6..11e34ed125 100644
--- a/target/i386/kvm/xen-emu.c
+++ b/target/i386/kvm/xen-emu.c
@@ -17,7 +17,7 @@
#include "xen-emu.h"
#include "xen.h"
#include "trace.h"
-
+#include "hw/i386/kvm/xen_overlay.h"
#include "standard-headers/xen/version.h"
static int kvm_gva_rw(CPUState *cs, uint64_t gva, void *_buf, size_t sz,
@@ -157,6 +157,14 @@ int kvm_xen_handle_exit(X86CPU *cpu, struct kvm_xen_exit
*exit)
if (exit->type != KVM_EXIT_XEN_HCALL)
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
* -ENOSYS. This case is for hypercalls which are unexpected. */
--
2.35.3
- [RFC PATCH v3 30/38] hw/xen: Implement EVTCHNOP_send, (continued)
- [RFC PATCH v3 16/38] i386/xen: implement HYPERVISOR_hvm_op, David Woodhouse, 2022/12/15
- [RFC PATCH v3 24/38] i386/xen: implement HYPERVISOR_sched_op, David Woodhouse, 2022/12/15
- [RFC PATCH v3 27/38] hw/xen: Implement EVTCHNOP_unmask, David Woodhouse, 2022/12/15
- [RFC PATCH v3 37/38] hw/xen: Support HVM_PARAM_CALLBACK_TYPE_GSI callback, David Woodhouse, 2022/12/15
- [RFC PATCH v3 20/38] i386/xen: handle VCPUOP_register_runstate_memory_area, David Woodhouse, 2022/12/15
- [RFC PATCH v3 13/38] i386/xen: manage and save/restore Xen guest long_mode setting,
David Woodhouse <=
- [RFC PATCH v3 05/38] i386/kvm: handle Xen HVM cpuid leaves, David Woodhouse, 2022/12/15
- [RFC PATCH v3 01/38] include: import xen public headers, David Woodhouse, 2022/12/15
- [RFC PATCH v3 18/38] i386/xen: handle VCPUOP_register_vcpu_info, David Woodhouse, 2022/12/15
- [RFC PATCH v3 10/38] i386/xen: implement HYPERCALL_xen_version, David Woodhouse, 2022/12/15
- [RFC PATCH v3 07/38] xen-platform: allow its creation with XEN_EMULATE mode, David Woodhouse, 2022/12/15
- [RFC PATCH v3 34/38] hw/xen: Implement EVTCHNOP_reset, David Woodhouse, 2022/12/15