2433 lines · 48.0 KB · C
RawDownload
#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.