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.


symbiotic fixups
[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
342
343 #ifdef CONFIG_DEBUG_INTERRUPTS
344         PrintDebug("<%d> Injecting Exception %d (CR2=%p) (EIP=%p)\n", 
345                    (int)info->num_exits, 
346                    guest_ctrl->EVENTINJ.vector, 
347                    (void *)(addr_t)info->ctrl_regs.cr2,
348                    (void *)(addr_t)info->rip);
349 #endif
350
351         v3_injecting_excp(info, excp);
352
353
354     } else if (info->intr_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_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_state.irq_pending = 1;
380                 info->intr_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
445     /*
446       PrintDebug("SVM Entry to CS=%p  rip=%p...\n", 
447       (void *)(addr_t)info->segments.cs.base, 
448       (void *)(addr_t)info->rip);
449     */
450
451 #ifdef CONFIG_SYMBIOTIC
452     if (info->sym_state.sym_call_active == 1) {
453         if (guest_ctrl->guest_ctrl.V_IRQ == 1) {
454             V3_Print("!!! Injecting Interrupt during Sym call !!!\n");
455         }
456     }
457 #endif
458
459
460     rdtscll(info->time_state.cached_host_tsc);
461     //    guest_ctrl->TSC_OFFSET = info->time_state.guest_tsc - info->time_state.cached_host_tsc;
462         
463     v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->cpu_id]);
464     
465     rdtscll(tmp_tsc);
466
467     //PrintDebug("SVM Returned\n");
468     
469     info->num_exits++;
470
471     v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc);
472
473 #ifdef CONFIG_SYMBIOTIC
474     if (info->sym_state.sym_call_active == 0) {
475         update_irq_state_atomic(info);
476     }
477 #else 
478     update_irq_state_atomic(info);
479 #endif
480
481     // Save Guest state from VMCB
482     info->rip = guest_state->rip;
483     info->vm_regs.rsp = guest_state->rsp;
484     info->vm_regs.rax = guest_state->rax;
485
486     info->cpl = guest_state->cpl;
487
488     info->ctrl_regs.cr0 = guest_state->cr0;
489     info->ctrl_regs.cr2 = guest_state->cr2;
490     info->ctrl_regs.cr3 = guest_state->cr3;
491     info->ctrl_regs.cr4 = guest_state->cr4;
492     info->dbg_regs.dr6 = guest_state->dr6;
493     info->dbg_regs.dr7 = guest_state->dr7;
494     info->ctrl_regs.cr8 = guest_ctrl->guest_ctrl.V_TPR;
495     info->ctrl_regs.rflags = guest_state->rflags;
496     info->ctrl_regs.efer = guest_state->efer;
497     
498     v3_get_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
499     info->cpu_mode = v3_get_vm_cpu_mode(info);
500     info->mem_mode = v3_get_vm_mem_mode(info);
501     /* ** */
502
503
504     // save exit info here
505     exit_code = guest_ctrl->exit_code;
506     exit_info1 = guest_ctrl->exit_info1;
507     exit_info2 = guest_ctrl->exit_info2;
508
509
510     // reenable global interrupts after vm exit
511     v3_stgi();
512
513  
514     // Conditionally yield the CPU if the timeslice has expired
515     v3_yield_cond(info);
516
517
518     if (v3_handle_svm_exit(info, exit_code, exit_info1, exit_info2) != 0) {
519         PrintError("Error in SVM exit handler\n");
520         return -1;
521     }
522
523 #ifdef CONFIG_SYMBIOTIC
524     if (info->sym_state.sym_call_active == 0) {
525         update_irq_state(info);
526     }
527 #else 
528     update_irq_state(info);
529 #endif
530
531     return 0;
532 }
533
534
535 static int 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 void v3_init_svm_hooks(struct v3_ctrl_ops * vmm_ops) {
696
697     // Setup the SVM specific vmm operations
698     vmm_ops->init_guest = &init_svm_guest;
699     vmm_ops->start_guest = &start_svm_guest;
700     vmm_ops->has_nested_paging = &has_svm_nested_paging;
701
702     return;
703 }
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756 #if 0
757 /* 
758  * Test VMSAVE/VMLOAD Latency 
759  */
760 #define vmsave ".byte 0x0F,0x01,0xDB ; "
761 #define vmload ".byte 0x0F,0x01,0xDA ; "
762 {
763     uint32_t start_lo, start_hi;
764     uint32_t end_lo, end_hi;
765     uint64_t start, end;
766     
767     __asm__ __volatile__ (
768                           "rdtsc ; "
769                           "movl %%eax, %%esi ; "
770                           "movl %%edx, %%edi ; "
771                           "movq  %%rcx, %%rax ; "
772                           vmsave
773                           "rdtsc ; "
774                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
775                           : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
776                           );
777     
778     start = start_hi;
779     start <<= 32;
780     start += start_lo;
781     
782     end = end_hi;
783     end <<= 32;
784     end += end_lo;
785     
786     PrintDebug("VMSave Cycle Latency: %d\n", (uint32_t)(end - start));
787     
788     __asm__ __volatile__ (
789                           "rdtsc ; "
790                           "movl %%eax, %%esi ; "
791                           "movl %%edx, %%edi ; "
792                           "movq  %%rcx, %%rax ; "
793                           vmload
794                           "rdtsc ; "
795                           : "=D"(start_hi), "=S"(start_lo), "=a"(end_lo),"=d"(end_hi)
796                               : "c"(host_vmcb[cpu_id]), "0"(0), "1"(0), "2"(0), "3"(0)
797                               );
798         
799         start = start_hi;
800         start <<= 32;
801         start += start_lo;
802
803         end = end_hi;
804         end <<= 32;
805         end += end_lo;
806
807
808         PrintDebug("VMLoad Cycle Latency: %d\n", (uint32_t)(end - start));
809     }
810     /* End Latency Test */
811
812 #endif
813
814
815
816
817
818
819
820 #if 0
821 void Init_VMCB_pe(vmcb_t *vmcb, struct guest_info vm_info) {
822   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
823   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
824   uint_t i = 0;
825
826
827   guest_state->rsp = vm_info.vm_regs.rsp;
828   guest_state->rip = vm_info.rip;
829
830
831   /* I pretty much just gutted this from TVMM */
832   /* Note: That means its probably wrong */
833
834   // set the segment registers to mirror ours
835   guest_state->cs.selector = 1<<3;
836   guest_state->cs.attrib.fields.type = 0xa; // Code segment+read
837   guest_state->cs.attrib.fields.S = 1;
838   guest_state->cs.attrib.fields.P = 1;
839   guest_state->cs.attrib.fields.db = 1;
840   guest_state->cs.attrib.fields.G = 1;
841   guest_state->cs.limit = 0xfffff;
842   guest_state->cs.base = 0;
843   
844   struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL};
845   for ( i = 0; segregs[i] != NULL; i++) {
846     struct vmcb_selector * seg = segregs[i];
847     
848     seg->selector = 2<<3;
849     seg->attrib.fields.type = 0x2; // Data Segment+read/write
850     seg->attrib.fields.S = 1;
851     seg->attrib.fields.P = 1;
852     seg->attrib.fields.db = 1;
853     seg->attrib.fields.G = 1;
854     seg->limit = 0xfffff;
855     seg->base = 0;
856   }
857
858
859   {
860     /* JRL THIS HAS TO GO */
861     
862     //    guest_state->tr.selector = GetTR_Selector();
863     guest_state->tr.attrib.fields.type = 0x9; 
864     guest_state->tr.attrib.fields.P = 1;
865     // guest_state->tr.limit = GetTR_Limit();
866     //guest_state->tr.base = GetTR_Base();// - 0x2000;
867     /* ** */
868   }
869
870
871   /* ** */
872
873
874   guest_state->efer |= EFER_MSR_svm_enable;
875   guest_state->rflags = 0x00000002; // The reserved bit is always 1
876   ctrl_area->svm_instrs.VMRUN = 1;
877   guest_state->cr0 = 0x00000001;    // PE 
878   ctrl_area->guest_ASID = 1;
879
880
881   //  guest_state->cpl = 0;
882
883
884
885   // Setup exits
886
887   ctrl_area->cr_writes.cr4 = 1;
888   
889   ctrl_area->exceptions.de = 1;
890   ctrl_area->exceptions.df = 1;
891   ctrl_area->exceptions.pf = 1;
892   ctrl_area->exceptions.ts = 1;
893   ctrl_area->exceptions.ss = 1;
894   ctrl_area->exceptions.ac = 1;
895   ctrl_area->exceptions.mc = 1;
896   ctrl_area->exceptions.gp = 1;
897   ctrl_area->exceptions.ud = 1;
898   ctrl_area->exceptions.np = 1;
899   ctrl_area->exceptions.of = 1;
900   ctrl_area->exceptions.nmi = 1;
901
902   
903
904   ctrl_area->instrs.IOIO_PROT = 1;
905   ctrl_area->IOPM_BASE_PA = (uint_t)V3_AllocPages(3);
906   
907   {
908     reg_ex_t tmp_reg;
909     tmp_reg.r_reg = ctrl_area->IOPM_BASE_PA;
910     memset((void*)(tmp_reg.e_reg.low), 0xffffffff, PAGE_SIZE * 2);
911   }
912
913   ctrl_area->instrs.INTR = 1;
914
915   
916   {
917     char gdt_buf[6];
918     char idt_buf[6];
919
920     memset(gdt_buf, 0, 6);
921     memset(idt_buf, 0, 6);
922
923
924     uint_t gdt_base, idt_base;
925     ushort_t gdt_limit, idt_limit;
926     
927     GetGDTR(gdt_buf);
928     gdt_base = *(ulong_t*)((uchar_t*)gdt_buf + 2) & 0xffffffff;
929     gdt_limit = *(ushort_t*)(gdt_buf) & 0xffff;
930     PrintDebug("GDT: base: %x, limit: %x\n", gdt_base, gdt_limit);
931
932     GetIDTR(idt_buf);
933     idt_base = *(ulong_t*)(idt_buf + 2) & 0xffffffff;
934     idt_limit = *(ushort_t*)(idt_buf) & 0xffff;
935     PrintDebug("IDT: base: %x, limit: %x\n",idt_base, idt_limit);
936
937
938     // gdt_base -= 0x2000;
939     //idt_base -= 0x2000;
940
941     guest_state->gdtr.base = gdt_base;
942     guest_state->gdtr.limit = gdt_limit;
943     guest_state->idtr.base = idt_base;
944     guest_state->idtr.limit = idt_limit;
945
946
947   }
948   
949   
950   // also determine if CPU supports nested paging
951   /*
952   if (vm_info.page_tables) {
953     //   if (0) {
954     // Flush the TLB on entries/exits
955     ctrl_area->TLB_CONTROL = 1;
956
957     // Enable Nested Paging
958     ctrl_area->NP_ENABLE = 1;
959
960     PrintDebug("NP_Enable at 0x%x\n", &(ctrl_area->NP_ENABLE));
961
962         // Set the Nested Page Table pointer
963     ctrl_area->N_CR3 |= ((addr_t)vm_info.page_tables & 0xfffff000);
964
965
966     //   ctrl_area->N_CR3 = Get_CR3();
967     // guest_state->cr3 |= (Get_CR3() & 0xfffff000);
968
969     guest_state->g_pat = 0x7040600070406ULL;
970
971     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));
972     PrintDebug("Set Guest CR3: lo: 0x%x  hi: 0x%x\n", (uint_t)*(&(guest_state->cr3)), (uint_t)*((unsigned char *)&(guest_state->cr3) + 4));
973     // Enable Paging
974     //    guest_state->cr0 |= 0x80000000;
975   }
976   */
977
978 }
979
980
981
982
983
984 #endif
985
986