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.


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