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.


refactoring to the point of compilation
[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     /** THESE NEED TO BE MOVED TO GLOBAL LOCATION **/
193     v3_init_svm_io_map(core->vm_info);
194     ctrl_area->IOPM_BASE_PA = (addr_t)V3_PAddr(core->vm_info->io_map.arch_data);
195     ctrl_area->instrs.IOIO_PROT = 1;
196
197     v3_init_svm_msr_map(core->vm_info);
198     ctrl_area->MSRPM_BASE_PA = (addr_t)V3_PAddr(core->vm_info->msr_map.arch_data);
199     ctrl_area->instrs.MSR_PROT = 1;
200     /** *** **/
201
202
203     PrintDebug("Exiting on interrupts\n");
204     ctrl_area->guest_ctrl.V_INTR_MASKING = 1;
205     ctrl_area->instrs.INTR = 1;
206
207
208     if (core->shdw_pg_mode == SHADOW_PAGING) {
209         PrintDebug("Creating initial shadow page table\n");
210         
211         /* JRL: This is a performance killer, and a simplistic solution */
212         /* We need to fix this */
213         ctrl_area->TLB_CONTROL = 1;
214         ctrl_area->guest_ASID = 1;
215         
216         
217         if (v3_init_passthrough_pts(core) == -1) {
218             PrintError("Could not initialize passthrough page tables\n");
219             return ;
220         }
221
222
223         core->shdw_pg_state.guest_cr0 = 0x0000000000000010LL;
224         PrintDebug("Created\n");
225         
226         core->ctrl_regs.cr0 |= 0x80000000;
227         core->ctrl_regs.cr3 = core->direct_map_pt;
228
229         ctrl_area->cr_reads.cr0 = 1;
230         ctrl_area->cr_writes.cr0 = 1;
231         //ctrl_area->cr_reads.cr4 = 1;
232         ctrl_area->cr_writes.cr4 = 1;
233         ctrl_area->cr_reads.cr3 = 1;
234         ctrl_area->cr_writes.cr3 = 1;
235
236         v3_hook_msr(core->vm_info, EFER_MSR, 
237                     &v3_handle_efer_read,
238                     &v3_handle_efer_write, 
239                     core);
240
241         ctrl_area->instrs.INVLPG = 1;
242
243         ctrl_area->exceptions.pf = 1;
244
245         guest_state->g_pat = 0x7040600070406ULL;
246
247
248
249     } else if (core->shdw_pg_mode == NESTED_PAGING) {
250         // Flush the TLB on entries/exits
251         ctrl_area->TLB_CONTROL = 1;
252         ctrl_area->guest_ASID = 1;
253
254         // Enable Nested Paging
255         ctrl_area->NP_ENABLE = 1;
256
257         PrintDebug("NP_Enable at 0x%p\n", (void *)&(ctrl_area->NP_ENABLE));
258
259         // Set the Nested Page Table pointer
260         if (v3_init_passthrough_pts(core) == -1) {
261             PrintError("Could not initialize Nested page tables\n");
262             return ;
263         }
264
265         ctrl_area->N_CR3 = core->direct_map_pt;
266
267         guest_state->g_pat = 0x7040600070406ULL;
268     }
269 }
270
271
272 int v3_init_svm_vmcb(struct guest_info * info, v3_vm_class_t vm_class) {
273
274     PrintDebug("Allocating VMCB\n");
275     info->vmm_data = (void*)Allocate_VMCB();
276     
277     if (vm_class == V3_PC_VM) {
278         PrintDebug("Initializing VMCB (addr=%p)\n", (void *)info->vmm_data);
279         Init_VMCB_BIOS((vmcb_t*)(info->vmm_data), info);
280     } else {
281         PrintError("Invalid VM class\n");
282         return -1;
283     }
284
285     return 0;
286 }
287
288
289
290 static int update_irq_exit_state(struct guest_info * info) {
291     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
292
293     if ((info->intr_core_state.irq_pending == 1) && (guest_ctrl->guest_ctrl.V_IRQ == 0)) {
294         
295 #ifdef CONFIG_DEBUG_INTERRUPTS
296         PrintDebug("INTAK cycle completed for irq %d\n", info->intr_core_state.irq_vector);
297 #endif
298
299         info->intr_core_state.irq_started = 1;
300         info->intr_core_state.irq_pending = 0;
301
302         v3_injecting_intr(info, info->intr_core_state.irq_vector, V3_EXTERNAL_IRQ);
303     }
304
305     if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 0)) {
306 #ifdef CONFIG_DEBUG_INTERRUPTS
307         PrintDebug("Interrupt %d taken by guest\n", info->intr_core_state.irq_vector);
308 #endif
309
310         // Interrupt was taken fully vectored
311         info->intr_core_state.irq_started = 0;
312
313     } else {
314 #ifdef CONFIG_DEBUG_INTERRUPTS
315         PrintDebug("EXIT INT INFO is set (vec=%d)\n", guest_ctrl->exit_int_info.vector);
316 #endif
317     }
318
319     return 0;
320 }
321
322
323 static int update_irq_entry_state(struct guest_info * info) {
324     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
325
326     if (v3_excp_pending(info)) {
327         uint_t excp = v3_get_excp_number(info);
328         
329         guest_ctrl->EVENTINJ.type = SVM_INJECTION_EXCEPTION;
330         
331         if (info->excp_state.excp_error_code_valid) {
332             guest_ctrl->EVENTINJ.error_code = info->excp_state.excp_error_code;
333             guest_ctrl->EVENTINJ.ev = 1;
334 #ifdef CONFIG_DEBUG_INTERRUPTS
335             PrintDebug("Injecting exception %d with error code %x\n", excp, guest_ctrl->EVENTINJ.error_code);
336 #endif
337         }
338         
339         guest_ctrl->EVENTINJ.vector = excp;
340         
341         guest_ctrl->EVENTINJ.valid = 1;
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     } else if (info->intr_core_state.irq_started == 1) {
353 #ifdef CONFIG_DEBUG_INTERRUPTS
354         PrintDebug("IRQ pending from previous injection\n");
355 #endif
356         guest_ctrl->guest_ctrl.V_IRQ = 1;
357         guest_ctrl->guest_ctrl.V_INTR_VECTOR = info->intr_core_state.irq_vector;
358         guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
359         guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
360
361     } else {
362         switch (v3_intr_pending(info)) {
363             case V3_EXTERNAL_IRQ: {
364                 uint32_t irq = v3_get_intr(info);
365
366                 guest_ctrl->guest_ctrl.V_IRQ = 1;
367                 guest_ctrl->guest_ctrl.V_INTR_VECTOR = irq;
368                 guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
369                 guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
370
371 #ifdef CONFIG_DEBUG_INTERRUPTS
372                 PrintDebug("Injecting Interrupt %d (EIP=%p)\n", 
373                            guest_ctrl->guest_ctrl.V_INTR_VECTOR, 
374                            (void *)(addr_t)info->rip);
375 #endif
376
377                 info->intr_core_state.irq_pending = 1;
378                 info->intr_core_state.irq_vector = irq;
379                 
380                 break;
381             }
382             case V3_NMI:
383                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
384                 break;
385             case V3_SOFTWARE_INTR:
386                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
387                 break;
388             case V3_VIRTUAL_IRQ:
389                 guest_ctrl->EVENTINJ.type = SVM_INJECTION_IRQ;
390                 break;
391
392             case V3_INVALID_INTR:
393             default:
394                 break;
395         }
396         
397     }
398
399     return 0;
400 }
401
402
403 /* 
404  * CAUTION and DANGER!!! 
405  * 
406  * The VMCB CANNOT(!!) be accessed outside of the clgi/stgi calls inside this function
407  * When exectuing a symbiotic call, the VMCB WILL be overwritten, so any dependencies 
408  * on its contents will cause things to break. The contents at the time of the exit WILL 
409  * change before the exit handler is executed.
410  */
411 int v3_svm_enter(struct guest_info * info) {
412     vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
413     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); 
414     ullong_t tmp_tsc;
415     addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0;
416
417     // Conditionally yield the CPU if the timeslice has expired
418     v3_yield_cond(info);
419
420     // disable global interrupts for vm state transition
421     v3_clgi();
422
423     // Synchronize the guest state to the VMCB
424     guest_state->cr0 = info->ctrl_regs.cr0;
425     guest_state->cr2 = info->ctrl_regs.cr2;
426     guest_state->cr3 = info->ctrl_regs.cr3;
427     guest_state->cr4 = info->ctrl_regs.cr4;
428     guest_state->dr6 = info->dbg_regs.dr6;
429     guest_state->dr7 = info->dbg_regs.dr7;
430     guest_ctrl->guest_ctrl.V_TPR = info->ctrl_regs.cr8 & 0xff;
431     guest_state->rflags = info->ctrl_regs.rflags;
432     guest_state->efer = info->ctrl_regs.efer;
433     
434     guest_state->cpl = info->cpl;
435
436     v3_set_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
437
438     guest_state->rax = info->vm_regs.rax;
439     guest_state->rip = info->rip;
440     guest_state->rsp = info->vm_regs.rsp;
441
442 #ifdef CONFIG_SYMBIOTIC
443     if (info->vm_info->sym_state.symcalls[info->cpu_id].sym_call_active == 0) {
444         update_irq_entry_state(info);
445     }
446 #else 
447     update_irq_entry_state(info);
448 #endif
449
450
451     /* ** */
452
453     /*
454       PrintDebug("SVM Entry to CS=%p  rip=%p...\n", 
455       (void *)(addr_t)info->segments.cs.base, 
456       (void *)(addr_t)info->rip);
457     */
458
459 #ifdef CONFIG_SYMBIOTIC
460     if (info->vm_info->sym_state.symcalls[info->cpu_id].sym_call_active == 1) {
461         if (guest_ctrl->guest_ctrl.V_IRQ == 1) {
462             V3_Print("!!! Injecting Interrupt during Sym call !!!\n");
463         }
464     }
465 #endif
466
467
468     rdtscll(info->time_state.cached_host_tsc);
469     guest_ctrl->TSC_OFFSET = info->time_state.guest_tsc - info->time_state.cached_host_tsc;
470         
471     v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->cpu_id]);
472     
473
474     v3_last_exit = (uint32_t)(guest_ctrl->exit_code);
475
476     //  v3_print_cond("SVM Returned: Exit Code: %x\n", (uint32_t)(guest_ctrl->exit_code));
477
478     rdtscll(tmp_tsc);
479
480     //PrintDebug("SVM Returned\n");
481     
482     info->num_exits++;
483
484     v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc);
485
486
487     // Save Guest state from VMCB
488     info->rip = guest_state->rip;
489     info->vm_regs.rsp = guest_state->rsp;
490     info->vm_regs.rax = guest_state->rax;
491
492     info->cpl = guest_state->cpl;
493
494     info->ctrl_regs.cr0 = guest_state->cr0;
495     info->ctrl_regs.cr2 = guest_state->cr2;
496     info->ctrl_regs.cr3 = guest_state->cr3;
497     info->ctrl_regs.cr4 = guest_state->cr4;
498     info->dbg_regs.dr6 = guest_state->dr6;
499     info->dbg_regs.dr7 = guest_state->dr7;
500     info->ctrl_regs.cr8 = guest_ctrl->guest_ctrl.V_TPR;
501     info->ctrl_regs.rflags = guest_state->rflags;
502     info->ctrl_regs.efer = guest_state->efer;
503     
504     v3_get_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
505     info->cpu_mode = v3_get_vm_cpu_mode(info);
506     info->mem_mode = v3_get_vm_mem_mode(info);
507     /* ** */
508
509
510     // save exit info here
511     exit_code = guest_ctrl->exit_code;
512     exit_info1 = guest_ctrl->exit_info1;
513     exit_info2 = guest_ctrl->exit_info2;
514
515
516 #ifdef CONFIG_SYMBIOTIC
517     if (info->vm_info->sym_state.symcalls[info->cpu_id].sym_call_active == 0) {
518         update_irq_exit_state(info);
519     }
520 #else
521     update_irq_exit_state(info);
522 #endif
523
524
525     // reenable global interrupts after vm exit
526     v3_stgi();
527
528  
529     // Conditionally yield the CPU if the timeslice has expired
530     v3_yield_cond(info);
531
532
533     if (v3_handle_svm_exit(info, exit_code, exit_info1, exit_info2) != 0) {
534         PrintError("Error in SVM exit handler\n");
535         return -1;
536     }
537
538
539     return 0;
540 }
541
542
543 int v3_start_svm_guest(struct guest_info *info) {
544     //    vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
545     //  vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
546
547
548
549     PrintDebug("Launching SVM VM (vmcb=%p)\n", (void *)info->vmm_data);
550     //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
551     
552     info->vm_info->run_state = VM_RUNNING;
553     rdtscll(info->yield_start_cycle);
554
555
556     while (1) {
557         if (v3_svm_enter(info) == -1) {
558             vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
559             addr_t host_addr;
560             addr_t linear_addr = 0;
561             
562             info->vm_info->run_state = VM_ERROR;
563             
564             V3_Print("SVM ERROR!!\n"); 
565             
566             v3_print_guest_state(info);
567             
568             V3_Print("SVM Exit Code: %p\n", (void *)(addr_t)guest_ctrl->exit_code); 
569             
570             V3_Print("exit_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
571             V3_Print("exit_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
572             
573             V3_Print("exit_info2 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info2));
574             V3_Print("exit_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
575             
576             linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
577             
578             if (info->mem_mode == PHYSICAL_MEM) {
579                 guest_pa_to_host_va(info, linear_addr, &host_addr);
580             } else if (info->mem_mode == VIRTUAL_MEM) {
581                 guest_va_to_host_va(info, linear_addr, &host_addr);
582             }
583             
584             V3_Print("Host Address of rip = 0x%p\n", (void *)host_addr);
585             
586             V3_Print("Instr (15 bytes) at %p:\n", (void *)host_addr);
587             v3_dump_mem((uint8_t *)host_addr, 15);
588             
589             v3_print_stack(info);
590
591             break;
592         }
593         
594 /*
595         if ((info->num_exits % 5000) == 0) {
596             V3_Print("SVM Exit number %d\n", (uint32_t)info->num_exits);
597         }
598 */
599         
600     }
601     return 0;
602 }
603
604
605
606
607
608 /* Checks machine SVM capability */
609 /* Implemented from: AMD Arch Manual 3, sect 15.4 */ 
610 int v3_is_svm_capable() {
611     uint_t vm_cr_low = 0, vm_cr_high = 0;
612     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
613
614     v3_cpuid(CPUID_EXT_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
615   
616     PrintDebug("CPUID_EXT_FEATURE_IDS_ecx=0x%x\n", ecx);
617
618     if ((ecx & CPUID_EXT_FEATURE_IDS_ecx_svm_avail) == 0) {
619       V3_Print("SVM Not Available\n");
620       return 0;
621     }  else {
622         v3_get_msr(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
623         
624         PrintDebug("SVM_VM_CR_MSR = 0x%x 0x%x\n", vm_cr_high, vm_cr_low);
625         
626         if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 1) {
627             V3_Print("SVM is available but is disabled.\n");
628             
629             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
630             
631             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
632             
633             if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
634                 V3_Print("SVM BIOS Disabled, not unlockable\n");
635             } else {
636                 V3_Print("SVM is locked with a key\n");
637             }
638             return 0;
639
640         } else {
641             V3_Print("SVM is available and  enabled.\n");
642
643             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
644             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_eax=0x%x\n", eax);
645             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ebx=0x%x\n", ebx);
646             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ecx=0x%x\n", ecx);
647             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
648
649             return 1;
650         }
651     }
652 }
653
654 static int has_svm_nested_paging() {
655     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
656
657     v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
658
659     //PrintDebug("CPUID_EXT_FEATURE_IDS_edx=0x%x\n", edx);
660
661     if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
662         V3_Print("SVM Nested Paging not supported\n");
663         return 0;
664     } else {
665         V3_Print("SVM Nested Paging supported\n");
666         return 1;
667     }
668 }
669
670
671 void v3_init_svm_cpu(int cpu_id) {
672     reg_ex_t msr;
673     extern v3_cpu_arch_t v3_cpu_types[];
674
675     // Enable SVM on the CPU
676     v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
677     msr.e_reg.low |= EFER_MSR_svm_enable;
678     v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
679
680     V3_Print("SVM Enabled\n");
681
682     // Setup the host state save area
683     host_vmcbs[cpu_id] = (addr_t)V3_AllocPages(4);
684
685     /* 64-BIT-ISSUE */
686     //  msr.e_reg.high = 0;
687     //msr.e_reg.low = (uint_t)host_vmcb;
688     msr.r_reg = host_vmcbs[cpu_id];
689
690     PrintDebug("Host State being saved at %p\n", (void *)host_vmcbs[cpu_id]);
691     v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
692
693
694     if (has_svm_nested_paging() == 1) {
695         v3_cpu_types[cpu_id] = V3_SVM_REV3_CPU;
696     } else {
697         v3_cpu_types[cpu_id] = V3_SVM_CPU;
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
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