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 initial memory hook support, still need decoder
[palacios.git] / palacios / src / palacios / vmm_ctrl_regs.c
1 #include <palacios/vmm_mem.h>
2 #include <palacios/vmm.h>
3 #include <palacios/vmcb.h>
4 #include <palacios/vmm_emulate.h>
5 #include <palacios/vm_guest_mem.h>
6 #include <palacios/vmm_ctrl_regs.h>
7
8
9 /* Segmentation is a problem here...
10  *
11  * When we get a memory operand, presumably we use the default segment (which is?) 
12  * unless an alternate segment was specfied in the prefix...
13  */
14
15
16 int handle_cr0_write(struct guest_info * info) {
17   char instr[15];
18   
19   
20   if (info->cpu_mode == REAL) {
21     int index = 0;
22     int ret;
23
24     // The real rip address is actually a combination of the rip + CS base 
25     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
26     if (ret != 15) {
27       // I think we should inject a GPF into the guest
28       PrintDebug("Could not read instruction (ret=%d)\n", ret);
29       return -1;
30     }
31
32     while (is_prefix_byte(instr[index])) {
33       index++; 
34     }
35
36     if ((instr[index] == cr_access_byte) && 
37         (instr[index + 1] == lmsw_byte) && 
38         (MODRM_REG(instr[index + 2]) == lmsw_reg_byte)) {
39  
40       addr_t first_operand;
41       addr_t second_operand;
42       struct cr0_real *real_cr0;
43       struct cr0_real *new_cr0;
44       operand_type_t addr_type;
45       char new_cr0_val = 0;
46       // LMSW
47       // decode mod/RM
48       index += 2;
49  
50       real_cr0 = (struct cr0_real*)&(info->ctrl_regs.cr0);
51
52       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
53
54
55       if (addr_type == REG_OPERAND) {
56         new_cr0 = (struct cr0_real *)first_operand;
57       } else if (addr_type == MEM_OPERAND) {
58         addr_t host_addr;
59
60         if (guest_pa_to_host_va(info, first_operand + (info->segments.ds.base << 4), &host_addr) == -1) {
61           // gpf the guest
62           return -1;
63         }
64
65         new_cr0 = (struct cr0_real *)host_addr;
66       } else {
67         // error... don't know what to do
68         return -1;
69       }
70                  
71       if ((new_cr0->pe == 1) && (real_cr0->pe == 0)) {
72         info->cpu_mode = PROTECTED;
73       } else if ((new_cr0->pe == 0) && (real_cr0->pe == 1)) {
74         info->cpu_mode = REAL;
75       }
76       
77       new_cr0_val = *(char*)(new_cr0) & 0x0f;
78
79
80       if (info->page_mode == SHADOW_PAGING) {
81         struct cr0_real * shadow_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
82
83         PrintDebug("Old CR0=%x, Old Shadow CR0=%x\n", *real_cr0, *shadow_cr0);  
84         /* struct cr0_real is only 4 bits wide, 
85          * so we can overwrite the real_cr0 without worrying about the shadow fields
86          */
87         *(char*)real_cr0 &= 0xf0;
88         *(char*)real_cr0 |= new_cr0_val;
89         
90         *(char*)shadow_cr0 &= 0xf0;
91         *(char*)shadow_cr0 |= new_cr0_val;
92
93         PrintDebug("New CR0=%x, New Shadow CR0=%x\n", *real_cr0, *shadow_cr0);  
94       } else {
95         PrintDebug("Old CR0=%x\n", *real_cr0);  
96         // for now we just pass through....
97         *(char*)real_cr0 &= 0xf0;
98         *(char*)real_cr0 |= new_cr0_val;
99
100         PrintDebug("New CR0=%x\n", *real_cr0);  
101       }
102
103
104       info->rip += index;
105
106     } else if ((instr[index] == cr_access_byte) && 
107                (instr[index + 1] == clts_byte)) {
108       // CLTS
109       PrintDebug("CLTS unhandled\n");
110       return -1;
111
112     } else if ((instr[index] == cr_access_byte) && 
113                (instr[index + 1] = mov_to_cr_byte)) {
114       addr_t first_operand;
115       addr_t second_operand;
116       struct cr0_32 *real_cr0;
117       struct cr0_32 *new_cr0;
118       operand_type_t addr_type;
119      
120       
121       index += 2;
122  
123       real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
124
125       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
126
127       if (addr_type != REG_OPERAND) {
128         /* Mov to CR0 Can only be a 32 bit register */
129         // FIX ME
130         return -1;
131       }
132
133       new_cr0 = (struct cr0_32 *)first_operand;
134
135       if (new_cr0->pe == 1) {
136         PrintDebug("Entering Protected Mode\n");
137         info->cpu_mode = PROTECTED;
138       }
139
140       if (new_cr0->pg == 1) {
141         // GPF the guest??
142         return -1;
143       }
144
145       if (info->page_mode == SHADOW_PAGING) {
146         struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
147         
148         PrintDebug("Old CR0=%x, Old Shadow CR0=%x\n", *real_cr0, *shadow_cr0);  
149         *real_cr0 = *new_cr0;
150         real_cr0->pg = 1;
151
152         *shadow_cr0 = *new_cr0;
153
154         PrintDebug("New CR0=%x, New Shadow CR0=%x\n", *real_cr0, *shadow_cr0);  
155       } else {
156         PrintDebug("Old CR0=%x\n", *real_cr0);  
157         *real_cr0 = *new_cr0;
158         PrintDebug("New CR0=%x\n", *real_cr0);  
159       }
160
161       info->rip += index;
162
163     } else {
164       PrintDebug("Unsupported Instruction\n");
165       // unsupported instruction, UD the guest
166       return -1;
167     }
168
169
170   } else if (info->cpu_mode == PROTECTED) {
171     int index = 0;
172     int ret;
173
174     PrintDebug("Protected Mode write to CR0\n");
175
176     // The real rip address is actually a combination of the rip + CS base 
177     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
178     if (ret != 15) {
179       // I think we should inject a GPF into the guest
180       PrintDebug("Could not read instruction (ret=%d)\n", ret);
181       return -1;
182     }
183
184     while (is_prefix_byte(instr[index])) {
185       index++; 
186     }
187
188     if ((instr[index] == cr_access_byte) && 
189         (instr[index + 1] == mov_to_cr_byte)) {
190     
191       addr_t first_operand;
192       addr_t second_operand;
193       struct cr0_32 *real_cr0;
194       struct cr0_32 *new_cr0;
195       operand_type_t addr_type;
196
197       index += 2;
198  
199       real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
200
201       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
202
203       if (addr_type != REG_OPERAND) {
204         return -1;
205       }
206
207       new_cr0 = (struct cr0_32 *)first_operand;
208
209
210       if (info->page_mode == SHADOW_PAGING) {
211         struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
212
213         if (new_cr0->pg == 1){
214           struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
215
216           info->cpu_mode = PROTECTED_PG;
217           
218           *shadow_cr0 = *new_cr0;
219           *real_cr0 = *new_cr0;
220
221           //
222           // Activate Shadow Paging
223           //
224           PrintDebug("Turning on paging in the guest\n");
225
226           info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
227           
228
229         } else if (new_cr0->pe == 0) {
230           info->cpu_mode = REAL;
231
232           *shadow_cr0 = *new_cr0;
233           *real_cr0 = *new_cr0;
234           real_cr0->pg = 1;
235         }
236
237
238       } else {
239         *real_cr0 = *new_cr0;
240       }
241
242       info->rip += index;
243     }
244     
245   } else { 
246     PrintDebug("Unknown Mode write to CR0\n");
247     return -1;
248   }
249   return 0;
250 }
251
252
253 int handle_cr0_read(struct guest_info * info) {
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, info->rip, &(info->segments.cs)), 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*)&(info->ctrl_regs.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 + (info->segments.ds.base << 4), &host_addr) == -1) {
294           // gpf the guest
295           PrintDebug("Could not convert guest physical address to host virtual address\n");
296           return -1;
297         }
298         
299         first_operand = host_addr;
300       } else {
301         // Register operand
302         // Should be ok??
303       }
304
305       cr0_val = *(char*)cr0 & 0x0f;
306
307       *(char *)first_operand &= 0xf0;
308       *(char *)first_operand |= cr0_val;
309
310       PrintDebug("index = %d, rip = %x\n", index, (ulong_t)(info->rip));
311       info->rip += index;
312       PrintDebug("new_rip = %x\n", (ulong_t)(info->rip));
313     } else if ((instr[index] == cr_access_byte) &&
314                (instr[index+1] == mov_from_cr_byte)) {
315       /* Mov from CR0
316        * This can only take a 32 bit register argument in anything less than 64 bit mode.
317        */
318       addr_t first_operand;
319       addr_t second_operand;
320       operand_type_t addr_type;
321
322       struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
323
324       index += 2;
325
326       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
327      
328       struct cr0_32 * virt_cr0 = (struct cr0_32 *)first_operand;
329   
330       if (addr_type != REG_OPERAND) {
331         // invalid opcode to guest
332         PrintDebug("Invalid operand type in mov from CR0\n");
333         return -1;
334       }
335
336       if (info->page_mode == SHADOW_PAGING) {
337         *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
338       } else {
339         *virt_cr0 = *real_cr0;
340       }
341
342       info->rip += index;
343
344     } else {
345       PrintDebug("Unknown read instr from CR0\n");
346       return -1;
347     }
348
349   } else if (info->cpu_mode == PROTECTED) {
350     int index = 0;
351     int ret;
352
353     // The real rip address is actually a combination of the rip + CS base 
354     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
355     if (ret != 15) {
356       // I think we should inject a GPF into the guest
357       PrintDebug("Could not read Proteced mode instruction (ret=%d)\n", ret);
358       return -1;
359     }
360
361     while (is_prefix_byte(instr[index])) {
362       index++; 
363     }
364
365
366     if ((instr[index] == cr_access_byte) &&
367         (instr[index+1] == mov_from_cr_byte)) {
368       addr_t first_operand;
369       addr_t second_operand;
370       operand_type_t addr_type;
371       struct cr0_32 * virt_cr0;
372       struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
373
374       index += 2;
375
376       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
377
378       if (addr_type != REG_OPERAND) {
379         PrintDebug("Invalid operand type in mov from CR0\n");
380         return -1;
381       }
382       
383       virt_cr0 = (struct cr0_32 *)first_operand;
384
385       if (info->page_mode == SHADOW_PAGING) {
386         *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
387       } else {
388         *virt_cr0 = *real_cr0;
389       }
390       
391       info->rip += index;
392
393     } else { 
394       PrintDebug("Unknown read instruction from CR0\n");
395       return -1;
396     }
397
398   } else {
399     PrintDebug("Unknown mode read from CR0\n");
400     return -1;
401   }
402
403
404   return 0;
405 }
406
407
408
409
410 int handle_cr3_write(struct guest_info * info) {
411   if ((info->cpu_mode == PROTECTED) || (info->cpu_mode == PROTECTED_PG)) {
412     int index = 0;
413     int ret;
414     char instr[15];
415
416
417     /* Isn't the RIP a Guest Virtual Address???????? */
418     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
419     if (ret != 15) {
420       PrintDebug("Could not read instruction (ret=%d)\n", ret);
421       return -1;
422     }
423     
424     while (is_prefix_byte(instr[index])) {
425       index++;
426     }
427
428     if ((instr[index] == cr_access_byte) && 
429         (instr[index + 1] == mov_to_cr_byte)) {
430
431       addr_t first_operand;
432       addr_t second_operand;
433       struct cr3_32 * new_cr3;
434       //      struct cr3_32 * real_cr3;
435       operand_type_t addr_type;
436
437       index += 2;
438
439       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
440
441       if (addr_type != REG_OPERAND) {
442         /* Mov to CR3 can only be a 32 bit register */
443         return -1;
444       }
445
446       new_cr3 = (struct cr3_32 *)first_operand;
447
448       if (info->page_mode == SHADOW_PAGING) {
449         addr_t shadow_pt;
450         struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
451         struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
452
453         /* Delete the current Page Tables */
454         delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(shadow_cr3));
455
456         *guest_cr3 = *new_cr3;
457
458         // Something like this
459         shadow_pt =  create_new_shadow_pt32(info);
460         //shadow_pt = setup_shadow_pt32(info, CR3_TO_PDE32(*(addr_t *)new_cr3));
461
462
463         /* Copy Various flags */
464         *shadow_cr3 = *new_cr3;
465         
466         shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);
467
468         if (info->cpu_mode == PROTECTED_PG) {
469           // If we aren't in paged mode then we have to preserve the identity mapped CR3
470           info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
471         }
472       }
473
474       info->rip += index;
475
476     } else {
477       PrintDebug("Unknown Instruction\n");
478       return -1;
479     }
480   } else {
481     PrintDebug("Invalid operating Mode\n");
482     return -1;
483   }
484
485   return 0;
486 }
487
488
489
490
491 int handle_cr3_read(struct guest_info * info) {
492   if ((info->cpu_mode == PROTECTED) || (info->cpu_mode == PROTECTED_PG)) {
493     int index = 0;
494     int ret;
495     char instr[15];
496
497     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
498     if (ret != 15) {
499       PrintDebug("Could not read instruction (ret=%d)\n", ret);
500       return -1;
501     }
502     
503     while (is_prefix_byte(instr[index])) {
504       index++;
505     }
506
507     if ((instr[index] == cr_access_byte) && 
508         (instr[index + 1] == mov_from_cr_byte)) {
509       addr_t first_operand;
510       addr_t second_operand;
511       struct cr3_32 * virt_cr3;
512       struct cr3_32 * real_cr3 = (struct cr3_32 *)&(info->ctrl_regs.cr3);
513       operand_type_t addr_type;
514
515       index += 2;
516
517       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
518
519       if (addr_type != REG_OPERAND) {
520         /* Mov to CR3 can only be a 32 bit register */
521         return -1;
522       }
523
524       virt_cr3 = (struct cr3_32 *)first_operand;
525
526       if (info->page_mode == SHADOW_PAGING) {
527         *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
528       } else {
529         *virt_cr3 = *real_cr3;
530       }
531       
532       info->rip += index;
533     } else {
534       PrintDebug("Unknown Instruction\n");
535       return -1;
536     }
537   } else {
538     PrintDebug("Invalid operating Mode\n");
539     return -1;
540   }
541
542   return 0;
543 }