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.


More minor fixes on time keeping. VMM clock now appears to be essentially accurate...
[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
563     PrintDebug("Starting SVM core %u\n",info->cpu_id);
564     if (info->cpu_mode==INIT) { 
565         PrintDebug("SVM core %u: I am an AP in INIT mode, waiting for that to change\n",info->cpu_id);
566         while (info->cpu_mode==INIT) {
567             v3_yield(info);
568             //PrintDebug("SVM core %u: still waiting for INIT\n",info->cpu_id);
569         }
570         PrintDebug("SVM core %u: I am out of INIT\n",info->cpu_id);
571         if (info->cpu_mode==SIPI) { 
572             PrintDebug("SVM core %u: I am waiting on a SIPI to set my starting address\n",info->cpu_id);
573             while (info->cpu_mode==SIPI) {
574                 v3_yield(info);
575                 //PrintDebug("SVM core %u: still waiting for SIPI\n",info->cpu_id);
576             }
577         }
578         PrintDebug("SVM core %u: I have my SIPI\n", info->cpu_id);
579     }
580
581     if (info->cpu_mode!=REAL) { 
582         PrintError("SVM core %u: I am not in REAL mode at launch!  Huh?!\n", info->cpu_id);
583         return -1;
584     }
585
586     PrintDebug("SVM core %u: I am starting at CS=0x%x (base=0x%p, limit=0x%x),  RIP=0x%p\n", 
587                info->cpu_id, info->segments.cs.selector, (void*)(info->segments.cs.base), 
588                info->segments.cs.limit,(void*)(info->rip));
589
590
591
592     PrintDebug("SVM core %u: Launching SVM VM (vmcb=%p)\n", info->cpu_id, (void *)info->vmm_data);
593     //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
594     
595     info->vm_info->run_state = VM_RUNNING;
596     v3_start_time(info);
597
598     while (1) {
599         if (v3_svm_enter(info) == -1) {
600             vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
601             addr_t host_addr;
602             addr_t linear_addr = 0;
603             
604             info->vm_info->run_state = VM_ERROR;
605             
606             V3_Print("SVM core %u: SVM ERROR!!\n", info->cpu_id); 
607             
608             v3_print_guest_state(info);
609             
610             V3_Print("SVM core %u: SVM Exit Code: %p\n", info->cpu_id, (void *)(addr_t)guest_ctrl->exit_code); 
611             
612             V3_Print("SVM core %u: exit_info1 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info1));
613             V3_Print("SVM core %u: exit_info1 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
614             
615             V3_Print("SVM core %u: exit_info2 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info2));
616             V3_Print("SVM core %u: exit_info2 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
617             
618             linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
619             
620             if (info->mem_mode == PHYSICAL_MEM) {
621                 v3_gpa_to_hva(info, linear_addr, &host_addr);
622             } else if (info->mem_mode == VIRTUAL_MEM) {
623                 v3_gva_to_hva(info, linear_addr, &host_addr);
624             }
625             
626             V3_Print("SVM core %u: Host Address of rip = 0x%p\n", info->cpu_id, (void *)host_addr);
627             
628             V3_Print("SVM core %u: Instr (15 bytes) at %p:\n", info->cpu_id, (void *)host_addr);
629             v3_dump_mem((uint8_t *)host_addr, 15);
630             
631             v3_print_stack(info);
632
633             break;
634         }
635         
636 /*
637         if ((info->num_exits % 5000) == 0) {
638             V3_Print("SVM Exit number %d\n", (uint32_t)info->num_exits);
639         }
640 */
641         
642     }
643
644     // Need to take down the other cores on error... 
645
646     return 0;
647 }
648
649
650
651
652
653 /* Checks machine SVM capability */
654 /* Implemented from: AMD Arch Manual 3, sect 15.4 */ 
655 int v3_is_svm_capable() {
656     uint_t vm_cr_low = 0, vm_cr_high = 0;
657     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
658
659     v3_cpuid(CPUID_EXT_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
660   
661     PrintDebug("CPUID_EXT_FEATURE_IDS_ecx=0x%x\n", ecx);
662
663     if ((ecx & CPUID_EXT_FEATURE_IDS_ecx_svm_avail) == 0) {
664       V3_Print("SVM Not Available\n");
665       return 0;
666     }  else {
667         v3_get_msr(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
668         
669         PrintDebug("SVM_VM_CR_MSR = 0x%x 0x%x\n", vm_cr_high, vm_cr_low);
670         
671         if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 1) {
672             V3_Print("SVM is available but is disabled.\n");
673             
674             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
675             
676             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
677             
678             if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
679                 V3_Print("SVM BIOS Disabled, not unlockable\n");
680             } else {
681                 V3_Print("SVM is locked with a key\n");
682             }
683             return 0;
684
685         } else {
686             V3_Print("SVM is available and  enabled.\n");
687
688             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
689             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_eax=0x%x\n", eax);
690             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ebx=0x%x\n", ebx);
691             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ecx=0x%x\n", ecx);
692             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
693
694             return 1;
695         }
696     }
697 }
698
699 static int has_svm_nested_paging() {
700     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
701
702     v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
703
704     //PrintDebug("CPUID_EXT_FEATURE_IDS_edx=0x%x\n", edx);
705
706     if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
707         V3_Print("SVM Nested Paging not supported\n");
708         return 0;
709     } else {
710         V3_Print("SVM Nested Paging supported\n");
711         return 1;
712     }
713 }
714
715
716 void v3_init_svm_cpu(int cpu_id) {
717     reg_ex_t msr;
718     extern v3_cpu_arch_t v3_cpu_types[];
719
720     // Enable SVM on the CPU
721     v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
722     msr.e_reg.low |= EFER_MSR_svm_enable;
723     v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
724
725     V3_Print("SVM Enabled\n");
726
727     // Setup the host state save area
728     host_vmcbs[cpu_id] = (addr_t)V3_AllocPages(4);
729
730     /* 64-BIT-ISSUE */
731     //  msr.e_reg.high = 0;
732     //msr.e_reg.low = (uint_t)host_vmcb;
733     msr.r_reg = host_vmcbs[cpu_id];
734
735     PrintDebug("Host State being saved at %p\n", (void *)host_vmcbs[cpu_id]);
736     v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
737
738
739     if (has_svm_nested_paging() == 1) {
740         v3_cpu_types[cpu_id] = V3_SVM_REV3_CPU;
741     } else {
742         v3_cpu_types[cpu_id] = V3_SVM_CPU;
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
792
793
794
795
796
797
798
799 #if 0
800 /* 
801  * Test VMSAVE/VMLOAD Latency 
802  */
803 #define vmsave ".byte 0x0F,0x01,0xDB ; "
804 #define vmload ".byte 0x0F,0x01,0xDA ; "
805 {
806     uint32_t start_lo, start_hi;
807     uint32_t end_lo, end_hi;
808     uint64_t start, end;
809     
810     __asm__ __volatile__ (
811                           "rdtsc ; "
812                           "movl %%eax, %%esi ; "
813                           "movl %%edx, %%edi ; "
814                           "movq  %%rcx, %%rax ; "
815                           vmsave
816                           "rdtsc ; "
817                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
818                           : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
819                           );
820     
821     start = start_hi;
822     start <<= 32;
823     start += start_lo;
824     
825     end = end_hi;
826     end <<= 32;
827     end += end_lo;
828     
829     PrintDebug("VMSave Cycle Latency: %d\n", (uint32_t)(end - start));
830     
831     __asm__ __volatile__ (
832                           "rdtsc ; "
833                           "movl %%eax, %%esi ; "
834                           "movl %%edx, %%edi ; "
835                           "movq  %%rcx, %%rax ; "
836                           vmload
837                           "rdtsc ; "
838                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
839                               : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
840                               );
841         
842         start = start_hi;
843         start <<= 32;
844         start += start_lo;
845
846         end = end_hi;
847         end <<= 32;
848         end += end_lo;
849
850
851         PrintDebug("VMLoad Cycle Latency: %d\n", (uint32_t)(end - start));
852     }
853     /* End Latency Test */
854
855 #endif
856
857
858
859
860
861
862
863 #if 0
864 void Init_VMCB_pe(vmcb_t *vmcb, struct guest_info vm_info) {
865   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
866   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
867   uint_t i = 0;
868
869
870   guest_state->rsp = vm_info.vm_regs.rsp;
871   guest_state->rip = vm_info.rip;
872
873
874   /* I pretty much just gutted this from TVMM */
875   /* Note: That means its probably wrong */
876
877   // set the segment registers to mirror ours
878   guest_state->cs.selector = 1<<3;
879   guest_state->cs.attrib.fields.type = 0xa; // Code segment+read
880   guest_state->cs.attrib.fields.S = 1;
881   guest_state->cs.attrib.fields.P = 1;
882   guest_state->cs.attrib.fields.db = 1;
883   guest_state->cs.attrib.fields.G = 1;
884   guest_state->cs.limit = 0xfffff;
885   guest_state->cs.base = 0;
886   
887   struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL};
888   for ( i = 0; segregs[i] != NULL; i++) {
889     struct vmcb_selector * seg = segregs[i];
890     
891     seg->selector = 2<<3;
892     seg->attrib.fields.type = 0x2; // Data Segment+read/write
893     seg->attrib.fields.S = 1;
894     seg->attrib.fields.P = 1;
895     seg->attrib.fields.db = 1;
896     seg->attrib.fields.G = 1;
897     seg->limit = 0xfffff;
898     seg->base = 0;
899   }
900
901
902   {
903     /* JRL THIS HAS TO GO */
904     
905     //    guest_state->tr.selector = GetTR_Selector();
906     guest_state->tr.attrib.fields.type = 0x9; 
907     guest_state->tr.attrib.fields.P = 1;
908     // guest_state->tr.limit = GetTR_Limit();
909     //guest_state->tr.base = GetTR_Base();// - 0x2000;
910     /* ** */
911   }
912
913
914   /* ** */
915
916
917   guest_state->efer |= EFER_MSR_svm_enable;
918   guest_state->rflags = 0x00000002; // The reserved bit is always 1
919   ctrl_area->svm_instrs.VMRUN = 1;
920   guest_state->cr0 = 0x00000001;    // PE 
921   ctrl_area->guest_ASID = 1;
922
923
924   //  guest_state->cpl = 0;
925
926
927
928   // Setup exits
929
930   ctrl_area->cr_writes.cr4 = 1;
931   
932   ctrl_area->exceptions.de = 1;
933   ctrl_area->exceptions.df = 1;
934   ctrl_area->exceptions.pf = 1;
935   ctrl_area->exceptions.ts = 1;
936   ctrl_area->exceptions.ss = 1;
937   ctrl_area->exceptions.ac = 1;
938   ctrl_area->exceptions.mc = 1;
939   ctrl_area->exceptions.gp = 1;
940   ctrl_area->exceptions.ud = 1;
941   ctrl_area->exceptions.np = 1;
942   ctrl_area->exceptions.of = 1;
943   ctrl_area->exceptions.nmi = 1;
944
945   
946
947   ctrl_area->instrs.IOIO_PROT = 1;
948   ctrl_area->IOPM_BASE_PA = (uint_t)V3_AllocPages(3);
949   
950   {
951     reg_ex_t tmp_reg;
952     tmp_reg.r_reg = ctrl_area->IOPM_BASE_PA;
953     memset((void*)(tmp_reg.e_reg.low), 0xffffffff, PAGE_SIZE * 2);
954   }
955
956   ctrl_area->instrs.INTR = 1;
957
958   
959   {
960     char gdt_buf[6];
961     char idt_buf[6];
962
963     memset(gdt_buf, 0, 6);
964     memset(idt_buf, 0, 6);
965
966
967     uint_t gdt_base, idt_base;
968     ushort_t gdt_limit, idt_limit;
969     
970     GetGDTR(gdt_buf);
971     gdt_base = *(ulong_t*)((uchar_t*)gdt_buf + 2) & 0xffffffff;
972     gdt_limit = *(ushort_t*)(gdt_buf) & 0xffff;
973     PrintDebug("GDT: base: %x, limit: %x\n", gdt_base, gdt_limit);
974
975     GetIDTR(idt_buf);
976     idt_base = *(ulong_t*)(idt_buf + 2) & 0xffffffff;
977     idt_limit = *(ushort_t*)(idt_buf) & 0xffff;
978     PrintDebug("IDT: base: %x, limit: %x\n",idt_base, idt_limit);
979
980
981     // gdt_base -= 0x2000;
982     //idt_base -= 0x2000;
983
984     guest_state->gdtr.base = gdt_base;
985     guest_state->gdtr.limit = gdt_limit;
986     guest_state->idtr.base = idt_base;
987     guest_state->idtr.limit = idt_limit;
988
989
990   }
991   
992   
993   // also determine if CPU supports nested paging
994   /*
995   if (vm_info.page_tables) {
996     //   if (0) {
997     // Flush the TLB on entries/exits
998     ctrl_area->TLB_CONTROL = 1;
999
1000     // Enable Nested Paging
1001     ctrl_area->NP_ENABLE = 1;
1002
1003     PrintDebug("NP_Enable at 0x%x\n", &(ctrl_area->NP_ENABLE));
1004
1005         // Set the Nested Page Table pointer
1006     ctrl_area->N_CR3 |= ((addr_t)vm_info.page_tables & 0xfffff000);
1007
1008
1009     //   ctrl_area->N_CR3 = Get_CR3();
1010     // guest_state->cr3 |= (Get_CR3() & 0xfffff000);
1011
1012     guest_state->g_pat = 0x7040600070406ULL;
1013
1014     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));
1015     PrintDebug("Set Guest CR3: lo: 0x%x  hi: 0x%x\n", (uint_t)*(&(guest_state->cr3)), (uint_t)*((unsigned char *)&(guest_state->cr3) + 4));
1016     // Enable Paging
1017     //    guest_state->cr0 |= 0x80000000;
1018   }
1019   */
1020
1021 }
1022
1023
1024
1025
1026
1027 #endif
1028
1029