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.


*** empty log message ***
[palacios.git] / palacios / src / geekos / svm.c
1 #include <geekos/svm.h>
2 #include <geekos/vmm.h>
3
4 #include <geekos/vmcb.h>
5
6 extern struct vmm_os_hooks * os_hooks;
7
8 extern uint_t cpuid_ecx(uint_t op);
9 extern uint_t cpuid_edx(uint_t op);
10 extern void Get_MSR(uint_t MSR, uint_t * high_byte, uint_t * low_byte); 
11 extern void Set_MSR(uint_t MSR, uint_t high_byte, uint_t low_byte);
12 extern uint_t launch_svm(vmcb_t * vmcb_addr);
13
14
15 /* Checks machine SVM capability */
16 /* Implemented from: AMD Arch Manual 3, sect 15.4 */ 
17 int is_svm_capable() {
18   uint_t ret =  cpuid_ecx(CPUID_FEATURE_IDS);
19   uint_t vm_cr_low = 0, vm_cr_high = 0;
20
21
22   if ((ret & CPUID_FEATURE_IDS_ecx_svm_avail) == 0) {
23     PrintDebug("SVM Not Available\n");
24     return 0;
25   } 
26
27   Get_MSR(SVM_VM_CR_MSR, &vm_cr_high, &vm_cr_low);
28
29   if ((vm_cr_low & SVM_VM_CR_MSR_svmdis) == 0) {
30     return 1;
31   }
32
33   ret = cpuid_edx(CPUID_SVM_REV_AND_FEATURE_IDS);
34   
35   if ((ret & CPUID_SVM_REV_AND_FEATURE_IDS_edx_svml) == 0) {
36     PrintDebug("SVM BIOS Disabled, not unlockable\n");
37   } else {
38     PrintDebug("SVM is locked with a key\n");
39   }
40
41   return 0;
42 }
43
44
45
46 void Init_SVM(struct vmm_ctrl_ops * vmm_ops) {
47   reg_ex_t msr;
48   void * host_state;
49
50
51   // setup 
52   Get_MSR(EFER_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
53   msr.e_reg.low |= EFER_MSR_svm_enable;
54   Set_MSR(EFER_MSR, 0, msr.e_reg.low);
55   
56   PrintDebug("SVM Enabled\n");
57
58
59   // Setup the host state save area
60   host_state = os_hooks->Allocate_Pages(1);
61   
62   msr.e_reg.high = 0;
63   msr.e_reg.low = (uint_t)host_state;
64
65
66   PrintDebug("Host State being saved at %x\n", (uint_t)host_state);
67   Set_MSR(SVM_VM_HSAVE_PA_MSR, msr.e_reg.high, msr.e_reg.low);
68
69
70
71   // Setup the SVM specific vmm operations
72   vmm_ops->init_guest = &init_svm_guest;
73   vmm_ops->start_guest = &start_svm_guest;
74
75
76   return;
77 }
78
79
80 int init_svm_guest(struct guest_info *info) {
81   PrintDebug("Allocating VMCB\n");
82   info->vmm_data = (void*)Allocate_VMCB();
83
84   PrintDebug("Initializing VMCB (addr=%x)\n", info->vmm_data);
85   Init_VMCB((vmcb_t*)(info->vmm_data), *info);
86
87   return 0;
88 }
89
90
91 // can we start a kernel thread here...
92 int start_svm_guest(struct guest_info *info) {
93   vmcb_ctrl_t * guest_ctrl = 0;
94
95   ulong_t exit_code = 0;
96
97   PrintDebug("Launching SVM VM (vmcb=%x)\n", info->vmm_data);
98
99   launch_svm((vmcb_t*)(info->vmm_data));
100
101   guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
102
103
104   PrintDebug("SVM Returned: (Exit Code=%x) (VMCB=%x)\n",&(guest_ctrl->exit_code), info->vmm_data); 
105
106
107   exit_code = guest_ctrl->exit_code;
108
109   PrintDebug("SVM Returned: Exit Code: %x\n",exit_code); 
110
111   return 0;
112 }
113
114
115
116 vmcb_t * Allocate_VMCB() {
117   vmcb_t * vmcb_page = (vmcb_t*)os_hooks->Allocate_Pages(1);
118
119
120   memset(vmcb_page, 0, 4096);
121
122   return vmcb_page;
123 }
124
125
126
127 void Init_VMCB(vmcb_t *vmcb, guest_info_t vm_info) {
128   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
129   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
130   uint_t i = 0;
131
132
133   guest_state->rsp = vm_info.rsp;
134   guest_state->rip = vm_info.rip;
135
136
137   /* I pretty much just gutted this from TVMM */
138   /* Note: That means its probably wrong */
139
140   // set the segment registers to mirror ours
141   guest_state->cs.selector = 0;
142   guest_state->cs.attrib.fields.type = 0xa; // Code segment+read
143   guest_state->cs.attrib.fields.S = 1;
144   guest_state->cs.attrib.fields.P = 1;
145   guest_state->cs.attrib.fields.db = 1;
146   guest_state->cs.limit = 0xffffffff;
147   guest_state->cs.base = 0;
148   
149   struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL};
150   for ( i = 0; segregs[i] != NULL; i++) {
151     struct vmcb_selector * seg = segregs[i];
152     
153     seg->selector = 0;
154     seg->attrib.fields.type = 0x2; // Data Segment+read/write
155     seg->attrib.fields.S = 1;
156     seg->attrib.fields.P = 1;
157     seg->attrib.fields.db = 1;
158     seg->limit = 0xffffffff;
159     seg->base = 0;
160   }
161
162
163   guest_state->efer |= EFER_MSR_svm_enable;
164   guest_state->cr0 = 0x00000001;    // PE 
165   guest_state->rflags = 0x00000002; // The reserved bit is always 1
166   ctrl_area->svm_instrs.instrs.VMRUN = 1;
167   ctrl_area->guest_ASID = 1;
168
169
170
171   /* ** */
172
173 }