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.


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