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.


initial shadow paging support
[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     if ((instr[index] == cr_access_byte) && 
191         (instr[index + 1] == mov_to_cr_byte)) {
192     
193       addr_t first_operand;
194       addr_t second_operand;
195       struct cr0_32 *real_cr0;
196       struct cr0_32 *new_cr0;
197       operand_type_t addr_type;
198
199       index += 2;
200  
201       real_cr0 = (struct cr0_32*)&(guest_state->cr0);
202
203       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
204
205       if (addr_type != REG_OPERAND) {
206         return -1;
207       }
208
209       new_cr0 = (struct cr0_32 *)first_operand;
210
211
212       if (info->page_mode == SHADOW_PAGING) {
213         struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
214
215         if (new_cr0->pg == 1){
216           struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
217
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           PrintDebug("Turning on paging in the guest\n");
227
228           guest_state->cr3 = *(addr_t*)shadow_cr3;
229           
230
231         } else if (new_cr0->pe == 0) {
232           info->cpu_mode = REAL;
233
234           *shadow_cr0 = *new_cr0;
235           *real_cr0 = *new_cr0;
236           real_cr0->pg = 1;
237         }
238
239
240       } else {
241         *real_cr0 = *new_cr0;
242       }
243
244       info->rip += index;
245     }
246     
247   } else { 
248     PrintDebug("Unknown Mode write to CR0\n");
249     return -1;
250   }
251   return 0;
252 }
253
254
255 int handle_cr0_read(struct guest_info * info) {
256   //vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
257   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
258   char instr[15];
259
260   if (info->cpu_mode == REAL) {
261     int index = 0;
262     int ret;
263
264     // The real rip address is actually a combination of the rip + CS base 
265     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.selector), 15, instr);
266     if (ret != 15) {
267       // I think we should inject a GPF into the guest
268       PrintDebug("Could not read Real Mode instruction (ret=%d)\n", ret);
269       return -1;
270     }
271
272
273     while (is_prefix_byte(instr[index])) {
274       index++; 
275     }
276
277     if ((instr[index] == cr_access_byte) && 
278         (instr[index + 1] == smsw_byte) && 
279         (MODRM_REG(instr[index + 2]) == smsw_reg_byte)) {
280
281       addr_t first_operand;
282       addr_t second_operand;
283       struct cr0_real *cr0;
284       operand_type_t addr_type;
285       char cr0_val = 0;
286
287       index += 2;
288       
289       cr0 = (struct cr0_real*)&(guest_state->cr0);
290       
291       
292       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
293       
294       if (addr_type == MEM_OPERAND) {
295         addr_t host_addr;
296         
297         if (guest_pa_to_host_va(info, first_operand + (guest_state->ds.base << 4), &host_addr) == -1) {
298           // gpf the guest
299           return -1;
300         }
301         
302         first_operand = host_addr;
303       } else {
304         // error... don't know what to do
305         return -1;
306       }
307
308       cr0_val = *(char*)cr0 & 0x0f;
309
310       *(char *)first_operand &= 0xf0;
311       *(char *)first_operand |= cr0_val;
312
313       PrintDebug("index = %d, rip = %x\n", index, (ulong_t)(info->rip));
314       info->rip += index;
315       PrintDebug("new_rip = %x\n", (ulong_t)(info->rip));
316     } else if ((instr[index] == cr_access_byte) &&
317                (instr[index+1] == mov_from_cr_byte)) {
318       /* Mov from CR0
319        * This can only take a 32 bit register argument in anything less than 64 bit mode.
320        */
321       addr_t first_operand;
322       addr_t second_operand;
323       operand_type_t addr_type;
324
325       struct cr0_32 * real_cr0 = (struct cr0_32 *)&(guest_state->cr0);
326
327       index += 2;
328
329       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
330      
331       struct cr0_32 * virt_cr0 = (struct cr0_32 *)first_operand;
332   
333       if (addr_type != REG_OPERAND) {
334         // invalid opcode to guest
335         PrintDebug("Invalid operand type in mov from CR0\n");
336         return -1;
337       }
338
339       if (info->page_mode == SHADOW_PAGING) {
340         *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
341       } else {
342         *virt_cr0 = *real_cr0;
343       }
344
345       info->rip += index;
346
347     } else {
348       PrintDebug("Unknown read instr from CR0\n");
349       return -1;
350     }
351
352   } else if (info->cpu_mode == PROTECTED) {
353     int index = 0;
354     int ret;
355
356     // The real rip address is actually a combination of the rip + CS base 
357     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
358     if (ret != 15) {
359       // I think we should inject a GPF into the guest
360       PrintDebug("Could not read Proteced mode instruction (ret=%d)\n", ret);
361       return -1;
362     }
363
364     while (is_prefix_byte(instr[index])) {
365       index++; 
366     }
367
368
369     if ((instr[index] == cr_access_byte) &&
370         (instr[index+1] == mov_from_cr_byte)) {
371       addr_t first_operand;
372       addr_t second_operand;
373       operand_type_t addr_type;
374       struct cr0_32 * virt_cr0;
375       struct cr0_32 * real_cr0 = (struct cr0_32 *)&(guest_state->cr0);
376
377       index += 2;
378
379       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
380
381       if (addr_type != REG_OPERAND) {
382         PrintDebug("Invalid operand type in mov from CR0\n");
383         return -1;
384       }
385       
386       virt_cr0 = (struct cr0_32 *)first_operand;
387
388       if (info->page_mode == SHADOW_PAGING) {
389         *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
390       } else {
391         *virt_cr0 = *real_cr0;
392       }
393       
394       info->rip += index;
395
396     } else { 
397       PrintDebug("Unknown read instruction from CR0\n");
398       return -1;
399     }
400
401   } else {
402     PrintDebug("Unknown mode read from CR0\n");
403     return -1;
404   }
405
406
407   return 0;
408 }
409
410
411
412
413 int handle_cr3_write(struct guest_info * info) {
414   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
415
416
417   if ((info->cpu_mode == PROTECTED) || (info->cpu_mode == PROTECTED_PG)) {
418     int index = 0;
419     int ret;
420     char instr[15];
421
422     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
423     if (ret != 15) {
424       PrintDebug("Could not read instruction (ret=%d)\n", ret);
425       return -1;
426     }
427     
428     while (is_prefix_byte(instr[index])) {
429       index++;
430     }
431
432     if ((instr[index] == cr_access_byte) && 
433         (instr[index + 1] == mov_to_cr_byte)) {
434
435       addr_t first_operand;
436       addr_t second_operand;
437       struct cr3_32 * new_cr3;
438       //      struct cr3_32 * real_cr3;
439       operand_type_t addr_type;
440
441       index += 2;
442
443       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
444
445       if (addr_type != REG_OPERAND) {
446         /* Mov to CR3 can only be a 32 bit register */
447         return -1;
448       }
449
450       new_cr3 = (struct cr3_32 *)first_operand;
451
452       if (info->page_mode == SHADOW_PAGING) {
453         addr_t shadow_pt;
454         struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
455         struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
456
457
458         *guest_cr3 = *new_cr3;
459
460         // Something like this
461         shadow_pt =  create_new_shadow_pt32(info);
462         //shadow_pt = setup_shadow_pt32(info, CR3_TO_PDE32(*(addr_t *)new_cr3));
463
464         /* Copy Various flags */
465         *shadow_cr3 = *new_cr3;
466         
467         shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);
468
469         if (info->cpu_mode == PROTECTED_PG) {
470           // If we aren't in paged mode then we have to preserve the identity mapped CR3
471           guest_state->cr3 = *(addr_t*)shadow_cr3;
472         }
473       }
474
475       info->rip += index;
476
477     } else {
478       PrintDebug("Unknown Instruction\n");
479       return -1;
480     }
481   } else {
482     PrintDebug("Invalid operating Mode\n");
483     return -1;
484   }
485
486   return 0;
487 }
488
489
490
491
492 int handle_cr3_read(struct guest_info * info) {
493   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
494
495   if ((info->cpu_mode == PROTECTED) || (info->cpu_mode == PROTECTED_PG)) {
496     int index = 0;
497     int ret;
498     char instr[15];
499
500     ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
501     if (ret != 15) {
502       PrintDebug("Could not read instruction (ret=%d)\n", ret);
503       return -1;
504     }
505     
506     while (is_prefix_byte(instr[index])) {
507       index++;
508     }
509
510     if ((instr[index] == cr_access_byte) && 
511         (instr[index + 1] == mov_from_cr_byte)) {
512       addr_t first_operand;
513       addr_t second_operand;
514       struct cr3_32 * virt_cr3;
515       struct cr3_32 * real_cr3 = (struct cr3_32 *)&(guest_state->cr3);
516       operand_type_t addr_type;
517
518       index += 2;
519
520       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
521
522       if (addr_type != REG_OPERAND) {
523         /* Mov to CR3 can only be a 32 bit register */
524         return -1;
525       }
526
527       virt_cr3 = (struct cr3_32 *)first_operand;
528
529       if (info->page_mode == SHADOW_PAGING) {
530         *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
531       } else {
532         *virt_cr3 = *real_cr3;
533       }
534       
535       info->rip += index;
536     } else {
537       PrintDebug("Unknown Instruction\n");
538       return -1;
539     }
540   } else {
541     PrintDebug("Invalid operating Mode\n");
542     return -1;
543   }
544
545   return 0;
546 }