Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Fixed (hopefully) bug introduced previously by moving update_timers outside of the...
[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.ICEBP = 1;
91     ctrl_area->svm_instrs.WBINVD = 1;
92     ctrl_area->svm_instrs.MONITOR = 1;
93     ctrl_area->svm_instrs.MWAIT_always = 1;
94     ctrl_area->svm_instrs.MWAIT_if_armed = 1;
95     ctrl_area->instrs.INVLPGA = 1;
96     ctrl_area->instrs.CPUID = 1;
97
98     ctrl_area->instrs.HLT = 1;
99
100 #ifdef CONFIG_TIME_VIRTUALIZE_TSC
101     ctrl_area->instrs.RDTSC = 1;
102     ctrl_area->svm_instrs.RDTSCP = 1;
103 #endif
104
105     // guest_state->cr0 = 0x00000001;    // PE 
106   
107     /*
108       ctrl_area->exceptions.de = 1;
109       ctrl_area->exceptions.df = 1;
110       
111       ctrl_area->exceptions.ts = 1;
112       ctrl_area->exceptions.ss = 1;
113       ctrl_area->exceptions.ac = 1;
114       ctrl_area->exceptions.mc = 1;
115       ctrl_area->exceptions.gp = 1;
116       ctrl_area->exceptions.ud = 1;
117       ctrl_area->exceptions.np = 1;
118       ctrl_area->exceptions.of = 1;
119       
120       ctrl_area->exceptions.nmi = 1;
121     */
122     
123
124     ctrl_area->instrs.NMI = 1;
125     ctrl_area->instrs.SMI = 0; // allow SMIs to run in guest
126     ctrl_area->instrs.INIT = 1;
127     ctrl_area->instrs.PAUSE = 1;
128     ctrl_area->instrs.shutdown_evts = 1;
129
130
131     /* DEBUG FOR RETURN CODE */
132     ctrl_area->exit_code = 1;
133
134
135     /* Setup Guest Machine state */
136
137     core->vm_regs.rsp = 0x00;
138     core->rip = 0xfff0;
139
140     core->vm_regs.rdx = 0x00000f00;
141
142
143     core->cpl = 0;
144
145     core->ctrl_regs.rflags = 0x00000002; // The reserved bit is always 1
146     core->ctrl_regs.cr0 = 0x60010010; // Set the WP flag so the memory hooks work in real-mode
147     core->ctrl_regs.efer |= EFER_MSR_svm_enable;
148
149
150
151
152
153     core->segments.cs.selector = 0xf000;
154     core->segments.cs.limit = 0xffff;
155     core->segments.cs.base = 0x0000000f0000LL;
156
157     // (raw attributes = 0xf3)
158     core->segments.cs.type = 0x3;
159     core->segments.cs.system = 0x1;
160     core->segments.cs.dpl = 0x3;
161     core->segments.cs.present = 1;
162
163
164
165     struct v3_segment * segregs [] = {&(core->segments.ss), &(core->segments.ds), 
166                                       &(core->segments.es), &(core->segments.fs), 
167                                       &(core->segments.gs), NULL};
168
169     for ( i = 0; segregs[i] != NULL; i++) {
170         struct v3_segment * seg = segregs[i];
171         
172         seg->selector = 0x0000;
173         //    seg->base = seg->selector << 4;
174         seg->base = 0x00000000;
175         seg->limit = ~0u;
176
177         // (raw attributes = 0xf3)
178         seg->type = 0x3;
179         seg->system = 0x1;
180         seg->dpl = 0x3;
181         seg->present = 1;
182     }
183
184     core->segments.gdtr.limit = 0x0000ffff;
185     core->segments.gdtr.base = 0x0000000000000000LL;
186     core->segments.idtr.limit = 0x0000ffff;
187     core->segments.idtr.base = 0x0000000000000000LL;
188
189     core->segments.ldtr.selector = 0x0000;
190     core->segments.ldtr.limit = 0x0000ffff;
191     core->segments.ldtr.base = 0x0000000000000000LL;
192     core->segments.tr.selector = 0x0000;
193     core->segments.tr.limit = 0x0000ffff;
194     core->segments.tr.base = 0x0000000000000000LL;
195
196
197     core->dbg_regs.dr6 = 0x00000000ffff0ff0LL;
198     core->dbg_regs.dr7 = 0x0000000000000400LL;
199
200
201     ctrl_area->IOPM_BASE_PA = (addr_t)V3_PAddr(core->vm_info->io_map.arch_data);
202     ctrl_area->instrs.IOIO_PROT = 1;
203             
204     ctrl_area->MSRPM_BASE_PA = (addr_t)V3_PAddr(core->vm_info->msr_map.arch_data);
205     ctrl_area->instrs.MSR_PROT = 1;   
206
207
208     PrintDebug("Exiting on interrupts\n");
209     ctrl_area->guest_ctrl.V_INTR_MASKING = 1;
210     ctrl_area->instrs.INTR = 1;
211
212
213     if (core->shdw_pg_mode == SHADOW_PAGING) {
214         PrintDebug("Creating initial shadow page table\n");
215         
216         /* JRL: This is a performance killer, and a simplistic solution */
217         /* We need to fix this */
218         ctrl_area->TLB_CONTROL = 1;
219         ctrl_area->guest_ASID = 1;
220         
221         
222         if (v3_init_passthrough_pts(core) == -1) {
223             PrintError("Could not initialize passthrough page tables\n");
224             return ;
225         }
226
227
228         core->shdw_pg_state.guest_cr0 = 0x0000000000000010LL;
229         PrintDebug("Created\n");
230         
231         core->ctrl_regs.cr0 |= 0x80000000;
232         core->ctrl_regs.cr3 = core->direct_map_pt;
233
234         ctrl_area->cr_reads.cr0 = 1;
235         ctrl_area->cr_writes.cr0 = 1;
236         //ctrl_area->cr_reads.cr4 = 1;
237         ctrl_area->cr_writes.cr4 = 1;
238         ctrl_area->cr_reads.cr3 = 1;
239         ctrl_area->cr_writes.cr3 = 1;
240
241         v3_hook_msr(core->vm_info, EFER_MSR, 
242                     &v3_handle_efer_read,
243                     &v3_handle_efer_write, 
244                     core);
245
246         ctrl_area->instrs.INVLPG = 1;
247
248         ctrl_area->exceptions.pf = 1;
249
250         guest_state->g_pat = 0x7040600070406ULL;
251
252
253
254     } else if (core->shdw_pg_mode == NESTED_PAGING) {
255         // Flush the TLB on entries/exits
256         ctrl_area->TLB_CONTROL = 1;
257         ctrl_area->guest_ASID = 1;
258
259         // Enable Nested Paging
260         ctrl_area->NP_ENABLE = 1;
261
262         PrintDebug("NP_Enable at 0x%p\n", (void *)&(ctrl_area->NP_ENABLE));
263
264         // Set the Nested Page Table pointer
265         if (v3_init_passthrough_pts(core) == -1) {
266             PrintError("Could not initialize Nested page tables\n");
267             return ;
268         }
269
270         ctrl_area->N_CR3 = core->direct_map_pt;
271
272         guest_state->g_pat = 0x7040600070406ULL;
273     }
274 }
275
276
277 int v3_init_svm_vmcb(struct guest_info * info, v3_vm_class_t vm_class) {
278
279     PrintDebug("Allocating VMCB\n");
280     info->vmm_data = (void*)Allocate_VMCB();
281     
282     if (vm_class == V3_PC_VM) {
283         PrintDebug("Initializing VMCB (addr=%p)\n", (void *)info->vmm_data);
284         Init_VMCB_BIOS((vmcb_t*)(info->vmm_data), info);
285     } else {
286         PrintError("Invalid VM class\n");
287         return -1;
288     }
289
290     return 0;
291 }
292
293
294
295 static int update_irq_exit_state(struct guest_info * info) {
296     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
297
298     // Fix for QEMU bug using EVENTINJ as an internal cache
299     guest_ctrl->EVENTINJ.valid = 0;
300
301     if ((info->intr_core_state.irq_pending == 1) && (guest_ctrl->guest_ctrl.V_IRQ == 0)) {
302         
303 #ifdef CONFIG_DEBUG_INTERRUPTS
304         PrintDebug("INTAK cycle completed for irq %d\n", info->intr_core_state.irq_vector);
305 #endif
306
307         info->intr_core_state.irq_started = 1;
308         info->intr_core_state.irq_pending = 0;
309
310         v3_injecting_intr(info, info->intr_core_state.irq_vector, V3_EXTERNAL_IRQ);
311     }
312
313     if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 0)) {
314 #ifdef CONFIG_DEBUG_INTERRUPTS
315         PrintDebug("Interrupt %d taken by guest\n", info->intr_core_state.irq_vector);
316 #endif
317
318         // Interrupt was taken fully vectored
319         info->intr_core_state.irq_started = 0;
320
321     } else if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 1)) {
322 #ifdef CONFIG_DEBUG_INTERRUPTS
323         PrintDebug("EXIT INT INFO is set (vec=%d)\n", guest_ctrl->exit_int_info.vector);
324 #endif
325     }
326
327     return 0;
328 }
329
330
331 static int update_irq_entry_state(struct guest_info * info) {
332     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
333
334
335     if (info->intr_core_state.irq_pending == 0) {
336         guest_ctrl->guest_ctrl.V_IRQ = 0;
337         guest_ctrl->guest_ctrl.V_INTR_VECTOR = 0;
338     }
339     
340     if (v3_excp_pending(info)) {
341         uint_t excp = v3_get_excp_number(info);
342         
343         guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
344         
345         if (info->excp_state.excp_error_code_valid) {
346             guest_ctrl->EVENTINJ.error_code = info->excp_state.excp_error_code;
347             guest_ctrl->EVENTINJ.ev = 1;
348 #ifdef CONFIG_DEBUG_INTERRUPTS
349             PrintDebug("Injecting exception %d with error code %x\n", excp, guest_ctrl->EVENTINJ.error_code);
350 #endif
351         }
352         
353         guest_ctrl->EVENTINJ.vector = excp;
354         
355         guest_ctrl->EVENTINJ.valid = 1;
356
357 #ifdef CONFIG_DEBUG_INTERRUPTS
358         PrintDebug("<%d> Injecting Exception %d (CR2=%p) (EIP=%p)\n", 
359                    (int)info->num_exits, 
360                    guest_ctrl->EVENTINJ.vector, 
361                    (void *)(addr_t)info->ctrl_regs.cr2,
362                    (void *)(addr_t)info->rip);
363 #endif
364
365         v3_injecting_excp(info, excp);
366     } else if (info->intr_core_state.irq_started == 1) {
367 #ifdef CONFIG_DEBUG_INTERRUPTS
368         PrintDebug("IRQ pending from previous injection\n");
369 #endif
370         guest_ctrl->guest_ctrl.V_IRQ = 1;
371         guest_ctrl->guest_ctrl.V_INTR_VECTOR = info->intr_core_state.irq_vector;
372         guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
373         guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
374
375     } else {
376         switch (v3_intr_pending(info)) {
377             case V3_EXTERNAL_IRQ: {
378                 uint32_t irq = v3_get_intr(info);
379
380                 guest_ctrl->guest_ctrl.V_IRQ = 1;
381                 guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
382                 guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
383                 guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
384
385 #ifdef CONFIG_DEBUG_INTERRUPTS
386                 PrintDebug("Injecting Interrupt %d (EIP=%p)\n", 
387                            guest_ctrl->guest_ctrl.V_INTR_VECTOR, 
388                            (void *)(addr_t)info->rip);
389 #endif
390
391                 info->intr_core_state.irq_pending = 1;
392                 info->intr_core_state.irq_vector = irq;
393                 
394                 break;
395             }
396             case V3_NMI:
397                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
398                 break;
399             case V3_SOFTWARE_INTR:
400                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
401                 break;
402             case V3_VIRTUAL_IRQ:
403                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_IRQ;
404                 break;
405
406             case V3_INVALID_INTR:
407             default:
408                 break;
409         }
410         
411     }
412
413     return 0;
414 }
415
416
417 /* 
418  * CAUTION and DANGER!!! 
419  * 
420  * The VMCB CANNOT(!!) be accessed outside of the clgi/stgi calls inside this function
421  * When exectuing a symbiotic call, the VMCB WILL be overwritten, so any dependencies 
422  * on its contents will cause things to break. The contents at the time of the exit WILL 
423  * change before the exit handler is executed.
424  */
425 int v3_svm_enter(struct guest_info * info) {
426     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
427     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); 
428     addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0;
429
430     v3_adjust_time(info);
431
432     // Conditionally yield the CPU if the timeslice has expired
433     v3_yield_cond(info);
434
435     // disable global interrupts for vm state transition
436     v3_clgi();
437
438     // Synchronize the guest state to the VMCB
439     guest_state->cr0 = info->ctrl_regs.cr0;
440     guest_state->cr2 = info->ctrl_regs.cr2;
441     guest_state->cr3 = info->ctrl_regs.cr3;
442     guest_state->cr4 = info->ctrl_regs.cr4;
443     guest_state->dr6 = info->dbg_regs.dr6;
444     guest_state->dr7 = info->dbg_regs.dr7;
445     guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
446     guest_state->rflags = info->ctrl_regs.rflags;
447     guest_state->efer = info->ctrl_regs.efer;
448     
449     guest_state->cpl = info->cpl;
450
451     v3_set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
452
453     guest_state->rax = info->vm_regs.rax;
454     guest_state->rip = info->rip;
455     guest_state->rsp = info->vm_regs.rsp;
456
457 #ifdef CONFIG_SYMCALL
458     if (info->sym_core_state.symcall_state.sym_call_active == 0) {
459         update_irq_entry_state(info);
460     }
461 #else 
462     update_irq_entry_state(info);
463 #endif
464
465
466     /* ** */
467
468     /*
469       PrintDebug("SVM Entry to CS=%p  rip=%p...\n", 
470       (void *)(addr_t)info->segments.cs.base, 
471       (void *)(addr_t)info->rip);
472     */
473
474 #ifdef CONFIG_SYMCALL
475     if (info->sym_core_state.symcall_state.sym_call_active == 1) {
476         if (guest_ctrl->guest_ctrl.V_IRQ == 1) {
477             V3_Print("!!! Injecting Interrupt during Sym call !!!\n");
478         }
479     }
480 #endif
481
482     v3_update_timers(info);
483     guest_ctrl->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
484
485     //V3_Print("Calling v3_svm_launch\n");
486
487     v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->cpu_id]);
488
489     //V3_Print("SVM Returned: Exit Code: %x, guest_rip=%lx\n", (uint32_t)(guest_ctrl->exit_code), (unsigned long)guest_state->rip);
490
491     v3_last_exit = (uint32_t)(guest_ctrl->exit_code);
492
493     //PrintDebug("SVM Returned\n");
494     
495     info->num_exits++;
496
497     // Save Guest state from VMCB
498     info->rip = guest_state->rip;
499     info->vm_regs.rsp = guest_state->rsp;
500     info->vm_regs.rax = guest_state->rax;
501
502     info->cpl = guest_state->cpl;
503
504     info->ctrl_regs.cr0 = guest_state->cr0;
505     info->ctrl_regs.cr2 = guest_state->cr2;
506     info->ctrl_regs.cr3 = guest_state->cr3;
507     info->ctrl_regs.cr4 = guest_state->cr4;
508     info->dbg_regs.dr6 = guest_state->dr6;
509     info->dbg_regs.dr7 = guest_state->dr7;
510     info->ctrl_regs.cr8 = guest_ctrl->guest_ctrl.V_TPR;
511     info->ctrl_regs.rflags = guest_state->rflags;
512     info->ctrl_regs.efer = guest_state->efer;
513     
514     v3_get_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
515     info->cpu_mode = v3_get_vm_cpu_mode(info);
516     info->mem_mode = v3_get_vm_mem_mode(info);
517     /* ** */
518
519
520     // save exit info here
521     exit_code = guest_ctrl->exit_code;
522     exit_info1 = guest_ctrl->exit_info1;
523     exit_info2 = guest_ctrl->exit_info2;
524
525
526 #ifdef CONFIG_SYMCALL
527     if (info->sym_core_state.symcall_state.sym_call_active == 0) {
528         update_irq_exit_state(info);
529     }
530 #else
531     update_irq_exit_state(info);
532 #endif
533
534
535     // reenable global interrupts after vm exit
536     v3_stgi();
537
538  
539     // Conditionally yield the CPU if the timeslice has expired
540     v3_yield_cond(info);
541
542
543
544     if (v3_handle_svm_exit(info, exit_code, exit_info1, exit_info2) != 0) {
545         PrintError("Error in SVM exit handler\n");
546         return -1;
547     }
548
549
550     return 0;
551 }
552
553
554 int v3_start_svm_guest(struct guest_info * info) {
555     //    vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
556     //  vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
557
558     PrintDebug("Starting SVM core %u\n", info->cpu_id);
559
560     if (info->cpu_id == 0) {
561         info->core_run_state = CORE_RUNNING;
562         info->vm_info->run_state = VM_RUNNING;
563     } else  { 
564         PrintDebug("SVM core %u: Waiting for core initialization\n", info->cpu_id);
565
566         while (info->core_run_state == CORE_STOPPED) {
567             v3_yield(info);
568             //PrintDebug("SVM core %u: still waiting for INIT\n",info->cpu_id);
569         }
570
571         PrintDebug("SVM core %u initialized\n", info->cpu_id);
572     } 
573
574     PrintDebug("SVM core %u: I am starting at CS=0x%x (base=0x%p, limit=0x%x),  RIP=0x%p\n", 
575                info->cpu_id, info->segments.cs.selector, (void *)(info->segments.cs.base), 
576                info->segments.cs.limit, (void *)(info->rip));
577
578
579
580     PrintDebug("SVM core %u: Launching SVM VM (vmcb=%p)\n", info->cpu_id, (void *)info->vmm_data);
581     //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
582     
583     v3_start_time(info);
584
585     while (1) {
586
587         if (info->vm_info->run_state == VM_STOPPED) {
588             info->core_run_state = CORE_STOPPED;
589             break;
590         }
591         
592         if (v3_svm_enter(info) == -1) {
593             vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
594             addr_t host_addr;
595             addr_t linear_addr = 0;
596             
597             info->vm_info->run_state = VM_ERROR;
598             
599             V3_Print("SVM core %u: SVM ERROR!!\n", info->cpu_id); 
600             
601             v3_print_guest_state(info);
602             
603             V3_Print("SVM core %u: SVM Exit Code: %p\n", info->cpu_id, (void *)(addr_t)guest_ctrl->exit_code); 
604             
605             V3_Print("SVM core %u: exit_info1 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info1));
606             V3_Print("SVM core %u: exit_info1 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
607             
608             V3_Print("SVM core %u: exit_info2 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info2));
609             V3_Print("SVM core %u: exit_info2 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
610             
611             linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
612             
613             if (info->mem_mode == PHYSICAL_MEM) {
614                 v3_gpa_to_hva(info, linear_addr, &host_addr);
615             } else if (info->mem_mode == VIRTUAL_MEM) {
616                 v3_gva_to_hva(info, linear_addr, &host_addr);
617             }
618             
619             V3_Print("SVM core %u: Host Address of rip = 0x%p\n", info->cpu_id, (void *)host_addr);
620             
621             V3_Print("SVM core %u: Instr (15 bytes) at %p:\n", info->cpu_id, (void *)host_addr);
622             v3_dump_mem((uint8_t *)host_addr, 15);
623             
624             v3_print_stack(info);
625
626             break;
627         }
628
629
630         if (info->vm_info->run_state == VM_STOPPED) {
631             info->core_run_state = CORE_STOPPED;
632             break;
633         }
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