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.


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