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.


Basic HRT startup for HVM, plus assorted cleanup
[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
853 #ifdef V3_CONFIG_HVM
854     if (v3_setup_hvm_hrt_core_for_boot(info)) { 
855         PrintError(info->vm_info, info, "Failed to setup HRT core...\n");
856         return -1;
857     }
858 #endif
859  
860
861             
862
863
864     while (1) {
865
866         if (info->core_run_state == CORE_STOPPED) {
867
868             if (info->vcpu_id == 0) {
869                 info->core_run_state = CORE_RUNNING;
870             } else  { 
871                 PrintDebug(info->vm_info, info, "SVM core %u (on %u): Waiting for core initialization\n", info->vcpu_id, info->pcpu_id);
872
873                 V3_NO_WORK(info);
874
875                 while (info->core_run_state == CORE_STOPPED) {
876                     
877                     if (info->vm_info->run_state == VM_STOPPED) {
878                         // The VM was stopped before this core was initialized. 
879                         return 0;
880                     }
881                     
882                     V3_STILL_NO_WORK(info);
883
884                     //PrintDebug(info->vm_info, info, "SVM core %u: still waiting for INIT\n", info->vcpu_id);
885                 }
886
887                 V3_HAVE_WORK_AGAIN(info);
888                 
889                 PrintDebug(info->vm_info, info, "SVM core %u(on %u) initialized\n", info->vcpu_id, info->pcpu_id);
890                 
891                 // We'll be paranoid about race conditions here
892                 v3_wait_at_barrier(info);
893             } 
894             
895             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", 
896                        info->vcpu_id, info->pcpu_id, 
897                        info->segments.cs.selector, (void *)(info->segments.cs.base), 
898                        info->segments.cs.limit, (void *)(info->rip));
899             
900             
901             
902             PrintDebug(info->vm_info, info, "SVM core %u: Launching SVM VM (vmcb=%p) (on cpu %u)\n", 
903                        info->vcpu_id, (void *)info->vmm_data, info->pcpu_id);
904             //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
905             
906             v3_start_time(info);
907         }
908         
909         if (info->vm_info->run_state == VM_STOPPED) {
910             info->core_run_state = CORE_STOPPED;
911             break;
912         }
913
914 #ifdef V3_CONFIG_PMU_TELEMETRY
915         v3_pmu_telemetry_start(info);
916 #endif
917         
918 #ifdef V3_CONFIG_PWRSTAT_TELEMETRY
919         v3_pwrstat_telemetry_start(info);
920 #endif
921         
922         if (v3_svm_enter(info) == -1) {
923             vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
924             addr_t host_addr;
925             addr_t linear_addr = 0;
926             
927             info->vm_info->run_state = VM_ERROR;
928             
929             V3_Print(info->vm_info, info, "SVM core %u: SVM ERROR!!\n", info->vcpu_id); 
930             
931             v3_print_guest_state(info);
932             
933             V3_Print(info->vm_info, info, "SVM core %u: SVM Exit Code: %p\n", info->vcpu_id, (void *)(addr_t)guest_ctrl->exit_code); 
934             
935             V3_Print(info->vm_info, info, "SVM core %u: exit_info1 low = 0x%.8x\n", info->vcpu_id, *(uint_t*)&(guest_ctrl->exit_info1));
936             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));
937             
938             V3_Print(info->vm_info, info, "SVM core %u: exit_info2 low = 0x%.8x\n", info->vcpu_id, *(uint_t*)&(guest_ctrl->exit_info2));
939             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));
940             
941             linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
942             
943             if (info->mem_mode == PHYSICAL_MEM) {
944                 v3_gpa_to_hva(info, linear_addr, &host_addr);
945             } else if (info->mem_mode == VIRTUAL_MEM) {
946                 v3_gva_to_hva(info, linear_addr, &host_addr);
947             }
948             
949             V3_Print(info->vm_info, info, "SVM core %u: Host Address of rip = 0x%p\n", info->vcpu_id, (void *)host_addr);
950             
951             V3_Print(info->vm_info, info, "SVM core %u: Instr (15 bytes) at %p:\n", info->vcpu_id, (void *)host_addr);
952             v3_dump_mem((uint8_t *)host_addr, 15);
953             
954             v3_print_stack(info);
955             
956             break;
957         }
958         
959         v3_wait_at_barrier(info);
960         
961
962         if (info->vm_info->run_state == VM_STOPPED) {
963             info->core_run_state = CORE_STOPPED;
964             break;
965         }
966
967         
968
969 /*
970         if ((info->num_exits % 50000) == 0) {
971             V3_Print(info->vm_info, info, "SVM Exit number %d\n", (uint32_t)info->num_exits);
972             v3_print_guest_state(info);
973         }
974 */
975         
976     }
977
978 #ifdef V3_CONFIG_PMU_TELEMETRY
979     v3_pmu_telemetry_end(info);
980 #endif
981
982 #ifdef V3_CONFIG_PWRSTAT_TELEMETRY
983     v3_pwrstat_telemetry_end(info);
984 #endif
985     // Need to take down the other cores on error... 
986
987     return 0;
988 }
989
990
991
992
993 int v3_reset_svm_vm_core(struct guest_info * core, addr_t rip) {
994     // init vmcb_bios
995
996     // Write the RIP, CS, and descriptor
997     // assume the rest is already good to go
998     //
999     // vector VV -> rip at 0
1000     //              CS = VV00
1001     //  This means we start executing at linear address VV000
1002     //
1003     // So the selector needs to be VV00
1004     // and the base needs to be VV000
1005     //
1006     core->rip = 0;
1007     core->segments.cs.selector = rip << 8;
1008     core->segments.cs.limit = 0xffff;
1009     core->segments.cs.base = rip << 12;
1010
1011     return 0;
1012 }
1013
1014
1015
1016
1017
1018
1019 /* Checks machine SVM capability */
1020 /* Implemented from: AMD Arch Manual 3, sect 15.4 */ 
1021 int v3_is_svm_capable() {
1022     uint_t vm_cr_low = 0, vm_cr_high = 0;
1023     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
1024
1025     v3_cpuid(CPUID_EXT_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
1026   
1027     PrintDebug(VM_NONE, VCORE_NONE,  "CPUID_EXT_FEATURE_IDS_ecx=0x%x\n", ecx);
1028
1029     if ((ecx & CPUID_EXT_FEATURE_IDS_ecx_svm_avail) == 0) {
1030       V3_Print(VM_NONE, VCORE_NONE,  "SVM Not Available\n");
1031       return 0;
1032     }  else {
1033         v3_get_msr(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
1034         
1035         PrintDebug(VM_NONE, VCORE_NONE, "SVM_VM_CR_MSR = 0x%x 0x%x\n", vm_cr_high, vm_cr_low);
1036         
1037         if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 1) {
1038             V3_Print(VM_NONE, VCORE_NONE, "SVM is available but is disabled.\n");
1039             
1040             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
1041             
1042             PrintDebug(VM_NONE, VCORE_NONE,  "CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
1043             
1044             if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
1045                 V3_Print(VM_NONE, VCORE_NONE,  "SVM BIOS Disabled, not unlockable\n");
1046             } else {
1047                 V3_Print(VM_NONE, VCORE_NONE,  "SVM is locked with a key\n");
1048             }
1049             return 0;
1050
1051         } else {
1052             V3_Print(VM_NONE, VCORE_NONE,  "SVM is available and  enabled.\n");
1053
1054             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
1055             PrintDebug(VM_NONE, VCORE_NONE, "CPUID_SVM_REV_AND_FEATURE_IDS_eax=0x%x\n", eax);
1056             PrintDebug(VM_NONE, VCORE_NONE, "CPUID_SVM_REV_AND_FEATURE_IDS_ebx=0x%x\n", ebx);
1057             PrintDebug(VM_NONE, VCORE_NONE, "CPUID_SVM_REV_AND_FEATURE_IDS_ecx=0x%x\n", ecx);
1058             PrintDebug(VM_NONE, VCORE_NONE, "CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
1059
1060             return 1;
1061         }
1062     }
1063 }
1064
1065 static int has_svm_nested_paging() {
1066     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
1067     
1068     v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
1069     
1070     //PrintDebug(VM_NONE, VCORE_NONE,  "CPUID_EXT_FEATURE_IDS_edx=0x%x\n", edx);
1071     
1072     if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
1073         V3_Print(VM_NONE, VCORE_NONE, "SVM Nested Paging not supported\n");
1074         return 0;
1075     } else {
1076         V3_Print(VM_NONE, VCORE_NONE, "SVM Nested Paging supported\n");
1077         return 1;
1078     }
1079  }
1080  
1081
1082
1083 void v3_init_svm_cpu(int cpu_id) {
1084     reg_ex_t msr;
1085     extern v3_cpu_arch_t v3_cpu_types[];
1086
1087     // Enable SVM on the CPU
1088     v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
1089     msr.e_reg.low |= EFER_MSR_svm_enable;
1090     v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
1091
1092     V3_Print(VM_NONE, VCORE_NONE,  "SVM Enabled\n");
1093
1094     // Setup the host state save area
1095     host_vmcbs[cpu_id] = (addr_t)V3_AllocPages(4); // need not be shadow-safe, not exposed to guest
1096
1097     if (!host_vmcbs[cpu_id]) {
1098         PrintError(VM_NONE, VCORE_NONE,  "Failed to allocate VMCB\n");
1099         return;
1100     }
1101
1102     /* 64-BIT-ISSUE */
1103     //  msr.e_reg.high = 0;
1104     //msr.e_reg.low = (uint_t)host_vmcb;
1105     msr.r_reg = host_vmcbs[cpu_id];
1106
1107     PrintDebug(VM_NONE, VCORE_NONE,  "Host State being saved at %p\n", (void *)host_vmcbs[cpu_id]);
1108     v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
1109
1110
1111     if (has_svm_nested_paging() == 1) {
1112         v3_cpu_types[cpu_id] = V3_SVM_REV3_CPU;
1113     } else {
1114         v3_cpu_types[cpu_id] = V3_SVM_CPU;
1115     }
1116 }
1117
1118
1119
1120 void v3_deinit_svm_cpu(int cpu_id) {
1121     reg_ex_t msr;
1122     extern v3_cpu_arch_t v3_cpu_types[];
1123
1124     // reset SVM_VM_HSAVE_PA_MSR
1125     // Does setting it to NULL disable??
1126     msr.r_reg = 0;
1127     v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
1128
1129     // Disable SVM?
1130     v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
1131     msr.e_reg.low &= ~EFER_MSR_svm_enable;
1132     v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
1133
1134     v3_cpu_types[cpu_id] = V3_INVALID_CPU;
1135
1136     V3_FreePages((void *)host_vmcbs[cpu_id], 4);
1137
1138     V3_Print(VM_NONE, VCORE_NONE,  "Host CPU %d host area freed, and SVM disabled\n", cpu_id);
1139     return;
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
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191 #if 0
1192 /* 
1193  * Test VMSAVE/VMLOAD Latency 
1194  */
1195 #define vmsave ".byte 0x0F,0x01,0xDB ; "
1196 #define vmload ".byte 0x0F,0x01,0xDA ; "
1197 {
1198     uint32_t start_lo, start_hi;
1199     uint32_t end_lo, end_hi;
1200     uint64_t start, end;
1201     
1202     __asm__ __volatile__ (
1203                           "rdtsc ; "
1204                           "movl %%eax, %%esi ; "
1205                           "movl %%edx, %%edi ; "
1206                           "movq  %%rcx, %%rax ; "
1207                           vmsave
1208                           "rdtsc ; "
1209                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
1210                           : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
1211                           );
1212     
1213     start = start_hi;
1214     start <<= 32;
1215     start += start_lo;
1216     
1217     end = end_hi;
1218     end <<= 32;
1219     end += end_lo;
1220     
1221     PrintDebug(core->vm_info, core, "VMSave Cycle Latency: %d\n", (uint32_t)(end - start));
1222     
1223     __asm__ __volatile__ (
1224                           "rdtsc ; "
1225                           "movl %%eax, %%esi ; "
1226                           "movl %%edx, %%edi ; "
1227                           "movq  %%rcx, %%rax ; "
1228                           vmload
1229                           "rdtsc ; "
1230                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
1231                               : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
1232                               );
1233         
1234         start = start_hi;
1235         start <<= 32;
1236         start += start_lo;
1237
1238         end = end_hi;
1239         end <<= 32;
1240         end += end_lo;
1241
1242
1243         PrintDebug(core->vm_info, core, "VMLoad Cycle Latency: %d\n", (uint32_t)(end - start));
1244     }
1245     /* End Latency Test */
1246
1247 #endif
1248
1249
1250
1251
1252
1253
1254
1255 #if 0
1256 void Init_VMCB_pe(vmcb_t *vmcb, struct guest_info vm_info) {
1257   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
1258   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
1259   uint_t i = 0;
1260
1261
1262   guest_state->rsp = vm_info.vm_regs.rsp;
1263   guest_state->rip = vm_info.rip;
1264
1265
1266   /* I pretty much just gutted this from TVMM */
1267   /* Note: That means its probably wrong */
1268
1269   // set the segment registers to mirror ours
1270   guest_state->cs.selector = 1<<3;
1271   guest_state->cs.attrib.fields.type = 0xa; // Code segment+read
1272   guest_state->cs.attrib.fields.S = 1;
1273   guest_state->cs.attrib.fields.P = 1;
1274   guest_state->cs.attrib.fields.db = 1;
1275   guest_state->cs.attrib.fields.G = 1;
1276   guest_state->cs.limit = 0xfffff;
1277   guest_state->cs.base = 0;
1278   
1279   struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL};
1280   for ( i = 0; segregs[i] != NULL; i++) {
1281     struct vmcb_selector * seg = segregs[i];
1282     
1283     seg->selector = 2<<3;
1284     seg->attrib.fields.type = 0x2; // Data Segment+read/write
1285     seg->attrib.fields.S = 1;
1286     seg->attrib.fields.P = 1;
1287     seg->attrib.fields.db = 1;
1288     seg->attrib.fields.G = 1;
1289     seg->limit = 0xfffff;
1290     seg->base = 0;
1291   }
1292
1293
1294   {
1295     /* JRL THIS HAS TO GO */
1296     
1297     //    guest_state->tr.selector = GetTR_Selector();
1298     guest_state->tr.attrib.fields.type = 0x9; 
1299     guest_state->tr.attrib.fields.P = 1;
1300     // guest_state->tr.limit = GetTR_Limit();
1301     //guest_state->tr.base = GetTR_Base();// - 0x2000;
1302     /* ** */
1303   }
1304
1305
1306   /* ** */
1307
1308
1309   guest_state->efer |= EFER_MSR_svm_enable;
1310   guest_state->rflags = 0x00000002; // The reserved bit is always 1
1311   ctrl_area->svm_instrs.VMRUN = 1;
1312   guest_state->cr0 = 0x00000001;    // PE 
1313   ctrl_area->guest_ASID = 1;
1314
1315
1316   //  guest_state->cpl = 0;
1317
1318
1319
1320   // Setup exits
1321
1322   ctrl_area->cr_writes.cr4 = 1;
1323   
1324   ctrl_area->exceptions.de = 1;
1325   ctrl_area->exceptions.df = 1;
1326   ctrl_area->exceptions.pf = 1;
1327   ctrl_area->exceptions.ts = 1;
1328   ctrl_area->exceptions.ss = 1;
1329   ctrl_area->exceptions.ac = 1;
1330   ctrl_area->exceptions.mc = 1;
1331   ctrl_area->exceptions.gp = 1;
1332   ctrl_area->exceptions.ud = 1;
1333   ctrl_area->exceptions.np = 1;
1334   ctrl_area->exceptions.of = 1;
1335   ctrl_area->exceptions.nmi = 1;
1336
1337   
1338
1339   ctrl_area->instrs.IOIO_PROT = 1;
1340   ctrl_area->IOPM_BASE_PA = (uint_t)V3_AllocPages(3); // need not be shadow-safe, not exposed to guest
1341
1342   if (!ctrl_area->IOPM_BASE_PA) { 
1343       PrintError(core->vm_info, core, "Cannot allocate IO bitmap\n");
1344       return;
1345   }
1346   
1347   {
1348     reg_ex_t tmp_reg;
1349     tmp_reg.r_reg = ctrl_area->IOPM_BASE_PA;
1350     memset((void*)(tmp_reg.e_reg.low), 0xffffffff, PAGE_SIZE * 2);
1351   }
1352
1353   ctrl_area->instrs.INTR = 1;
1354
1355   
1356   {
1357     char gdt_buf[6];
1358     char idt_buf[6];
1359
1360     memset(gdt_buf, 0, 6);
1361     memset(idt_buf, 0, 6);
1362
1363
1364     uint_t gdt_base, idt_base;
1365     ushort_t gdt_limit, idt_limit;
1366     
1367     GetGDTR(gdt_buf);
1368     gdt_base = *(ulong_t*)((uchar_t*)gdt_buf + 2) & 0xffffffff;
1369     gdt_limit = *(ushort_t*)(gdt_buf) & 0xffff;
1370     PrintDebug(core->vm_info, core, "GDT: base: %x, limit: %x\n", gdt_base, gdt_limit);
1371
1372     GetIDTR(idt_buf);
1373     idt_base = *(ulong_t*)(idt_buf + 2) & 0xffffffff;
1374     idt_limit = *(ushort_t*)(idt_buf) & 0xffff;
1375     PrintDebug(core->vm_info, core, "IDT: base: %x, limit: %x\n",idt_base, idt_limit);
1376
1377
1378     // gdt_base -= 0x2000;
1379     //idt_base -= 0x2000;
1380
1381     guest_state->gdtr.base = gdt_base;
1382     guest_state->gdtr.limit = gdt_limit;
1383     guest_state->idtr.base = idt_base;
1384     guest_state->idtr.limit = idt_limit;
1385
1386
1387   }
1388   
1389   
1390   // also determine if CPU supports nested paging
1391   /*
1392   if (vm_info.page_tables) {
1393     //   if (0) {
1394     // Flush the TLB on entries/exits
1395     ctrl_area->TLB_CONTROL = 1;
1396
1397     // Enable Nested Paging
1398     ctrl_area->NP_ENABLE = 1;
1399
1400     PrintDebug(core->vm_info, core, "NP_Enable at 0x%x\n", &(ctrl_area->NP_ENABLE));
1401
1402         // Set the Nested Page Table pointer
1403     ctrl_area->N_CR3 |= ((addr_t)vm_info.page_tables & 0xfffff000);
1404
1405
1406     //   ctrl_area->N_CR3 = Get_CR3();
1407     // guest_state->cr3 |= (Get_CR3() & 0xfffff000);
1408
1409     guest_state->g_pat = 0x7040600070406ULL;
1410
1411     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));
1412     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));
1413     // Enable Paging
1414     //    guest_state->cr0 |= 0x80000000;
1415   }
1416   */
1417
1418 }
1419
1420
1421
1422
1423
1424 #endif
1425
1426