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.


booting geekos up to the timer initialization
[palacios.git] / palacios / src / palacios / svm_ctrl_regs.c
1 #include <palacios/svm_ctrl_regs.h>
2 #include <palacios/vmm_mem.h>
3 #include <palacios/vmm.h>
4 #include <palacios/vmcb.h>
5 #include <palacios/vmm_emulate.h>
6 #include <palacios/vm_guest_mem.h>
7 #include <palacios/vmm_ctrl_regs.h>
8
9
10 /* Segmentation is a problem here...
11  *
12  * When we get a memory operand, presumably we use the default segment (which is?) 
13  * unless an alternate segment was specfied in the prefix...
14  */
15
16
17 int handle_cr0_write(struct guest_info * info) {
18   //vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
19   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
20   char instr[15];
21   
22   
23   if (info->cpu_mode == REAL) {
24     int index = 0;
25     int ret;
26
27     // The real rip address is actually a combination of the rip + CS base 
28     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.selector), 15, instr);
29     if (ret != 15) {
30       // I think we should inject a GPF into the guest
31       PrintDebug("Could not read instruction (ret=%d)\n", ret);
32       return -1;
33     }
34
35     while (is_prefix_byte(instr[index])) {
36       index++; 
37     }
38
39     if ((instr[index] == cr_access_byte) && 
40         (instr[index + 1] == lmsw_byte) && 
41         (MODRM_REG(instr[index + 2]) == lmsw_reg_byte)) {
42  
43       addr_t first_operand;
44       addr_t second_operand;
45       struct cr0_real *real_cr0;
46       struct cr0_real *new_cr0;
47       operand_type_t addr_type;
48       char new_cr0_val = 0;
49       // LMSW
50       // decode mod/RM
51       index += 2;
52  
53       real_cr0 = (struct cr0_real*)&(guest_state->cr0);
54
55       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
56
57
58       if (addr_type == REG_OPERAND) {
59         new_cr0 = (struct cr0_real *)first_operand;
60       } else if (addr_type == MEM_OPERAND) {
61         addr_t host_addr;
62
63         if (guest_pa_to_host_va(info, first_operand + (guest_state->ds.base << 4), &host_addr) == -1) {
64           // gpf the guest
65           return -1;
66         }
67
68         new_cr0 = (struct cr0_real *)host_addr;
69       } else {
70         // error... don't know what to do
71         return -1;
72       }
73                  
74       if ((new_cr0->pe == 1) && (real_cr0->pe == 0)) {
75         info->cpu_mode = PROTECTED;
76       } else if ((new_cr0->pe == 0) && (real_cr0->pe == 1)) {
77         info->cpu_mode = REAL;
78       }
79       
80       new_cr0_val = *(char*)(new_cr0) & 0x0f;
81
82
83       if (info->page_mode == SHADOW_PAGING) {
84         struct cr0_real * shadow_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
85
86         PrintDebug("Old CR0=%x, Old Shadow CR0=%x\n", *real_cr0, *shadow_cr0);  
87         /* struct cr0_real is only 4 bits wide, 
88          * so we can overwrite the real_cr0 without worrying about the shadow fields
89          */
90         *(char*)real_cr0 &= 0xf0;
91         *(char*)real_cr0 |= new_cr0_val;
92         
93         *(char*)shadow_cr0 &= 0xf0;
94         *(char*)shadow_cr0 |= new_cr0_val;
95
96         PrintDebug("New CR0=%x, New Shadow CR0=%x\n", *real_cr0, *shadow_cr0);  
97       } else {
98         PrintDebug("Old CR0=%x\n", *real_cr0);  
99         // for now we just pass through....
100         *(char*)real_cr0 &= 0xf0;
101         *(char*)real_cr0 |= new_cr0_val;
102
103         PrintDebug("New CR0=%x\n", *real_cr0);  
104       }
105
106
107       info->rip += index;
108
109     } else if ((instr[index] == cr_access_byte) && 
110                (instr[index + 1] == clts_byte)) {
111       // CLTS
112
113
114     } else if ((instr[index] == cr_access_byte) && 
115                (instr[index + 1] = mov_to_cr_byte)) {
116       addr_t first_operand;
117       addr_t second_operand;
118       struct cr0_32 *real_cr0;
119       struct cr0_32 *new_cr0;
120       operand_type_t addr_type;
121      
122       
123       index += 2;
124  
125       real_cr0 = (struct cr0_32*)&(guest_state->cr0);
126
127       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
128
129       if (addr_type != REG_OPERAND) {
130         /* Mov to CR0 Can only be a 32 bit register */
131         // FIX ME
132         return -1;
133       }
134
135       new_cr0 = (struct cr0_32 *)first_operand;
136
137       if (new_cr0->pe == 1) {
138         PrintDebug("Entering Protected Mode\n");
139         info->cpu_mode = PROTECTED;
140       }
141
142       if (new_cr0->pg == 1) {
143         // GPF the guest??
144         return -1;
145       }
146
147       if (info->page_mode == SHADOW_PAGING) {
148         struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
149         
150         PrintDebug("Old CR0=%x, Old Shadow CR0=%x\n", *real_cr0, *shadow_cr0);  
151         *real_cr0 = *new_cr0;
152         real_cr0->pg = 1;
153
154         *shadow_cr0 = *new_cr0;
155
156         PrintDebug("New CR0=%x, New Shadow CR0=%x\n", *real_cr0, *shadow_cr0);  
157       } else {
158         PrintDebug("Old CR0=%x\n", *real_cr0);  
159         *real_cr0 = *new_cr0;
160         PrintDebug("New CR0=%x\n", *real_cr0);  
161       }
162
163       info->rip += index;
164
165     } else {
166       PrintDebug("Unsupported Instruction\n");
167       // unsupported instruction, UD the guest
168       return -1;
169     }
170
171
172   } else if (info->cpu_mode == PROTECTED) {
173     int index = 0;
174     int ret;
175
176     PrintDebug("Protected Mode write to CR0\n");
177
178     // The real rip address is actually a combination of the rip + CS base 
179     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
180     if (ret != 15) {
181       // I think we should inject a GPF into the guest
182       PrintDebug("Could not read instruction (ret=%d)\n", ret);
183       return -1;
184     }
185
186     while (is_prefix_byte(instr[index])) {
187       index++; 
188     }
189
190
191     /* CHECK IF MOV_TO_CR CAN TAKE MEMORY OPERANDS... */
192     if ((instr[index] == cr_access_byte) && 
193         (instr[index + 1] == mov_to_cr_byte)) {
194     
195       addr_t first_operand;
196       addr_t second_operand;
197       struct cr0_32 *real_cr0;
198       struct cr0_32 *new_cr0;
199       operand_type_t addr_type;
200
201       index += 2;
202  
203       real_cr0 = (struct cr0_32*)&(guest_state->cr0);
204
205       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
206
207       if (addr_type != REG_OPERAND) {
208         return -1;
209       }
210
211       new_cr0 = (struct cr0_32 *)first_operand;
212
213
214       if (info->page_mode == SHADOW_PAGING) {
215         struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
216
217         if (new_cr0->pg == 1){
218           info->cpu_mode = PROTECTED_PG;
219           
220           *shadow_cr0 = *new_cr0;
221           *real_cr0 = *new_cr0;
222
223           //
224           // Activate Shadow Paging
225           //
226
227         } else if (new_cr0->pe == 0) {
228           info->cpu_mode = REAL;
229
230           *shadow_cr0 = *new_cr0;
231           *real_cr0 = *new_cr0;
232           real_cr0->pg = 1;
233         }
234
235
236       } else {
237         *real_cr0 = *new_cr0;
238       }
239
240       info->rip += index;
241     }
242     
243   } else { 
244     PrintDebug("Unknown Mode write to CR0\n");
245     return -1;
246   }
247   return 0;
248 }
249
250
251 int handle_cr0_read(struct guest_info * info) {
252   //vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
253   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
254   char instr[15];
255
256   if (info->cpu_mode == REAL) {
257     int index = 0;
258     int ret;
259
260     // The real rip address is actually a combination of the rip + CS base 
261     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.selector), 15, instr);
262     if (ret != 15) {
263       // I think we should inject a GPF into the guest
264       PrintDebug("Could not read Real Mode instruction (ret=%d)\n", ret);
265       return -1;
266     }
267
268
269     while (is_prefix_byte(instr[index])) {
270       index++; 
271     }
272
273     if ((instr[index] == cr_access_byte) && 
274         (instr[index + 1] == smsw_byte) && 
275         (MODRM_REG(instr[index + 2]) == smsw_reg_byte)) {
276
277       addr_t first_operand;
278       addr_t second_operand;
279       struct cr0_real *cr0;
280       operand_type_t addr_type;
281       char cr0_val = 0;
282
283       index += 2;
284       
285       cr0 = (struct cr0_real*)&(guest_state->cr0);
286       
287       
288       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
289       
290       if (addr_type == MEM_OPERAND) {
291         addr_t host_addr;
292         
293         if (guest_pa_to_host_va(info, first_operand + (guest_state->ds.base << 4), &host_addr) == -1) {
294           // gpf the guest
295           return -1;
296         }
297         
298         first_operand = host_addr;
299       } else {
300         // error... don't know what to do
301         return -1;
302       }
303
304       cr0_val = *(char*)cr0 & 0x0f;
305
306       *(char *)first_operand &= 0xf0;
307       *(char *)first_operand |= cr0_val;
308
309       PrintDebug("index = %d, rip = %x\n", index, (ulong_t)(info->rip));
310       info->rip += index;
311       PrintDebug("new_rip = %x\n", (ulong_t)(info->rip));
312     } else if ((instr[index] == cr_access_byte) &&
313                (instr[index+1] == mov_from_cr_byte)) {
314       /* Mov from CR0
315        * This can only take a 32 bit register argument in anything less than 64 bit mode.
316        */
317       addr_t first_operand;
318       addr_t second_operand;
319       operand_type_t addr_type;
320
321       struct cr0_32 * real_cr0 = (struct cr0_32 *)&(guest_state->cr0);
322
323       index += 2;
324
325       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
326      
327       struct cr0_32 * virt_cr0 = (struct cr0_32 *)first_operand;
328   
329       if (addr_type != REG_OPERAND) {
330         // invalid opcode to guest
331         PrintDebug("Invalid operand type in mov from CR0\n");
332         return -1;
333       }
334
335       if (info->page_mode == SHADOW_PAGING) {
336         *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
337       } else {
338         *virt_cr0 = *real_cr0;
339       }
340
341       info->rip += index;
342
343     } else {
344       PrintDebug("Unknown read instr from CR0\n");
345       return -1;
346     }
347
348   } else if (info->cpu_mode == PROTECTED) {
349     int index = 0;
350     int ret;
351
352     // The real rip address is actually a combination of the rip + CS base 
353     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
354     if (ret != 15) {
355       // I think we should inject a GPF into the guest
356       PrintDebug("Could not read Proteced mode instruction (ret=%d)\n", ret);
357       return -1;
358     }
359
360     while (is_prefix_byte(instr[index])) {
361       index++; 
362     }
363
364
365     if ((instr[index] == cr_access_byte) &&
366         (instr[index+1] == mov_from_cr_byte)) {
367       addr_t first_operand;
368       addr_t second_operand;
369       operand_type_t addr_type;
370       struct cr0_32 * virt_cr0;
371       struct cr0_32 * real_cr0 = (struct cr0_32 *)&(guest_state->cr0);
372
373       index += 2;
374
375       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
376
377       if (addr_type != REG_OPERAND) {
378         PrintDebug("Invalid operand type in mov from CR0\n");
379         return -1;
380       }
381       
382       virt_cr0 = (struct cr0_32 *)first_operand;
383
384       if (info->page_mode == SHADOW_PAGING) {
385         *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
386       } else {
387         *virt_cr0 = *real_cr0;
388       }
389       
390       info->rip += index;
391
392     } else { 
393       PrintDebug("Unknown read instruction from CR0\n");
394       return -1;
395     }
396
397   } else {
398     PrintDebug("Unknown mode read from CR0\n");
399     return -1;
400   }
401
402
403   return 0;
404 }