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.


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