10 typedef struct ExitInfo ExitInfo;
25 char *x86segreg[8] = {
26 "cs", "ds", "es", "fs", "gs", "ss",
30 skipinstr(ExitInfo *ei)
32 rset(RPC, rget(RPC) + ei->ilen);
36 iohandler(ExitInfo *ei)
38 int port, len, inc, isin;
44 static int seglook[8] = {SEGES, SEGCS, SEGSS, SEGDS, SEGFS, SEGGS};
47 port = ei->qual >> 16 & 0xffff;
48 len = (ei->qual & 7) + 1;
49 isin = (ei->qual & 8) != 0;
50 if((ei->qual & 1<<4) == 0){ /* not a string instruction */
52 val = io(1, port, 0, len);
53 rsetsz(RAX, val, len);
55 io(0, port, rget(RAX), len);
59 if((rget("flags") & 0x400) != 0) inc = -len;
61 switch(ei->iinfo >> 7 & 7){
62 case 0: asz = 2; break;
63 default: asz = 4; break;
64 case 2: asz = 8; break;
66 if((ei->qual & 1<<5) != 0)
67 cx = rgetsz(RCX, asz);
70 addr = isin ? rget(RDI) : rget(RSI);
74 seg = seglook[ei->iinfo >> 15 & 7];
75 memset(&tlb, 0, sizeof(TLB));
78 vval = io(1, port, 0, len);
79 if(x86access(seg, addr, asz, &vval, len, ACCW, &tlb) < 0)
82 if(x86access(seg, addr, asz, &vval, len, ACCR, &tlb) < 0)
84 io(0, port, vval, len);
90 if((ei->qual & 1<<5) != 0)
93 rsetsz(RDI, addr, asz);
95 rsetsz(RSI, addr, asz);
99 defaultmmio(int op, uvlong addr, uvlong val)
103 vmerror("read from unmapped address %#ullx (pc=%#ullx)", addr, rget(RPC));
106 vmerror("write to unmapped address %#ullx (val=%#ullx,pc=%#ullx)", addr, val, rget(RPC));
113 eptfault(ExitInfo *ei)
119 typedef struct CPUID CPUID;
122 u32int ax, bx, cx, dx;
124 static CPUID *cpuidf;
128 auxcpuidproc(void *vpfd)
135 open("/dev/null", OREAD);
138 procexecl(nil, "/bin/aux/cpuid", "cpuid", "-r", nil);
139 threadexits("exec: %r");
151 procrfork(auxcpuidproc, pfd, 4096, RFFDG);
153 bp = Bfdopen(pfd[1], OREAD);
154 if(bp == nil) sysfatal("Bopenfd: %r");
155 for(; l = Brdstr(bp, '\n', 1), l != nil; free(l)){
156 if(tokenize(l, f, 5) < 5) continue;
157 cpuidf = realloc(cpuidf, (ncpuidf + 1) * sizeof(CPUID));
158 cp = cpuidf + ncpuidf++;
159 cp->idx = strtoul(f[0], nil, 16);
160 cp->ax = strtoul(f[1], nil, 16);
161 cp->bx = strtoul(f[2], nil, 16);
162 cp->cx = strtoul(f[3], nil, 16);
163 cp->dx = strtoul(f[4], nil, 16);
174 for(cp = cpuidf; cp < cpuidf + ncpuidf; cp++)
185 u32int ax, bx, cx, dx;
191 if(cp == nil) cp = &def;
193 case 0: /* highest register & GenuineIntel */
199 case 1: /* features */
201 bx = cp->bx & 0xffff;
202 cx = cp->cx & 0x60de2203;
203 dx = cp->dx & 0x0782a179;
205 case 2: goto literal; /* cache stuff */
206 case 3: goto zero; /* processor serial number */
207 case 4: goto zero; /* cache stuff */
208 case 5: goto zero; /* monitor/mwait */
209 case 6: goto zero; /* thermal management */
210 case 7: goto zero; /* more features */
211 case 10: goto zero; /* performance counters */
212 case 0x80000000: /* highest register */
216 case 0x80000001: /* signature & ext features */
220 if(sizeof(uintptr) == 8)
221 dx = cp->dx & 0x24100800;
223 dx = cp->dx & 0x04100000;
225 case 0x80000002: goto literal; /* brand string */
226 case 0x80000003: goto literal; /* brand string */
227 case 0x80000004: goto literal; /* brand string */
228 case 0x80000005: goto zero; /* reserved */
229 case 0x80000006: goto literal; /* cache info */
230 case 0x80000007: goto zero; /* invariant tsc */
231 case 0x80000008: goto literal; /* address bits */
239 vmerror("unknown cpuid field eax=%#ux", ax);
255 rdwrmsr(ExitInfo *ei)
261 rd = ei->name[1] == 'r';
263 val = (uvlong)rget(RDX) << 32 | rget(RAX);
266 if(rd) val = rget("pat");
267 else rset("pat", val);
269 case 0x8B: val = 0; break; /* microcode update */
272 vmerror("read from unknown MSR %#ux ignored", cx);
275 vmerror("write to unknown MSR %#ux ignored (val=%#ullx)", cx, val);
279 rset(RAX, (u32int)val);
280 rset(RDX, (u32int)(val >> 32));
288 static char *dr[8] = { "dr0", "dr1", "dr2", "dr3", nil, nil, "dr6", "dr7" };
297 rset(x86reg[q >> 8 & 15], rget(dr[q & 7]));
299 rset(dr[q & 7], rget(x86reg[q >> 8 & 15]));
313 vmdebug("illegal CR0 write, value %#ux", rget(x86reg[q >> 8 & 15]));
314 rset("cr0real", rget(x86reg[q >> 8 & 15]));
318 vmerror("shouldn't happen: trap on MOV from CR0");
319 rset(x86reg[q >> 8 & 15], rget("cr0fake"));
323 vmerror("shouldn't happen: trap on CLTS");
324 rset("cr0real", rget("cr0real") & ~8);
328 vmerror("LMSW handler unimplemented");
329 postexc("#ud", NOERRC);
335 vmdebug("illegal CR4 write, value %#ux", rget(x86reg[q >> 8 & 15]));
336 rset("cr4real", rget(x86reg[q >> 8 & 15]));
340 vmerror("shouldn't happen: trap on MOV from CR4");
341 rset(x86reg[q >> 8 & 15], rget("cr3fake"));
345 vmerror("unknown CR4 operation %d", q);
346 postexc("#ud", NOERRC);
350 vmerror("access to unknown control register CR%d", ei->qual & 15);
351 postexc("#ud", NOERRC);
358 rset("dr6", rget("dr6") | ei->qual);
359 postexc("#db", NOERRC);
371 irqackhand(ExitInfo *ei)
376 typedef struct ExitType ExitType;
379 void (*f)(ExitInfo *);
381 static ExitType etypes[] = {
385 {"eptfault", eptfault},
386 {"*ack", irqackhand},
395 processexit(char *msg)
397 static char msgc[1024];
406 nf = tokenize(msgc, f, nelem(f));
407 if(nf < 2) sysfatal("invalid wait message: %s", msg);
408 memset(&ei, 0, sizeof(ei));
411 ei.qual = strtoull(f[1], nil, 0);
412 for(i = 2; i < nf; i += 2){
413 if(strcmp(f[i], "pc") == 0)
414 rpoke(RPC, strtoull(f[i+1], nil, 0), 1);
415 else if(strcmp(f[i], "sp") == 0)
416 rpoke(RSP, strtoull(f[i+1], nil, 0), 1);
417 else if(strcmp(f[i], "ax") == 0)
418 rpoke(RAX, strtoull(f[i+1], nil, 0), 1);
419 else if(strcmp(f[i], "ilen") == 0)
420 ei.ilen = strtoul(f[i+1], nil, 0);
421 else if(strcmp(f[i], "iinfo") == 0)
422 ei.iinfo = strtoul(f[i+1], nil, 0);
423 else if(strcmp(f[i], "pa") == 0)
424 ei.pa = strtoull(f[i+1], nil, 0);
425 else if(strcmp(f[i], "va") == 0)
426 ei.va = strtoull(f[i+1], nil, 0);
428 if(*f[0] == '*') getexit++;
429 for(et = etypes; et < etypes + nelem(etypes); et++)
430 if(strcmp(et->name, f[0]) == 0){
435 vmerror("vmx: unknown instruction %s", f[0]+1);
436 postexc("#ud", NOERRC);
440 vmerror("vmx: unknown notification %s", f[0]+1);
444 vmerror("unknown exit: %s", msg);
447 sysfatal("unknown exit: %s", msg);