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.


2bfdf1aa610c8b80906fd1c43ad56d15f99eb6ff
[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 * Init_VMX() {
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
544
545   SerialPrintLevel(100,"ret=%d\n", ret);
546   SerialPrintLevel(100,"Revision: %x\n", *(uint_t *)(vmcs_ptr_low));
547   vmx_abort = *(uint_t*)(((char *)vmcs_ptr_low)+4);
548     
549   struct VM *vm = FindVM();
550
551   if (vmx_abort != 0) {
552     SerialPrintLevel(1000,"VM ABORTED w/ code: %x\n", vmx_abort);
553     return -1;
554   }
555
556   vm->registers = regs;
557
558   if (CopyOutVMCSData(&(vm->vmcs)) != 0) {
559     SerialPrintLevel(1000,"Could not copy out VMCS\n");
560     return -1;
561   }
562
563
564   SerialPrint("Guest esp: 0x%x (%u)\n", vm->vmcs.guestStateArea.rsp, vm->vmcs.guestStateArea.rsp);
565
566   SerialPrintLevel(100,"VM Exit for reason: %d (%x)\n", 
567               vm->vmcs.exitInfoFields.reason & 0x00000fff,
568               vm->vmcs.exitInfoFields.reason);  
569
570   if (vm->vmcs.exitInfoFields.reason & (0x1<<29) ) { 
571     SerialPrintLevel(1000,"VM Exit is from VMX root operation.  Panicking\n");
572     VMXPanic();
573   }
574
575   if (vm->vmcs.exitInfoFields.reason & (0x1<<31) ) { 
576     SerialPrintLevel(1000,"VM Exit is due to a VM entry failure.  Shouldn't happen here. Panicking\n");
577     SerialPrint_VMCSData(&(vm->vmcs));
578     VMXPanic();
579   }
580
581   switch (vm->vmcs.exitInfoFields.reason) {
582   case VM_EXIT_REASON_INFO_EXCEPTION_OR_NMI:
583     ret = HandleExceptionOrNMI(vm);
584     break;
585   case VM_EXIT_REASON_EXTERNAL_INTR:
586     ret = HandleExternalIRQExit(vm);
587     break;
588   case VM_EXIT_REASON_TRIPLE_FAULT:
589     ret = PanicUnhandledVMExit(vm);
590     break;
591   case VM_EXIT_REASON_INIT_SIGNAL:
592     ret = PanicUnhandledVMExit(vm);
593     break;
594   case VM_EXIT_REASON_STARTUP_IPI:
595     ret = PanicUnhandledVMExit(vm);
596     break;
597   case VM_EXIT_REASON_IO_SMI:
598     ret = PanicUnhandledVMExit(vm);
599     break;
600   case VM_EXIT_REASON_OTHER_SMI:
601     ret = PanicUnhandledVMExit(vm);
602     break;
603   case VM_EXIT_REASON_INTR_WINDOW:
604     ret = PanicUnhandledVMExit(vm);
605     break;
606   case VM_EXIT_REASON_NMI_WINDOW:
607     ret = PanicUnhandledVMExit(vm);
608     break;
609   case VM_EXIT_REASON_TASK_SWITCH:
610     ret = PanicUnhandledVMExit(vm);
611     break;
612   case VM_EXIT_REASON_CPUID:
613     ret = PanicUnhandledVMExit(vm);
614     break;
615   case VM_EXIT_REASON_INVD:
616     ret = PanicUnhandledVMExit(vm);
617     break;
618   case VM_EXIT_REASON_INVLPG:
619     ret = PanicUnhandledVMExit(vm);
620     break;
621   case VM_EXIT_REASON_RDPMC:
622     ret = PanicUnhandledVMExit(vm);
623     break;
624   case VM_EXIT_REASON_RDTSC:
625     ret = PanicUnhandledVMExit(vm);
626     break;
627   case VM_EXIT_REASON_RSM:
628     ret = PanicUnhandledVMExit(vm);
629     break;
630   case VM_EXIT_REASON_VMCALL:
631     ret = PanicUnhandledVMExit(vm);
632     break;
633   case VM_EXIT_REASON_VMCLEAR:
634     ret = PanicUnhandledVMExit(vm);
635     break;
636   case VM_EXIT_REASON_VMLAUNCH:
637     ret = PanicUnhandledVMExit(vm);
638     break;
639   case VM_EXIT_REASON_VMPTRLD:
640     ret = PanicUnhandledVMExit(vm);
641     break;
642   case VM_EXIT_REASON_VMPTRST:
643     ret = PanicUnhandledVMExit(vm);
644     break;
645   case VM_EXIT_REASON_VMREAD:
646     ret = PanicUnhandledVMExit(vm);
647     break;
648   case VM_EXIT_REASON_VMRESUME:
649     ret = PanicUnhandledVMExit(vm);
650     break;
651   case VM_EXIT_REASON_VMWRITE:
652     ret = PanicUnhandledVMExit(vm);
653     break;
654   case VM_EXIT_REASON_VMXOFF:
655     ret = PanicUnhandledVMExit(vm);
656     break;
657   case VM_EXIT_REASON_VMXON:
658     ret = PanicUnhandledVMExit(vm);
659     break;
660   case VM_EXIT_REASON_CR_REG_ACCESSES:
661     ret = PanicUnhandledVMExit(vm);
662     break;
663   case VM_EXIT_REASON_MOV_DR:
664     ret = PanicUnhandledVMExit(vm);
665     break;
666   case VM_EXIT_REASON_IO_INSTR:
667     ret = HandleInOutExit(vm);
668     break;
669   case VM_EXIT_REASON_RDMSR:
670     ret = PanicUnhandledVMExit(vm);
671     break;
672   case VM_EXIT_REASON_WRMSR:
673     ret = PanicUnhandledVMExit(vm);
674     break;
675   case VM_EXIT_REASON_ENTRY_FAIL_INVALID_GUEST_STATE:
676     ret = PanicUnhandledVMExit(vm);
677     break;
678   case VM_EXIT_REASON_ENTRY_FAIL_MSR_LOAD:
679     ret = PanicUnhandledVMExit(vm);
680     break;
681   case VM_EXIT_REASON_MWAIT:
682     ret = PanicUnhandledVMExit(vm);
683     break;
684   case VM_EXIT_REASON_MONITOR:
685     ret = PanicUnhandledVMExit(vm);
686     break;
687   case VM_EXIT_REASON_PAUSE:
688     ret = PanicUnhandledVMExit(vm);
689     break;
690   case VM_EXIT_REASON_ENTRY_FAILURE_MACHINE_CHECK:
691     ret = PanicUnhandledVMExit(vm);
692     break;
693   case VM_EXIT_REASON_TPR_BELOW_THRESHOLD:
694     ret = PanicUnhandledVMExit(vm);
695     break;
696   default:
697     ret = PanicUnhandledVMExit(vm);
698     break;
699   }
700   
701   
702   regs = vm->registers;
703   CopyInVMCSData(&(vm->vmcs));
704
705   /*
706     {
707     VMCS_CLEAR(vmcs_ptr);
708     }
709   */
710
711   SerialPrintLevel(100,"Returning from Do_VMM: %d\n", ret);
712  
713   return ret;
714 }
715
716
717 static void ConfigureExits(struct VM *vm)
718 {
719   CopyOutVMCSExecCtrlFields(&(vm->vmcs.execCtrlFields));
720
721   vm->vmcs.execCtrlFields.pinCtrls |= 0 
722     // EXTERNAL_INTERRUPT_EXITING 
723     | NMI_EXITING;
724   vm->vmcs.execCtrlFields.procCtrls |= 0
725     // INTERRUPT_WINDOWS_EXIT 
726     | USE_TSC_OFFSETTING
727     | HLT_EXITING  
728     |INVLPG_EXITING           
729     |MWAIT_EXITING            
730     |RDPMC_EXITING           
731     |RDTSC_EXITING         
732     |MOVDR_EXITING         
733     |UNCONDITION_IO_EXITING
734     |MONITOR_EXITING       
735     |PAUSE_EXITING         ;
736
737   CopyInVMCSExecCtrlFields(&(vm->vmcs.execCtrlFields));
738   
739   CopyOutVMCSExitCtrlFields(&(vm->vmcs.exitCtrlFields));
740
741   vm->vmcs.exitCtrlFields.exitCtrls |= ACK_IRQ_ON_EXIT;
742   
743   CopyInVMCSExitCtrlFields(&(vm->vmcs.exitCtrlFields));
744
745
746 /*   VMCS_READ(VM_EXIT_CTRLS, &flags); */
747 /*   flags |= ACK_IRQ_ON_EXIT; */
748 /*   VMCS_WRITE(VM_EXIT_CTRLS, &flags); */
749 }
750
751
752 extern int RunVMM();
753 extern int SAFE_VM_LAUNCH();
754
755 int MyLaunch(struct VM *vm)
756 {
757   ullong_t vmcs = (ullong_t)((uint_t) (vm->vmcsregion));
758   uint_t entry_eip = vm->descriptor.entry_ip;
759   uint_t exit_eip = vm->descriptor.exit_eip;
760   uint_t guest_esp = vm->descriptor.guest_esp;
761   uint_t f = 0xffffffff;
762   uint_t tmpReg = 0;
763   int ret;
764   int vmm_ret = 0;
765
766   SerialPrint("Guest ESP: 0x%x (%u)\n", guest_esp, guest_esp);
767
768   exit_eip=(uint_t)RunVMM;
769
770   SerialPrintLevel(100,"Clear\n");
771   VMCS_CLEAR(vmcs);
772   SerialPrintLevel(100,"Load\n");
773   VMCS_LOAD(vmcs);
774
775
776   SerialPrintLevel(100,"VMCS_LINK_PTR\n");
777   VMCS_WRITE(VMCS_LINK_PTR, &f);
778   SerialPrintLevel(100,"VMCS_LINK_PTR_HIGH\n");
779   VMCS_WRITE(VMCS_LINK_PTR_HIGH, &f);
780
781  
782   SetCtrlBitsCorrectly(IA32_VMX_PINBASED_CTLS_MSR, PIN_VM_EXEC_CTRLS);
783   SetCtrlBitsCorrectly(IA32_VMX_PROCBASED_CTLS_MSR, PROC_VM_EXEC_CTRLS);
784   SetCtrlBitsCorrectly(IA32_VMX_EXIT_CTLS_MSR, VM_EXIT_CTRLS);
785   SetCtrlBitsCorrectly(IA32_VMX_ENTRY_CTLS_MSR, VM_ENTRY_CTRLS);
786
787   //
788   //
789   //SetCtrlBitsCorrectly(IA32_something,GUEST_IA32_DEBUGCTL);
790   //SetCtrlBitsCorrectly(IA32_something,GUEST_IA32_DEBUGCTL_HIGH);
791
792
793   /* Host state */
794   SerialPrintLevel(100,"Setting up host state\n");
795   SetCRBitsCorrectly(IA32_VMX_CR0_FIXED0_MSR, IA32_VMX_CR0_FIXED1_MSR, HOST_CR0);
796   SetCRBitsCorrectly(IA32_VMX_CR4_FIXED0_MSR, IA32_VMX_CR4_FIXED1_MSR, HOST_CR4);
797   ret = Init_VMCS_HostState();
798
799   if (ret != VMX_SUCCESS) {
800     if (ret == VMX_FAIL_VALID) {
801       SerialPrintLevel(100,"Init Host state: VMCS FAILED WITH ERROR\n");
802     } else {
803       SerialPrintLevel(100,"Init Host state: Invalid VMCS\n");
804     }
805     return ret;
806   }
807
808   //  SerialPrintLevel(100,"HOST_RIP: %x (%u)\n", exit_eip, exit_eip);
809   VMCS_WRITE(HOST_RIP, &exit_eip);
810
811   /* Guest state */
812   SerialPrintLevel(100,"Setting up guest state\n");
813   SerialPrintLevel(100,"GUEST_RIP: %x (%u)\n", entry_eip, entry_eip);
814   VMCS_WRITE(GUEST_RIP,&entry_eip);
815
816   SetCRBitsCorrectly(IA32_VMX_CR0_FIXED0_MSR, IA32_VMX_CR0_FIXED1_MSR, GUEST_CR0);
817   SetCRBitsCorrectly(IA32_VMX_CR4_FIXED0_MSR, IA32_VMX_CR4_FIXED1_MSR, GUEST_CR4);
818   ret = Init_VMCS_GuestState();
819
820   SerialPrintLevel(100,"InitGuestState returned\n");
821   if (ret != VMX_SUCCESS) {
822     if (ret == VMX_FAIL_VALID) {
823       SerialPrintLevel(100,"Init Guest state: VMCS FAILED WITH ERROR\n");
824     } else {
825       SerialPrintLevel(100,"Init Guest state: Invalid VMCS\n");
826     }
827     return ret;
828   }
829   SerialPrintLevel(100,"GUEST_RSP: %x (%u)\n", guest_esp, (uint_t)guest_esp);
830   VMCS_WRITE(GUEST_RSP,&guest_esp);
831
832   //  tmpReg = 0x4100;
833   tmpReg = 0xffffffff;
834   if (VMCS_WRITE(EXCEPTION_BITMAP,&tmpReg ) != VMX_SUCCESS) {
835     Print("Bitmap error\n");
836   }
837
838   ConfigureExits(vm);
839
840   SerialPrintLevel(100,"VMCS_LAUNCH\n");
841
842   vm->state=VM_VMXASSIST_STARTUP;
843
844   vmm_ret = SAFE_VM_LAUNCH();
845
846   SerialPrintLevel(100,"VMM error %d\n", vmm_ret);
847
848   return vmm_ret;
849 }
850
851
852
853   
854 int VMLaunch(struct VMDescriptor *vm) 
855 {
856   VMCS * vmcs = CreateVMCS();
857   int rc;
858
859   ullong_t vmcs_ptr = (ullong_t)((uint_t)vmcs);
860   uint_t top = (vmcs_ptr>>32)&0xffffffff;
861   uint_t bottom = (vmcs_ptr)&0xffffffff;
862
863   theVM.vmcsregion = vmcs;
864   theVM.descriptor = *vm;
865
866   SerialPrintLevel(100,"vmcs_ptr_top=%x vmcs_ptr_bottom=%x, eip=%x\n", top, bottom, vm->entry_ip);
867   rc=MyLaunch(&theVM); // vmcs_ptr, vm->entry_ip, vm->exit_eip, vm->guest_esp);
868   SerialPrintLevel(100,"Returned from MyLaunch();\n");
869   return rc;
870 }
871
872
873 VmxOnRegion * CreateVmxOnRegion() {
874   union VMX_MSR basicMSR;
875   VmxOnRegion * region = (VmxOnRegion *)Alloc_Page();
876
877   Get_MSR(IA32_VMX_BASIC_MSR, &basicMSR.regs.high, &basicMSR.regs.low);
878   //  memcpy(region, &basicMSR.vmxBasic.revision, sizeof(uint_t));
879
880   *(ulong_t*)region = basicMSR.vmxBasic.revision;
881
882   Print("VMX revision: 0x%lu\n", *(ulong_t *)region);
883
884   return region;
885 }
886
887 VMCS * CreateVMCS() {
888   union VMX_MSR basicMSR;
889   VMCS * vmcs = (VMCS *)Alloc_Page();
890
891   Get_MSR(IA32_VMX_BASIC_MSR, &basicMSR.regs.high, &basicMSR.regs.low);
892   *(ulong_t *)vmcs = basicMSR.vmxBasic.revision;
893   *(ulong_t *)((char*)vmcs + 4) = 0;
894
895   SerialPrintLevel(100,"VMCS Region size: %u\n", basicMSR.vmxBasic.regionSize);
896   SerialPrintLevel(100,"VMCS Abort: %x\n",*(uint_t *)(((char*)vmcs)+4));
897
898   return vmcs;
899 }