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.


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