]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/icanhasvmx.c
change icanhasvmx to report extra info only with -v
[plan9front.git] / sys / src / cmd / aux / icanhasvmx.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 Biobuf *out;
6
7 enum {
8         VMX_BASIC_MSR = 0x480,
9         VMX_PINB_CTLS_MSR = 0x481,
10         VMX_PROCB_CTLS_MSR = 0x482,
11         VMX_VMEXIT_CTLS_MSR = 0x483,
12         VMX_VMENTRY_CTLS_MSR = 0x484,
13         VMX_MISC_MSR = 0x485,
14         VMX_CR0_FIXED0 = 0x486,
15         VMX_CR0_FIXED1 = 0x487,
16         VMX_CR4_FIXED0 = 0x488,
17         VMX_CR4_FIXED1 = 0x489,
18         VMX_VMCS_ENUM = 0x48A,
19         VMX_PROCB_CTLS2_MSR = 0x48B,
20         VMX_VPIDEPT_MSR = 0x48C,
21         VMX_TRUE_PINB_CTLS_MSR = 0x48D,
22         VMX_TRUE_PROCB_CTLS_MSR = 0x48E,
23         VMX_TRUE_EXIT_CTLS_MSR = 0x48F,
24         VMX_TRUE_ENTRY_CTLS_MSR = 0x490,
25         VMX_VMFUNC_MSR = 0x491,
26
27         PROCB_IRQWIN = 1<<2,
28         PROCB_EXITHLT = 1<<7,
29         PROCB_EXITINVLPG = 1<<9,
30         PROCB_EXITMWAIT = 1<<10,
31         PROCB_EXITRDPMC = 1<<11,
32         PROCB_EXITRDTSC = 1<<12,
33         PROCB_EXITCR3LD = 1<<15,
34         PROCB_EXITCR3ST = 1<<16,
35         PROCB_EXITCR8LD = 1<<19,
36         PROCB_EXITCR8ST = 1<<20,
37         PROCB_EXITMOVDR = 1<<23,
38         PROCB_EXITIO = 1<<24,
39         PROCB_MONTRAP = 1<<27,
40         PROCB_EXITMONITOR = 1<<29,
41         PROCB_EXITPAUSE = 1<<30,
42         PROCB_USECTLS2 = 1<<31,
43         
44         PROCB_EPT = 1<<1,
45         PROCB_EXITGDT = 1<<2,
46         PROCB_VPID = 1<<5,
47         PROCB_UNRESTR = 1<<7,
48 };
49
50 int
51 cpuidcheck(void)
52 {
53         int pfd[2];
54         Biobuf *bp;
55         char *l, *f[64];
56         int i, rc;
57         
58         pipe(pfd);
59         switch(rfork(RFPROC|RFFDG)){
60         case 0:
61                 close(pfd[1]);
62                 close(0);
63                 open("/dev/null", OREAD);
64                 dup(pfd[0], 1);
65                 execl("/bin/aux/cpuid", "cpuid", nil);
66                 sysfatal("execl: %r");
67                 break;
68         case -1: sysfatal("rfork: %r");
69         }
70         close(pfd[0]);
71         bp = Bfdopen(pfd[1], OREAD);
72         if(bp == nil) sysfatal("Bfdopen: %r");
73         for(; l = Brdstr(bp, '\n', 10), l != nil; free(l)){
74                 rc = tokenize(l, f, nelem(f));
75                 if(rc < 1) continue;
76                 if(strcmp(f[0], "features") != 0) continue;
77                 for(i = 1; i < rc; i++)
78                         if(strcmp(f[i], "vmx") == 0){
79                                 Bterm(bp);
80                                 close(pfd[1]);
81                                 waitpid();
82                                 return 0;
83                         }
84         }
85         Bterm(bp);
86         close(pfd[1]);
87         waitpid();
88         return -1;
89 }
90
91 static int msrfd;
92
93 u64int
94 rdmsr(u32int addr)
95 {
96         u64int rv;
97
98         if(pread(msrfd, &rv, 8, addr) < 0) sysfatal("pread: %r");
99         return rv;
100 }
101
102 void
103 wrmsr(u32int addr, u64int val)
104 {
105         if(pwrite(msrfd, &val, 8, addr) < 0) sysfatal("pwrite: %r");
106 }
107
108 static char *pinbits[64] = {
109         [0] "extirq", [3] "nmiexit", [5] "virtnmi", [6] "preempt", [7] "procpostirq"
110 };
111
112 static char *procbits[64] = {
113         [2] "irqwin", [3] "tscoffset", [7] "hltexit", [9] "invlpgexit", [10] "mwaitexit",
114         [11] "rdpmcexit", [12] "rdtscexit", [15] "cr3ldexit", [16] "cr3stexit", [19] "cr8ldexit",
115         [20] "cr8stexit", [21] "tprshadow", [22] "nmiwin", [23] "movdrexit", [24] "ioexit",
116         [25] "iobitmap", [27] "mtf", [28] "msrbitmap", [29] "monitorexit", [30] "pauseexit",
117 };
118
119 static char *proc2bits[64] = {
120         [0] "virtapic", [1] "ept", [2] "gdtexit", [3] "rdtscp", [4] "virtx2apic", [5] "vpid",
121         [6] "wbinvdexit", [7] "unrestr", [8] "apicregs", [9] "virtirq", [10] "pauseloopexit",
122         [11] "rdrandexit", [12] "invpcid", [13] "vmfunc", [14] "vmcsshadow", [15] "enclsexit",
123         [16] "rdseedexit", [17] "pml", [18] "#ve", [19] "conceal", [20] "xsave", [22] "eptxmode",
124         [25] "tscscale",
125 };
126
127 static char *exitbits[64] = {
128         [2] "savedebug", [9] "host64", [12] "saveperfglobal", [15] "ackextirq",
129         [16] "savepat", [17] "loadpat", [20] "saveefer", [21] "loadefer", [22] "savepreempt",
130         [23] "savebndcfgs", [24] "concealexits",
131 };
132
133 static char *entrybits[64] = {
134         [2] "loaddebug", [9] "guest64", [10] "entrysmm", [11] "dualmonitor", [13] "loadperfglobal",
135         [14] "loadpat", [15] "loadefer", [16] "loadbndcfgs", [17] "concealentries",
136 };
137
138 static char *miscbits[64] = {
139         [5] "longmodeswitch", [6] "hlt", [7] "shutdown", [8] "ipi", [14] "pt", [15] "rdmsrsmm",
140         [28] "smmblock", [29] "vmwriteany", [30] "zerolenswirq",
141 };
142
143 static char *cr0bits[64] = {
144         [0] "pe", [1] "mp", [2] "em", [3] "ts", [4] "et", [5] "ne", [6] "wp", [18] "am",
145         [29] "nw", [30] "cd", [31] "pg",
146 };
147
148 static char *cr4bits[64] = {
149         [0] "vme", [1] "pvi", [2] "tsd", [3] "de", [4] "pse", [5] "pae", [6] "mce", [7] "pge",
150         [8] "pce", [9] "osxfsr", [10] "osxmmxcpt", [11] "umip", [13] "vmxe", [14] "smxe",
151         [16] "fsgsbase", [17] "pcide", [18] "osxsave", [20] "smep", [21] "smap", [22] "pke"
152 };
153
154 static char *eptbits[64] = {
155         [0] "xonly", [6] "pwl4", [8] "ucmem", [14] "wbmem", [16] "2MBpage", [17] "1GBpage",
156         [20] "invept", [21] "dirtybits", [22] "violexitinfo", [25] "invept.single", [26] "invept.all",
157 };
158
159 static char *vpidbits[64] = {
160         [32] "invvpid", [40] "invvpid.addr", [41] "invvpid.single", [42] "invvpid.all", [43] "invvpid.noglob",
161 };
162
163 void
164 printbits(char *id, uvlong allowed, uvlong forced, char **s)
165 {
166         int i, l;
167
168         l = -1;
169         for(i = 0; i < 64; i++){
170                 if(s[i] == nil) continue;
171                 if(((allowed|forced) & 1ULL<<i) == 0) continue;
172                 if((uint)l > 80){
173                         if(l >= 0)
174                                 Bprint(out, "\n");
175                         l = Bprint(out, "%s ", id);
176                 }
177                 if((forced & 1ULL<<i) != 0) l += Bprint(out, "!");
178                 l += Bprint(out, "%s ", s[i]);
179         }
180         if(l >= 0)
181                 Bprint(out, "\n");
182 }
183
184 void
185 printbits32(char *id, uvlong w, char **s)
186 {
187         printbits(id, (u32int)(w >> 32), (u32int)w, s);
188 }
189
190 u64int
191 rawprint(char *s, int addr)
192 {
193         u64int msr;
194         
195         msr = rdmsr(addr);
196         Bprint(out, "%s %#.16ullx\n", s, msr);
197         return msr;
198 }
199
200 void
201 main(int argc, char **argv)
202 {
203         u64int msr, msr2;
204         int ext;
205         static int no, raw, verbose;
206         
207         ARGBEGIN {
208         case 'r': raw++; verbose++; break;
209         case 'v': verbose++; break;
210         default: goto usage;
211         } ARGEND;
212         if(argc != 0){
213         usage:
214                 fprint(2, "usage: %s [-r]\n", argv0);
215                 exits("usage");
216         }
217         
218         out = Bfdopen(1, OWRITE);
219         if(out == nil) sysfatal("Bfdopen: %r");
220         msrfd = open("#P/msr", OREAD);
221         if(msrfd < 0) sysfatal("open: %r");
222         if(cpuidcheck() < 0) sysfatal("CPU does not support VMX");
223         if(!verbose){
224                 msr = rdmsr(0x3a);
225                 if((msr & 5) == 0) wrmsr(0x3a, msr | 5);
226                 if((rdmsr(0x3a) & 5) != 5){
227                         print("VMX disabled by BIOS\n");
228                         no++;
229                 }
230                 msr = rdmsr(VMX_PROCB_CTLS_MSR);
231                 if((vlong)msr >= 0){
232                         print("no secondary controls\n");
233                         no++;
234                 }else{
235                         msr = rdmsr(VMX_PROCB_CTLS2_MSR);
236                         if((msr >> 32 & PROCB_EPT) == 0){
237                                 print("no EPT support\n");
238                                 no++;
239                         }
240                         if((msr >> 32 & PROCB_VPID) == 0){
241                                 print("no VPID support\n");
242                                 no++;
243                         }
244                 }
245                 if(no == 0)
246                         print("VMX is supported\n");
247                 else
248                         print("Some needed features are missing\n");
249         }else if(!raw){
250                 msr = rdmsr(VMX_BASIC_MSR);
251                 Bprint(out, "vmcsrev %#ux\n", (u32int)msr & 0x7fffffff);
252                 Bprint(out, "vmxonsz %d\n", (u32int)(msr >> 32) & 0x1fff);
253                 Bprint(out, "vmcsmem %d\n", (u32int)(msr >> 50) & 15);
254                 ext = (u32int)(msr >> 55) & 1;
255                 Bprint(out, "extcontrols %d\n", ext);
256                 
257                 msr = rdmsr(ext ? VMX_TRUE_PINB_CTLS_MSR : VMX_PINB_CTLS_MSR);
258                 printbits32("pin", msr, pinbits);
259                 msr = rdmsr(ext ? VMX_TRUE_PROCB_CTLS_MSR : VMX_PROCB_CTLS_MSR);
260                 printbits32("proc", msr, procbits);
261                 if((msr & 1ULL<<63) != 0){
262                         msr = rdmsr(VMX_PROCB_CTLS2_MSR);
263                         printbits32("proc2", msr, proc2bits);
264                 }
265                 msr = rdmsr(ext ? VMX_TRUE_ENTRY_CTLS_MSR : VMX_VMENTRY_CTLS_MSR);
266                 printbits32("entry", msr, entrybits);
267                 msr = rdmsr(ext ? VMX_TRUE_EXIT_CTLS_MSR : VMX_VMEXIT_CTLS_MSR);
268                 printbits32("exit", msr, exitbits);
269                 msr = rdmsr(VMX_MISC_MSR);
270                 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));
271                 printbits("misc", msr, 0, miscbits);
272                 msr = rdmsr(VMX_CR0_FIXED0);
273                 msr2 = rdmsr(VMX_CR0_FIXED1);
274                 printbits("cr0fixed", msr & msr2, ~msr & ~msr2, cr0bits);
275                 msr = rdmsr(VMX_CR4_FIXED0);
276                 msr2 = rdmsr(VMX_CR4_FIXED1);
277                 printbits("cr4fixed", msr & msr2, ~msr & ~msr2, cr4bits);
278                 Bprint(out, "vmcsenum %#ullx\n", rdmsr(VMX_VMCS_ENUM));
279                 if(no == 0){
280                         msr = rdmsr(VMX_VPIDEPT_MSR);
281                         printbits("ept", msr, 0, eptbits);
282                         printbits("vpid", msr, 0, vpidbits);
283                 }
284         }else{
285                 msr = rawprint("basic", VMX_BASIC_MSR);
286                 ext = (u32int)(msr >> 55) & 1;
287                 rawprint("pin", ext ? VMX_TRUE_PINB_CTLS_MSR : VMX_PINB_CTLS_MSR);
288                 msr = rawprint("proc", ext ? VMX_TRUE_PROCB_CTLS_MSR : VMX_PROCB_CTLS_MSR);
289                 if((msr & 1ULL<<63) != 0)
290                         rawprint("proc2", VMX_PROCB_CTLS2_MSR);
291                 rawprint("entry", ext ? VMX_TRUE_ENTRY_CTLS_MSR : VMX_VMENTRY_CTLS_MSR);
292                 rawprint("exit", ext ? VMX_TRUE_EXIT_CTLS_MSR : VMX_VMEXIT_CTLS_MSR);
293                 rawprint("misc", VMX_MISC_MSR);
294                 rawprint("cr0fixed0", VMX_CR0_FIXED0);
295                 rawprint("cr0fixed1", VMX_CR0_FIXED1);
296                 rawprint("cr4fixed0", VMX_CR4_FIXED0);
297                 rawprint("cr4fixed1", VMX_CR4_FIXED1);
298                 rawprint("vmcsenum", VMX_VMCS_ENUM);
299                 if(no == 0)
300                         rawprint("vpidept", VMX_VPIDEPT_MSR);
301         }
302
303         exits(nil);
304 }