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.


Added memory ranges
[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   // Enable SVM on the CPU
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 /** 
117  *  We handle the svm exits here
118  *  This function should probably be moved to another file to keep things managable....
119  */
120 int handle_svm_exit(struct VMM_GPRs guest_gprs) {
121
122   return 0;
123 }
124
125
126 vmcb_t * Allocate_VMCB() {
127   vmcb_t * vmcb_page = (vmcb_t*)os_hooks->Allocate_Pages(1);
128
129
130   memset(vmcb_page, 0, 4096);
131
132   return vmcb_page;
133 }
134
135
136
137 void Init_VMCB(vmcb_t *vmcb, guest_info_t vm_info) {
138   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA(vmcb);
139   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA(vmcb);
140   uint_t i = 0;
141
142
143   guest_state->rsp = vm_info.rsp;
144   guest_state->rip = vm_info.rip;
145
146
147   /* I pretty much just gutted this from TVMM */
148   /* Note: That means its probably wrong */
149
150   // set the segment registers to mirror ours
151   guest_state->cs.selector = 0;
152   guest_state->cs.attrib.fields.type = 0xa; // Code segment+read
153   guest_state->cs.attrib.fields.S = 1;
154   guest_state->cs.attrib.fields.P = 1;
155   guest_state->cs.attrib.fields.db = 1;
156   guest_state->cs.limit = 0xffffffff;
157   guest_state->cs.base = 0;
158   
159   struct vmcb_selector *segregs [] = {&(guest_state->ss), &(guest_state->ds), &(guest_state->es), &(guest_state->fs), &(guest_state->gs), NULL};
160   for ( i = 0; segregs[i] != NULL; i++) {
161     struct vmcb_selector * seg = segregs[i];
162     
163     seg->selector = 0;
164     seg->attrib.fields.type = 0x2; // Data Segment+read/write
165     seg->attrib.fields.S = 1;
166     seg->attrib.fields.P = 1;
167     seg->attrib.fields.db = 1;
168     seg->limit = 0xffffffff;
169     seg->base = 0;
170   }
171
172
173   guest_state->efer |= EFER_MSR_svm_enable;
174   guest_state->cr0 = 0x00000001;    // PE 
175   guest_state->rflags = 0x00000002; // The reserved bit is always 1
176   ctrl_area->svm_instrs.instrs.VMRUN = 1;
177   ctrl_area->guest_ASID = 1;
178
179
180
181   /* ** */
182
183 }