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