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