svn commit: r339312 - in head/sys/amd64: include vmm/intel
John Baldwin
jhb at FreeBSD.org
Thu Oct 11 18:27:20 UTC 2018
Author: jhb
Date: Thu Oct 11 18:27:19 2018
New Revision: 339312
URL: https://svnweb.freebsd.org/changeset/base/339312
Log:
Fully restore the GDTR, IDTR, and LDTR after VT-x VM exits.
The VT-x VMCS only stores the base address of the GDTR and IDTR. As a
result, VM exits use a fixed limit of 0xffff for the host GDTR and
IDTR losing the smaller limits set in when the initial GDT is loaded
on each CPU during boot. Explicitly save and restore the full GDTR
and IDTR contents around VM entries and exits to restore the correct
limit.
Similarly, explicitly save and restore the LDT selector. VM exits
always clear the host LDTR as if the LDT was loaded with a NULL
selector and a userspace hypervisor is probably using a NULL selector
anyway, but save and restore the LDT explicitly just to be safe.
PR: 230773
Reported by: John Levon <levon at movementarian.org>
Reviewed by: kib
Tested by: araujo
Approved by: re (rgrimes)
MFC after: 1 week
Modified:
head/sys/amd64/include/cpufunc.h
head/sys/amd64/vmm/intel/vmx.c
Modified: head/sys/amd64/include/cpufunc.h
==============================================================================
--- head/sys/amd64/include/cpufunc.h Thu Oct 11 18:26:18 2018 (r339311)
+++ head/sys/amd64/include/cpufunc.h Thu Oct 11 18:27:19 2018 (r339312)
@@ -730,6 +730,15 @@ lldt(u_short sel)
__asm __volatile("lldt %0" : : "r" (sel));
}
+static __inline u_short
+sldt(void)
+{
+ u_short sel;
+
+ __asm __volatile("sldt %0" : "=r" (sel));
+ return (sel);
+}
+
static __inline void
ltr(u_short sel)
{
Modified: head/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx.c Thu Oct 11 18:26:18 2018 (r339311)
+++ head/sys/amd64/vmm/intel/vmx.c Thu Oct 11 18:27:19 2018 (r339312)
@@ -2833,6 +2833,8 @@ vmx_run(void *arg, int vcpu, register_t rip, pmap_t pm
struct vm_exit *vmexit;
struct vlapic *vlapic;
uint32_t exit_reason;
+ struct region_descriptor gdtr, idtr;
+ uint16_t ldt_sel;
vmx = arg;
vm = vmx->vm;
@@ -2924,10 +2926,30 @@ vmx_run(void *arg, int vcpu, register_t rip, pmap_t pm
break;
}
+ /*
+ * VM exits restore the base address but not the
+ * limits of GDTR and IDTR. The VMCS only stores the
+ * base address, so VM exits set the limits to 0xffff.
+ * Save and restore the full GDTR and IDTR to restore
+ * the limits.
+ *
+ * The VMCS does not save the LDTR at all, and VM
+ * exits clear LDTR as if a NULL selector were loaded.
+ * The userspace hypervisor probably doesn't use a
+ * LDT, but save and restore it to be safe.
+ */
+ sgdt(&gdtr);
+ sidt(&idtr);
+ ldt_sel = sldt();
+
vmx_run_trace(vmx, vcpu);
vmx_dr_enter_guest(vmxctx);
rc = vmx_enter_guest(vmxctx, vmx, launched);
vmx_dr_leave_guest(vmxctx);
+
+ bare_lgdt(&gdtr);
+ lidt(&idtr);
+ lldt(ldt_sel);
/* Collect some information for VM exit processing */
vmexit->rip = rip = vmcs_guest_rip();
More information about the svn-src-all
mailing list