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.


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