diff --git a/sys/src/cmd/aux/icanhasvmx.c b/sys/src/cmd/aux/icanhasvmx.c new file mode 100644 index 000000000..9a9c315b8 --- /dev/null +++ b/sys/src/cmd/aux/icanhasvmx.c @@ -0,0 +1,302 @@ +#include +#include +#include + +Biobuf *out; + +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_VPIDEPT_MSR = 0x48C, + 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, + + PROCB_IRQWIN = 1<<2, + 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_EXITMONITOR = 1<<29, + PROCB_EXITPAUSE = 1<<30, + PROCB_USECTLS2 = 1<<31, + + PROCB_EPT = 1<<1, + PROCB_EXITGDT = 1<<2, + PROCB_VPID = 1<<5, + PROCB_UNRESTR = 1<<7, +}; + +int +cpuidcheck(void) +{ + int pfd[2]; + Biobuf *bp; + char *l, *f[64]; + int i, rc; + + pipe(pfd); + switch(rfork(RFPROC|RFFDG)){ + case 0: + close(pfd[1]); + close(0); + open("/dev/null", OREAD); + dup(pfd[0], 1); + execl("/bin/aux/cpuid", "cpuid", nil); + sysfatal("execl: %r"); + break; + case -1: sysfatal("rfork: %r"); + } + close(pfd[0]); + bp = Bfdopen(pfd[1], OREAD); + if(bp == nil) sysfatal("Bfdopen: %r"); + for(; l = Brdstr(bp, '\n', 10), l != nil; free(l)){ + rc = tokenize(l, f, nelem(f)); + if(rc < 1) continue; + if(strcmp(f[0], "features") != 0) continue; + for(i = 1; i < rc; i++) + if(strcmp(f[i], "vmx") == 0){ + Bterm(bp); + close(pfd[1]); + waitpid(); + return 0; + } + } + Bterm(bp); + close(pfd[1]); + waitpid(); + return -1; +} + +static int msrfd; + +u64int +rdmsr(u32int addr) +{ + u64int rv; + + if(pread(msrfd, &rv, 8, addr) < 0) sysfatal("pread: %r"); + return rv; +} + +void +wrmsr(u32int addr, u64int val) +{ + if(pwrite(msrfd, &val, 8, addr) < 0) sysfatal("pwrite: %r"); +} + +static char *pinbits[64] = { + [0] "extirq", [3] "nmiexit", [5] "virtnmi", [6] "preempt", [7] "procpostirq" +}; + +static char *procbits[64] = { + [2] "irqwin", [3] "tscoffset", [7] "hltexit", [9] "invlpgexit", [10] "mwaitexit", + [11] "rdpmcexit", [12] "rdtscexit", [15] "cr3ldexit", [16] "cr3stexit", [19] "cr8ldexit", + [20] "cr8stexit", [21] "tprshadow", [22] "nmiwin", [23] "movdrexit", [24] "ioexit", + [25] "iobitmap", [27] "mtf", [28] "msrbitmap", [29] "monitorexit", [30] "pauseexit", +}; + +static char *proc2bits[64] = { + [0] "virtapic", [1] "ept", [2] "gdtexit", [3] "rdtscp", [4] "virtx2apic", [5] "vpid", + [6] "wbinvdexit", [7] "unrestr", [8] "apicregs", [9] "virtirq", [10] "pauseloopexit", + [11] "rdrandexit", [12] "invpcid", [13] "vmfunc", [14] "vmcsshadow", [15] "enclsexit", + [16] "rdseedexit", [17] "pml", [18] "#ve", [19] "conceal", [20] "xsave", [22] "eptxmode", + [25] "tscscale", +}; + +static char *exitbits[64] = { + [2] "savedebug", [9] "host64", [12] "saveperfglobal", [15] "ackextirq", + [16] "savepat", [17] "loadpat", [20] "saveefer", [21] "loadefer", [22] "savepreempt", + [23] "savebndcfgs", [24] "concealexits", +}; + +static char *entrybits[64] = { + [2] "loaddebug", [9] "guest64", [10] "entrysmm", [11] "dualmonitor", [13] "loadperfglobal", + [14] "loadpat", [15] "loadefer", [16] "loadbndcfgs", [17] "concealentries", +}; + +static char *miscbits[64] = { + [5] "longmodeswitch", [6] "hlt", [7] "shutdown", [8] "ipi", [14] "pt", [15] "rdmsrsmm", + [28] "smmblock", [29] "vmwriteany", [30] "zerolenswirq", +}; + +static char *cr0bits[64] = { + [0] "pe", [1] "mp", [2] "em", [3] "ts", [4] "et", [5] "ne", [6] "wp", [18] "am", + [29] "nw", [30] "cd", [31] "pg", +}; + +static char *cr4bits[64] = { + [0] "vme", [1] "pvi", [2] "tsd", [3] "de", [4] "pse", [5] "pae", [6] "mce", [7] "pge", + [8] "pce", [9] "osxfsr", [10] "osxmmxcpt", [11] "umip", [13] "vmxe", [14] "smxe", + [16] "fsgsbase", [17] "pcide", [18] "osxsave", [20] "smep", [21] "smap", [22] "pke" +}; + +static char *eptbits[64] = { + [0] "xonly", [6] "pwl4", [8] "ucmem", [14] "wbmem", [16] "2MBpage", [17] "1GBpage", + [20] "invept", [21] "dirtybits", [22] "violexitinfo", [25] "invept.single", [26] "invept.all", +}; + +static char *vpidbits[64] = { + [32] "invvpid", [40] "invvpid.addr", [41] "invvpid.single", [42] "invvpid.all", [43] "invvpid.noglob", +}; + +void +printbits(char *id, uvlong allowed, uvlong forced, char **s) +{ + int i, l; + + l = -1; + for(i = 0; i < 64; i++){ + if(s[i] == nil) continue; + if(((allowed|forced) & 1ULL< 80){ + if(l >= 0) + Bprint(out, "\n"); + l = Bprint(out, "%s ", id); + } + if((forced & 1ULL<= 0) + Bprint(out, "\n"); +} + +void +printbits32(char *id, uvlong w, char **s) +{ + printbits(id, (u32int)(w >> 32), (u32int)w, s); +} + +u64int +rawprint(char *s, int addr) +{ + u64int msr; + + msr = rdmsr(addr); + Bprint(out, "%s %#.16ullx\n", s, msr); + return msr; +} + +void +main(int argc, char **argv) +{ + u64int msr, msr2; + int ext; + static int no, raw; + + ARGBEGIN { + case 'r': raw++; break; + default: goto usage; + } ARGEND; + if(argc != 0){ + usage: + fprint(2, "usage: %s [-r]\n", argv0); + exits("usage"); + } + + out = Bfdopen(1, OWRITE); + if(out == nil) sysfatal("Bfdopen: %r"); + msrfd = open("#P/msr", OREAD); + if(msrfd < 0) sysfatal("open: %r"); + if(cpuidcheck() < 0) sysfatal("CPU does not support VMX"); + msr = rdmsr(0x3a); + if((msr & 5) == 0) wrmsr(0x3a, msr | 5); + if((rdmsr(0x3a) & 5) != 5){ + fprint(2, "VMX disabled by BIOS"); + no++; + } + msr = rdmsr(VMX_PROCB_CTLS_MSR); + if((vlong)msr >= 0){ + fprint(2, "no secondary controls"); + no++; + }else{ + msr = rdmsr(VMX_PROCB_CTLS2_MSR); + if((msr >> 32 & PROCB_EPT) == 0){ + fprint(2, "no EPT support"); + no++; + } + if((msr >> 32 & PROCB_VPID) == 0){ + fprint(2, "no VPID support"); + no++; + } + } + if(no == 0) + fprint(2, "VMX is supported\n"); + + if(!raw){ + msr = rdmsr(VMX_BASIC_MSR); + Bprint(out, "vmcsrev %#ux\n", (u32int)msr & 0x7fffffff); + Bprint(out, "vmxonsz %d\n", (u32int)(msr >> 32) & 0x1fff); + Bprint(out, "vmcsmem %d\n", (u32int)(msr >> 50) & 15); + ext = (u32int)(msr >> 55) & 1; + Bprint(out, "extcontrols %d\n", ext); + + msr = rdmsr(ext ? VMX_TRUE_PINB_CTLS_MSR : VMX_PINB_CTLS_MSR); + printbits32("pin", msr, pinbits); + msr = rdmsr(ext ? VMX_TRUE_PROCB_CTLS_MSR : VMX_PROCB_CTLS_MSR); + printbits32("proc", msr, procbits); + if((msr & 1ULL<<63) != 0){ + msr = rdmsr(VMX_PROCB_CTLS2_MSR); + printbits32("proc2", msr, proc2bits); + } + msr = rdmsr(ext ? VMX_TRUE_ENTRY_CTLS_MSR : VMX_VMENTRY_CTLS_MSR); + printbits32("entry", msr, entrybits); + msr = rdmsr(ext ? VMX_TRUE_EXIT_CTLS_MSR : VMX_VMEXIT_CTLS_MSR); + printbits32("exit", msr, exitbits); + msr = rdmsr(VMX_MISC_MSR); + Bprint(out, "misc preemptdiv:%d cr3targ:%d maxmsr:%d mseg:%#ux\n", (int)msr & 0x1f, (int)msr >> 16 & 0x1ff, (int)msr >> 25 & 7, (int)(msr >> 32)); + printbits("misc", msr, 0, miscbits); + msr = rdmsr(VMX_CR0_FIXED0); + msr2 = rdmsr(VMX_CR0_FIXED1); + printbits("cr0fixed", msr & msr2, ~msr & ~msr2, cr0bits); + msr = rdmsr(VMX_CR4_FIXED0); + msr2 = rdmsr(VMX_CR4_FIXED1); + printbits("cr4fixed", msr & msr2, ~msr & ~msr2, cr4bits); + Bprint(out, "vmcsenum %#ullx\n", rdmsr(VMX_VMCS_ENUM)); + if(no == 0){ + msr = rdmsr(VMX_VPIDEPT_MSR); + printbits("ept", msr, 0, eptbits); + printbits("vpid", msr, 0, vpidbits); + } + }else{ + msr = rawprint("basic", VMX_BASIC_MSR); + ext = (u32int)(msr >> 55) & 1; + rawprint("pin", ext ? VMX_TRUE_PINB_CTLS_MSR : VMX_PINB_CTLS_MSR); + msr = rawprint("proc", ext ? VMX_TRUE_PROCB_CTLS_MSR : VMX_PROCB_CTLS_MSR); + if((msr & 1ULL<<63) != 0) + rawprint("proc2", VMX_PROCB_CTLS2_MSR); + rawprint("entry", ext ? VMX_TRUE_ENTRY_CTLS_MSR : VMX_VMENTRY_CTLS_MSR); + rawprint("exit", ext ? VMX_TRUE_EXIT_CTLS_MSR : VMX_VMEXIT_CTLS_MSR); + rawprint("misc", VMX_MISC_MSR); + rawprint("cr0fixed0", VMX_CR0_FIXED0); + rawprint("cr0fixed1", VMX_CR0_FIXED1); + rawprint("cr4fixed0", VMX_CR4_FIXED0); + rawprint("cr4fixed1", VMX_CR4_FIXED1); + rawprint("vmcsenum", VMX_VMCS_ENUM); + if(no == 0) + rawprint("vpidept", VMX_VPIDEPT_MSR); + } + + Bterm(out); + exits(nil); +} diff --git a/sys/src/cmd/aux/mkfile b/sys/src/cmd/aux/mkfile index e6684f46e..3ccc5acfb 100644 --- a/sys/src/cmd/aux/mkfile +++ b/sys/src/cmd/aux/mkfile @@ -20,6 +20,7 @@ TARG=\ esd\ getflags\ icanhasmsi\ + icanhasvmx\ lines\ listen\ listen1\