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.


Fixed merge of apic.c
[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 #include <palacios/svm.h>
22 #include <palacios/vmm.h>
23
24 #include <palacios/vmcb.h>
25 #include <palacios/vmm_mem.h>
26 #include <palacios/vmm_paging.h>
27 #include <palacios/svm_handler.h>
28
29 #include <palacios/vmm_debug.h>
30 #include <palacios/vm_guest_mem.h>
31
32 #include <palacios/vmm_decoder.h>
33 #include <palacios/vmm_string.h>
34 #include <palacios/vmm_lowlevel.h>
35 #include <palacios/svm_msr.h>
36
37 #include <palacios/vmm_rbtree.h>
38
39 #include <palacios/vmm_direct_paging.h>
40
41 #include <palacios/vmm_ctrl_regs.h>
42 #include <palacios/svm_io.h>
43
44 #include <palacios/vmm_sprintf.h>
45
46
47 #ifndef CONFIG_DEBUG_SVM
48 #undef PrintDebug
49 #define PrintDebug(fmt, args...)
50 #endif
51
52
53 uint32_t v3_last_exit;
54
55 // This is a global pointer to the host's VMCB
56 static addr_t host_vmcbs[CONFIG_MAX_CPUS] = { [0 ... CONFIG_MAX_CPUS - 1] = 0};
57
58
59
60 extern void v3_stgi();
61 extern void v3_clgi();
62 //extern int v3_svm_launch(vmcb_t * vmcb, struct v3_gprs * vm_regs, uint64_t * fs, uint64_t * gs);
63 extern int v3_svm_launch(vmcb_t * vmcb, struct v3_gprs * vm_regs, vmcb_t * host_vmcb);
64
65
66 static vmcb_t * Allocate_VMCB() {
67     vmcb_t * vmcb_page = (vmcb_t *)V3_VAddr(V3_AllocPages(1));
68
69     memset(vmcb_page, 0, 4096);
70
71     return vmcb_page;
72 }
73
74
75
76 static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) {
77     vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
78     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
79     uint_t i;
80
81
82     //
83     ctrl_area->svm_instrs.VMRUN = 1;
84     ctrl_area->svm_instrs.VMMCALL = 1;
85     ctrl_area->svm_instrs.VMLOAD = 1;
86     ctrl_area->svm_instrs.VMSAVE = 1;
87     ctrl_area->svm_instrs.STGI = 1;
88     ctrl_area->svm_instrs.CLGI = 1;
89     ctrl_area->svm_instrs.SKINIT = 1;
90     ctrl_area->svm_instrs.RDTSCP = 1;
91     ctrl_area->svm_instrs.ICEBP = 1;
92     ctrl_area->svm_instrs.WBINVD = 1;
93     ctrl_area->svm_instrs.MONITOR = 1;
94     ctrl_area->svm_instrs.MWAIT_always = 1;
95     ctrl_area->svm_instrs.MWAIT_if_armed = 1;
96     ctrl_area->instrs.INVLPGA = 1;
97     ctrl_area->instrs.CPUID = 1;
98
99     ctrl_area->instrs.HLT = 1;
100     // guest_state->cr0 = 0x00000001;    // PE 
101   
102     /*
103       ctrl_area->exceptions.de = 1;
104       ctrl_area->exceptions.df = 1;
105       
106       ctrl_area->exceptions.ts = 1;
107       ctrl_area->exceptions.ss = 1;
108       ctrl_area->exceptions.ac = 1;
109       ctrl_area->exceptions.mc = 1;
110       ctrl_area->exceptions.gp = 1;
111       ctrl_area->exceptions.ud = 1;
112       ctrl_area->exceptions.np = 1;
113       ctrl_area->exceptions.of = 1;
114       
115       ctrl_area->exceptions.nmi = 1;
116     */
117     
118
119     ctrl_area->instrs.NMI = 1;
120     ctrl_area->instrs.SMI = 0; // allow SMIs to run in guest
121     ctrl_area->instrs.INIT = 1;
122     ctrl_area->instrs.PAUSE = 1;
123     ctrl_area->instrs.shutdown_evts = 1;
124
125
126     /* DEBUG FOR RETURN CODE */
127     ctrl_area->exit_code = 1;
128
129
130     /* Setup Guest Machine state */
131
132     core->vm_regs.rsp = 0x00;
133     core->rip = 0xfff0;
134
135     core->vm_regs.rdx = 0x00000f00;
136
137
138     core->cpl = 0;
139
140     core->ctrl_regs.rflags = 0x00000002; // The reserved bit is always 1
141     core->ctrl_regs.cr0 = 0x60010010; // Set the WP flag so the memory hooks work in real-mode
142     core->ctrl_regs.efer |= EFER_MSR_svm_enable;
143
144
145
146
147
148     core->segments.cs.selector = 0xf000;
149     core->segments.cs.limit = 0xffff;
150     core->segments.cs.base = 0x0000000f0000LL;
151
152     // (raw attributes = 0xf3)
153     core->segments.cs.type = 0x3;
154     core->segments.cs.system = 0x1;
155     core->segments.cs.dpl = 0x3;
156     core->segments.cs.present = 1;
157
158
159
160     struct v3_segment * segregs [] = {&(core->segments.ss), &(core->segments.ds), 
161                                       &(core->segments.es), &(core->segments.fs), 
162                                       &(core->segments.gs), NULL};
163
164     for ( i = 0; segregs[i] != NULL; i++) {
165         struct v3_segment * seg = segregs[i];
166         
167         seg->selector = 0x0000;
168         //    seg->base = seg->selector << 4;
169         seg->base = 0x00000000;
170         seg->limit = ~0u;
171
172         // (raw attributes = 0xf3)
173         seg->type = 0x3;
174         seg->system = 0x1;
175         seg->dpl = 0x3;
176         seg->present = 1;
177     }
178
179     core->segments.gdtr.limit = 0x0000ffff;
180     core->segments.gdtr.base = 0x0000000000000000LL;
181     core->segments.idtr.limit = 0x0000ffff;
182     core->segments.idtr.base = 0x0000000000000000LL;
183
184     core->segments.ldtr.selector = 0x0000;
185     core->segments.ldtr.limit = 0x0000ffff;
186     core->segments.ldtr.base = 0x0000000000000000LL;
187     core->segments.tr.selector = 0x0000;
188     core->segments.tr.limit = 0x0000ffff;
189     core->segments.tr.base = 0x0000000000000000LL;
190
191
192     core->dbg_regs.dr6 = 0x00000000ffff0ff0LL;
193     core->dbg_regs.dr7 = 0x0000000000000400LL;
194
195
196     ctrl_area->IOPM_BASE_PA = (addr_t)V3_PAddr(core->vm_info->io_map.arch_data);
197     ctrl_area->instrs.IOIO_PROT = 1;
198             
199     ctrl_area->MSRPM_BASE_PA = (addr_t)V3_PAddr(core->vm_info->msr_map.arch_data);
200     ctrl_area->instrs.MSR_PROT = 1;   
201
202
203     PrintDebug("Exiting on interrupts\n");
204     ctrl_area->guest_ctrl.V_INTR_MASKING = 1;
205     ctrl_area->instrs.INTR = 1;
206
207
208     if (core->shdw_pg_mode == SHADOW_PAGING) {
209         PrintDebug("Creating initial shadow page table\n");
210         
211         /* JRL: This is a performance killer, and a simplistic solution */
212         /* We need to fix this */
213         ctrl_area->TLB_CONTROL = 1;
214         ctrl_area->guest_ASID = 1;
215         
216         
217         if (v3_init_passthrough_pts(core) == -1) {
218             PrintError("Could not initialize passthrough page tables\n");
219             return ;
220         }
221
222
223         core->shdw_pg_state.guest_cr0 = 0x0000000000000010LL;
224         PrintDebug("Created\n");
225         
226         core->ctrl_regs.cr0 |= 0x80000000;
227         core->ctrl_regs.cr3 = core->direct_map_pt;
228
229         ctrl_area->cr_reads.cr0 = 1;
230         ctrl_area->cr_writes.cr0 = 1;
231         //ctrl_area->cr_reads.cr4 = 1;
232         ctrl_area->cr_writes.cr4 = 1;
233         ctrl_area->cr_reads.cr3 = 1;
234         ctrl_area->cr_writes.cr3 = 1;
235
236         v3_hook_msr(core->vm_info, EFER_MSR, 
237                     &v3_handle_efer_read,
238                     &v3_handle_efer_write, 
239                     core);
240
241         ctrl_area->instrs.INVLPG = 1;
242
243         ctrl_area->exceptions.pf = 1;
244
245         guest_state->g_pat = 0x7040600070406ULL;
246
247
248
249     } else if (core->shdw_pg_mode == NESTED_PAGING) {
250         // Flush the TLB on entries/exits
251         ctrl_area->TLB_CONTROL = 1;
252         ctrl_area->guest_ASID = 1;
253
254         // Enable Nested Paging
255         ctrl_area->NP_ENABLE = 1;
256
257         PrintDebug("NP_Enable at 0x%p\n", (void *)&(ctrl_area->NP_ENABLE));
258
259         // Set the Nested Page Table pointer
260         if (v3_init_passthrough_pts(core) == -1) {
261             PrintError("Could not initialize Nested page tables\n");
262             return ;
263         }
264
265         ctrl_area->N_CR3 = core->direct_map_pt;
266
267         guest_state->g_pat = 0x7040600070406ULL;
268     }
269 }
270
271
272 int v3_init_svm_vmcb(struct guest_info * info, v3_vm_class_t vm_class) {
273
274     PrintDebug("Allocating VMCB\n");
275     info->vmm_data = (void*)Allocate_VMCB();
276     
277     if (vm_class == V3_PC_VM) {
278         PrintDebug("Initializing VMCB (addr=%p)\n", (void *)info->vmm_data);
279         Init_VMCB_BIOS((vmcb_t*)(info->vmm_data), info);
280     } else {
281         PrintError("Invalid VM class\n");
282         return -1;
283     }
284
285     return 0;
286 }
287
288
289
290 static int update_irq_exit_state(struct guest_info * info) {
291     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
292
293     // Fix for QEMU bug using EVENTINJ as an internal cache
294     guest_ctrl->EVENTINJ.valid = 0;
295
296     if ((info->intr_core_state.irq_pending == 1) && (guest_ctrl->guest_ctrl.V_IRQ == 0)) {
297         
298 #ifdef CONFIG_DEBUG_INTERRUPTS
299         PrintDebug("INTAK cycle completed for irq %d\n", info->intr_core_state.irq_vector);
300 #endif
301
302         info->intr_core_state.irq_started = 1;
303         info->intr_core_state.irq_pending = 0;
304
305         v3_injecting_intr(info, info->intr_core_state.irq_vector, V3_EXTERNAL_IRQ);
306     }
307
308     if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 0)) {
309 #ifdef CONFIG_DEBUG_INTERRUPTS
310         PrintDebug("Interrupt %d taken by guest\n", info->intr_core_state.irq_vector);
311 #endif
312
313         // Interrupt was taken fully vectored
314         info->intr_core_state.irq_started = 0;
315
316     } else if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 1)) {
317 #ifdef CONFIG_DEBUG_INTERRUPTS
318         PrintDebug("EXIT INT INFO is set (vec=%d)\n", guest_ctrl->exit_int_info.vector);
319 #endif
320     }
321
322     return 0;
323 }
324
325
326 static int update_irq_entry_state(struct guest_info * info) {
327     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
328
329
330     if (info->intr_core_state.irq_pending == 0) {
331         guest_ctrl->guest_ctrl.V_IRQ = 0;
332         guest_ctrl->guest_ctrl.V_INTR_VECTOR = 0;
333     }
334     
335     if (v3_excp_pending(info)) {
336         uint_t excp = v3_get_excp_number(info);
337         
338         guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
339         
340         if (info->excp_state.excp_error_code_valid) {
341             guest_ctrl->EVENTINJ.error_code = info->excp_state.excp_error_code;
342             guest_ctrl->EVENTINJ.ev = 1;
343 #ifdef CONFIG_DEBUG_INTERRUPTS
344             PrintDebug("Injecting exception %d with error code %x\n", excp, guest_ctrl->EVENTINJ.error_code);
345 #endif
346         }
347         
348         guest_ctrl->EVENTINJ.vector = excp;
349         
350         guest_ctrl->EVENTINJ.valid = 1;
351
352 #ifdef CONFIG_DEBUG_INTERRUPTS
353         PrintDebug("<%d> Injecting Exception %d (CR2=%p) (EIP=%p)\n", 
354                    (int)info->num_exits, 
355                    guest_ctrl->EVENTINJ.vector, 
356                    (void *)(addr_t)info->ctrl_regs.cr2,
357                    (void *)(addr_t)info->rip);
358 #endif
359
360         v3_injecting_excp(info, excp);
361     } else if (info->intr_core_state.irq_started == 1) {
362 #ifdef CONFIG_DEBUG_INTERRUPTS
363         PrintDebug("IRQ pending from previous injection\n");
364 #endif
365         guest_ctrl->guest_ctrl.V_IRQ = 1;
366         guest_ctrl->guest_ctrl.V_INTR_VECTOR = info->intr_core_state.irq_vector;
367         guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
368         guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
369
370     } else {
371         switch (v3_intr_pending(info)) {
372             case V3_EXTERNAL_IRQ: {
373                 uint32_t irq = v3_get_intr(info);
374
375                 guest_ctrl->guest_ctrl.V_IRQ = 1;
376                 guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
377                 guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
378                 guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
379
380 #ifdef CONFIG_DEBUG_INTERRUPTS
381                 PrintDebug("Injecting Interrupt %d (EIP=%p)\n", 
382                            guest_ctrl->guest_ctrl.V_INTR_VECTOR, 
383                            (void *)(addr_t)info->rip);
384 #endif
385
386                 info->intr_core_state.irq_pending = 1;
387                 info->intr_core_state.irq_vector = irq;
388                 
389                 break;
390             }
391             case V3_NMI:
392                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
393                 break;
394             case V3_SOFTWARE_INTR:
395                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
396                 break;
397             case V3_VIRTUAL_IRQ:
398                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_IRQ;
399                 break;
400
401             case V3_INVALID_INTR:
402             default:
403                 break;
404         }
405         
406     }
407
408     return 0;
409 }
410
411
412 /* 
413  * CAUTION and DANGER!!! 
414  * 
415  * The VMCB CANNOT(!!) be accessed outside of the clgi/stgi calls inside this function
416  * When exectuing a symbiotic call, the VMCB WILL be overwritten, so any dependencies 
417  * on its contents will cause things to break. The contents at the time of the exit WILL 
418  * change before the exit handler is executed.
419  */
420 int v3_svm_enter(struct guest_info * info) {
421     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
422     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); 
423     addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0;
424
425     // Conditionally yield the CPU if the timeslice has expired
426     v3_yield_cond(info);
427
428     // disable global interrupts for vm state transition
429     v3_clgi();
430
431     // Synchronize the guest state to the VMCB
432     guest_state->cr0 = info->ctrl_regs.cr0;
433     guest_state->cr2 = info->ctrl_regs.cr2;
434     guest_state->cr3 = info->ctrl_regs.cr3;
435     guest_state->cr4 = info->ctrl_regs.cr4;
436     guest_state->dr6 = info->dbg_regs.dr6;
437     guest_state->dr7 = info->dbg_regs.dr7;
438     guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
439     guest_state->rflags = info->ctrl_regs.rflags;
440     guest_state->efer = info->ctrl_regs.efer;
441     
442     guest_state->cpl = info->cpl;
443
444     v3_set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
445
446     guest_state->rax = info->vm_regs.rax;
447     guest_state->rip = info->rip;
448     guest_state->rsp = info->vm_regs.rsp;
449
450 #ifdef CONFIG_SYMCALL
451     if (info->sym_core_state.symcall_state.sym_call_active == 0) {
452         update_irq_entry_state(info);
453     }
454 #else 
455     update_irq_entry_state(info);
456 #endif
457
458
459     /* ** */
460
461     /*
462       PrintDebug("SVM Entry to CS=%p  rip=%p...\n", 
463       (void *)(addr_t)info->segments.cs.base, 
464       (void *)(addr_t)info->rip);
465     */
466
467 #ifdef CONFIG_SYMCALL
468     if (info->sym_core_state.symcall_state.sym_call_active == 1) {
469         if (guest_ctrl->guest_ctrl.V_IRQ == 1) {
470             V3_Print("!!! Injecting Interrupt during Sym call !!!\n");
471         }
472     }
473 #endif
474
475     v3_update_timers(info);
476
477     guest_ctrl->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
478
479     //V3_Print("Calling v3_svm_launch\n");
480
481     v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->cpu_id]);
482
483     v3_adjust_time(info);
484
485     //V3_Print("SVM Returned: Exit Code: %x, guest_rip=%lx\n", (uint32_t)(guest_ctrl->exit_code), (unsigned long)guest_state->rip);
486
487     v3_last_exit = (uint32_t)(guest_ctrl->exit_code);
488
489     //PrintDebug("SVM Returned\n");
490     
491     info->num_exits++;
492
493     // Save Guest state from VMCB
494     info->rip = guest_state->rip;
495     info->vm_regs.rsp = guest_state->rsp;
496     info->vm_regs.rax = guest_state->rax;
497
498     info->cpl = guest_state->cpl;
499
500     info->ctrl_regs.cr0 = guest_state->cr0;
501     info->ctrl_regs.cr2 = guest_state->cr2;
502     info->ctrl_regs.cr3 = guest_state->cr3;
503     info->ctrl_regs.cr4 = guest_state->cr4;
504     info->dbg_regs.dr6 = guest_state->dr6;
505     info->dbg_regs.dr7 = guest_state->dr7;
506     info->ctrl_regs.cr8 = guest_ctrl->guest_ctrl.V_TPR;
507     info->ctrl_regs.rflags = guest_state->rflags;
508     info->ctrl_regs.efer = guest_state->efer;
509     
510     v3_get_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
511     info->cpu_mode = v3_get_vm_cpu_mode(info);
512     info->mem_mode = v3_get_vm_mem_mode(info);
513     /* ** */
514
515
516     // save exit info here
517     exit_code = guest_ctrl->exit_code;
518     exit_info1 = guest_ctrl->exit_info1;
519     exit_info2 = guest_ctrl->exit_info2;
520
521
522 #ifdef CONFIG_SYMCALL
523     if (info->sym_core_state.symcall_state.sym_call_active == 0) {
524         update_irq_exit_state(info);
525     }
526 #else
527     update_irq_exit_state(info);
528 #endif
529
530
531     // reenable global interrupts after vm exit
532     v3_stgi();
533
534  
535     // Conditionally yield the CPU if the timeslice has expired
536     v3_yield_cond(info);
537
538
539
540     if (v3_handle_svm_exit(info, exit_code, exit_info1, exit_info2) != 0) {
541         PrintError("Error in SVM exit handler\n");
542         return -1;
543     }
544
545
546     return 0;
547 }
548
549
550 int v3_start_svm_guest(struct guest_info *info) {
551     //    vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
552     //  vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
553
554
555     PrintDebug("Starting SVM core %u\n",info->cpu_id);
556     if (info->cpu_mode==INIT) { 
557         PrintDebug("SVM core %u: I am an AP in INIT mode, waiting for that to change\n",info->cpu_id);
558         while (info->cpu_mode==INIT) {
559             v3_yield(info);
560             //PrintDebug("SVM core %u: still waiting for INIT\n",info->cpu_id);
561         }
562         PrintDebug("SVM core %u: I am out of INIT\n",info->cpu_id);
563         if (info->cpu_mode==SIPI) { 
564             PrintDebug("SVM core %u: I am waiting on a SIPI to set my starting address\n",info->cpu_id);
565             while (info->cpu_mode==SIPI) {
566                 v3_yield(info);
567                 //PrintDebug("SVM core %u: still waiting for SIPI\n",info->cpu_id);
568             }
569         }
570         PrintDebug("SVM core %u: I have my SIPI\n", info->cpu_id);
571     }
572
573     if (info->cpu_mode!=REAL) { 
574         PrintError("SVM core %u: I am not in REAL mode at launch!  Huh?!\n", info->cpu_id);
575         return -1;
576     }
577
578     PrintDebug("SVM core %u: I am starting at CS=0x%x (base=0x%p, limit=0x%x),  RIP=0x%p\n", 
579                info->cpu_id, info->segments.cs.selector, (void*)(info->segments.cs.base), 
580                info->segments.cs.limit,(void*)(info->rip));
581
582
583
584     PrintDebug("SVM core %u: Launching SVM VM (vmcb=%p)\n", info->cpu_id, (void *)info->vmm_data);
585     //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
586     
587     info->vm_info->run_state = VM_RUNNING;
588     v3_start_time(info);
589
590     while (1) {
591         if (v3_svm_enter(info) == -1) {
592             vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
593             addr_t host_addr;
594             addr_t linear_addr = 0;
595             
596             info->vm_info->run_state = VM_ERROR;
597             
598             V3_Print("SVM core %u: SVM ERROR!!\n", info->cpu_id); 
599             
600             v3_print_guest_state(info);
601             
602             V3_Print("SVM core %u: SVM Exit Code: %p\n", info->cpu_id, (void *)(addr_t)guest_ctrl->exit_code); 
603             
604             V3_Print("SVM core %u: exit_info1 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info1));
605             V3_Print("SVM core %u: exit_info1 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
606             
607             V3_Print("SVM core %u: exit_info2 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info2));
608             V3_Print("SVM core %u: exit_info2 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
609             
610             linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
611             
612             if (info->mem_mode == PHYSICAL_MEM) {
613                 v3_gpa_to_hva(info, linear_addr, &host_addr);
614             } else if (info->mem_mode == VIRTUAL_MEM) {
615                 v3_gva_to_hva(info, linear_addr, &host_addr);
616             }
617             
618             V3_Print("SVM core %u: Host Address of rip = 0x%p\n", info->cpu_id, (void *)host_addr);
619             
620             V3_Print("SVM core %u: Instr (15 bytes) at %p:\n", info->cpu_id, (void *)host_addr);
621             v3_dump_mem((uint8_t *)host_addr, 15);
622             
623             v3_print_stack(info);
624
625             break;
626         }
627         
628 /*
629         if ((info->num_exits % 5000) == 0) {
630             V3_Print("SVM Exit number %d\n", (uint32_t)info->num_exits);
631         }
632 */
633         
634     }
635
636     // Need to take down the other cores on error... 
637
638     return 0;
639 }
640
641
642
643
644
645 /* Checks machine SVM capability */
646 /* Implemented from: AMD Arch Manual 3, sect 15.4 */ 
647 int v3_is_svm_capable() {
648     uint_t vm_cr_low = 0, vm_cr_high = 0;
649     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
650
651     v3_cpuid(CPUID_EXT_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
652   
653     PrintDebug("CPUID_EXT_FEATURE_IDS_ecx=0x%x\n", ecx);
654
655     if ((ecx & CPUID_EXT_FEATURE_IDS_ecx_svm_avail) == 0) {
656       V3_Print("SVM Not Available\n");
657       return 0;
658     }  else {
659         v3_get_msr(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
660         
661         PrintDebug("SVM_VM_CR_MSR = 0x%x 0x%x\n", vm_cr_high, vm_cr_low);
662         
663         if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 1) {
664             V3_Print("SVM is available but is disabled.\n");
665             
666             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
667             
668             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
669             
670             if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
671                 V3_Print("SVM BIOS Disabled, not unlockable\n");
672             } else {
673                 V3_Print("SVM is locked with a key\n");
674             }
675             return 0;
676
677         } else {
678             V3_Print("SVM is available and  enabled.\n");
679
680             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
681             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_eax=0x%x\n", eax);
682             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ebx=0x%x\n", ebx);
683             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ecx=0x%x\n", ecx);
684             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
685
686             return 1;
687         }
688     }
689 }
690
691 static int has_svm_nested_paging() {
692     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
693
694     v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
695
696     //PrintDebug("CPUID_EXT_FEATURE_IDS_edx=0x%x\n", edx);
697
698     if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
699         V3_Print("SVM Nested Paging not supported\n");
700         return 0;
701     } else {
702         V3_Print("SVM Nested Paging supported\n");
703         return 1;
704     }
705 }
706
707
708 void v3_init_svm_cpu(int cpu_id) {
709     reg_ex_t msr;
710     extern v3_cpu_arch_t v3_cpu_types[];
711
712     // Enable SVM on the CPU
713     v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
714     msr.e_reg.low |= EFER_MSR_svm_enable;
715     v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
716
717     V3_Print("SVM Enabled\n");
718
719     // Setup the host state save area
720     host_vmcbs[cpu_id] = (addr_t)V3_AllocPages(4);
721
722     /* 64-BIT-ISSUE */
723     //  msr.e_reg.high = 0;
724     //msr.e_reg.low = (uint_t)host_vmcb;
725     msr.r_reg = host_vmcbs[cpu_id];
726
727     PrintDebug("Host State being saved at %p\n", (void *)host_vmcbs[cpu_id]);
728     v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
729
730
731     if (has_svm_nested_paging() == 1) {
732         v3_cpu_types[cpu_id] = V3_SVM_REV3_CPU;
733     } else {
734         v3_cpu_types[cpu_id] = V3_SVM_CPU;
735     }
736 }
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791 #if 0
792 /* 
793  * Test VMSAVE/VMLOAD Latency 
794  */
795 #define vmsave ".byte 0x0F,0x01,0xDB ; "
796 #define vmload ".byte 0x0F,0x01,0xDA ; "
797 {
798     uint32_t start_lo, start_hi;
799     uint32_t end_lo, end_hi;
800     uint64_t start, end;
801     
802     __asm__ __volatile__ (
803                           "rdtsc ; "
804                           "movl %%eax, %%esi ; "
805                           "movl %%edx, %%edi ; "
806                           "movq  %%rcx, %%rax ; "
807                           vmsave
808                           "rdtsc ; "
809                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
810                           : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
811                           );
812     
813     start = start_hi;
814     start <<= 32;
815     start += start_lo;
816     
817     end = end_hi;
818     end <<= 32;
819     end += end_lo;
820     
821     PrintDebug("VMSave Cycle Latency: %d\n", (uint32_t)(end - start));
822     
823     __asm__ __volatile__ (
824                           "rdtsc ; "
825                           "movl %%eax, %%esi ; "
826                           "movl %%edx, %%edi ; "
827                           "movq  %%rcx, %%rax ; "
828                           vmload
829                           "rdtsc ; "
830                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
831                               : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
832                               );
833         
834         start = start_hi;
835         start <<= 32;
836         start += start_lo;
837
838         end = end_hi;
839         end <<= 32;
840         end += end_lo;
841
842
843         PrintDebug("VMLoad Cycle Latency: %d\n", (uint32_t)(end - start));
844     }
845     /* End Latency Test */
846
847 #endif
848
849
850
851
852
853
854
855 #if 0
856 void Init_VMCB_pe(vmcb_t *vmcb, struct guest_info vm_info) {
857   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
858   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
859   uint_t i = 0;
860
861
862   guest_state->rsp = vm_info.vm_regs.rsp;
863   guest_state->rip = vm_info.rip;
864
865
866   /* I pretty much just gutted this from TVMM */
867   /* Note: That means its probably wrong */
868
869   // set the segment registers to mirror ours
870   guest_state->cs.selector = 1<<3;
871   guest_state->cs.attrib.fields.type = 0xa; // Code segment+read
872   guest_state->cs.attrib.fields.S = 1;
873   guest_state->cs.attrib.fields.P = 1;
874   guest_state->cs.attrib.fields.db = 1;
875   guest_state->cs.attrib.fields.G = 1;
876   guest_state->cs.limit = 0xfffff;
877   guest_state->cs.base = 0;
878   
879   struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL};
880   for ( i = 0; segregs[i] != NULL; i++) {
881     struct vmcb_selector * seg = segregs[i];
882     
883     seg->selector = 2<<3;
884     seg->attrib.fields.type = 0x2; // Data Segment+read/write
885     seg->attrib.fields.S = 1;
886     seg->attrib.fields.P = 1;
887     seg->attrib.fields.db = 1;
888     seg->attrib.fields.G = 1;
889     seg->limit = 0xfffff;
890     seg->base = 0;
891   }
892
893
894   {
895     /* JRL THIS HAS TO GO */
896     
897     //    guest_state->tr.selector = GetTR_Selector();
898     guest_state->tr.attrib.fields.type = 0x9; 
899     guest_state->tr.attrib.fields.P = 1;
900     // guest_state->tr.limit = GetTR_Limit();
901     //guest_state->tr.base = GetTR_Base();// - 0x2000;
902     /* ** */
903   }
904
905
906   /* ** */
907
908
909   guest_state->efer |= EFER_MSR_svm_enable;
910   guest_state->rflags = 0x00000002; // The reserved bit is always 1
911   ctrl_area->svm_instrs.VMRUN = 1;
912   guest_state->cr0 = 0x00000001;    // PE 
913   ctrl_area->guest_ASID = 1;
914
915
916   //  guest_state->cpl = 0;
917
918
919
920   // Setup exits
921
922   ctrl_area->cr_writes.cr4 = 1;
923   
924   ctrl_area->exceptions.de = 1;
925   ctrl_area->exceptions.df = 1;
926   ctrl_area->exceptions.pf = 1;
927   ctrl_area->exceptions.ts = 1;
928   ctrl_area->exceptions.ss = 1;
929   ctrl_area->exceptions.ac = 1;
930   ctrl_area->exceptions.mc = 1;
931   ctrl_area->exceptions.gp = 1;
932   ctrl_area->exceptions.ud = 1;
933   ctrl_area->exceptions.np = 1;
934   ctrl_area->exceptions.of = 1;
935   ctrl_area->exceptions.nmi = 1;
936
937   
938
939   ctrl_area->instrs.IOIO_PROT = 1;
940   ctrl_area->IOPM_BASE_PA = (uint_t)V3_AllocPages(3);
941   
942   {
943     reg_ex_t tmp_reg;
944     tmp_reg.r_reg = ctrl_area->IOPM_BASE_PA;
945     memset((void*)(tmp_reg.e_reg.low), 0xffffffff, PAGE_SIZE * 2);
946   }
947
948   ctrl_area->instrs.INTR = 1;
949
950   
951   {
952     char gdt_buf[6];
953     char idt_buf[6];
954
955     memset(gdt_buf, 0, 6);
956     memset(idt_buf, 0, 6);
957
958
959     uint_t gdt_base, idt_base;
960     ushort_t gdt_limit, idt_limit;
961     
962     GetGDTR(gdt_buf);
963     gdt_base = *(ulong_t*)((uchar_t*)gdt_buf + 2) & 0xffffffff;
964     gdt_limit = *(ushort_t*)(gdt_buf) & 0xffff;
965     PrintDebug("GDT: base: %x, limit: %x\n", gdt_base, gdt_limit);
966
967     GetIDTR(idt_buf);
968     idt_base = *(ulong_t*)(idt_buf + 2) & 0xffffffff;
969     idt_limit = *(ushort_t*)(idt_buf) & 0xffff;
970     PrintDebug("IDT: base: %x, limit: %x\n",idt_base, idt_limit);
971
972
973     // gdt_base -= 0x2000;
974     //idt_base -= 0x2000;
975
976     guest_state->gdtr.base = gdt_base;
977     guest_state->gdtr.limit = gdt_limit;
978     guest_state->idtr.base = idt_base;
979     guest_state->idtr.limit = idt_limit;
980
981
982   }
983   
984   
985   // also determine if CPU supports nested paging
986   /*
987   if (vm_info.page_tables) {
988     //   if (0) {
989     // Flush the TLB on entries/exits
990     ctrl_area->TLB_CONTROL = 1;
991
992     // Enable Nested Paging
993     ctrl_area->NP_ENABLE = 1;
994
995     PrintDebug("NP_Enable at 0x%x\n", &(ctrl_area->NP_ENABLE));
996
997         // Set the Nested Page Table pointer
998     ctrl_area->N_CR3 |= ((addr_t)vm_info.page_tables & 0xfffff000);
999
1000
1001     //   ctrl_area->N_CR3 = Get_CR3();
1002     // guest_state->cr3 |= (Get_CR3() & 0xfffff000);
1003
1004     guest_state->g_pat = 0x7040600070406ULL;
1005
1006     PrintDebug("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));
1007     PrintDebug("Set Guest CR3: lo: 0x%x  hi: 0x%x\n", (uint_t)*(&(guest_state->cr3)), (uint_t)*((unsigned char *)&(guest_state->cr3) + 4));
1008     // Enable Paging
1009     //    guest_state->cr0 |= 0x80000000;
1010   }
1011   */
1012
1013 }
1014
1015
1016
1017
1018
1019 #endif
1020
1021