ref: 74241e31aaaebb55883c96c6d1e2681930c44245
parent: 3b123799abb25845737429d04770991d75feab1c
author: aiju <devnull@localhost>
date: Wed Jun 14 13:38:01 EDT 2017
devvmx: support pat and efer registers
--- a/sys/src/9/pc/devvmx.c
+++ b/sys/src/9/pc/devvmx.c
@@ -72,6 +72,11 @@
VMEXIT_CTLS = 0x400c,
VMEXIT_HOST64 = 1<<9,
+ VMEXIT_LD_IA32_PERF_GLOBAL_CTRL = 1<<12,
+ VMEXIT_ST_IA32_PAT = 1<<18,
+ VMEXIT_LD_IA32_PAT = 1<<19,
+ VMEXIT_ST_IA32_EFER = 1<<20,
+ VMEXIT_LD_IA32_EFER = 1<<21,
VMEXIT_MSRSTCNT = 0x400e,
VMEXIT_MSRLDCNT = 0x4010,
@@ -78,6 +83,9 @@
VMENTRY_CTLS = 0x4012,
VMENTRY_GUEST64 = 1<<9,
+ VMENTRY_LD_IA32_PERF_GLOBAL_CTRL = 1<<13,
+ VMENTRY_LD_IA32_PAT = 1<<14,
+ VMENTRY_LD_IA32_EFER = 1<<15,
VMENTRY_MSRLDCNT = 0x4014,
VMENTRY_INTRINFO = 0x4016,
@@ -133,6 +141,10 @@
GUEST_RSP = 0x681C,
GUEST_RIP = 0x681E,
GUEST_RFLAGS = 0x6820,
+ GUEST_IA32_DEBUGCTL = 0x2802,
+ GUEST_IA32_PAT = 0x2804,
+ GUEST_IA32_EFER = 0x2806,
+ GUEST_IA32_PERF_GLOBAL_CTRL = 0x2808,
HOST_ES = 0xC00,
HOST_CS = 0xC02,
@@ -151,6 +163,9 @@
HOST_IDTR = 0x6C0E,
HOST_RSP = 0x6C14,
HOST_RIP = 0x6C16,
+ HOST_IA32_PAT = 0x2C00,
+ HOST_IA32_EFER = 0x2C02,
+ HOST_IA32_PERF_GLOBAL_CTRL = 0x2C04,
GUEST_CANINTR = 0x4824,
@@ -179,6 +194,18 @@
INVLOCAL = 1,
};
+enum {
+ CR0RSVD = 0x1ffaffc0,
+ CR4RSVD = 0xff889000,
+ CR4MCE = 1<<6,
+ CR4VMXE = 1<<13,
+ CR4SMXE = 1<<14,
+ CR4PKE = 1<<22,
+
+ CR0KERNEL = CR0RSVD | (uintptr)0xFFFFFFFF00000000ULL,
+ CR4KERNEL = CR4RSVD | CR4VMXE | CR4SMXE | CR4MCE | CR4PKE | (uintptr)0xFFFFFFFF00000000ULL
+};
+
typedef struct Vmx Vmx;
typedef struct VmCmd VmCmd;
typedef struct VmMem VmMem;
@@ -299,8 +326,20 @@
}
}
+static uvlong
+parseval(char *s, int sz)
+{
+ uvlong v;
+ char *p;
+
+ if(sz == 0) sz = sizeof(uintptr);
+ v = strtoull(s, &p, 0);
+ if(p == s || *p != 0 || v >> sz * 8 != 0) error("invalid value");
+ return v;
+}
+
static char *
-cr0read(char *p, char *e)
+cr0fakeread(char *p, char *e)
{
uvlong guest, mask, shadow;
@@ -311,7 +350,7 @@
}
static char *
-cr4read(char *p, char *e)
+cr4fakeread(char *p, char *e)
{
uvlong guest, mask, shadow;
@@ -322,6 +361,46 @@
}
static int
+cr0realwrite(char *s)
+{
+ uvlong v;
+
+ v = parseval(s, 8);
+ vmcswrite(GUEST_CR0, vmcsread(GUEST_CR0) & CR0KERNEL | v & ~CR0KERNEL);
+ return 0;
+}
+
+static int
+cr0maskwrite(char *s)
+{
+ uvlong v;
+
+ v = parseval(s, 8);
+ vmcswrite(GUEST_CR0MASK, vmcsread(GUEST_CR0MASK) | CR0KERNEL);
+ return 0;
+}
+
+static int
+cr4realwrite(char *s)
+{
+ uvlong v;
+
+ v = parseval(s, 8);
+ vmcswrite(GUEST_CR4, vmcsread(GUEST_CR4) & CR4KERNEL | v & ~CR4KERNEL);
+ return 0;
+}
+
+static int
+cr4maskwrite(char *s)
+{
+ uvlong v;
+
+ v = parseval(s, 8);
+ vmcswrite(GUEST_CR4MASK, vmcsread(GUEST_CR4MASK) | CR4KERNEL);
+ return 0;
+}
+
+static int
readonly(char *)
{
return -1;
@@ -383,10 +462,16 @@
{GUEST_LDTRBASE, 0, "ldtrbase"},
{GUEST_LDTRLIMIT, 4, "ldtrlimit"},
{GUEST_LDTRPERM, 4, "ldtrperm"},
- {GUEST_CR0, 0, "cr0", cr0read, readonly},
+ {GUEST_CR0, 0, "cr0real", nil, cr0realwrite},
+ {GUEST_CR0SHADOW, 0, "cr0fake", cr0fakeread},
+ {GUEST_CR0MASK, 0, "cr0mask", nil, cr0maskwrite},
{UREG(trap), 0, "cr2"},
{GUEST_CR3, 0, "cr3"},
- {GUEST_CR4, 0, "cr4", cr4read, readonly},
+ {GUEST_CR4, 0, "cr4real", nil, cr4realwrite},
+ {GUEST_CR4SHADOW, 0, "cr4fake", cr4fakeread},
+ {GUEST_CR4MASK, 0, "cr4mask", nil, cr4maskwrite},
+ {GUEST_IA32_PAT, 8, "pat"},
+ {GUEST_IA32_EFER, 8, "efer"},
{VM_INSTRERR, 4, "instructionerror", nil, readonly},
{VM_EXREASON, 4, "exitreason", nil, readonly},
{VM_EXQUALIF, 0, "exitqualification", nil, readonly},
@@ -655,6 +740,7 @@
if(rdmsr(VMX_VMEXIT_CTLS_MSR, &msr) < 0) error("rdmsr(VMX_VMEXIT_CTLS_MSR failed");
x = (u32int)msr;
if(sizeof(uintptr) == 8) x |= VMEXIT_HOST64;
+ x |= VMEXIT_LD_IA32_PAT | VMEXIT_LD_IA32_EFER;
x &= msr >> 32;
vmcswrite(VMEXIT_CTLS, x);
@@ -661,6 +747,7 @@
if(rdmsr(VMX_VMENTRY_CTLS_MSR, &msr) < 0) error("rdmsr(VMX_VMENTRY_CTLS_MSR failed");
x = (u32int)msr;
if(sizeof(uintptr) == 8) x |= VMENTRY_GUEST64;
+ x |= VMENTRY_LD_IA32_PAT | VMENTRY_LD_IA32_EFER;
x &= msr >> 32;
vmcswrite(VMENTRY_CTLS, x);
@@ -688,6 +775,10 @@
vmcswrite(HOST_TRBASE, (uintptr) m->tss);
vmcswrite(HOST_GDTR, (uintptr) m->gdt);
vmcswrite(HOST_IDTR, IDTADDR);
+ if(rdmsr(0x277, &msr) < 0) error("rdmsr(IA32_PAT) failed");
+ vmcswrite(HOST_IA32_PAT, msr);
+ if(rdmsr(0xc0000080, &msr) < 0) error("rdmsr(IA32_EFER) failed");
+ vmcswrite(HOST_IA32_EFER, msr);
vmcswrite(EXC_BITMAP, 1<<18);
vmcswrite(PFAULT_MASK, 0);
@@ -713,14 +804,8 @@
vmcswrite(GUEST_SSPERM, (SEGG|SEGB|SEGP|SEGPL(0)|SEGDATA|SEGW) >> 8 | 1);
vmcswrite(GUEST_LDTRPERM, 1<<16);
- enum {
- CR0RSVD = 0x1ffaffc0,
- CR4RSVD = 0xff889000,
- CR4VMXE = 1<<13,
- CR4SMXE = 1<<14,
- };
- vmcswrite(GUEST_CR0MASK, CR0RSVD | (uintptr)0xFFFFFFFF00000000ULL);
- vmcswrite(GUEST_CR4MASK, CR4RSVD | CR4VMXE | CR4SMXE | (uintptr)0xFFFFFFFF00000000ULL);
+ vmcswrite(GUEST_CR0MASK, CR0KERNEL);
+ vmcswrite(GUEST_CR4MASK, CR4KERNEL);
vmcswrite(GUEST_CR0, getcr0() & ~(1<<31));
vmcswrite(GUEST_CR3, 0);
vmcswrite(GUEST_CR4, getcr4());
@@ -727,6 +812,9 @@
vmcswrite(GUEST_CR0SHADOW, getcr0());
vmcswrite(GUEST_CR4SHADOW, getcr4() & ~CR4VMXE);
+ vmcswrite(GUEST_IA32_PAT, 0x0007040600070406ULL);
+ vmcswrite(GUEST_IA32_EFER, 0);
+
vmcswrite(GUEST_TRBASE, (uintptr) m->tss);
vmcswrite(GUEST_TRLIMIT, 0xffff);
vmcswrite(GUEST_TRPERM, (SEGTSS|SEGPL(0)|SEGP) >> 8 | 2);
@@ -919,7 +1007,7 @@
val = strtoull(f[1], &rp, 0);
sz = r->size;
if(sz == 0) sz = sizeof(uintptr);
- if(*rp != 0 || val >> 8 * sz != 0) error("invalid value");
+ if(rp == f[1] || *rp != 0 || val >> 8 * sz != 0) error("invalid value");
if(r->offset >= 0)
vmcswrite(r->offset, val);
else{