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