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.


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