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.


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