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.


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