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.


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