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.


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