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.


Jack's changes to split up stucts for multi-core.
[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_Print("Calling v3_svm_launch\n");
472         
473     v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->cpu_id]);
474     
475     //V3_Print("SVM Returned: Exit Code: %x, guest_rip=%lx\n", (uint32_t)(guest_ctrl->exit_code), (unsigned long)guest_state->rip);
476
477
478     v3_last_exit = (uint32_t)(guest_ctrl->exit_code);
479
480     rdtscll(tmp_tsc);
481
482     //PrintDebug("SVM Returned\n");
483     
484     info->num_exits++;
485
486     v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc);
487
488
489     // Save Guest state from VMCB
490     info->rip = guest_state->rip;
491     info->vm_regs.rsp = guest_state->rsp;
492     info->vm_regs.rax = guest_state->rax;
493
494     info->cpl = guest_state->cpl;
495
496     info->ctrl_regs.cr0 = guest_state->cr0;
497     info->ctrl_regs.cr2 = guest_state->cr2;
498     info->ctrl_regs.cr3 = guest_state->cr3;
499     info->ctrl_regs.cr4 = guest_state->cr4;
500     info->dbg_regs.dr6 = guest_state->dr6;
501     info->dbg_regs.dr7 = guest_state->dr7;
502     info->ctrl_regs.cr8 = guest_ctrl->guest_ctrl.V_TPR;
503     info->ctrl_regs.rflags = guest_state->rflags;
504     info->ctrl_regs.efer = guest_state->efer;
505     
506     v3_get_vmcb_segments((vmcb_t*)(info->vmm_data), &(info->segments));
507     info->cpu_mode = v3_get_vm_cpu_mode(info);
508     info->mem_mode = v3_get_vm_mem_mode(info);
509     /* ** */
510
511
512     // save exit info here
513     exit_code = guest_ctrl->exit_code;
514     exit_info1 = guest_ctrl->exit_info1;
515     exit_info2 = guest_ctrl->exit_info2;
516
517
518 #ifdef CONFIG_SYMBIOTIC
519     if (info->vm_info->sym_state.symcalls[info->cpu_id].sym_call_active == 0) {
520         update_irq_exit_state(info);
521     }
522 #else
523     update_irq_exit_state(info);
524 #endif
525
526
527     // reenable global interrupts after vm exit
528     v3_stgi();
529
530  
531     // Conditionally yield the CPU if the timeslice has expired
532     v3_yield_cond(info);
533
534
535     if (v3_handle_svm_exit(info, exit_code, exit_info1, exit_info2) != 0) {
536         PrintError("Error in SVM exit handler\n");
537         return -1;
538     }
539
540
541     return 0;
542 }
543
544
545 int v3_start_svm_guest(struct guest_info *info) {
546     //    vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
547     //  vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
548
549
550
551     PrintDebug("Launching SVM VM (vmcb=%p)\n", (void *)info->vmm_data);
552     //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
553     
554     info->vm_info->run_state = VM_RUNNING;
555     rdtscll(info->yield_start_cycle);
556
557
558     while (1) {
559         if (v3_svm_enter(info) == -1) {
560             vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
561             addr_t host_addr;
562             addr_t linear_addr = 0;
563             
564             info->vm_info->run_state = VM_ERROR;
565             
566             V3_Print("SVM ERROR!!\n"); 
567             
568             v3_print_guest_state(info);
569             
570             V3_Print("SVM Exit Code: %p\n", (void *)(addr_t)guest_ctrl->exit_code); 
571             
572             V3_Print("exit_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
573             V3_Print("exit_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
574             
575             V3_Print("exit_info2 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info2));
576             V3_Print("exit_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
577             
578             linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
579             
580             if (info->mem_mode == PHYSICAL_MEM) {
581                 guest_pa_to_host_va(info, linear_addr, &host_addr);
582             } else if (info->mem_mode == VIRTUAL_MEM) {
583                 guest_va_to_host_va(info, linear_addr, &host_addr);
584             }
585             
586             V3_Print("Host Address of rip = 0x%p\n", (void *)host_addr);
587             
588             V3_Print("Instr (15 bytes) at %p:\n", (void *)host_addr);
589             v3_dump_mem((uint8_t *)host_addr, 15);
590             
591             v3_print_stack(info);
592
593             break;
594         }
595         
596 /*
597         if ((info->num_exits % 5000) == 0) {
598             V3_Print("SVM Exit number %d\n", (uint32_t)info->num_exits);
599         }
600 */
601         
602     }
603     return 0;
604 }
605
606
607
608
609
610 /* Checks machine SVM capability */
611 /* Implemented from: AMD Arch Manual 3, sect 15.4 */ 
612 int v3_is_svm_capable() {
613     uint_t vm_cr_low = 0, vm_cr_high = 0;
614     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
615
616     v3_cpuid(CPUID_EXT_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
617   
618     PrintDebug("CPUID_EXT_FEATURE_IDS_ecx=0x%x\n", ecx);
619
620     if ((ecx & CPUID_EXT_FEATURE_IDS_ecx_svm_avail) == 0) {
621       V3_Print("SVM Not Available\n");
622       return 0;
623     }  else {
624         v3_get_msr(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
625         
626         PrintDebug("SVM_VM_CR_MSR = 0x%x 0x%x\n", vm_cr_high, vm_cr_low);
627         
628         if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 1) {
629             V3_Print("SVM is available but is disabled.\n");
630             
631             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
632             
633             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
634             
635             if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
636                 V3_Print("SVM BIOS Disabled, not unlockable\n");
637             } else {
638                 V3_Print("SVM is locked with a key\n");
639             }
640             return 0;
641
642         } else {
643             V3_Print("SVM is available and  enabled.\n");
644
645             v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
646             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_eax=0x%x\n", eax);
647             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ebx=0x%x\n", ebx);
648             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_ecx=0x%x\n", ecx);
649             PrintDebug("CPUID_SVM_REV_AND_FEATURE_IDS_edx=0x%x\n", edx);
650
651             return 1;
652         }
653     }
654 }
655
656 static int has_svm_nested_paging() {
657     uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
658
659     v3_cpuid(CPUID_SVM_REV_AND_FEATURE_IDS, &eax, &ebx, &ecx, &edx);
660
661     //PrintDebug("CPUID_EXT_FEATURE_IDS_edx=0x%x\n", edx);
662
663     if ((edx & CPUID_SVM_REV_AND_FEATURE_IDS_edx_np) == 0) {
664         V3_Print("SVM Nested Paging not supported\n");
665         return 0;
666     } else {
667         V3_Print("SVM Nested Paging supported\n");
668         return 1;
669     }
670 }
671
672
673 void v3_init_svm_cpu(int cpu_id) {
674     reg_ex_t msr;
675     extern v3_cpu_arch_t v3_cpu_types[];
676
677     // Enable SVM on the CPU
678     v3_get_msr(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
679     msr.e_reg.low |= EFER_MSR_svm_enable;
680     v3_set_msr(EFER_MSR, 0, msr.e_reg.low);
681
682     V3_Print("SVM Enabled\n");
683
684     // Setup the host state save area
685     host_vmcbs[cpu_id] = (addr_t)V3_AllocPages(4);
686
687     /* 64-BIT-ISSUE */
688     //  msr.e_reg.high = 0;
689     //msr.e_reg.low = (uint_t)host_vmcb;
690     msr.r_reg = host_vmcbs[cpu_id];
691
692     PrintDebug("Host State being saved at %p\n", (void *)host_vmcbs[cpu_id]);
693     v3_set_msr(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
694
695
696     if (has_svm_nested_paging() == 1) {
697         v3_cpu_types[cpu_id] = V3_SVM_REV3_CPU;
698     } else {
699         v3_cpu_types[cpu_id] = V3_SVM_CPU;
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
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