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.


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