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.


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