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.


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