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.


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