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.


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