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.


Fix interrupt injection bug due to caching irq vectors after vector mappings have...
[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     // Synchronize the guest state to the VMCB
429     guest_state->cr0 = info->ctrl_regs.cr0;
430     guest_state->cr2 = info->ctrl_regs.cr2;
431     guest_state->cr3 = info->ctrl_regs.cr3;
432     guest_state->cr4 = info->ctrl_regs.cr4;
433     guest_state->dr6 = info->dbg_regs.dr6;
434     guest_state->dr7 = info->dbg_regs.dr7;
435     guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
436     guest_state->rflags = info->ctrl_regs.rflags;
437     guest_state->efer = info->ctrl_regs.efer;
438     
439     guest_state->cpl = info->cpl;
440
441     v3_set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
442
443     guest_state->rax = info->vm_regs.rax;
444     guest_state->rip = info->rip;
445     guest_state->rsp = info->vm_regs.rsp;
446
447 #ifdef CONFIG_SYMBIOTIC
448     if (info->sym_state.sym_call_active == 0) {
449         update_irq_entry_state(info);
450     }
451 #else 
452     update_irq_entry_state(info);
453 #endif
454
455
456     /* ** */
457
458     /*
459       PrintDebug("SVM Entry to CS=%p  rip=%p...\n", 
460       (void *)(addr_t)info->segments.cs.base, 
461       (void *)(addr_t)info->rip);
462     */
463
464 #ifdef CONFIG_SYMBIOTIC
465     if (info->sym_state.sym_call_active == 1) {
466         if (guest_ctrl->guest_ctrl.V_IRQ == 1) {
467             V3_Print("!!! Injecting Interrupt during Sym call !!!\n");
468         }
469     }
470 #endif
471
472
473     rdtscll(info->time_state.cached_host_tsc);
474     guest_ctrl->TSC_OFFSET = info->time_state.guest_tsc - info->time_state.cached_host_tsc;
475         
476     v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->cpu_id]);
477     
478
479     v3_last_exit = (uint32_t)(guest_ctrl->exit_code);
480
481     //  v3_print_cond("SVM Returned: Exit Code: %x\n", (uint32_t)(guest_ctrl->exit_code));
482
483     rdtscll(tmp_tsc);
484
485     //PrintDebug("SVM Returned\n");
486     
487     info->num_exits++;
488
489     v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc);
490
491
492     // Save Guest state from VMCB
493     info->rip = guest_state->rip;
494     info->vm_regs.rsp = guest_state->rsp;
495     info->vm_regs.rax = guest_state->rax;
496
497     info->cpl = guest_state->cpl;
498
499     info->ctrl_regs.cr0 = guest_state->cr0;
500     info->ctrl_regs.cr2 = guest_state->cr2;
501     info->ctrl_regs.cr3 = guest_state->cr3;
502     info->ctrl_regs.cr4 = guest_state->cr4;
503     info->dbg_regs.dr6 = guest_state->dr6;
504     info->dbg_regs.dr7 = guest_state->dr7;
505     info->ctrl_regs.cr8 = guest_ctrl->guest_ctrl.V_TPR;
506     info->ctrl_regs.rflags = guest_state->rflags;
507     info->ctrl_regs.efer = guest_state->efer;
508     
509     v3_get_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
510     info->cpu_mode = v3_get_vm_cpu_mode(info);
511     info->mem_mode = v3_get_vm_mem_mode(info);
512     /* ** */
513
514
515     // save exit info here
516     exit_code = guest_ctrl->exit_code;
517     exit_info1 = guest_ctrl->exit_info1;
518     exit_info2 = guest_ctrl->exit_info2;
519
520
521 #ifdef CONFIG_SYMBIOTIC
522     if (info->sym_state.sym_call_active == 0) {
523         update_irq_exit_state(info);
524     }
525 #else
526     update_irq_exit_state(info);
527 #endif
528
529
530     // reenable global interrupts after vm exit
531     v3_stgi();
532
533  
534     // Conditionally yield the CPU if the timeslice has expired
535     v3_yield_cond(info);
536
537
538     if (v3_handle_svm_exit(info, exit_code, exit_info1, exit_info2) != 0) {
539         PrintError("Error in SVM exit handler\n");
540         return -1;
541     }
542
543
544     return 0;
545 }
546
547
548 int v3_start_svm_guest(struct guest_info *info) {
549     //    vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
550     //  vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
551
552
553
554     PrintDebug("Launching SVM VM (vmcb=%p)\n", (void *)info->vmm_data);
555     //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
556     
557     info->run_state = VM_RUNNING;
558     rdtscll(info->yield_start_cycle);
559
560
561     while (1) {
562         if (v3_svm_enter(info) == -1) {
563             vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
564             addr_t host_addr;
565             addr_t linear_addr = 0;
566             
567             info->run_state = VM_ERROR;
568             
569             V3_Print("SVM ERROR!!\n"); 
570             
571             v3_print_guest_state(info);
572             
573             V3_Print("SVM Exit Code: %p\n", (void *)(addr_t)guest_ctrl->exit_code); 
574             
575             V3_Print("exit_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
576             V3_Print("exit_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
577             
578             V3_Print("exit_info2 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info2));
579             V3_Print("exit_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
580             
581             linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
582             
583             if (info->mem_mode == PHYSICAL_MEM) {
584                 guest_pa_to_host_va(info, linear_addr, &host_addr);
585             } else if (info->mem_mode == VIRTUAL_MEM) {
586                 guest_va_to_host_va(info, linear_addr, &host_addr);
587             }
588             
589             V3_Print("Host Address of rip = 0x%p\n", (void *)host_addr);
590             
591             V3_Print("Instr (15 bytes) at %p:\n", (void *)host_addr);
592             v3_dump_mem((uint8_t *)host_addr, 15);
593             
594             v3_print_stack(info);
595
596             break;
597         }
598         
599 /*
600         if ((info->num_exits % 5000) == 0) {
601             V3_Print("SVM Exit number %d\n", (uint32_t)info->num_exits);
602         }
603 */
604         
605     }
606     return 0;
607 }
608
609
610
611
612
613 /* Checks machine SVM capability */
614 /* Implemented from: AMD Arch Manual 3, sect 15.4 */ 
615 int v3_is_svm_capable() {
616     uint_t vm_cr_low = 0, vm_cr_high = 0;
617     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
618
619     v3_cpuid(CPUID_EXT_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
620   
621     PrintDebug("CPUID_EXT_FEATURE_IDS_ecx=0x%x\n", ecx);
622
623     if ((ecx & CPUID_EXT_FEATURE_IDS_ecx_svm_avail) == 0) {
624       V3_Print("SVM Not Available\n");
625       return 0;
626     }  else {
627         v3_get_msr(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
628         
629         PrintDebug("SVM_VM_CR_MSR = 0x%x 0x%x\n", vm_cr_high, vm_cr_low);
630         
631         if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 1) {
632             V3_Print("SVM is available but is disabled.\n");
633             
634             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
635             
636             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
637             
638             if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
639                 V3_Print("SVM BIOS Disabled, not unlockable\n");
640             } else {
641                 V3_Print("SVM is locked with a key\n");
642             }
643             return 0;
644
645         } else {
646             V3_Print("SVM is available and  enabled.\n");
647
648             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
649             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_eax=0x%x\n", eax);
650             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ebx=0x%x\n", ebx);
651             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ecx=0x%x\n", ecx);
652             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
653
654             return 1;
655         }
656     }
657 }
658
659 static int has_svm_nested_paging() {
660     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
661
662     v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
663
664     //PrintDebug("CPUID_EXT_FEATURE_IDS_edx=0x%x\n", edx);
665
666     if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
667         V3_Print("SVM Nested Paging not supported\n");
668         return 0;
669     } else {
670         V3_Print("SVM Nested Paging supported\n");
671         return 1;
672     }
673 }
674
675
676 void v3_init_svm_cpu(int cpu_id) {
677     reg_ex_t msr;
678     extern v3_cpu_arch_t v3_cpu_types[];
679
680     // Enable SVM on the CPU
681     v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
682     msr.e_reg.low |= EFER_MSR_svm_enable;
683     v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
684
685     V3_Print("SVM Enabled\n");
686
687     // Setup the host state save area
688     host_vmcbs[cpu_id] = (addr_t)V3_AllocPages(4);
689
690     /* 64-BIT-ISSUE */
691     //  msr.e_reg.high = 0;
692     //msr.e_reg.low = (uint_t)host_vmcb;
693     msr.r_reg = host_vmcbs[cpu_id];
694
695     PrintDebug("Host State being saved at %p\n", (void *)host_vmcbs[cpu_id]);
696     v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
697
698
699     if (has_svm_nested_paging() == 1) {
700         v3_cpu_types[cpu_id] = V3_SVM_REV3_CPU;
701     } else {
702         v3_cpu_types[cpu_id] = V3_SVM_CPU;
703     }
704 }
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 #if 0
760 /* 
761  * Test VMSAVE/VMLOAD Latency 
762  */
763 #define vmsave ".byte 0x0F,0x01,0xDB ; "
764 #define vmload ".byte 0x0F,0x01,0xDA ; "
765 {
766     uint32_t start_lo, start_hi;
767     uint32_t end_lo, end_hi;
768     uint64_t start, end;
769     
770     __asm__ __volatile__ (
771                           "rdtsc ; "
772                           "movl %%eax, %%esi ; "
773                           "movl %%edx, %%edi ; "
774                           "movq  %%rcx, %%rax ; "
775                           vmsave
776                           "rdtsc ; "
777                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
778                           : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
779                           );
780     
781     start = start_hi;
782     start <<= 32;
783     start += start_lo;
784     
785     end = end_hi;
786     end <<= 32;
787     end += end_lo;
788     
789     PrintDebug("VMSave Cycle Latency: %d\n", (uint32_t)(end - start));
790     
791     __asm__ __volatile__ (
792                           "rdtsc ; "
793                           "movl %%eax, %%esi ; "
794                           "movl %%edx, %%edi ; "
795                           "movq  %%rcx, %%rax ; "
796                           vmload
797                           "rdtsc ; "
798                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
799                               : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
800                               );
801         
802         start = start_hi;
803         start <<= 32;
804         start += start_lo;
805
806         end = end_hi;
807         end <<= 32;
808         end += end_lo;
809
810
811         PrintDebug("VMLoad Cycle Latency: %d\n", (uint32_t)(end - start));
812     }
813     /* End Latency Test */
814
815 #endif
816
817
818
819
820
821
822
823 #if 0
824 void Init_VMCB_pe(vmcb_t *vmcb, struct guest_info vm_info) {
825   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
826   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
827   uint_t i = 0;
828
829
830   guest_state->rsp = vm_info.vm_regs.rsp;
831   guest_state->rip = vm_info.rip;
832
833
834   /* I pretty much just gutted this from TVMM */
835   /* Note: That means its probably wrong */
836
837   // set the segment registers to mirror ours
838   guest_state->cs.selector = 1<<3;
839   guest_state->cs.attrib.fields.type = 0xa; // Code segment+read
840   guest_state->cs.attrib.fields.S = 1;
841   guest_state->cs.attrib.fields.P = 1;
842   guest_state->cs.attrib.fields.db = 1;
843   guest_state->cs.attrib.fields.G = 1;
844   guest_state->cs.limit = 0xfffff;
845   guest_state->cs.base = 0;
846   
847   struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL};
848   for ( i = 0; segregs[i] != NULL; i++) {
849     struct vmcb_selector * seg = segregs[i];
850     
851     seg->selector = 2<<3;
852     seg->attrib.fields.type = 0x2; // Data Segment+read/write
853     seg->attrib.fields.S = 1;
854     seg->attrib.fields.P = 1;
855     seg->attrib.fields.db = 1;
856     seg->attrib.fields.G = 1;
857     seg->limit = 0xfffff;
858     seg->base = 0;
859   }
860
861
862   {
863     /* JRL THIS HAS TO GO */
864     
865     //    guest_state->tr.selector = GetTR_Selector();
866     guest_state->tr.attrib.fields.type = 0x9; 
867     guest_state->tr.attrib.fields.P = 1;
868     // guest_state->tr.limit = GetTR_Limit();
869     //guest_state->tr.base = GetTR_Base();// - 0x2000;
870     /* ** */
871   }
872
873
874   /* ** */
875
876
877   guest_state->efer |= EFER_MSR_svm_enable;
878   guest_state->rflags = 0x00000002; // The reserved bit is always 1
879   ctrl_area->svm_instrs.VMRUN = 1;
880   guest_state->cr0 = 0x00000001;    // PE 
881   ctrl_area->guest_ASID = 1;
882
883
884   //  guest_state->cpl = 0;
885
886
887
888   // Setup exits
889
890   ctrl_area->cr_writes.cr4 = 1;
891   
892   ctrl_area->exceptions.de = 1;
893   ctrl_area->exceptions.df = 1;
894   ctrl_area->exceptions.pf = 1;
895   ctrl_area->exceptions.ts = 1;
896   ctrl_area->exceptions.ss = 1;
897   ctrl_area->exceptions.ac = 1;
898   ctrl_area->exceptions.mc = 1;
899   ctrl_area->exceptions.gp = 1;
900   ctrl_area->exceptions.ud = 1;
901   ctrl_area->exceptions.np = 1;
902   ctrl_area->exceptions.of = 1;
903   ctrl_area->exceptions.nmi = 1;
904
905   
906
907   ctrl_area->instrs.IOIO_PROT = 1;
908   ctrl_area->IOPM_BASE_PA = (uint_t)V3_AllocPages(3);
909   
910   {
911     reg_ex_t tmp_reg;
912     tmp_reg.r_reg = ctrl_area->IOPM_BASE_PA;
913     memset((void*)(tmp_reg.e_reg.low), 0xffffffff, PAGE_SIZE * 2);
914   }
915
916   ctrl_area->instrs.INTR = 1;
917
918   
919   {
920     char gdt_buf[6];
921     char idt_buf[6];
922
923     memset(gdt_buf, 0, 6);
924     memset(idt_buf, 0, 6);
925
926
927     uint_t gdt_base, idt_base;
928     ushort_t gdt_limit, idt_limit;
929     
930     GetGDTR(gdt_buf);
931     gdt_base = *(ulong_t*)((uchar_t*)gdt_buf + 2) & 0xffffffff;
932     gdt_limit = *(ushort_t*)(gdt_buf) & 0xffff;
933     PrintDebug("GDT: base: %x, limit: %x\n", gdt_base, gdt_limit);
934
935     GetIDTR(idt_buf);
936     idt_base = *(ulong_t*)(idt_buf + 2) & 0xffffffff;
937     idt_limit = *(ushort_t*)(idt_buf) & 0xffff;
938     PrintDebug("IDT: base: %x, limit: %x\n",idt_base, idt_limit);
939
940
941     // gdt_base -= 0x2000;
942     //idt_base -= 0x2000;
943
944     guest_state->gdtr.base = gdt_base;
945     guest_state->gdtr.limit = gdt_limit;
946     guest_state->idtr.base = idt_base;
947     guest_state->idtr.limit = idt_limit;
948
949
950   }
951   
952   
953   // also determine if CPU supports nested paging
954   /*
955   if (vm_info.page_tables) {
956     //   if (0) {
957     // Flush the TLB on entries/exits
958     ctrl_area->TLB_CONTROL = 1;
959
960     // Enable Nested Paging
961     ctrl_area->NP_ENABLE = 1;
962
963     PrintDebug("NP_Enable at 0x%x\n", &(ctrl_area->NP_ENABLE));
964
965         // Set the Nested Page Table pointer
966     ctrl_area->N_CR3 |= ((addr_t)vm_info.page_tables & 0xfffff000);
967
968
969     //   ctrl_area->N_CR3 = Get_CR3();
970     // guest_state->cr3 |= (Get_CR3() & 0xfffff000);
971
972     guest_state->g_pat = 0x7040600070406ULL;
973
974     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));
975     PrintDebug("Set Guest CR3: lo: 0x%x  hi: 0x%x\n", (uint_t)*(&(guest_state->cr3)), (uint_t)*((unsigned char *)&(guest_state->cr3) + 4));
976     // Enable Paging
977     //    guest_state->cr0 |= 0x80000000;
978   }
979   */
980
981 }
982
983
984
985
986
987 #endif
988
989