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.


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