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.


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