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.


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