Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/nvmm/x86 On AMD, the segments have a simple "present...



details:   https://anonhg.NetBSD.org/src/rev/d05045ede72a
branches:  trunk
changeset: 839329:d05045ede72a
user:      maxv <maxv%NetBSD.org@localhost>
date:      Thu Feb 14 09:37:31 2019 +0000

description:
On AMD, the segments have a simple "present" bit. On Intel however there
is an extra "unusable" bit, which has a twisted meaning. We can't just
ignore this bit, because when unset, the CPU performs extra checks on the
other attributes, which may cause VMENTRY to fail and the guest to be
killed.

Typically, on Qemu, some guests like Windows XP trigger two consecutive
getstate+setstate calls, and while processing them, we end up wrongfully
removing the "unusable" bits that were previously set.

Fix that by forcing "unusable = !present". Each hypervisor I could check
does something different, but this seems to be the least problematic
solution for now.

While here, the fields of vmx_guest_segs are VMX indexes, so they should
be uint64_t (no functional change).

diffstat:

 sys/dev/nvmm/x86/nvmm_x86_vmx.c |  16 ++++++++++------
 1 files changed, 10 insertions(+), 6 deletions(-)

diffs (51 lines):

diff -r 86a7b20a0df3 -r d05045ede72a sys/dev/nvmm/x86/nvmm_x86_vmx.c
--- a/sys/dev/nvmm/x86/nvmm_x86_vmx.c   Thu Feb 14 08:18:25 2019 +0000
+++ b/sys/dev/nvmm/x86/nvmm_x86_vmx.c   Thu Feb 14 09:37:31 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: nvmm_x86_vmx.c,v 1.1 2019/02/13 16:03:16 maxv Exp $    */
+/*     $NetBSD: nvmm_x86_vmx.c,v 1.2 2019/02/14 09:37:31 maxv Exp $    */
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.1 2019/02/13 16:03:16 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.2 2019/02/14 09:37:31 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -674,9 +674,9 @@
 };
 
 static const struct {
-       uint16_t selector;
-       uint16_t attrib;
-       uint32_t limit;
+       uint64_t selector;
+       uint64_t attrib;
+       uint64_t limit;
        uint64_t base;
 } vmx_guest_segs[NVMM_X64_NSEG] = {
        [NVMM_X64_SEG_ES] = {
@@ -2113,7 +2113,8 @@
            __SHIFTIN(segs[idx].attrib.avl, VMX_SEG_ATTRIB_AVL) |
            __SHIFTIN(segs[idx].attrib.lng, VMX_SEG_ATTRIB_LONG) |
            __SHIFTIN(segs[idx].attrib.def32, VMX_SEG_ATTRIB_DEF32) |
-           __SHIFTIN(segs[idx].attrib.gran, VMX_SEG_ATTRIB_GRAN);
+           __SHIFTIN(segs[idx].attrib.gran, VMX_SEG_ATTRIB_GRAN) |
+           (!segs[idx].attrib.p ? VMX_SEG_ATTRIB_UNUSABLE : 0);
 
        if (idx != NVMM_X64_SEG_GDT && idx != NVMM_X64_SEG_IDT) {
                vmx_vmwrite(vmx_guest_segs[idx].selector, segs[idx].selector);
@@ -2142,6 +2143,9 @@
        segs[idx].attrib.lng = __SHIFTOUT(attrib, VMX_SEG_ATTRIB_LONG);
        segs[idx].attrib.def32 = __SHIFTOUT(attrib, VMX_SEG_ATTRIB_DEF32);
        segs[idx].attrib.gran = __SHIFTOUT(attrib, VMX_SEG_ATTRIB_GRAN);
+       if (attrib & VMX_SEG_ATTRIB_UNUSABLE) {
+               segs[idx].attrib.p = 0;
+       }
 }
 
 static inline bool



Home | Main Index | Thread Index | Old Index