Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


added generic VMM framework
[palacios.git] / palacios / src / geekos / vmx.c
1 #include <geekos/vmx.h>
2 #include <geekos/vmcs.h>
3 #include <geekos/mem.h>
4 #include <geekos/serial.h>
5 #include <geekos/segment.h>
6 #include <geekos/gdt.h>
7 #include <geekos/idt.h>
8
9
10 #include <geekos/cpu.h>
11 #include <geekos/io_devs.h>
12
13
14 extern void Get_MSR(unsigned int msr, uint_t * high, uint_t * low);
15 extern void Set_MSR(unsigned int msr, uint_t high, uint_t low);
16 extern int Enable_VMX(ullong_t regionPtr);
17 extern int cpuid_ecx(unsigned int op);
18 extern int Launch_VM(ullong_t vmcsPtr, uint_t eip);
19
20 #define NUMPORTS 65536
21
22
23 #define VMXASSIST_INFO_PORT   0x0e9
24 #define ROMBIOS_PANIC_PORT    0x400
25 #define ROMBIOS_PANIC_PORT2   0x401
26 #define ROMBIOS_INFO_PORT     0x402
27 #define ROMBIOS_DEBUG_PORT    0x403
28
29
30
31 static struct VM theVM;
32
33 static uint_t GetLinearIP(struct VM *vm)
34 {
35   if (vm->state==VM_VMXASSIST_V8086_BIOS || vm->state==VM_VMXASSIST_V8086) { 
36     return vm->vmcs.guestStateArea.cs.baseAddr + vm->vmcs.guestStateArea.rip;
37   } else {
38     return vm->vmcs.guestStateArea.rip;
39   }
40 }
41
42
43 static void VMXPanic()
44 {
45   while (1) {}
46 }
47
48
49 #define MAX_CODE 512
50 #define INSTR_OFFSET_START 17
51 #define NOP_SEQ_LEN        10
52 #define INSTR_OFFSET_END   (INSTR_OFFSET_START+NOP_SEQ_LEN-1)
53 #define TEMPLATE_CODE_LEN  35
54
55 uint_t oldesp=0;
56 uint_t myregs=0;
57
58 // simply execute the instruction that is faulting and return
59 static int ExecFaultingInstructionInVMM(struct VM *vm)
60 {
61   uint_t address = GetLinearIP(vm);
62   myregs = (uint_t)&(vm->registers);
63   
64
65   SerialPrintLevel(1000,"About the execute faulting instruction!\n");
66   SerialPrintLevel(1000,"Instruction is:\n");
67   SerialMemDump((void*)(address),vm->vmcs.exitInfoFields.instrLength);
68   
69
70   SerialPrintLevel(1000,"The template code is:\n");
71   SerialMemDump(&&template_code,TEMPLATE_CODE_LEN);
72
73   // clone the template code
74   //memcpy(&&template_code,code,MAX_CODE);
75   
76   // clean up the nop field
77   memset(&&template_code+INSTR_OFFSET_START,*((uchar_t *)(&&template_code+0)),NOP_SEQ_LEN);
78   // overwrite the nops with the faulting instruction
79   memcpy(&&template_code+INSTR_OFFSET_START, (void*)(address),vm->vmcs.exitInfoFields.instrLength);
80   
81   SerialPrintLevel(1000,"Finished modifying the template code, which now is:\n");
82   SerialMemDump(&&template_code,TEMPLATE_CODE_LEN);
83
84   SerialPrintLevel(1000,"Now entering modified template code\n");
85
86
87  template_code:
88   // Template code stores current registers,
89   // restores registers, has a landing pad of noops 
90   // that will be modified, restores current regs, and then returns
91   //
92   // Note that this currently ignores cr0, cr3, cr4, dr7, rsp, rip, and rflags
93   // it also blythly assumes it can exec the instruction in protected mode
94   //
95   __asm__ __volatile__ ("nop\n"               // for cloning purposes                          (1 byte)
96                         "pusha\n"             // push our current regs onto the current stack  (1 byte)
97                         "movl %0, %%eax\n"    // Get oldesp location                           (5 bytes)
98                         "movl %%esp, (%%eax)\n"  // store the current stack pointer in oldesp       (2 bytes)
99                         "movl %1, %%eax\n"    // Get regs location                             (5 bytes)
100                         "movl (%%eax), %%esp\n"  // point esp at regs                               (2 bytes)
101                         "popa\n"              // now we have the VM registers restored            (1 byte)
102                         "nop\n"               // now we execute the actual instruction         (1 byte x 10)
103                         "nop\n"               // now we execute the actual instruction
104                         "nop\n"               // now we execute the actual instruction
105                         "nop\n"               // now we execute the actual instruction
106                         "nop\n"               // now we execute the actual instruction
107                         "nop\n"               // now we execute the actual instruction
108                         "nop\n"               // now we execute the actual instruction
109                         "nop\n"               // now we execute the actual instruction
110                         "nop\n"               // now we execute the actual instruction
111                         "nop\n"               // now we execute the actual instruction
112                         // need to copy back to the VM registers!
113                         "movl %0, %%eax\n"     // recapture oldesp location                     (5 bytes)
114                         "movl (%%eax), %%esp\n"   // now we'll get our esp back from oldesp       (2 bytes)
115                         "popa\n"              // and restore our GP regs and we're done       (1 byte)
116                         : "=m"(oldesp)
117                         : "m"(myregs)
118                         );
119   
120   SerialPrintLevel(1000,"Survived executing the faulting instruction and returning.\n");
121
122   vm->vmcs.guestStateArea.rip += vm->vmcs.exitInfoFields.instrLength;
123
124   return 0;
125
126 }
127
128
129 int is_vmx_capable() {
130   uint_t ret;
131   union VMX_MSR featureMSR;
132   
133   ret = cpuid_ecx(1);
134   if (ret & CPUID_1_ECX_VTXFLAG) {
135     Get_MSR(IA32_FEATURE_CONTROL_MSR, &featureMSR.regs.high, &featureMSR.regs.low);
136
137     SerialPrintLevel(100,"MSRREGlow: 0x%.8x\n", featureMSR.regs.low);
138
139     if ((featureMSR.regs.low & FEATURE_CONTROL_VALID) != FEATURE_CONTROL_VALID) {
140       PrintBoth("VMX is locked -- enable in the BIOS\n");
141       return 0;
142     }
143   } else {
144     PrintBoth("VMX not supported on this cpu\n");
145     return 0;
146   }
147
148   return 1;
149
150 }
151
152
153 VmxOnRegion * Init_VMX() {
154   uint_t ret;
155   VmxOnRegion * region = NULL;
156
157
158   region = CreateVmxOnRegion();
159
160
161   ret = Enable_VMX((ullong_t)((uint_t)region));
162   if (ret == 0) {
163     PrintBoth("VMX Enabled\n");
164   } else {
165     PrintBoth("VMX failure (ret = %d)\n", ret);
166   }
167
168   theVM.vmxonregion = region;
169
170   return region;
171 }
172
173 extern uint_t VMCS_CLEAR();
174 extern uint_t VMCS_LOAD();
175 extern uint_t VMCS_STORE();
176 extern uint_t VMCS_LAUNCH();
177 extern uint_t VMCS_RESUME();
178 extern uint_t Init_VMCS_HostState();
179 extern uint_t Init_VMCS_GuestState();
180
181 void SetCtrlBitsCorrectly(int msrno, int vmcsno)
182 {
183   uint_t reserved =0;
184   union VMX_MSR msr;
185
186   SerialPrintLevel(100,"SetCtrlBitsCorrectly(%x,%x)\n",msrno,vmcsno);
187   Get_MSR(msrno, &msr.regs.high, &msr.regs.low);
188   SerialPrintLevel(100,"MSR %x = %x : %x \n", msrno, msr.regs.high, msr.regs.low);
189   reserved = msr.regs.low;
190   reserved &= msr.regs.high;
191   VMCS_WRITE(vmcsno, &reserved);
192 }
193
194
195 void SetCRBitsCorrectly(int msr0no, int msr1no, int vmcsno)
196 {
197   uint_t reserved =0;
198   union VMX_MSR msr0, msr1;
199
200   SerialPrintLevel(100,"SetCRBitsCorrectly(%x,%x,%x)\n",msr0no,msr1no,vmcsno);
201   Get_MSR(msr0no, &msr0.regs.high, &msr0.regs.low);
202   Get_MSR(msr1no, &msr1.regs.high, &msr1.regs.low);
203   SerialPrintLevel(100,"MSR %x = %x, %x =  %x \n", msr0no, msr0.regs.low, msr1no, msr1.regs.low);
204   reserved = msr0.regs.low;
205   reserved &= msr1.regs.low;
206   VMCS_WRITE(vmcsno, &reserved);
207 }
208
209
210 extern int Get_CR2();
211 extern int vmRunning;
212
213
214 static int PanicUnhandledVMExit(struct VM *vm)
215 {
216   Print("Panicking due to VMExit with reason %u\n",vm->vmcs.exitInfoFields.reason);
217   SerialPrint("Panicking due to VMExit with reason %u\n",vm->vmcs.exitInfoFields.reason);
218   SerialPrint_VMCS_ALL();
219   SerialPrint_VMX_Regs(&(vm->registers));
220   VMXPanic();
221   return 0;
222 }
223
224
225 static int HandleVMPrintsAndPanics(struct VM *vm, uint_t port, uint_t data)
226 {
227   if (port==VMXASSIST_INFO_PORT &&
228       (vm->state == VM_VMXASSIST_STARTUP || 
229        vm->state == VM_VMXASSIST_V8086_BIOS ||
230        vm->state == VM_VMXASSIST_V8086)) { 
231     // Communication channel from VMXAssist
232     SerialPrintLevel(1000,"VMXASSIST Output Port\n");
233     PrintBoth("%c",data&0xff);
234     return 1;
235   } 
236
237   if ((port==ROMBIOS_PANIC_PORT || 
238        port==ROMBIOS_PANIC_PORT2 || 
239        port==ROMBIOS_DEBUG_PORT ||
240        port==ROMBIOS_INFO_PORT) &&
241       (vm->state==VM_VMXASSIST_V8086_BIOS)) {
242     // rombios is communicating
243     SerialPrintLevel(1000,"ROMBIOS Output Port\n");
244     //    PrintBoth("%c",data&0xff);
245     return 1;
246   }
247
248   if (port==BOOT_STATE_CARD_PORT && vm->state==VM_VMXASSIST_V8086_BIOS) { 
249     // rombios is sending something to the display card
250     SerialPrintLevel(1000,"Hex Display: 0x%x\n",data&0xff);
251     return 1;
252   }
253   return 0;
254 }
255
256 static int HandleInOutExit(struct VM *vm)
257 {
258   uint_t address;
259
260   struct VMCSExitInfoFields *exitinfo = &(vm->vmcs.exitInfoFields);
261   struct VMExitIOQual * qual = (struct VMExitIOQual *)&(vm->vmcs.exitInfoFields.qualification);
262   struct VMXRegs *regs = &(vm->registers);
263
264   address=GetLinearIP(vm);
265
266   SerialPrintLevel(1000,"Handling Input/Output Instruction Exit\n");
267   if (SERIAL_PRINT_DEBUG && 1000>=SERIAL_PRINT_DEBUG_LEVEL) {
268       SerialPrint_VMX_Regs(regs);
269   }
270   SerialPrintLevel(1000,"Qualifications=0x%x\n",exitinfo->qualification);
271   SerialPrintLevel(1000,"Reason=0x%x\n",exitinfo->reason);
272   SerialPrintLevel(1000,"IO Port: 0x%x (%d)\n", qual->port, qual->port);
273   SerialPrintLevel(1000,"Instruction Info=%x\n",exitinfo->instrInfo);
274   SerialPrintLevel(1000,"%x : %s %s %s instruction of length %d for %d bytes from/to port 0x%x\n",
275                    address,
276                    qual->dir == 0 ? "output" : "input",
277                    qual->string ==0 ? "nonstring" : "STRING",
278                    qual->REP == 0 ? "with no rep" : "WITH REP",
279                    exitinfo->instrLength, 
280                    qual->accessSize==0 ? 1 : qual->accessSize==1 ? 2 : 4,
281                    qual->port);
282
283   if (qual->port==PIC_MASTER_CMD_ISR_PORT ||
284       qual->port==PIC_MASTER_IMR_PORT ||
285       qual->port==PIC_SLAVE_CMD_ISR_PORT ||
286       qual->port==PIC_SLAVE_IMR_PORT) {
287     SerialPrintLevel(1000, "PIC Access\n");
288   }
289                   
290
291   if (qual->dir==1 && qual->REP==0 && qual->string==0) { 
292     char byte = In_Byte(qual->port);
293
294     vm->vmcs.guestStateArea.rip += exitinfo->instrLength;
295     regs->eax = (regs->eax & 0xffffff00) | byte;
296     SerialPrintLevel(1000,"Returning 0x%x in eax\n",(regs->eax));
297   }
298
299   if (qual->dir==0 && qual->REP==0 && qual->string==0) { 
300     // See if we need to handle the outb as a signal or
301     // print from the VM
302     if (HandleVMPrintsAndPanics(vm,qual->port,regs->eax)) {
303     } else {
304       // If not, just go ahead and do the outb
305       Out_Byte(qual->port,regs->eax);
306       SerialPrintLevel(1000,"Wrote 0x%x to port\n",(regs->eax));
307     }
308     vm->vmcs.guestStateArea.rip += exitinfo->instrLength;
309   }
310
311   return 0;
312 }  
313
314
315 static int HandleExternalIRQExit(struct VM *vm)
316 {
317   struct VMCSExitInfoFields * exitinfo = &(vm->vmcs.exitInfoFields);
318   struct VMExitIntInfo * intInfo  = (struct VMExitIntInfo *)&(vm->vmcs.exitInfoFields.intInfo);
319
320   SerialPrintLevel(1000,"External Interrupt captured\n");
321   SerialPrintLevel(100,"IntInfo: %x\n", exitinfo->intInfo);
322
323
324   if (!intInfo->valid) {
325      // interrupts are off, but this interrupt is not acknoledged (still pending)
326      // so we turn on interrupts to deliver appropriately in the
327      // host
328     SerialPrintLevel(100,"External Interrupt is invald.  Turning Interrupts back on\n");
329     asm("sti");
330     return 0;
331   } 
332
333   // At this point, interrupts are off and the interrupt has been 
334   // acknowledged.  We will now handle the interrupt ourselves 
335   // and turn interrupts  back on in the host
336
337   SerialPrintLevel(100,"type: %d\n", intInfo->type);
338   SerialPrintLevel(100,"number: %d\n", intInfo->nr);
339
340   SerialPrint("Interrupt %d occuring now and handled by HandleExternalIRQExit\n",intInfo->nr);
341
342   switch (intInfo->type) {
343   case 0:  {  // ext. IRQ
344     // In the following, we construct an "int x" instruction
345     // where x is the specific interrupt number that is raised
346     // then we execute that instruciton
347     // because we are in host context, that means it is delivered as normal
348     // through the host IDT
349      
350      ((char*)(&&ext_int_seq_start))[1] = intInfo->nr;
351  
352      SerialPrintLevel(100,"Interrupt instruction setup done %x\n", *((ushort_t *)(&&ext_int_seq_start)));
353      
354 ext_int_seq_start:
355      asm("int $0");
356   }
357
358     break;
359   case 2: // NMI
360     SerialPrintLevel(100,"Type: NMI\n");
361     break;
362   case 3: // hw exception
363     SerialPrintLevel(100,"Type: HW Exception\n");
364     break;
365   case 4: // sw exception
366     SerialPrintLevel(100,"Type: SW Exception\n");
367     break;
368   default:
369     SerialPrintLevel(100,"Invalid Interrupt Type\n");
370     return -1;
371   }
372   
373   if (intInfo->valid && intInfo->errorCode) {
374     SerialPrintLevel(100,"IntError: %x\n", exitinfo->intErrorCode);
375   }
376
377
378   return 0;
379
380 }
381
382
383
384 void DecodeCurrentInstruction(struct VM *vm, struct Instruction *inst)
385 {
386   // this is a gruesome hack
387   uint_t address = GetLinearIP(vm);
388   uint_t length = vm->vmcs.exitInfoFields.instrLength;
389   unsigned char *t = (unsigned char *) address;
390
391
392   
393   SerialPrintLevel(100,"DecodeCurrentInstruction: instruction is\n");
394   SerialMemDump(t,length);
395   
396   if (length==3 && t[0]==0x0f && t[1]==0x22 && t[2]==0xc0) { 
397     // mov from eax to cr0
398     // usually used to signal
399     inst->type=VM_MOV_TO_CR0;
400     inst->address=address;
401     inst->size=length;
402     inst->input1=vm->registers.eax;
403     inst->input2=vm->vmcs.guestStateArea.cr0;
404     inst->output=vm->registers.eax;
405     SerialPrintLevel(100,"MOV FROM EAX TO CR0\n");
406   } else {
407     inst->type=VM_UNKNOWN_INST;
408   }
409 }
410
411
412 static void V8086ModeSegmentRegisterFixup(struct VM *vm)
413 {
414   vm->vmcs.guestStateArea.cs.baseAddr=vm->vmcs.guestStateArea.cs.selector<<4;
415   vm->vmcs.guestStateArea.es.baseAddr=vm->vmcs.guestStateArea.es.selector<<4;
416   vm->vmcs.guestStateArea.ss.baseAddr=vm->vmcs.guestStateArea.ss.selector<<4;
417   vm->vmcs.guestStateArea.ds.baseAddr=vm->vmcs.guestStateArea.ds.selector<<4;
418   vm->vmcs.guestStateArea.fs.baseAddr=vm->vmcs.guestStateArea.fs.selector<<4;
419   vm->vmcs.guestStateArea.gs.baseAddr=vm->vmcs.guestStateArea.gs.selector<<4;
420 }
421
422 static void SetupV8086ModeForBoot(struct VM *vm)
423 {
424   vm->state = VM_VMXASSIST_V8086_BIOS;
425
426   // Put guest into V8086 mode on return
427   vm->vmcs.guestStateArea.rflags |= EFLAGS_VM | EFLAGS_IOPL_HI | EFLAGS_IOPL_LO ;
428   
429   // We will start at f000:fff0 on return
430   //
431   // We want this to look as much as possible as a processor
432   // reset
433   vm->vmcs.guestStateArea.rip = 0xfff0;  // note, 16 bit rip
434   vm->vmcs.guestStateArea.cs.selector = 0xf000;
435   vm->vmcs.guestStateArea.cs.limit=0xffff;
436   vm->vmcs.guestStateArea.cs.access.as_dword = 0xf3;
437
438   vm->vmcs.guestStateArea.ss.selector = 0x0000;
439   vm->vmcs.guestStateArea.ss.limit=0xffff;
440   vm->vmcs.guestStateArea.ss.access.as_dword = 0xf3;
441
442   vm->vmcs.guestStateArea.ds.selector = 0x0000;
443   vm->vmcs.guestStateArea.ds.limit=0xffff;
444   vm->vmcs.guestStateArea.ds.access.as_dword = 0xf3;
445
446   vm->vmcs.guestStateArea.es.selector = 0x0000;
447   vm->vmcs.guestStateArea.es.limit=0xffff;
448   vm->vmcs.guestStateArea.es.access.as_dword = 0xf3;
449
450   vm->vmcs.guestStateArea.fs.selector = 0x0000;
451   vm->vmcs.guestStateArea.fs.limit=0xffff;
452   vm->vmcs.guestStateArea.fs.access.as_dword = 0xf3;
453
454   vm->vmcs.guestStateArea.gs.selector = 0x0000;
455   vm->vmcs.guestStateArea.gs.limit=0xffff;
456   vm->vmcs.guestStateArea.gs.access.as_dword = 0xf3;
457   
458   V8086ModeSegmentRegisterFixup(vm);
459
460   SerialPrint_VMCSData(&(vm->vmcs));
461
462 }
463   
464
465
466 static int HandleExceptionOrNMI(struct VM *vm)
467 {
468   struct Instruction inst;
469   uint_t num;
470   uint_t type;
471   uint_t errorvalid;
472   uint_t error;
473   uint_t ext=0;
474   uint_t idt=0;
475   uint_t ti=0;
476   uint_t selectorindex=0;
477
478   SerialPrintLevel(1000,"Exception or NMI occurred\n");
479   
480   num=vm->vmcs.exitInfoFields.intInfo & 0xff;
481   type=(vm->vmcs.exitInfoFields.intInfo & 0x700)>>8;
482   errorvalid=(vm->vmcs.exitInfoFields.intInfo & 0x800)>>11;
483   if (errorvalid) { 
484     error=vm->vmcs.exitInfoFields.intErrorCode;
485     ext=error&0x1;
486     idt=(error&0x2)>>1;
487     ti=(error&0x4)>>2;
488     selectorindex=(error>>3)&0xffff;
489   }
490   
491   SerialPrint("Exception %d now - handled by HandleExceptionOrNMI\n",num);
492
493   SerialPrintLevel(1000,"Exception Number %u : %s\n", num, exception_names[num]);
494   SerialPrintLevel(1000,"Exception Type %u : %s\n", type, exception_type_names[type]);
495   if (errorvalid) { 
496     if (ext) { 
497       SerialPrintLevel(1000,"External\n");
498     } else {
499       SerialPrintLevel(1000,"%s - Selector Index is %u\n", idt ? "IDT" : ti ? "LDT" : "GDT", selectorindex);
500     }
501   }
502
503   DecodeCurrentInstruction(vm,&inst);
504
505   if (inst.type==VM_MOV_TO_CR0) {
506     SerialPrintLevel(1000,"MOV TO CR0, oldvalue=0x%x, newvalue=0x%x\n",inst.input2, inst.input1);
507     if ((inst.input2 & CR0_PE) && !(inst.input1 & CR0_PE) && vm->state==VM_VMXASSIST_STARTUP) {
508       // This is VMXAssist signalling for us to turn on V8086 mode and
509       // jump into the bios
510       SerialPrintLevel(1000,"VMXAssist is signaling us for switch to V8086 mode and jump to 0xf000:fff0\n");
511       SetupV8086ModeForBoot(vm);
512       goto leave;
513     } else {
514       SerialPrintLevel(1000,"Instruction is a write to CR0, but we don't understand it so we'll just exec it\n");
515     } 
516   } 
517
518
519   SerialPrintLevel(1000,"Trying to execute the faulting instruction in VMM context now\n");
520   ExecFaultingInstructionInVMM(vm);
521
522     leave:
523   //
524   //PanicUnhandledVMExit(vmcs,regs);
525   //VMXPanic();
526   return 0;
527 }
528
529
530 static struct VM *FindVM()
531 {
532   return &theVM;
533 }
534
535
536 int Do_VMM(struct VMXRegs regs) 
537 {
538
539   ullong_t vmcs_ptr = 0;
540   uint_t vmcs_ptr_low = 0;
541   int ret = 0;
542   uint_t vmx_abort = 0;
543
544
545   
546   SerialPrintLevel(100,"Vm Exit\n");
547   ret = VMCS_STORE(&vmcs_ptr);
548   vmcs_ptr &= 0xffffffff;
549   vmcs_ptr_low +=  vmcs_ptr;
550
551
552
553
554   SerialPrintLevel(100,"ret=%d\n", ret);
555   SerialPrintLevel(100,"Revision: %x\n", *(uint_t *)(vmcs_ptr_low));
556   vmx_abort = *(uint_t*)(((char *)vmcs_ptr_low)+4);
557     
558   struct VM *vm = FindVM();
559
560   if (vmx_abort != 0) {
561     SerialPrintLevel(1000,"VM ABORTED w/ code: %x\n", vmx_abort);
562     return -1;
563   }
564
565   vm->registers = regs;
566
567   if (CopyOutVMCSData(&(vm->vmcs)) != 0) {
568     SerialPrintLevel(1000,"Could not copy out VMCS\n");
569     return -1;
570   }
571
572
573   SerialPrint("Guest esp: 0x%x (%u)\n", vm->vmcs.guestStateArea.rsp, vm->vmcs.guestStateArea.rsp);
574
575   SerialPrintLevel(100,"VM Exit for reason: %d (%x)\n", 
576               vm->vmcs.exitInfoFields.reason & 0x00000fff,
577               vm->vmcs.exitInfoFields.reason);  
578
579   if (vm->vmcs.exitInfoFields.reason & (0x1<<29) ) { 
580     SerialPrintLevel(1000,"VM Exit is from VMX root operation.  Panicking\n");
581     VMXPanic();
582   }
583
584   if (vm->vmcs.exitInfoFields.reason & (0x1<<31) ) { 
585     SerialPrintLevel(1000,"VM Exit is due to a VM entry failure.  Shouldn't happen here. Panicking\n");
586     SerialPrint_VMCSData(&(vm->vmcs));
587     VMXPanic();
588   }
589
590   switch (vm->vmcs.exitInfoFields.reason) {
591   case VM_EXIT_REASON_INFO_EXCEPTION_OR_NMI:
592     ret = HandleExceptionOrNMI(vm);
593     break;
594   case VM_EXIT_REASON_EXTERNAL_INTR:
595     ret = HandleExternalIRQExit(vm);
596     break;
597   case VM_EXIT_REASON_TRIPLE_FAULT:
598     ret = PanicUnhandledVMExit(vm);
599     break;
600   case VM_EXIT_REASON_INIT_SIGNAL:
601     ret = PanicUnhandledVMExit(vm);
602     break;
603   case VM_EXIT_REASON_STARTUP_IPI:
604     ret = PanicUnhandledVMExit(vm);
605     break;
606   case VM_EXIT_REASON_IO_SMI:
607     ret = PanicUnhandledVMExit(vm);
608     break;
609   case VM_EXIT_REASON_OTHER_SMI:
610     ret = PanicUnhandledVMExit(vm);
611     break;
612   case VM_EXIT_REASON_INTR_WINDOW:
613     ret = PanicUnhandledVMExit(vm);
614     break;
615   case VM_EXIT_REASON_NMI_WINDOW:
616     ret = PanicUnhandledVMExit(vm);
617     break;
618   case VM_EXIT_REASON_TASK_SWITCH:
619     ret = PanicUnhandledVMExit(vm);
620     break;
621   case VM_EXIT_REASON_CPUID:
622     ret = PanicUnhandledVMExit(vm);
623     break;
624   case VM_EXIT_REASON_INVD:
625     ret = PanicUnhandledVMExit(vm);
626     break;
627   case VM_EXIT_REASON_INVLPG:
628     ret = PanicUnhandledVMExit(vm);
629     break;
630   case VM_EXIT_REASON_RDPMC:
631     ret = PanicUnhandledVMExit(vm);
632     break;
633   case VM_EXIT_REASON_RDTSC:
634     ret = PanicUnhandledVMExit(vm);
635     break;
636   case VM_EXIT_REASON_RSM:
637     ret = PanicUnhandledVMExit(vm);
638     break;
639   case VM_EXIT_REASON_VMCALL:
640     ret = PanicUnhandledVMExit(vm);
641     break;
642   case VM_EXIT_REASON_VMCLEAR:
643     ret = PanicUnhandledVMExit(vm);
644     break;
645   case VM_EXIT_REASON_VMLAUNCH:
646     ret = PanicUnhandledVMExit(vm);
647     break;
648   case VM_EXIT_REASON_VMPTRLD:
649     ret = PanicUnhandledVMExit(vm);
650     break;
651   case VM_EXIT_REASON_VMPTRST:
652     ret = PanicUnhandledVMExit(vm);
653     break;
654   case VM_EXIT_REASON_VMREAD:
655     ret = PanicUnhandledVMExit(vm);
656     break;
657   case VM_EXIT_REASON_VMRESUME:
658     ret = PanicUnhandledVMExit(vm);
659     break;
660   case VM_EXIT_REASON_VMWRITE:
661     ret = PanicUnhandledVMExit(vm);
662     break;
663   case VM_EXIT_REASON_VMXOFF:
664     ret = PanicUnhandledVMExit(vm);
665     break;
666   case VM_EXIT_REASON_VMXON:
667     ret = PanicUnhandledVMExit(vm);
668     break;
669   case VM_EXIT_REASON_CR_REG_ACCESSES:
670     ret = PanicUnhandledVMExit(vm);
671     break;
672   case VM_EXIT_REASON_MOV_DR:
673     ret = PanicUnhandledVMExit(vm);
674     break;
675   case VM_EXIT_REASON_IO_INSTR:
676     ret = HandleInOutExit(vm);
677     break;
678   case VM_EXIT_REASON_RDMSR:
679     ret = PanicUnhandledVMExit(vm);
680     break;
681   case VM_EXIT_REASON_WRMSR:
682     ret = PanicUnhandledVMExit(vm);
683     break;
684   case VM_EXIT_REASON_ENTRY_FAIL_INVALID_GUEST_STATE:
685     ret = PanicUnhandledVMExit(vm);
686     break;
687   case VM_EXIT_REASON_ENTRY_FAIL_MSR_LOAD:
688     ret = PanicUnhandledVMExit(vm);
689     break;
690   case VM_EXIT_REASON_MWAIT:
691     ret = PanicUnhandledVMExit(vm);
692     break;
693   case VM_EXIT_REASON_MONITOR:
694     ret = PanicUnhandledVMExit(vm);
695     break;
696   case VM_EXIT_REASON_PAUSE:
697     ret = PanicUnhandledVMExit(vm);
698     break;
699   case VM_EXIT_REASON_ENTRY_FAILURE_MACHINE_CHECK:
700     ret = PanicUnhandledVMExit(vm);
701     break;
702   case VM_EXIT_REASON_TPR_BELOW_THRESHOLD:
703     ret = PanicUnhandledVMExit(vm);
704     break;
705   default:
706     ret = PanicUnhandledVMExit(vm);
707     break;
708   }
709   
710   
711   regs = vm->registers;
712   CopyInVMCSData(&(vm->vmcs));
713
714   /*
715     {
716     VMCS_CLEAR(vmcs_ptr);
717     }
718   */
719
720   SerialPrintLevel(100,"Returning from Do_VMM: %d\n", ret);
721  
722   return ret;
723 }
724
725
726 static void ConfigureExits(struct VM *vm)
727 {
728   CopyOutVMCSExecCtrlFields(&(vm->vmcs.execCtrlFields));
729
730   vm->vmcs.execCtrlFields.pinCtrls |= 0 
731     // EXTERNAL_INTERRUPT_EXITING 
732     | NMI_EXITING;
733   vm->vmcs.execCtrlFields.procCtrls |= 0
734     // INTERRUPT_WINDOWS_EXIT 
735     | USE_TSC_OFFSETTING
736     | HLT_EXITING  
737     |INVLPG_EXITING           
738     |MWAIT_EXITING            
739     |RDPMC_EXITING           
740     |RDTSC_EXITING         
741     |MOVDR_EXITING         
742     |UNCONDITION_IO_EXITING
743     |MONITOR_EXITING       
744     |PAUSE_EXITING         ;
745
746   CopyInVMCSExecCtrlFields(&(vm->vmcs.execCtrlFields));
747   
748   CopyOutVMCSExitCtrlFields(&(vm->vmcs.exitCtrlFields));
749
750   vm->vmcs.exitCtrlFields.exitCtrls |= ACK_IRQ_ON_EXIT;
751   
752   CopyInVMCSExitCtrlFields(&(vm->vmcs.exitCtrlFields));
753
754
755 /*   VMCS_READ(VM_EXIT_CTRLS, &flags); */
756 /*   flags |= ACK_IRQ_ON_EXIT; */
757 /*   VMCS_WRITE(VM_EXIT_CTRLS, &flags); */
758 }
759
760
761 extern int RunVMM();
762 extern int SAFE_VM_LAUNCH();
763
764 int MyLaunch(struct VM *vm)
765 {
766   ullong_t vmcs = (ullong_t)((uint_t) (vm->vmcsregion));
767   uint_t entry_eip = vm->descriptor.entry_ip;
768   uint_t exit_eip = vm->descriptor.exit_eip;
769   uint_t guest_esp = vm->descriptor.guest_esp;
770   uint_t f = 0xffffffff;
771   uint_t tmpReg = 0;
772   int ret;
773   int vmm_ret = 0;
774
775   SerialPrint("Guest ESP: 0x%x (%u)\n", guest_esp, guest_esp);
776
777   exit_eip=(uint_t)RunVMM;
778
779   SerialPrintLevel(100,"Clear\n");
780   VMCS_CLEAR(vmcs);
781   SerialPrintLevel(100,"Load\n");
782   VMCS_LOAD(vmcs);
783
784
785   SerialPrintLevel(100,"VMCS_LINK_PTR\n");
786   VMCS_WRITE(VMCS_LINK_PTR, &f);
787   SerialPrintLevel(100,"VMCS_LINK_PTR_HIGH\n");
788   VMCS_WRITE(VMCS_LINK_PTR_HIGH, &f);
789
790  
791   SetCtrlBitsCorrectly(IA32_VMX_PINBASED_CTLS_MSR, PIN_VM_EXEC_CTRLS);
792   SetCtrlBitsCorrectly(IA32_VMX_PROCBASED_CTLS_MSR, PROC_VM_EXEC_CTRLS);
793   SetCtrlBitsCorrectly(IA32_VMX_EXIT_CTLS_MSR, VM_EXIT_CTRLS);
794   SetCtrlBitsCorrectly(IA32_VMX_ENTRY_CTLS_MSR, VM_ENTRY_CTRLS);
795
796   //
797   //
798   //SetCtrlBitsCorrectly(IA32_something,GUEST_IA32_DEBUGCTL);
799   //SetCtrlBitsCorrectly(IA32_something,GUEST_IA32_DEBUGCTL_HIGH);
800
801
802   /* Host state */
803   SerialPrintLevel(100,"Setting up host state\n");
804   SetCRBitsCorrectly(IA32_VMX_CR0_FIXED0_MSR, IA32_VMX_CR0_FIXED1_MSR, HOST_CR0);
805   SetCRBitsCorrectly(IA32_VMX_CR4_FIXED0_MSR, IA32_VMX_CR4_FIXED1_MSR, HOST_CR4);
806   ret = Init_VMCS_HostState();
807
808   if (ret != VMX_SUCCESS) {
809     if (ret == VMX_FAIL_VALID) {
810       SerialPrintLevel(100,"Init Host state: VMCS FAILED WITH ERROR\n");
811     } else {
812       SerialPrintLevel(100,"Init Host state: Invalid VMCS\n");
813     }
814     return ret;
815   }
816
817   //  SerialPrintLevel(100,"HOST_RIP: %x (%u)\n", exit_eip, exit_eip);
818   VMCS_WRITE(HOST_RIP, &exit_eip);
819
820   /* Guest state */
821   SerialPrintLevel(100,"Setting up guest state\n");
822   SerialPrintLevel(100,"GUEST_RIP: %x (%u)\n", entry_eip, entry_eip);
823   VMCS_WRITE(GUEST_RIP,&entry_eip);
824
825   SetCRBitsCorrectly(IA32_VMX_CR0_FIXED0_MSR, IA32_VMX_CR0_FIXED1_MSR, GUEST_CR0);
826   SetCRBitsCorrectly(IA32_VMX_CR4_FIXED0_MSR, IA32_VMX_CR4_FIXED1_MSR, GUEST_CR4);
827   ret = Init_VMCS_GuestState();
828
829   SerialPrintLevel(100,"InitGuestState returned\n");
830   if (ret != VMX_SUCCESS) {
831     if (ret == VMX_FAIL_VALID) {
832       SerialPrintLevel(100,"Init Guest state: VMCS FAILED WITH ERROR\n");
833     } else {
834       SerialPrintLevel(100,"Init Guest state: Invalid VMCS\n");
835     }
836     return ret;
837   }
838   SerialPrintLevel(100,"GUEST_RSP: %x (%u)\n", guest_esp, (uint_t)guest_esp);
839   VMCS_WRITE(GUEST_RSP,&guest_esp);
840
841   //  tmpReg = 0x4100;
842   tmpReg = 0xffffffff;
843   if (VMCS_WRITE(EXCEPTION_BITMAP,&tmpReg ) != VMX_SUCCESS) {
844     Print("Bitmap error\n");
845   }
846
847   ConfigureExits(vm);
848
849   SerialPrintLevel(100,"VMCS_LAUNCH\n");
850
851   vm->state=VM_VMXASSIST_STARTUP;
852
853   vmm_ret = SAFE_VM_LAUNCH();
854
855   SerialPrintLevel(100,"VMM error %d\n", vmm_ret);
856
857   return vmm_ret;
858 }
859
860
861
862   
863 int VMLaunch(struct VMDescriptor *vm) 
864 {
865   VMCS * vmcs = CreateVMCS();
866   int rc;
867
868   ullong_t vmcs_ptr = (ullong_t)((uint_t)vmcs);
869   uint_t top = (vmcs_ptr>>32)&0xffffffff;
870   uint_t bottom = (vmcs_ptr)&0xffffffff;
871
872   theVM.vmcsregion = vmcs;
873   theVM.descriptor = *vm;
874
875   SerialPrintLevel(100,"vmcs_ptr_top=%x vmcs_ptr_bottom=%x, eip=%x\n", top, bottom, vm->entry_ip);
876   rc=MyLaunch(&theVM); // vmcs_ptr, vm->entry_ip, vm->exit_eip, vm->guest_esp);
877   SerialPrintLevel(100,"Returned from MyLaunch();\n");
878   return rc;
879 }
880
881
882 VmxOnRegion * CreateVmxOnRegion() {
883   union VMX_MSR basicMSR;
884   VmxOnRegion * region = (VmxOnRegion *)Alloc_Page();
885
886   Get_MSR(IA32_VMX_BASIC_MSR, &basicMSR.regs.high, &basicMSR.regs.low);
887   //  memcpy(region, &basicMSR.vmxBasic.revision, sizeof(uint_t));
888
889   *(ulong_t*)region = basicMSR.vmxBasic.revision;
890
891   Print("VMX revision: 0x%lu\n", *(ulong_t *)region);
892
893   return region;
894 }
895
896 VMCS * CreateVMCS() {
897   union VMX_MSR basicMSR;
898   VMCS * vmcs = (VMCS *)Alloc_Page();
899
900   Get_MSR(IA32_VMX_BASIC_MSR, &basicMSR.regs.high, &basicMSR.regs.low);
901   *(ulong_t *)vmcs = basicMSR.vmxBasic.revision;
902   *(ulong_t *)((char*)vmcs + 4) = 0;
903
904   SerialPrintLevel(100,"VMCS Region size: %u\n", basicMSR.vmxBasic.regionSize);
905   SerialPrintLevel(100,"VMCS Abort: %x\n",*(uint_t *)(((char*)vmcs)+4));
906
907   return vmcs;
908 }