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.


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