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.


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