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.


Convert shadow paging to use 32 PAE (SVM)
[palacios.git] / palacios / src / palacios / svm.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, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21
22 #include <palacios/svm.h>
23 #include <palacios/vmm.h>
24
25 #include <palacios/vmcb.h>
26 #include <palacios/vmm_mem.h>
27 #include <palacios/vmm_paging.h>
28 #include <palacios/svm_handler.h>
29
30 #include <palacios/vmm_debug.h>
31 #include <palacios/vm_guest_mem.h>
32
33 #include <palacios/vmm_decoder.h>
34 #include <palacios/vmm_string.h>
35 #include <palacios/vmm_lowlevel.h>
36 #include <palacios/svm_msr.h>
37
38 #include <palacios/vmm_rbtree.h>
39 #include <palacios/vmm_barrier.h>
40 #include <palacios/vmm_debug.h>
41
42 #include <palacios/vmm_perftune.h>
43
44
45 #ifdef V3_CONFIG_CHECKPOINT
46 #include <palacios/vmm_checkpoint.h>
47 #endif
48
49 #include <palacios/vmm_direct_paging.h>
50
51 #include <palacios/vmm_ctrl_regs.h>
52 #include <palacios/svm_io.h>
53
54 #include <palacios/vmm_sprintf.h>
55
56 #ifdef V3_CONFIG_TM_FUNC
57 #include <extensions/trans_mem.h>
58 #endif
59
60 #ifndef V3_CONFIG_DEBUG_SVM
61 #undef PrintDebug
62 #define PrintDebug(fmt, args...)
63 #endif
64
65
66
67 uint32_t v3_last_exit;
68
69 // This is a global pointer to the host's VMCB
70 static addr_t host_vmcbs[V3_CONFIG_MAX_CPUS] = { [0 ... V3_CONFIG_MAX_CPUS - 1] = 0};
71
72
73
74 extern void v3_stgi();
75 extern void v3_clgi();
76 //extern int v3_svm_launch(vmcb_t * vmcb, struct v3_gprs * vm_regs, uint64_t * fs, uint64_t * gs);
77 extern int v3_svm_launch(vmcb_t * vmcb, struct v3_gprs * vm_regs, vmcb_t * host_vmcb);
78
79
80 static vmcb_t * Allocate_VMCB() {
81     vmcb_t * vmcb_page = NULL;
82     addr_t vmcb_pa = (addr_t)V3_AllocPages(1);   // need not be shadow safe, not exposed to guest
83
84     if ((void *)vmcb_pa == NULL) {
85       PrintError(VM_NONE, VCORE_NONE, "Error allocating VMCB\n");
86         return NULL;
87     }
88
89     vmcb_page = (vmcb_t *)V3_VAddr((void *)vmcb_pa);
90
91     memset(vmcb_page, 0, 4096);
92
93     return vmcb_page;
94 }
95
96
97 static int v3_svm_handle_efer_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data)
98 {
99     int status;
100
101     // Call arch-independent handler
102     if ((status = v3_handle_efer_write(core, msr, src, priv_data)) != 0) {
103         return status;
104     }
105
106     // SVM-specific code
107     {
108         // Ensure that hardware visible EFER.SVME bit is set (SVM Enable)
109         struct efer_64 * hw_efer = (struct efer_64 *)&(core->ctrl_regs.efer);
110         hw_efer->svme = 1;
111     }
112
113     return 0;
114 }
115
116
117 static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) {
118     vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
119     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
120     uint_t i;
121
122
123     //
124     ctrl_area->svm_instrs.VMRUN = 1;
125     ctrl_area->svm_instrs.VMMCALL = 1;
126     ctrl_area->svm_instrs.VMLOAD = 1;
127     ctrl_area->svm_instrs.VMSAVE = 1;
128     ctrl_area->svm_instrs.STGI = 1;
129     ctrl_area->svm_instrs.CLGI = 1;
130     ctrl_area->svm_instrs.SKINIT = 1;
131     ctrl_area->svm_instrs.ICEBP = 1;
132     ctrl_area->svm_instrs.WBINVD = 1;
133     ctrl_area->svm_instrs.MONITOR = 1;
134     ctrl_area->svm_instrs.MWAIT_always = 1;
135     ctrl_area->svm_instrs.MWAIT_if_armed = 1;
136     ctrl_area->instrs.INVLPGA = 1;
137     ctrl_area->instrs.CPUID = 1;
138
139     ctrl_area->instrs.HLT = 1;
140
141     /* Set at VMM launch as needed */
142     ctrl_area->instrs.RDTSC = 0;
143     ctrl_area->svm_instrs.RDTSCP = 0;
144
145     // guest_state->cr0 = 0x00000001;    // PE 
146   
147     /*
148       ctrl_area->exceptions.de = 1;
149       ctrl_area->exceptions.df = 1;
150       
151       ctrl_area->exceptions.ts = 1;
152       ctrl_area->exceptions.ss = 1;
153       ctrl_area->exceptions.ac = 1;
154       ctrl_area->exceptions.mc = 1;
155       ctrl_area->exceptions.gp = 1;
156       ctrl_area->exceptions.ud = 1;
157       ctrl_area->exceptions.np = 1;
158       ctrl_area->exceptions.of = 1;
159       
160       ctrl_area->exceptions.nmi = 1;
161     */
162
163 #ifdef V3_CONFIG_TM_FUNC
164     v3_tm_set_excp_intercepts(ctrl_area);
165 #endif
166     
167
168     ctrl_area->instrs.NMI = 1;
169     ctrl_area->instrs.SMI = 0; // allow SMIs to run in guest
170     ctrl_area->instrs.INIT = 1;
171     //    ctrl_area->instrs.PAUSE = 1;
172     ctrl_area->instrs.shutdown_evts = 1;
173
174
175     /* DEBUG FOR RETURN CODE */
176     ctrl_area->exit_code = 1;
177
178
179     /* Setup Guest Machine state */
180
181     core->vm_regs.rsp = 0x00;
182     core->rip = 0xfff0;
183
184     core->vm_regs.rdx = 0x00000f00;
185
186
187     core->cpl = 0;
188
189     core->ctrl_regs.rflags = 0x00000002; // The reserved bit is always 1
190     core->ctrl_regs.cr0 = 0x60010010; // Set the WP flag so the memory hooks work in real-mode
191     core->ctrl_regs.efer |= EFER_MSR_svm_enable;
192
193
194
195
196
197     core->segments.cs.selector = 0xf000;
198     core->segments.cs.limit = 0xffff;
199     core->segments.cs.base = 0x0000000f0000LL;
200
201     // (raw attributes = 0xf3)
202     core->segments.cs.type = 0x3;
203     core->segments.cs.system = 0x1;
204     core->segments.cs.dpl = 0x3;
205     core->segments.cs.present = 1;
206
207
208
209     struct v3_segment * segregs [] = {&(core->segments.ss), &(core->segments.ds), 
210                                       &(core->segments.es), &(core->segments.fs), 
211                                       &(core->segments.gs), NULL};
212
213     for ( i = 0; segregs[i] != NULL; i++) {
214         struct v3_segment * seg = segregs[i];
215         
216         seg->selector = 0x0000;
217         //    seg->base = seg->selector << 4;
218         seg->base = 0x00000000;
219         seg->limit = ~0u;
220
221         // (raw attributes = 0xf3)
222         seg->type = 0x3;
223         seg->system = 0x1;
224         seg->dpl = 0x3;
225         seg->present = 1;
226     }
227
228     core->segments.gdtr.limit = 0x0000ffff;
229     core->segments.gdtr.base = 0x0000000000000000LL;
230     core->segments.idtr.limit = 0x0000ffff;
231     core->segments.idtr.base = 0x0000000000000000LL;
232
233     core->segments.ldtr.selector = 0x0000;
234     core->segments.ldtr.limit = 0x0000ffff;
235     core->segments.ldtr.base = 0x0000000000000000LL;
236     core->segments.tr.selector = 0x0000;
237     core->segments.tr.limit = 0x0000ffff;
238     core->segments.tr.base = 0x0000000000000000LL;
239
240
241     core->dbg_regs.dr6 = 0x00000000ffff0ff0LL;
242     core->dbg_regs.dr7 = 0x0000000000000400LL;
243
244
245     ctrl_area->IOPM_BASE_PA = (addr_t)V3_PAddr(core->vm_info->io_map.arch_data);
246     ctrl_area->instrs.IOIO_PROT = 1;
247             
248     ctrl_area->MSRPM_BASE_PA = (addr_t)V3_PAddr(core->vm_info->msr_map.arch_data);
249     ctrl_area->instrs.MSR_PROT = 1;   
250
251
252     PrintDebug(core->vm_info, core, "Exiting on interrupts\n");
253     ctrl_area->guest_ctrl.V_INTR_MASKING = 1;
254     ctrl_area->instrs.INTR = 1;
255     // The above also assures the TPR changes (CR8) are only virtual
256
257
258     // However, we need to see TPR writes since they will
259     // affect the virtual apic
260     // we reflect out cr8 to ctrl_regs->apic_tpr
261     ctrl_area->cr_reads.cr8 = 1;
262     ctrl_area->cr_writes.cr8 = 1;
263     // We will do all TPR comparisons in the virtual apic
264     // We also do not want the V_TPR to be able to mask the PIC
265     ctrl_area->guest_ctrl.V_IGN_TPR = 1;
266
267     
268
269     v3_hook_msr(core->vm_info, EFER_MSR, 
270                 &v3_handle_efer_read,
271                 &v3_svm_handle_efer_write, 
272                 core);
273
274     if (core->shdw_pg_mode == SHADOW_PAGING) {
275         PrintDebug(core->vm_info, core, "Creating initial shadow page table\n");
276         
277         /* JRL: This is a performance killer, and a simplistic solution */
278         /* We need to fix this */
279         ctrl_area->TLB_CONTROL = 1;
280         ctrl_area->guest_ASID = 1;
281         
282         
283         if (v3_init_passthrough_pts(core) == -1) {
284             PrintError(core->vm_info, core, "Could not initialize passthrough page tables\n");
285             return ;
286         }
287
288
289         core->shdw_pg_state.guest_cr0 = 0x0000000000000010LL;
290         PrintDebug(core->vm_info, core, "Created\n");
291         
292         core->ctrl_regs.cr0 |= 0x80000000;
293
294         v3_activate_passthrough_pt(core);
295
296         ctrl_area->cr_reads.cr0 = 1;
297         ctrl_area->cr_writes.cr0 = 1;
298         //intercept cr4 read so shadow pager can use PAE independently of guest
299         ctrl_area->cr_reads.cr4 = 1;
300         ctrl_area->cr_writes.cr4 = 1;
301         ctrl_area->cr_reads.cr3 = 1;
302         ctrl_area->cr_writes.cr3 = 1;
303
304
305         ctrl_area->instrs.INVLPG = 1;
306
307         ctrl_area->exceptions.pf = 1;
308
309         guest_state->g_pat = 0x7040600070406ULL;
310
311
312     } else if (core->shdw_pg_mode == NESTED_PAGING) {
313         // Flush the TLB on entries/exits
314         ctrl_area->TLB_CONTROL = 1;
315         ctrl_area->guest_ASID = 1;
316
317         // Enable Nested Paging
318         ctrl_area->NP_ENABLE = 1;
319
320         PrintDebug(core->vm_info, core, "NP_Enable at 0x%p\n", (void *)&(ctrl_area->NP_ENABLE));
321
322         // Set the Nested Page Table pointer
323         if (v3_init_passthrough_pts(core) == -1) {
324             PrintError(core->vm_info, core, "Could not initialize Nested page tables\n");
325             return ;
326         }
327
328         ctrl_area->N_CR3 = core->direct_map_pt;
329
330         guest_state->g_pat = 0x7040600070406ULL;
331     }
332     
333     /* tell the guest that we don't support SVM */
334     v3_hook_msr(core->vm_info, SVM_VM_CR_MSR, 
335         &v3_handle_vm_cr_read,
336         &v3_handle_vm_cr_write, 
337         core);
338
339
340     {
341 #define INT_PENDING_AMD_MSR             0xc0010055
342
343         v3_hook_msr(core->vm_info, IA32_STAR_MSR, NULL, NULL, NULL);
344         v3_hook_msr(core->vm_info, IA32_LSTAR_MSR, NULL, NULL, NULL);
345         v3_hook_msr(core->vm_info, IA32_FMASK_MSR, NULL, NULL, NULL);
346         v3_hook_msr(core->vm_info, IA32_KERN_GS_BASE_MSR, NULL, NULL, NULL);
347         v3_hook_msr(core->vm_info, IA32_CSTAR_MSR, NULL, NULL, NULL);
348
349         v3_hook_msr(core->vm_info, SYSENTER_CS_MSR, NULL, NULL, NULL);
350         v3_hook_msr(core->vm_info, SYSENTER_ESP_MSR, NULL, NULL, NULL);
351         v3_hook_msr(core->vm_info, SYSENTER_EIP_MSR, NULL, NULL, NULL);
352
353
354         v3_hook_msr(core->vm_info, FS_BASE_MSR, NULL, NULL, NULL);
355         v3_hook_msr(core->vm_info, GS_BASE_MSR, NULL, NULL, NULL);
356
357         // Passthrough read operations are ok.
358         v3_hook_msr(core->vm_info, INT_PENDING_AMD_MSR, NULL, v3_msr_unhandled_write, NULL);
359     }
360 }
361
362
363 int v3_init_svm_vmcb(struct guest_info * core, v3_vm_class_t vm_class) {
364
365     PrintDebug(core->vm_info, core, "Allocating VMCB\n");
366     core->vmm_data = (void *)Allocate_VMCB();
367     
368     if (core->vmm_data == NULL) {
369         PrintError(core->vm_info, core, "Could not allocate VMCB, Exiting...\n");
370         return -1;
371     }
372
373     if (vm_class == V3_PC_VM) {
374         PrintDebug(core->vm_info, core, "Initializing VMCB (addr=%p)\n", (void *)core->vmm_data);
375         Init_VMCB_BIOS((vmcb_t*)(core->vmm_data), core);
376     } else {
377         PrintError(core->vm_info, core, "Invalid VM class\n");
378         return -1;
379     }
380
381     core->core_run_state = CORE_STOPPED;
382
383     return 0;
384 }
385
386
387 int v3_deinit_svm_vmcb(struct guest_info * core) {
388     V3_FreePages(V3_PAddr(core->vmm_data), 1);
389     return 0;
390 }
391
392
393 #ifdef V3_CONFIG_CHECKPOINT
394 int v3_svm_save_core(struct guest_info * core, void * ctx){
395
396   vmcb_saved_state_t * guest_area = GET_VMCB_SAVE_STATE_AREA(core->vmm_data); 
397
398   // Special case saves of data we need immediate access to
399   // in some cases
400   V3_CHKPT_SAVE(ctx, "CPL", core->cpl, failout);
401   V3_CHKPT_SAVE(ctx,"STAR", guest_area->star, failout); 
402   V3_CHKPT_SAVE(ctx,"CSTAR", guest_area->cstar, failout); 
403   V3_CHKPT_SAVE(ctx,"LSTAR", guest_area->lstar, failout); 
404   V3_CHKPT_SAVE(ctx,"SFMASK", guest_area->sfmask, failout); 
405   V3_CHKPT_SAVE(ctx,"KERNELGSBASE", guest_area->KernelGsBase, failout); 
406   V3_CHKPT_SAVE(ctx,"SYSENTER_CS", guest_area->sysenter_cs, failout); 
407   V3_CHKPT_SAVE(ctx,"SYSENTER_ESP", guest_area->sysenter_esp, failout); 
408   V3_CHKPT_SAVE(ctx,"SYSENTER_EIP", guest_area->sysenter_eip, failout); 
409   
410 // and then we save the whole enchilada
411   if (v3_chkpt_save(ctx, "VMCB_DATA", PAGE_SIZE, core->vmm_data)) { 
412     PrintError(core->vm_info, core, "Could not save SVM vmcb\n");
413     goto failout;
414   }
415   
416   return 0;
417
418  failout:
419   PrintError(core->vm_info, core, "Failed to save SVM state for core\n");
420   return -1;
421
422 }
423
424 int v3_svm_load_core(struct guest_info * core, void * ctx){
425     
426
427   vmcb_saved_state_t * guest_area = GET_VMCB_SAVE_STATE_AREA(core->vmm_data); 
428
429   // Reload what we special cased, which we will overwrite in a minute
430   V3_CHKPT_LOAD(ctx, "CPL", core->cpl, failout);
431   V3_CHKPT_LOAD(ctx,"STAR", guest_area->star, failout); 
432   V3_CHKPT_LOAD(ctx,"CSTAR", guest_area->cstar, failout); 
433   V3_CHKPT_LOAD(ctx,"LSTAR", guest_area->lstar, failout); 
434   V3_CHKPT_LOAD(ctx,"SFMASK", guest_area->sfmask, failout); 
435   V3_CHKPT_LOAD(ctx,"KERNELGSBASE", guest_area->KernelGsBase, failout); 
436   V3_CHKPT_LOAD(ctx,"SYSENTER_CS", guest_area->sysenter_cs, failout); 
437   V3_CHKPT_LOAD(ctx,"SYSENTER_ESP", guest_area->sysenter_esp, failout); 
438   V3_CHKPT_LOAD(ctx,"SYSENTER_EIP", guest_area->sysenter_eip, failout); 
439   
440   // and then we load the whole enchilada
441   if (v3_chkpt_load(ctx, "VMCB_DATA", PAGE_SIZE, core->vmm_data)) { 
442     PrintError(core->vm_info, core, "Could not load SVM vmcb\n");
443     goto failout;
444   }
445   
446   return 0;
447
448  failout:
449   PrintError(core->vm_info, core, "Failed to save SVM state for core\n");
450   return -1;
451
452 }
453 #endif
454
455 static int update_irq_exit_state(struct guest_info * info) {
456     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
457
458     // Fix for QEMU bug using EVENTINJ as an internal cache
459     guest_ctrl->EVENTINJ.valid = 0;
460
461     if ((info->intr_core_state.irq_pending == 1) && (guest_ctrl->guest_ctrl.V_IRQ == 0)) {
462         
463 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
464         PrintDebug(info->vm_info, info, "INTAK cycle completed for irq %d\n", info->intr_core_state.irq_vector);
465 #endif
466
467         info->intr_core_state.irq_started = 1;
468         info->intr_core_state.irq_pending = 0;
469
470         v3_injecting_intr(info, info->intr_core_state.irq_vector, V3_EXTERNAL_IRQ);
471     }
472
473     if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 0)) {
474 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
475         PrintDebug(info->vm_info, info, "Interrupt %d taken by guest\n", info->intr_core_state.irq_vector);
476 #endif
477
478         // Interrupt was taken fully vectored
479         info->intr_core_state.irq_started = 0;
480
481     } else if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 1)) {
482 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
483         PrintDebug(info->vm_info, info, "EXIT INT INFO is set (vec=%d)\n", guest_ctrl->exit_int_info.vector);
484 #endif
485     }
486
487     return 0;
488 }
489
490
491 static int update_irq_entry_state(struct guest_info * info) {
492     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
493
494
495     if (info->intr_core_state.irq_pending == 0) {
496         guest_ctrl->guest_ctrl.V_IRQ = 0;
497         guest_ctrl->guest_ctrl.V_INTR_VECTOR = 0;
498     }
499     
500     if (v3_excp_pending(info)) {
501         uint_t excp = v3_get_excp_number(info);
502         
503         guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
504         
505         if (info->excp_state.excp_error_code_valid) {
506             guest_ctrl->EVENTINJ.error_code = info->excp_state.excp_error_code;
507             guest_ctrl->EVENTINJ.ev = 1;
508 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
509             PrintDebug(info->vm_info, info, "Injecting exception %d with error code %x\n", excp, guest_ctrl->EVENTINJ.error_code);
510 #endif
511         }
512         
513         guest_ctrl->EVENTINJ.vector = excp;
514         
515         guest_ctrl->EVENTINJ.valid = 1;
516
517 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
518         PrintDebug(info->vm_info, info, "<%d> Injecting Exception %d (CR2=%p) (EIP=%p)\n", 
519                    (int)info->num_exits, 
520                    guest_ctrl->EVENTINJ.vector, 
521                    (void *)(addr_t)info->ctrl_regs.cr2,
522                    (void *)(addr_t)info->rip);
523 #endif
524
525         v3_injecting_excp(info, excp);
526     } else if (info->intr_core_state.irq_started == 1) {
527 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
528         PrintDebug(info->vm_info, info, "IRQ pending from previous injection\n");
529 #endif
530         guest_ctrl->guest_ctrl.V_IRQ = 1;
531         guest_ctrl->guest_ctrl.V_INTR_VECTOR = info->intr_core_state.irq_vector;
532
533         // We ignore the virtual TPR on this injection
534         // TPR/PPR tests have already been done in the APIC.
535         guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
536         guest_ctrl->guest_ctrl.V_INTR_PRIO = info->intr_core_state.irq_vector >> 4 ;  // 0xf;
537
538     } else {
539         switch (v3_intr_pending(info)) {
540             case V3_EXTERNAL_IRQ: {
541                 int irq = v3_get_intr(info); 
542
543                 if (irq<0) {
544                   break;
545                 }
546
547                 guest_ctrl->guest_ctrl.V_IRQ = 1;
548                 guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
549
550                 // We ignore the virtual TPR on this injection
551                 // TPR/PPR tests have already been done in the APIC.
552                 guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
553                 guest_ctrl->guest_ctrl.V_INTR_PRIO = info->intr_core_state.irq_vector >> 4 ;  // 0xf;
554
555 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
556                 PrintDebug(info->vm_info, info, "Injecting Interrupt %d (EIP=%p)\n", 
557                            guest_ctrl->guest_ctrl.V_INTR_VECTOR, 
558                            (void *)(addr_t)info->rip);
559 #endif
560
561                 info->intr_core_state.irq_pending = 1;
562                 info->intr_core_state.irq_vector = irq;
563                 
564                 break;
565             }
566             case V3_NMI:
567                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
568                 break;
569             case V3_SOFTWARE_INTR:
570                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
571
572 #ifdef V3_CONFIG_DEBUG_INTERRUPTS
573                 PrintDebug(info->vm_info, info, "Injecting software interrupt --  type: %d, vector: %d\n", 
574                            SVM_INJECTION_SOFT_INTR, info->intr_core_state.swintr_vector);
575 #endif
576                 guest_ctrl->EVENTINJ.vector = info->intr_core_state.swintr_vector;
577                 guest_ctrl->EVENTINJ.valid = 1;
578             
579                 /* reset swintr state */
580                 info->intr_core_state.swintr_posted = 0;
581                 info->intr_core_state.swintr_vector = 0;
582                 
583                 break;
584             case V3_VIRTUAL_IRQ:
585                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_IRQ;
586                 break;
587
588             case V3_INVALID_INTR:
589             default:
590                 break;
591         }
592         
593     }
594
595     return 0;
596 }
597
598 int 
599 v3_svm_config_tsc_virtualization(struct guest_info * info) {
600     vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
601
602
603     if (info->time_state.flags & VM_TIME_TRAP_RDTSC) {
604         ctrl_area->instrs.RDTSC = 1;
605         ctrl_area->svm_instrs.RDTSCP = 1;
606     } else {
607         ctrl_area->instrs.RDTSC = 0;
608         ctrl_area->svm_instrs.RDTSCP = 0;
609
610         if (info->time_state.flags & VM_TIME_TSC_PASSTHROUGH) {
611                 ctrl_area->TSC_OFFSET = 0;
612         } else {
613                 ctrl_area->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
614         }
615     }
616     return 0;
617 }
618
619 /* 
620  * CAUTION and DANGER!!! 
621  * 
622  * The VMCB CANNOT(!!) be accessed outside of the clgi/stgi calls inside this function
623  * When exectuing a symbiotic call, the VMCB WILL be overwritten, so any dependencies 
624  * on its contents will cause things to break. The contents at the time of the exit WILL 
625  * change before the exit handler is executed.
626  */
627 int v3_svm_enter(struct guest_info * info) {
628     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
629     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); 
630     addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0;
631     uint64_t guest_cycles = 0;
632
633     // Conditionally yield the CPU if the timeslice has expired
634     v3_schedule(info);
635
636     // Update timer devices after being in the VM before doing 
637     // IRQ updates, so that any interrupts they raise get seen 
638     // immediately.
639     v3_advance_time(info, NULL);
640     v3_update_timers(info);
641
642     // disable global interrupts for vm state transition
643     v3_clgi();
644
645     // Synchronize the guest state to the VMCB
646     guest_state->cr0 = info->ctrl_regs.cr0;
647     guest_state->cr2 = info->ctrl_regs.cr2;
648     guest_state->cr3 = info->ctrl_regs.cr3;
649     guest_state->cr4 = info->ctrl_regs.cr4;
650     guest_state->dr6 = info->dbg_regs.dr6;
651     guest_state->dr7 = info->dbg_regs.dr7;
652
653     // CR8 is now updated by read/writes and it contains the APIC TPR
654     // the V_TPR should be just the class part of that.
655     // This update is here just for completeness.  We currently
656     // are ignoring V_TPR on all injections and doing the priority logivc
657     // in the APIC.
658     // guest_ctrl->guest_ctrl.V_TPR = ((info->ctrl_regs.apic_tpr) >> 4) & 0xf;
659
660     //guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
661     // 
662     
663     guest_state->rflags = info->ctrl_regs.rflags;
664     guest_state->efer = info->ctrl_regs.efer;
665     
666     /* Synchronize MSRs */
667     guest_state->star = info->msrs.star;
668     guest_state->lstar = info->msrs.lstar;
669     guest_state->sfmask = info->msrs.sfmask;
670     guest_state->KernelGsBase = info->msrs.kern_gs_base;
671
672     guest_state->cpl = info->cpl;
673
674     v3_set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
675
676     guest_state->rax = info->vm_regs.rax;
677     guest_state->rip = info->rip;
678     guest_state->rsp = info->vm_regs.rsp;
679
680     V3_FP_ENTRY_RESTORE(info);
681
682 #ifdef V3_CONFIG_SYMCALL
683     if (info->sym_core_state.symcall_state.sym_call_active == 0) {
684         update_irq_entry_state(info);
685     }
686 #else 
687     update_irq_entry_state(info);
688 #endif
689
690 #ifdef V3_CONFIG_TM_FUNC
691     v3_tm_check_intr_state(info, guest_ctrl, guest_state);
692 #endif
693
694
695     /* ** */
696
697     /*
698       PrintDebug(info->vm_info, info, "SVM Entry to CS=%p  rip=%p...\n", 
699       (void *)(addr_t)info->segments.cs.base, 
700       (void *)(addr_t)info->rip);
701     */
702
703 #ifdef V3_CONFIG_SYMCALL
704     if (info->sym_core_state.symcall_state.sym_call_active == 1) {
705         if (guest_ctrl->guest_ctrl.V_IRQ == 1) {
706             V3_Print(info->vm_info, info, "!!! Injecting Interrupt during Sym call !!!\n");
707         }
708     }
709 #endif
710
711     v3_svm_config_tsc_virtualization(info);
712
713     //V3_Print(info->vm_info, info, "Calling v3_svm_launch\n");
714     {   
715         uint64_t entry_tsc = 0;
716         uint64_t exit_tsc = 0;
717         
718 #ifdef V3_CONFIG_PWRSTAT_TELEMETRY
719         v3_pwrstat_telemetry_enter(info);
720 #endif
721
722 #ifdef V3_CONFIG_PMU_TELEMETRY
723         v3_pmu_telemetry_enter(info);
724 #endif
725
726
727         rdtscll(entry_tsc);
728
729         v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[V3_Get_CPU()]);
730
731         rdtscll(exit_tsc);
732
733 #ifdef V3_CONFIG_PMU_TELEMETRY
734         v3_pmu_telemetry_exit(info);
735 #endif
736
737 #ifdef V3_CONFIG_PWRSTAT_TELEMETRY
738         v3_pwrstat_telemetry_exit(info);
739 #endif
740
741         guest_cycles = exit_tsc - entry_tsc;
742     }
743
744
745     //V3_Print(info->vm_info, info, "SVM Returned: Exit Code: %x, guest_rip=%lx\n", (uint32_t)(guest_ctrl->exit_code), (unsigned long)guest_state->rip);
746
747     v3_last_exit = (uint32_t)(guest_ctrl->exit_code);
748
749     v3_advance_time(info, &guest_cycles);
750
751     info->num_exits++;
752
753     V3_FP_EXIT_SAVE(info);
754
755     // Save Guest state from VMCB
756     info->rip = guest_state->rip;
757     info->vm_regs.rsp = guest_state->rsp;
758     info->vm_regs.rax = guest_state->rax;
759
760     info->cpl = guest_state->cpl;
761
762     info->ctrl_regs.cr0 = guest_state->cr0;
763     info->ctrl_regs.cr2 = guest_state->cr2;
764     info->ctrl_regs.cr3 = guest_state->cr3;
765     info->ctrl_regs.cr4 = guest_state->cr4;
766     info->dbg_regs.dr6 = guest_state->dr6;
767     info->dbg_regs.dr7 = guest_state->dr7;
768     //
769     // We do not track this anymore
770     // V_TPR is ignored and we do the logic in the APIC
771     //info->ctrl_regs.cr8 = guest_ctrl->guest_ctrl.V_TPR;
772     //
773     info->ctrl_regs.rflags = guest_state->rflags;
774     info->ctrl_regs.efer = guest_state->efer;
775     
776     /* Synchronize MSRs */
777     info->msrs.star =  guest_state->star;
778     info->msrs.lstar = guest_state->lstar;
779     info->msrs.sfmask = guest_state->sfmask;
780     info->msrs.kern_gs_base = guest_state->KernelGsBase;
781
782     v3_get_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
783     info->cpu_mode = v3_get_vm_cpu_mode(info);
784     info->mem_mode = v3_get_vm_mem_mode(info);
785     /* ** */
786
787     // save exit info here
788     exit_code = guest_ctrl->exit_code;
789     exit_info1 = guest_ctrl->exit_info1;
790     exit_info2 = guest_ctrl->exit_info2;
791
792 #ifdef V3_CONFIG_SYMCALL
793     if (info->sym_core_state.symcall_state.sym_call_active == 0) {
794         update_irq_exit_state(info);
795     }
796 #else
797     update_irq_exit_state(info);
798 #endif
799
800     // reenable global interrupts after vm exit
801     v3_stgi();
802  
803     // Conditionally yield the CPU if the timeslice has expired
804     v3_schedule(info);
805
806     // This update timers is for time-dependent handlers
807     // if we're slaved to host time
808     v3_advance_time(info, NULL);
809     v3_update_timers(info);
810
811     {
812         int ret = v3_handle_svm_exit(info, exit_code, exit_info1, exit_info2);
813         
814         if (ret != 0) {
815             PrintError(info->vm_info, info, "Error in SVM exit handler (ret=%d)\n", ret);
816             PrintError(info->vm_info, info, "  last Exit was %d (exit code=0x%llx)\n", v3_last_exit, (uint64_t) exit_code);
817             return -1;
818         }
819     }
820
821     if (info->timeouts.timeout_active) {
822         /* Check to see if any timeouts have expired */
823         v3_handle_timeouts(info, guest_cycles);
824     }
825
826
827     return 0;
828 }
829
830
831 int v3_start_svm_guest(struct guest_info * info) {
832     //    vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
833     //  vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
834
835     PrintDebug(info->vm_info, info, "Starting SVM core %u (on logical core %u)\n", info->vcpu_id, info->pcpu_id);
836
837     while (1) {
838
839         if (info->core_run_state == CORE_STOPPED) {
840
841             if (info->vcpu_id == 0) {
842                 info->core_run_state = CORE_RUNNING;
843             } else  { 
844                 PrintDebug(info->vm_info, info, "SVM core %u (on %u): Waiting for core initialization\n", info->vcpu_id, info->pcpu_id);
845
846                 V3_NO_WORK(info);
847
848                 while (info->core_run_state == CORE_STOPPED) {
849                     
850                     if (info->vm_info->run_state == VM_STOPPED) {
851                         // The VM was stopped before this core was initialized. 
852                         return 0;
853                     }
854                     
855                     V3_STILL_NO_WORK(info);
856
857                     //PrintDebug(info->vm_info, info, "SVM core %u: still waiting for INIT\n", info->vcpu_id);
858                 }
859
860                 V3_HAVE_WORK_AGAIN(info);
861                 
862                 PrintDebug(info->vm_info, info, "SVM core %u(on %u) initialized\n", info->vcpu_id, info->pcpu_id);
863                 
864                 // We'll be paranoid about race conditions here
865                 v3_wait_at_barrier(info);
866             } 
867             
868             PrintDebug(info->vm_info, info, "SVM core %u(on %u): I am starting at CS=0x%x (base=0x%p, limit=0x%x),  RIP=0x%p\n", 
869                        info->vcpu_id, info->pcpu_id, 
870                        info->segments.cs.selector, (void *)(info->segments.cs.base), 
871                        info->segments.cs.limit, (void *)(info->rip));
872             
873             
874             
875             PrintDebug(info->vm_info, info, "SVM core %u: Launching SVM VM (vmcb=%p) (on cpu %u)\n", 
876                        info->vcpu_id, (void *)info->vmm_data, info->pcpu_id);
877             //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
878             
879             v3_start_time(info);
880         }
881         
882         if (info->vm_info->run_state == VM_STOPPED) {
883             info->core_run_state = CORE_STOPPED;
884             break;
885         }
886         
887
888 #ifdef V3_CONFIG_PMU_TELEMETRY
889         v3_pmu_telemetry_start(info);
890 #endif
891         
892 #ifdef V3_CONFIG_PWRSTAT_TELEMETRY
893         v3_pwrstat_telemetry_start(info);
894 #endif
895         
896         if (v3_svm_enter(info) == -1) {
897             vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
898             addr_t host_addr;
899             addr_t linear_addr = 0;
900             
901             info->vm_info->run_state = VM_ERROR;
902             
903             V3_Print(info->vm_info, info, "SVM core %u: SVM ERROR!!\n", info->vcpu_id); 
904             
905             v3_print_guest_state(info);
906             
907             V3_Print(info->vm_info, info, "SVM core %u: SVM Exit Code: %p\n", info->vcpu_id, (void *)(addr_t)guest_ctrl->exit_code); 
908             
909             V3_Print(info->vm_info, info, "SVM core %u: exit_info1 low = 0x%.8x\n", info->vcpu_id, *(uint_t*)&(guest_ctrl->exit_info1));
910             V3_Print(info->vm_info, info, "SVM core %u: exit_info1 high = 0x%.8x\n", info->vcpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
911             
912             V3_Print(info->vm_info, info, "SVM core %u: exit_info2 low = 0x%.8x\n", info->vcpu_id, *(uint_t*)&(guest_ctrl->exit_info2));
913             V3_Print(info->vm_info, info, "SVM core %u: exit_info2 high = 0x%.8x\n", info->vcpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
914             
915             linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
916             
917             if (info->mem_mode == PHYSICAL_MEM) {
918                 v3_gpa_to_hva(info, linear_addr, &host_addr);
919             } else if (info->mem_mode == VIRTUAL_MEM) {
920                 v3_gva_to_hva(info, linear_addr, &host_addr);
921             }
922             
923             V3_Print(info->vm_info, info, "SVM core %u: Host Address of rip = 0x%p\n", info->vcpu_id, (void *)host_addr);
924             
925             V3_Print(info->vm_info, info, "SVM core %u: Instr (15 bytes) at %p:\n", info->vcpu_id, (void *)host_addr);
926             v3_dump_mem((uint8_t *)host_addr, 15);
927             
928             v3_print_stack(info);
929             
930             break;
931         }
932         
933         v3_wait_at_barrier(info);
934         
935
936         if (info->vm_info->run_state == VM_STOPPED) {
937             info->core_run_state = CORE_STOPPED;
938             break;
939         }
940
941         
942
943 /*
944         if ((info->num_exits % 50000) == 0) {
945             V3_Print(info->vm_info, info, "SVM Exit number %d\n", (uint32_t)info->num_exits);
946             v3_print_guest_state(info);
947         }
948 */
949         
950     }
951
952 #ifdef V3_CONFIG_PMU_TELEMETRY
953     v3_pmu_telemetry_end(info);
954 #endif
955
956 #ifdef V3_CONFIG_PWRSTAT_TELEMETRY
957     v3_pwrstat_telemetry_end(info);
958 #endif
959     // Need to take down the other cores on error... 
960
961     return 0;
962 }
963
964
965
966
967 int v3_reset_svm_vm_core(struct guest_info * core, addr_t rip) {
968     // init vmcb_bios
969
970     // Write the RIP, CS, and descriptor
971     // assume the rest is already good to go
972     //
973     // vector VV -> rip at 0
974     //              CS = VV00
975     //  This means we start executing at linear address VV000
976     //
977     // So the selector needs to be VV00
978     // and the base needs to be VV000
979     //
980     core->rip = 0;
981     core->segments.cs.selector = rip << 8;
982     core->segments.cs.limit = 0xffff;
983     core->segments.cs.base = rip << 12;
984
985     return 0;
986 }
987
988
989
990
991
992
993 /* Checks machine SVM capability */
994 /* Implemented from: AMD Arch Manual 3, sect 15.4 */ 
995 int v3_is_svm_capable() {
996     uint_t vm_cr_low = 0, vm_cr_high = 0;
997     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
998
999     v3_cpuid(CPUID_EXT_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
1000   
1001     PrintDebug(VM_NONE, VCORE_NONE,  "CPUID_EXT_FEATURE_IDS_ecx=0x%x\n", ecx);
1002
1003     if ((ecx & CPUID_EXT_FEATURE_IDS_ecx_svm_avail) == 0) {
1004       V3_Print(VM_NONE, VCORE_NONE,  "SVM Not Available\n");
1005       return 0;
1006     }  else {
1007         v3_get_msr(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
1008         
1009         PrintDebug(VM_NONE, VCORE_NONE, "SVM_VM_CR_MSR = 0x%x 0x%x\n", vm_cr_high, vm_cr_low);
1010         
1011         if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 1) {
1012             V3_Print(VM_NONE, VCORE_NONE, "SVM is available but is disabled.\n");
1013             
1014             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
1015             
1016             PrintDebug(VM_NONE, VCORE_NONE,  "CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
1017             
1018             if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
1019                 V3_Print(VM_NONE, VCORE_NONE,  "SVM BIOS Disabled, not unlockable\n");
1020             } else {
1021                 V3_Print(VM_NONE, VCORE_NONE,  "SVM is locked with a key\n");
1022             }
1023             return 0;
1024
1025         } else {
1026             V3_Print(VM_NONE, VCORE_NONE,  "SVM is available and  enabled.\n");
1027
1028             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
1029             PrintDebug(VM_NONE, VCORE_NONE, "CPUID_SVM_REV_AND_FEATURE_IDS_eax=0x%x\n", eax);
1030             PrintDebug(VM_NONE, VCORE_NONE, "CPUID_SVM_REV_AND_FEATURE_IDS_ebx=0x%x\n", ebx);
1031             PrintDebug(VM_NONE, VCORE_NONE, "CPUID_SVM_REV_AND_FEATURE_IDS_ecx=0x%x\n", ecx);
1032             PrintDebug(VM_NONE, VCORE_NONE, "CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
1033
1034             return 1;
1035         }
1036     }
1037 }
1038
1039 static int has_svm_nested_paging() {
1040     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
1041     
1042     v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
1043     
1044     //PrintDebug(VM_NONE, VCORE_NONE,  "CPUID_EXT_FEATURE_IDS_edx=0x%x\n", edx);
1045     
1046     if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
1047         V3_Print(VM_NONE, VCORE_NONE, "SVM Nested Paging not supported\n");
1048         return 0;
1049     } else {
1050         V3_Print(VM_NONE, VCORE_NONE, "SVM Nested Paging supported\n");
1051         return 1;
1052     }
1053  }
1054  
1055
1056
1057 void v3_init_svm_cpu(int cpu_id) {
1058     reg_ex_t msr;
1059     extern v3_cpu_arch_t v3_cpu_types[];
1060
1061     // Enable SVM on the CPU
1062     v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
1063     msr.e_reg.low |= EFER_MSR_svm_enable;
1064     v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
1065
1066     V3_Print(VM_NONE, VCORE_NONE,  "SVM Enabled\n");
1067
1068     // Setup the host state save area
1069     host_vmcbs[cpu_id] = (addr_t)V3_AllocPages(4); // need not be shadow-safe, not exposed to guest
1070
1071     if (!host_vmcbs[cpu_id]) {
1072         PrintError(VM_NONE, VCORE_NONE,  "Failed to allocate VMCB\n");
1073         return;
1074     }
1075
1076     /* 64-BIT-ISSUE */
1077     //  msr.e_reg.high = 0;
1078     //msr.e_reg.low = (uint_t)host_vmcb;
1079     msr.r_reg = host_vmcbs[cpu_id];
1080
1081     PrintDebug(VM_NONE, VCORE_NONE,  "Host State being saved at %p\n", (void *)host_vmcbs[cpu_id]);
1082     v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
1083
1084
1085     if (has_svm_nested_paging() == 1) {
1086         v3_cpu_types[cpu_id] = V3_SVM_REV3_CPU;
1087     } else {
1088         v3_cpu_types[cpu_id] = V3_SVM_CPU;
1089     }
1090 }
1091
1092
1093
1094 void v3_deinit_svm_cpu(int cpu_id) {
1095     reg_ex_t msr;
1096     extern v3_cpu_arch_t v3_cpu_types[];
1097
1098     // reset SVM_VM_HSAVE_PA_MSR
1099     // Does setting it to NULL disable??
1100     msr.r_reg = 0;
1101     v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
1102
1103     // Disable SVM?
1104     v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
1105     msr.e_reg.low &= ~EFER_MSR_svm_enable;
1106     v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
1107
1108     v3_cpu_types[cpu_id] = V3_INVALID_CPU;
1109
1110     V3_FreePages((void *)host_vmcbs[cpu_id], 4);
1111
1112     V3_Print(VM_NONE, VCORE_NONE,  "Host CPU %d host area freed, and SVM disabled\n", cpu_id);
1113     return;
1114 }
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165 #if 0
1166 /* 
1167  * Test VMSAVE/VMLOAD Latency 
1168  */
1169 #define vmsave ".byte 0x0F,0x01,0xDB ; "
1170 #define vmload ".byte 0x0F,0x01,0xDA ; "
1171 {
1172     uint32_t start_lo, start_hi;
1173     uint32_t end_lo, end_hi;
1174     uint64_t start, end;
1175     
1176     __asm__ __volatile__ (
1177                           "rdtsc ; "
1178                           "movl %%eax, %%esi ; "
1179                           "movl %%edx, %%edi ; "
1180                           "movq  %%rcx, %%rax ; "
1181                           vmsave
1182                           "rdtsc ; "
1183                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
1184                           : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
1185                           );
1186     
1187     start = start_hi;
1188     start <<= 32;
1189     start += start_lo;
1190     
1191     end = end_hi;
1192     end <<= 32;
1193     end += end_lo;
1194     
1195     PrintDebug(core->vm_info, core, "VMSave Cycle Latency: %d\n", (uint32_t)(end - start));
1196     
1197     __asm__ __volatile__ (
1198                           "rdtsc ; "
1199                           "movl %%eax, %%esi ; "
1200                           "movl %%edx, %%edi ; "
1201                           "movq  %%rcx, %%rax ; "
1202                           vmload
1203                           "rdtsc ; "
1204                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
1205                               : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
1206                               );
1207         
1208         start = start_hi;
1209         start <<= 32;
1210         start += start_lo;
1211
1212         end = end_hi;
1213         end <<= 32;
1214         end += end_lo;
1215
1216
1217         PrintDebug(core->vm_info, core, "VMLoad Cycle Latency: %d\n", (uint32_t)(end - start));
1218     }
1219     /* End Latency Test */
1220
1221 #endif
1222
1223
1224
1225
1226
1227
1228
1229 #if 0
1230 void Init_VMCB_pe(vmcb_t *vmcb, struct guest_info vm_info) {
1231   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
1232   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
1233   uint_t i = 0;
1234
1235
1236   guest_state->rsp = vm_info.vm_regs.rsp;
1237   guest_state->rip = vm_info.rip;
1238
1239
1240   /* I pretty much just gutted this from TVMM */
1241   /* Note: That means its probably wrong */
1242
1243   // set the segment registers to mirror ours
1244   guest_state->cs.selector = 1<<3;
1245   guest_state->cs.attrib.fields.type = 0xa; // Code segment+read
1246   guest_state->cs.attrib.fields.S = 1;
1247   guest_state->cs.attrib.fields.P = 1;
1248   guest_state->cs.attrib.fields.db = 1;
1249   guest_state->cs.attrib.fields.G = 1;
1250   guest_state->cs.limit = 0xfffff;
1251   guest_state->cs.base = 0;
1252   
1253   struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL};
1254   for ( i = 0; segregs[i] != NULL; i++) {
1255     struct vmcb_selector * seg = segregs[i];
1256     
1257     seg->selector = 2<<3;
1258     seg->attrib.fields.type = 0x2; // Data Segment+read/write
1259     seg->attrib.fields.S = 1;
1260     seg->attrib.fields.P = 1;
1261     seg->attrib.fields.db = 1;
1262     seg->attrib.fields.G = 1;
1263     seg->limit = 0xfffff;
1264     seg->base = 0;
1265   }
1266
1267
1268   {
1269     /* JRL THIS HAS TO GO */
1270     
1271     //    guest_state->tr.selector = GetTR_Selector();
1272     guest_state->tr.attrib.fields.type = 0x9; 
1273     guest_state->tr.attrib.fields.P = 1;
1274     // guest_state->tr.limit = GetTR_Limit();
1275     //guest_state->tr.base = GetTR_Base();// - 0x2000;
1276     /* ** */
1277   }
1278
1279
1280   /* ** */
1281
1282
1283   guest_state->efer |= EFER_MSR_svm_enable;
1284   guest_state->rflags = 0x00000002; // The reserved bit is always 1
1285   ctrl_area->svm_instrs.VMRUN = 1;
1286   guest_state->cr0 = 0x00000001;    // PE 
1287   ctrl_area->guest_ASID = 1;
1288
1289
1290   //  guest_state->cpl = 0;
1291
1292
1293
1294   // Setup exits
1295
1296   ctrl_area->cr_writes.cr4 = 1;
1297   
1298   ctrl_area->exceptions.de = 1;
1299   ctrl_area->exceptions.df = 1;
1300   ctrl_area->exceptions.pf = 1;
1301   ctrl_area->exceptions.ts = 1;
1302   ctrl_area->exceptions.ss = 1;
1303   ctrl_area->exceptions.ac = 1;
1304   ctrl_area->exceptions.mc = 1;
1305   ctrl_area->exceptions.gp = 1;
1306   ctrl_area->exceptions.ud = 1;
1307   ctrl_area->exceptions.np = 1;
1308   ctrl_area->exceptions.of = 1;
1309   ctrl_area->exceptions.nmi = 1;
1310
1311   
1312
1313   ctrl_area->instrs.IOIO_PROT = 1;
1314   ctrl_area->IOPM_BASE_PA = (uint_t)V3_AllocPages(3); // need not be shadow-safe, not exposed to guest
1315
1316   if (!ctrl_area->IOPM_BASE_PA) { 
1317       PrintError(core->vm_info, core, "Cannot allocate IO bitmap\n");
1318       return;
1319   }
1320   
1321   {
1322     reg_ex_t tmp_reg;
1323     tmp_reg.r_reg = ctrl_area->IOPM_BASE_PA;
1324     memset((void*)(tmp_reg.e_reg.low), 0xffffffff, PAGE_SIZE * 2);
1325   }
1326
1327   ctrl_area->instrs.INTR = 1;
1328
1329   
1330   {
1331     char gdt_buf[6];
1332     char idt_buf[6];
1333
1334     memset(gdt_buf, 0, 6);
1335     memset(idt_buf, 0, 6);
1336
1337
1338     uint_t gdt_base, idt_base;
1339     ushort_t gdt_limit, idt_limit;
1340     
1341     GetGDTR(gdt_buf);
1342     gdt_base = *(ulong_t*)((uchar_t*)gdt_buf + 2) & 0xffffffff;
1343     gdt_limit = *(ushort_t*)(gdt_buf) & 0xffff;
1344     PrintDebug(core->vm_info, core, "GDT: base: %x, limit: %x\n", gdt_base, gdt_limit);
1345
1346     GetIDTR(idt_buf);
1347     idt_base = *(ulong_t*)(idt_buf + 2) & 0xffffffff;
1348     idt_limit = *(ushort_t*)(idt_buf) & 0xffff;
1349     PrintDebug(core->vm_info, core, "IDT: base: %x, limit: %x\n",idt_base, idt_limit);
1350
1351
1352     // gdt_base -= 0x2000;
1353     //idt_base -= 0x2000;
1354
1355     guest_state->gdtr.base = gdt_base;
1356     guest_state->gdtr.limit = gdt_limit;
1357     guest_state->idtr.base = idt_base;
1358     guest_state->idtr.limit = idt_limit;
1359
1360
1361   }
1362   
1363   
1364   // also determine if CPU supports nested paging
1365   /*
1366   if (vm_info.page_tables) {
1367     //   if (0) {
1368     // Flush the TLB on entries/exits
1369     ctrl_area->TLB_CONTROL = 1;
1370
1371     // Enable Nested Paging
1372     ctrl_area->NP_ENABLE = 1;
1373
1374     PrintDebug(core->vm_info, core, "NP_Enable at 0x%x\n", &(ctrl_area->NP_ENABLE));
1375
1376         // Set the Nested Page Table pointer
1377     ctrl_area->N_CR3 |= ((addr_t)vm_info.page_tables & 0xfffff000);
1378
1379
1380     //   ctrl_area->N_CR3 = Get_CR3();
1381     // guest_state->cr3 |= (Get_CR3() & 0xfffff000);
1382
1383     guest_state->g_pat = 0x7040600070406ULL;
1384
1385     PrintDebug(core->vm_info, core, "Set Nested CR3: lo: 0x%x  hi: 0x%x\n", (uint_t)*(&(ctrl_area->N_CR3)), (uint_t)*((unsigned char *)&(ctrl_area->N_CR3) + 4));
1386     PrintDebug(core->vm_info, core, "Set Guest CR3: lo: 0x%x  hi: 0x%x\n", (uint_t)*(&(guest_state->cr3)), (uint_t)*((unsigned char *)&(guest_state->cr3) + 4));
1387     // Enable Paging
1388     //    guest_state->cr0 |= 0x80000000;
1389   }
1390   */
1391
1392 }
1393
1394
1395
1396
1397
1398 #endif
1399
1400