#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include "ureg.h" extern int vmxon(u64int);extern int vmxoff(void);extern int vmclear(u64int);extern int vmptrld(u64int);extern int vmlaunch(Ureg *, int);extern int vmread(u32int, uintptr *);extern int vmwrite(u32int, uintptr);extern int invept(u32int, uvlong, uvlong);extern int invvpid(u32int, uvlong, uvlong); static int gotvmx;static vlong procb_ctls, pinb_ctls; enum { VMX_BASIC_MSR = 0x480, VMX_PINB_CTLS_MSR = 0x481, VMX_PROCB_CTLS_MSR = 0x482, VMX_VMEXIT_CTLS_MSR = 0x483, VMX_VMENTRY_CTLS_MSR = 0x484, VMX_MISC_MSR = 0x485, VMX_CR0_FIXED0 = 0x486, VMX_CR0_FIXED1 = 0x487, VMX_CR4_FIXED0 = 0x488, VMX_CR4_FIXED1 = 0x489, VMX_VMCS_ENUM = 0x48A, VMX_PROCB_CTLS2_MSR = 0x48B, VMX_TRUE_PINB_CTLS_MSR = 0x48D, VMX_TRUE_PROCB_CTLS_MSR = 0x48E, VMX_TRUE_EXIT_CTLS_MSR = 0x48F, VMX_TRUE_ENTRY_CTLS_MSR = 0x490, VMX_VMFUNC_MSR = 0x491, PINB_CTLS = 0x4000, PINB_EXITIRQ = 1<<0, PINB_EXITNMI = 1<<3, PROCB_CTLS = 0x4002, PROCB_IRQWIN = 1<<2, PROCB_TSCOFFSET = 1<<3, PROCB_EXITHLT = 1<<7, PROCB_EXITINVLPG = 1<<9, PROCB_EXITMWAIT = 1<<10, PROCB_EXITRDPMC = 1<<11, PROCB_EXITRDTSC = 1<<12, PROCB_EXITCR3LD = 1<<15, PROCB_EXITCR3ST = 1<<16, PROCB_EXITCR8LD = 1<<19, PROCB_EXITCR8ST = 1<<20, PROCB_EXITMOVDR = 1<<23, PROCB_EXITIO = 1<<24, PROCB_MONTRAP = 1<<27, PROCB_MSRBITMAP = 1<<28, PROCB_EXITMONITOR = 1<<29, PROCB_EXITPAUSE = 1<<30, PROCB_USECTLS2 = 1<<31, PROCB_CTLS2 = 0x401E, PROCB_EPT = 1<<1, PROCB_EXITGDT = 1<<2, PROCB_VPID = 1<<5, PROCB_UNRESTR = 1<<7, EXC_BITMAP = 0x4004, PFAULT_MASK = 0x4006, PFAULT_MATCH = 0x4008, CR3_TARGCNT = 0x400a, MSR_BITMAP = 0x2004, VMEXIT_CTLS = 0x400c, VMEXIT_ST_DEBUG = 1<<2, 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, VMEXIT_MSRSTADDR = 0x2006, VMEXIT_MSRLDADDR = 0x2008, VMENTRY_MSRLDADDR = 0x200A, VMENTRY_CTLS = 0x4012, VMENTRY_LD_DEBUG = 1<<2, 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, VMENTRY_INTRCODE = 0x4018, VMENTRY_INTRILEN = 0x401a, VMCS_TSC_OFFSET = 0x2010, VMCS_LINK = 0x2800, GUEST_ES = 0x800, GUEST_CS = 0x802, GUEST_SS = 0x804, GUEST_DS = 0x806, GUEST_FS = 0x808, GUEST_GS = 0x80A, GUEST_LDTR = 0x80C, GUEST_TR = 0x80E, GUEST_CR0 = 0x6800, GUEST_CR3 = 0x6802, GUEST_CR4 = 0x6804, GUEST_ESLIMIT = 0x4800, GUEST_CSLIMIT = 0x4802, GUEST_SSLIMIT = 0x4804, GUEST_DSLIMIT = 0x4806, GUEST_FSLIMIT = 0x4808, GUEST_GSLIMIT = 0x480A, GUEST_LDTRLIMIT = 0x480C, GUEST_TRLIMIT = 0x480E, GUEST_GDTRLIMIT = 0x4810, GUEST_IDTRLIMIT = 0x4812, GUEST_ESPERM = 0x4814, GUEST_CSPERM = 0x4816, GUEST_SSPERM = 0x4818, GUEST_DSPERM = 0x481A, GUEST_FSPERM = 0x481C, GUEST_GSPERM = 0x481E, GUEST_LDTRPERM = 0x4820, GUEST_TRPERM = 0x4822, GUEST_CR0MASK = 0x6000, GUEST_CR4MASK = 0x6002, GUEST_CR0SHADOW = 0x6004, GUEST_CR4SHADOW = 0x6006, GUEST_ESBASE = 0x6806, GUEST_CSBASE = 0x6808, GUEST_SSBASE = 0x680A, GUEST_DSBASE = 0x680C, GUEST_FSBASE = 0x680E, GUEST_GSBASE = 0x6810, GUEST_LDTRBASE = 0x6812, GUEST_TRBASE = 0x6814, GUEST_GDTRBASE = 0x6816, GUEST_IDTRBASE = 0x6818, GUEST_DR7 = 0x681A, 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, HOST_SS = 0xC04, HOST_DS = 0xC06, HOST_FS = 0xC08, HOST_GS = 0xC0A, HOST_TR = 0xC0C, HOST_CR0 = 0x6C00, HOST_CR3 = 0x6C02, HOST_CR4 = 0x6C04, HOST_FSBASE = 0x6C06, HOST_GSBASE = 0x6C08, HOST_TRBASE = 0x6C0A, HOST_GDTR = 0x6C0C, 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, VM_INSTRERR = 0x4400, VM_EXREASON = 0x4402, VM_EXINTRINFO = 0x4404, VM_EXINTRCODE = 0x4406, VM_IDTVECINFO = 0x4408, VM_IDTVECCODE = 0x440A, VM_EXINSTRLEN = 0x440C, VM_EXINSTRINFO = 0x440E, VM_EXQUALIF = 0x6400, VM_IORCX = 0x6402, VM_IORSI = 0x6404, VM_IORDI = 0x6406, VM_IORIP = 0x6408, VM_GUESTVA = 0x640A, VM_GUESTPA = 0x2400, VM_VPID = 0x000, VM_EPTPIDX = 0x0004, VM_EPTP = 0x201A, VM_EPTPLA = 0x2024, INVLOCAL = 1,}; enum { CR0RSVD = 0x1ffaffc0, CR4RSVD = 0xff889000, CR4MCE = 1<<6, CR4VMXE = 1<<13, CR4SMXE = 1<<14, CR4PKE = 1<<22, CR0KERNEL = CR0RSVD | 0x30 | (uintptr)0xFFFFFFFF00000000ULL, CR4KERNEL = CR4RSVD | CR4VMXE | CR4SMXE | CR4MCE | CR4PKE | (uintptr)0xFFFFFFFF00000000ULL}; enum { MAXMSR = 512,}; typedef struct VmxMach VmxMach;typedef struct Vmx Vmx;typedef struct VmCmd VmCmd;typedef struct VmMem VmMem;typedef struct VmIntr VmIntr; struct VmMem { uvlong addr; Segment *seg; uintptr off; char *name; VmMem *next, *prev; u16int attr;}; struct VmxMach { char vmxon[4096]; /* has to be at the start for alignment */ QLock; int vms; Vmx *active;};#define vmxmach ((VmxMach*)((m)->vmx))#define vmxmachp(n) ((VmxMach*)(MACHP(n)->vmx)) struct VmIntr { u32int info, code, ilen;}; struct Vmx { uchar vmcs[4096]; /* page aligned */ uvlong pml4[512]; /* page aligned */ u32int msrbits[1024]; /* page aligned */ FPsave fp; /* page aligned */ u64int msrhost[MAXMSR*2]; /* 16 byte aligned */ u64int msrguest[MAXMSR*2]; /* 16 byte aligned */ enum { VMXINIT, VMXREADY, VMXRUNNING, VMXDEAD, VMXENDING, } state; int index, machno; char errstr[ERRMAX]; Ureg ureg; uvlong tscoffset; u32int procbctls; uintptr cr2; uintptr xcr0; uintptr dr[8]; /* DR7 is also kept in VMCS */ u8int launched; u8int vpid; enum { FLUSHVPID = 1, FLUSHEPT = 2, STEP = 4, POSTEX = 8, POSTIRQ = 16, } onentry; Rendez cmdwait; Lock cmdlock; VmCmd *firstcmd, **lastcmd; VmCmd *postponed; VmMem mem; enum { GOTEXIT = 1, GOTIRQACK = 2, } got; VmIntr exc, irq, irqack; int nmsr;}; struct VmCmd { enum { CMDFDONE = 1, CMDFFAIL = 2, CMDFPOSTP = 4, } flags; u8int scratched; Rendez; Lock; int (*cmd)(VmCmd *, va_list); int retval; char *errstr; va_list va; VmCmd *next; Vmx *vmx;}; static char Equit[] = "vmx: ending"; static char *statenames[] = { [VMXINIT] "init", [VMXREADY] "ready", [VMXRUNNING] "running", [VMXDEAD] "dead", [VMXENDING]"ending"}; static Vmx *moribund;static QLock vmxtablock;static Vmx **vmxtab;static int nvmxtab; voidvmxprocrestore(Proc *p){ int s; Vmx *vmx; s = splhi(); vmx = p->vmx; if(vmxmach->active != vmx){ if(vmx != nil && vmptrld(PADDR(vmx->vmcs)) < 0) panic("VMPTRLD(%p) failed", vmx->vmcs); vmxmach->active = vmx; } splx(s);} static u64intvmcsread(u32int addr){ int rc; u64int val; val = 0; rc = vmread(addr, (uintptr *) &val); if(rc >= 0 && sizeof(uintptr) == 4 && (addr & 0x6000) == 0x2000) rc = vmread(addr | 1, (uintptr *) &val + 1); if(rc < 0){ char errbuf[128]; snprint(errbuf, sizeof(errbuf), "vmcsread failed (%#.4ux)", addr); error(errbuf); } return val;} static voidvmcswrite(u32int addr, u64int val){ int rc; rc = vmwrite(addr, val); if(rc >= 0 && sizeof(uintptr) == 4 && (addr & 0x6000) == 0x2000) rc = vmwrite(addr | 1, val >> 32); if(rc < 0){ char errbuf[128]; snprint(errbuf, sizeof(errbuf), "vmcswrite failed (%#.4ux = %#.16ullx)", addr, val); error(errbuf); }} static uvlongparseval(char *s){ uvlong v; char *p; v = strtoull(s, &p, 0); if(p == s || *p != 0) error("invalid value"); return v;} static char *cr0fakeread(Vmx *, char *p, char *e){ uvlong guest, mask, shadow; guest = vmcsread(GUEST_CR0); mask = vmcsread(GUEST_CR0MASK); shadow = vmcsread(GUEST_CR0SHADOW); return seprint(p, e, "%#.*ullx", sizeof(uintptr) * 2, guest & ~mask | shadow & mask);} static char *cr4fakeread(Vmx *, char *p, char *e){ uvlong guest, mask, shadow; guest = vmcsread(GUEST_CR4); mask = vmcsread(GUEST_CR4MASK); shadow = vmcsread(GUEST_CR4SHADOW); return seprint(p, e, "%#.*ullx", sizeof(uintptr) * 2, guest & ~mask | shadow & mask);} static voidupdatelma(void){ uvlong cr0, efer, nefer, ectrl; if(sizeof(uintptr) != 8) return; cr0 = vmcsread(GUEST_CR0); efer = vmcsread(GUEST_IA32_EFER); nefer = efer & ~0x400 | efer << 2 & cr0 >> 21 & 0x400; if(efer == nefer) return; vmcswrite(GUEST_IA32_EFER, nefer); ectrl = vmcsread(VMENTRY_CTLS); ectrl = ectrl & ~0x200 | nefer >> 1 & 0x200; vmcswrite(VMENTRY_CTLS, ectrl);} static intcr0realwrite(Vmx *, char *s){ uvlong v; v = parseval(s); vmcswrite(GUEST_CR0, vmcsread(GUEST_CR0) & CR0KERNEL | v & ~CR0KERNEL); updatelma(); return 0;} static intcr0maskwrite(Vmx *, char *s){ uvlong v; v = parseval(s); vmcswrite(GUEST_CR0MASK, v | CR0KERNEL); return 0;} static inteferwrite(Vmx *, char *s){ uvlong v; v = parseval(s); vmcswrite(GUEST_IA32_EFER, v); updatelma(); return 0;} static intcr4realwrite(Vmx *, char *s){ uvlong v; v = parseval(s); vmcswrite(GUEST_CR4, vmcsread(GUEST_CR4) & CR4KERNEL | v & ~CR4KERNEL); return 0;} static intcr4maskwrite(Vmx *, char *s){ uvlong v; v = parseval(s); vmcswrite(GUEST_CR4MASK, v | CR4KERNEL); return 0;} static intdr7write(Vmx *vmx, char *s){ uvlong v; v = (u32int) parseval(s); vmcswrite(GUEST_DR7, vmx->dr[7] = (u32int) v); return 0;} static intxcr0write(Vmx *vmx, char *s){ vmx->xcr0 = (parseval(s) | 1) & m->xcr0; return 0;} Lines 1–500 of 2433. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "ureg.h" extern int vmxon(u64int); extern int vmxoff(void); extern int vmclear(u64int); extern int vmptrld(u64int); extern int vmlaunch(Ureg *, int); extern int vmread(u32int, uintptr *); extern int vmwrite(u32int, uintptr); extern int invept(u32int, uvlong, uvlong); extern int invvpid(u32int, uvlong, uvlong); static int gotvmx; static vlong procb_ctls, pinb_ctls; enum { VMX_BASIC_MSR = 0x480, VMX_PINB_CTLS_MSR = 0x481, VMX_PROCB_CTLS_MSR = 0x482, VMX_VMEXIT_CTLS_MSR = 0x483, VMX_VMENTRY_CTLS_MSR = 0x484, VMX_MISC_MSR = 0x485, VMX_CR0_FIXED0 = 0x486, VMX_CR0_FIXED1 = 0x487, VMX_CR4_FIXED0 = 0x488, VMX_CR4_FIXED1 = 0x489, VMX_VMCS_ENUM = 0x48A, VMX_PROCB_CTLS2_MSR = 0x48B, VMX_TRUE_PINB_CTLS_MSR = 0x48D, VMX_TRUE_PROCB_CTLS_MSR = 0x48E, VMX_TRUE_EXIT_CTLS_MSR = 0x48F, VMX_TRUE_ENTRY_CTLS_MSR = 0x490, VMX_VMFUNC_MSR = 0x491, PINB_CTLS = 0x4000, PINB_EXITIRQ = 1<<0, PINB_EXITNMI = 1<<3, PROCB_CTLS = 0x4002, PROCB_IRQWIN = 1<<2, PROCB_TSCOFFSET = 1<<3, PROCB_EXITHLT = 1<<7, PROCB_EXITINVLPG = 1<<9, PROCB_EXITMWAIT = 1<<10, PROCB_EXITRDPMC = 1<<11, PROCB_EXITRDTSC = 1<<12, PROCB_EXITCR3LD = 1<<15, PROCB_EXITCR3ST = 1<<16, PROCB_EXITCR8LD = 1<<19, PROCB_EXITCR8ST = 1<<20, PROCB_EXITMOVDR = 1<<23, PROCB_EXITIO = 1<<24, PROCB_MONTRAP = 1<<27, PROCB_MSRBITMAP = 1<<28, PROCB_EXITMONITOR = 1<<29, PROCB_EXITPAUSE = 1<<30, PROCB_USECTLS2 = 1<<31, PROCB_CTLS2 = 0x401E, PROCB_EPT = 1<<1, PROCB_EXITGDT = 1<<2, PROCB_VPID = 1<<5, PROCB_UNRESTR = 1<<7, EXC_BITMAP = 0x4004, PFAULT_MASK = 0x4006, PFAULT_MATCH = 0x4008, CR3_TARGCNT = 0x400a, MSR_BITMAP = 0x2004, VMEXIT_CTLS = 0x400c, VMEXIT_ST_DEBUG = 1<<2, 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, VMEXIT_MSRSTADDR = 0x2006, VMEXIT_MSRLDADDR = 0x2008, VMENTRY_MSRLDADDR = 0x200A, VMENTRY_CTLS = 0x4012, VMENTRY_LD_DEBUG = 1<<2, 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, VMENTRY_INTRCODE = 0x4018, VMENTRY_INTRILEN = 0x401a, VMCS_TSC_OFFSET = 0x2010, VMCS_LINK = 0x2800, GUEST_ES = 0x800, GUEST_CS = 0x802, GUEST_SS = 0x804, GUEST_DS = 0x806, GUEST_FS = 0x808, GUEST_GS = 0x80A, GUEST_LDTR = 0x80C, GUEST_TR = 0x80E, GUEST_CR0 = 0x6800, GUEST_CR3 = 0x6802, GUEST_CR4 = 0x6804, GUEST_ESLIMIT = 0x4800, GUEST_CSLIMIT = 0x4802, GUEST_SSLIMIT = 0x4804, GUEST_DSLIMIT = 0x4806, GUEST_FSLIMIT = 0x4808, GUEST_GSLIMIT = 0x480A, GUEST_LDTRLIMIT = 0x480C, GUEST_TRLIMIT = 0x480E, GUEST_GDTRLIMIT = 0x4810, GUEST_IDTRLIMIT = 0x4812, GUEST_ESPERM = 0x4814, GUEST_CSPERM = 0x4816, GUEST_SSPERM = 0x4818, GUEST_DSPERM = 0x481A, GUEST_FSPERM = 0x481C, GUEST_GSPERM = 0x481E, GUEST_LDTRPERM = 0x4820, GUEST_TRPERM = 0x4822, GUEST_CR0MASK = 0x6000, GUEST_CR4MASK = 0x6002, GUEST_CR0SHADOW = 0x6004, GUEST_CR4SHADOW = 0x6006, GUEST_ESBASE = 0x6806, GUEST_CSBASE = 0x6808, GUEST_SSBASE = 0x680A, GUEST_DSBASE = 0x680C, GUEST_FSBASE = 0x680E, GUEST_GSBASE = 0x6810, GUEST_LDTRBASE = 0x6812, GUEST_TRBASE = 0x6814, GUEST_GDTRBASE = 0x6816, GUEST_IDTRBASE = 0x6818, GUEST_DR7 = 0x681A, 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, HOST_SS = 0xC04, HOST_DS = 0xC06, HOST_FS = 0xC08, HOST_GS = 0xC0A, HOST_TR = 0xC0C, HOST_CR0 = 0x6C00, HOST_CR3 = 0x6C02, HOST_CR4 = 0x6C04, HOST_FSBASE = 0x6C06, HOST_GSBASE = 0x6C08, HOST_TRBASE = 0x6C0A, HOST_GDTR = 0x6C0C, 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, VM_INSTRERR = 0x4400, VM_EXREASON = 0x4402, VM_EXINTRINFO = 0x4404, VM_EXINTRCODE = 0x4406, VM_IDTVECINFO = 0x4408, VM_IDTVECCODE = 0x440A, VM_EXINSTRLEN = 0x440C, VM_EXINSTRINFO = 0x440E, VM_EXQUALIF = 0x6400, VM_IORCX = 0x6402, VM_IORSI = 0x6404, VM_IORDI = 0x6406, VM_IORIP = 0x6408, VM_GUESTVA = 0x640A, VM_GUESTPA = 0x2400, VM_VPID = 0x000, VM_EPTPIDX = 0x0004, VM_EPTP = 0x201A, VM_EPTPLA = 0x2024, INVLOCAL = 1, }; enum { CR0RSVD = 0x1ffaffc0, CR4RSVD = 0xff889000, CR4MCE = 1<<6, CR4VMXE = 1<<13, CR4SMXE = 1<<14, CR4PKE = 1<<22, CR0KERNEL = CR0RSVD | 0x30 | (uintptr)0xFFFFFFFF00000000ULL, CR4KERNEL = CR4RSVD | CR4VMXE | CR4SMXE | CR4MCE | CR4PKE | (uintptr)0xFFFFFFFF00000000ULL }; enum { MAXMSR = 512, }; typedef struct VmxMach VmxMach; typedef struct Vmx Vmx; typedef struct VmCmd VmCmd; typedef struct VmMem VmMem; typedef struct VmIntr VmIntr; struct VmMem { uvlong addr; Segment *seg; uintptr off; char *name; VmMem *next, *prev; u16int attr; }; struct VmxMach { char vmxon[4096]; /* has to be at the start for alignment */ QLock; int vms; Vmx *active; }; #define vmxmach ((VmxMach*)((m)->vmx)) #define vmxmachp(n) ((VmxMach*)(MACHP(n)->vmx)) struct VmIntr { u32int info, code, ilen; }; struct Vmx { uchar vmcs[4096]; /* page aligned */ uvlong pml4[512]; /* page aligned */ u32int msrbits[1024]; /* page aligned */ FPsave fp; /* page aligned */ u64int msrhost[MAXMSR*2]; /* 16 byte aligned */ u64int msrguest[MAXMSR*2]; /* 16 byte aligned */ enum { VMXINIT, VMXREADY, VMXRUNNING, VMXDEAD, VMXENDING, } state; int index, machno; char errstr[ERRMAX]; Ureg ureg; uvlong tscoffset; u32int procbctls; uintptr cr2; uintptr xcr0; uintptr dr[8]; /* DR7 is also kept in VMCS */ u8int launched; u8int vpid; enum { FLUSHVPID = 1, FLUSHEPT = 2, STEP = 4, POSTEX = 8, POSTIRQ = 16, } onentry; Rendez cmdwait; Lock cmdlock; VmCmd *firstcmd, **lastcmd; VmCmd *postponed; VmMem mem; enum { GOTEXIT = 1, GOTIRQACK = 2, } got; VmIntr exc, irq, irqack; int nmsr; }; struct VmCmd { enum { CMDFDONE = 1, CMDFFAIL = 2, CMDFPOSTP = 4, } flags; u8int scratched; Rendez; Lock; int (*cmd)(VmCmd *, va_list); int retval; char *errstr; va_list va; VmCmd *next; Vmx *vmx; }; static char Equit[] = "vmx: ending"; static char *statenames[] = { [VMXINIT] "init", [VMXREADY] "ready", [VMXRUNNING] "running", [VMXDEAD] "dead", [VMXENDING]"ending" }; static Vmx *moribund; static QLock vmxtablock; static Vmx **vmxtab; static int nvmxtab; void vmxprocrestore(Proc *p) { int s; Vmx *vmx; s = splhi(); vmx = p->vmx; if(vmxmach->active != vmx){ if(vmx != nil && vmptrld(PADDR(vmx->vmcs)) < 0) panic("VMPTRLD(%p) failed", vmx->vmcs); vmxmach->active = vmx; } splx(s); } static u64int vmcsread(u32int addr) { int rc; u64int val; val = 0; rc = vmread(addr, (uintptr *) &val); if(rc >= 0 && sizeof(uintptr) == 4 && (addr & 0x6000) == 0x2000) rc = vmread(addr | 1, (uintptr *) &val + 1); if(rc < 0){ char errbuf[128]; snprint(errbuf, sizeof(errbuf), "vmcsread failed (%#.4ux)", addr); error(errbuf); } return val; } static void vmcswrite(u32int addr, u64int val) { int rc; rc = vmwrite(addr, val); if(rc >= 0 && sizeof(uintptr) == 4 && (addr & 0x6000) == 0x2000) rc = vmwrite(addr | 1, val >> 32); if(rc < 0){ char errbuf[128]; snprint(errbuf, sizeof(errbuf), "vmcswrite failed (%#.4ux = %#.16ullx)", addr, val); error(errbuf); } } static uvlong parseval(char *s) { uvlong v; char *p; v = strtoull(s, &p, 0); if(p == s || *p != 0) error("invalid value"); return v; } static char * cr0fakeread(Vmx *, char *p, char *e) { uvlong guest, mask, shadow; guest = vmcsread(GUEST_CR0); mask = vmcsread(GUEST_CR0MASK); shadow = vmcsread(GUEST_CR0SHADOW); return seprint(p, e, "%#.*ullx", sizeof(uintptr) * 2, guest & ~mask | shadow & mask); } static char * cr4fakeread(Vmx *, char *p, char *e) { uvlong guest, mask, shadow; guest = vmcsread(GUEST_CR4); mask = vmcsread(GUEST_CR4MASK); shadow = vmcsread(GUEST_CR4SHADOW); return seprint(p, e, "%#.*ullx", sizeof(uintptr) * 2, guest & ~mask | shadow & mask); } static void updatelma(void) { uvlong cr0, efer, nefer, ectrl; if(sizeof(uintptr) != 8) return; cr0 = vmcsread(GUEST_CR0); efer = vmcsread(GUEST_IA32_EFER); nefer = efer & ~0x400 | efer << 2 & cr0 >> 21 & 0x400; if(efer == nefer) return; vmcswrite(GUEST_IA32_EFER, nefer); ectrl = vmcsread(VMENTRY_CTLS); ectrl = ectrl & ~0x200 | nefer >> 1 & 0x200; vmcswrite(VMENTRY_CTLS, ectrl); } static int cr0realwrite(Vmx *, char *s) { uvlong v; v = parseval(s); vmcswrite(GUEST_CR0, vmcsread(GUEST_CR0) & CR0KERNEL | v & ~CR0KERNEL); updatelma(); return 0; } static int cr0maskwrite(Vmx *, char *s) { uvlong v; v = parseval(s); vmcswrite(GUEST_CR0MASK, v | CR0KERNEL); return 0; } static int eferwrite(Vmx *, char *s) { uvlong v; v = parseval(s); vmcswrite(GUEST_IA32_EFER, v); updatelma(); return 0; } static int cr4realwrite(Vmx *, char *s) { uvlong v; v = parseval(s); vmcswrite(GUEST_CR4, vmcsread(GUEST_CR4) & CR4KERNEL | v & ~CR4KERNEL); return 0; } static int cr4maskwrite(Vmx *, char *s) { uvlong v; v = parseval(s); vmcswrite(GUEST_CR4MASK, v | CR4KERNEL); return 0; } static int dr7write(Vmx *vmx, char *s) { uvlong v; v = (u32int) parseval(s); vmcswrite(GUEST_DR7, vmx->dr[7] = (u32int) v); return 0; } static int xcr0write(Vmx *vmx, char *s) { vmx->xcr0 = (parseval(s) | 1) & m->xcr0; return 0; }