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 CR0 handling for PROTECTED_PG and for the CLTS instruction
[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_decoder.h>
5 #include <palacios/vm_guest_mem.h>
6 #include <palacios/vmm_ctrl_regs.h>
7
8
9
10 extern void SerialMemDump(unsigned char *start, int n);
11
12 /* Segmentation is a problem here...
13  *
14  * When we get a memory operand, presumably we use the default segment (which is?) 
15  * unless an alternate segment was specfied in the prefix...
16  */
17
18
19 int handle_cr0_write(struct guest_info * info) {
20   char instr[15];
21   
22   
23   switch (info->cpu_mode) { 
24   case REAL: 
25     {
26       int index = 0;
27       int ret;
28       
29       PrintDebug("Real Mode write to CR0 at linear guest pa 0x%x\n",get_addr_linear(info,info->rip,&(info->segments.cs)));
30
31       // The real rip address is actually a combination of the rip + CS base 
32       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
33       if (ret != 15) {
34         // I think we should inject a GPF into the guest
35         PrintDebug("Could not read instruction (ret=%d)\n", ret);
36         return -1;
37       }
38
39       while (is_prefix_byte(instr[index])) {
40         index++; 
41       }
42
43       if ((instr[index] == cr_access_byte) && 
44           (instr[index + 1] == lmsw_byte) && 
45           (MODRM_REG(instr[index + 2]) == lmsw_reg_byte)) {
46  
47         addr_t first_operand;
48         addr_t second_operand;
49         struct cr0_real *real_cr0;
50         struct cr0_real *new_cr0;
51         operand_type_t addr_type;
52         char new_cr0_val = 0;
53         // LMSW
54         // decode mod/RM
55         index += 2;
56  
57         real_cr0 = (struct cr0_real*)&(info->ctrl_regs.cr0);
58
59         addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
60
61
62         if (addr_type == REG_OPERAND) {
63           new_cr0 = (struct cr0_real *)first_operand;
64         } else if (addr_type == MEM_OPERAND) {
65           addr_t host_addr;
66
67           if (guest_pa_to_host_va(info, first_operand + (info->segments.ds.base << 4), &host_addr) == -1) {
68             // gpf the guest
69             return -1;
70           }
71
72           new_cr0 = (struct cr0_real *)host_addr;
73         } else {
74           PrintDebug("Memory operand in real mode write to CR0 is UNIMPLEMENTED\n");
75           // error... don't know what to do
76           return -1;
77         }
78                  
79         if ((new_cr0->pe == 1) && (real_cr0->pe == 0)) {
80           info->cpu_mode = PROTECTED;
81         } else if ((new_cr0->pe == 0) && (real_cr0->pe == 1)) {
82           info->cpu_mode = REAL;
83         }
84       
85         new_cr0_val = *(char*)(new_cr0) & 0x0f;
86
87
88         if (info->page_mode == SHADOW_PAGING) {
89           struct cr0_real * shadow_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
90
91           PrintDebug("Old CR0=%x, Old Shadow CR0=%x\n", *real_cr0, *shadow_cr0);        
92           /* struct cr0_real is only 4 bits wide, 
93            * so we can overwrite the real_cr0 without worrying about the shadow fields
94            */
95           *(char*)real_cr0 &= 0xf0;
96           *(char*)real_cr0 |= new_cr0_val;
97         
98           *(char*)shadow_cr0 &= 0xf0;
99           *(char*)shadow_cr0 |= new_cr0_val;
100
101           PrintDebug("New CR0=%x, New Shadow CR0=%x\n", *real_cr0, *shadow_cr0);        
102         } else {
103           PrintDebug("Old CR0=%x\n", *real_cr0);        
104           // for now we just pass through....
105           *(char*)real_cr0 &= 0xf0;
106           *(char*)real_cr0 |= new_cr0_val;
107
108           PrintDebug("New CR0=%x\n", *real_cr0);        
109         }
110
111
112         info->rip += index;
113
114       } else if ((instr[index] == cr_access_byte) && 
115                  (instr[index + 1] == clts_byte)) {
116         // CLTS
117         PrintDebug("CLTS unhandled in CR0 write\n");
118         return -1;
119
120       } else if ((instr[index] == cr_access_byte) && 
121                  (instr[index + 1] = mov_to_cr_byte)) {
122         addr_t first_operand;
123         addr_t second_operand;
124         struct cr0_32 *real_cr0;
125         struct cr0_32 *new_cr0;
126         operand_type_t addr_type;
127      
128       
129         index += 2;
130  
131         real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
132
133         addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
134
135         if (addr_type != REG_OPERAND) {
136           PrintDebug("Moving to CR0 from non-register operand in CR0 write\n");
137           /* Mov to CR0 Can only be a 32 bit register */
138           // FIX ME
139           return -1;
140         }
141
142         new_cr0 = (struct cr0_32 *)first_operand;
143
144         if (new_cr0->pe == 1) {
145           PrintDebug("Entering Protected Mode\n");
146           info->cpu_mode = PROTECTED;
147         }
148
149         if (new_cr0->pg == 1) {
150           PrintDebug("Paging is already turned on in switch to protected mode in CR0 write\n");
151
152           // GPF the guest??
153           return -1;
154         }
155
156         if (info->page_mode == SHADOW_PAGING) {
157           struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
158         
159           PrintDebug("Old CR0=%x, Old Shadow CR0=%x\n", *real_cr0, *shadow_cr0);        
160           *real_cr0 = *new_cr0;
161           real_cr0->pg = 1;
162
163           *shadow_cr0 = *new_cr0;
164
165           PrintDebug("New CR0=%x, New Shadow CR0=%x\n", *real_cr0, *shadow_cr0);        
166         } else {
167           PrintDebug("Old CR0=%x\n", *real_cr0);        
168           *real_cr0 = *new_cr0;
169           PrintDebug("New CR0=%x\n", *real_cr0);        
170         }
171
172         info->rip += index;
173
174       } else {
175         PrintDebug("Unsupported Instruction\n");
176         // unsupported instruction, UD the guest
177         return -1;
178       }
179
180     } 
181     break;
182  
183   case PROTECTED: 
184   case PROTECTED_PG:
185     {
186
187       int index = 0;
188       int ret;
189
190       PrintDebug("Protected %s Mode write to CR0 at guest %s linear rip 0x%x\n", 
191                  info->cpu_mode==PROTECTED_PG ? "Paged" : "",
192                  info->cpu_mode==PROTECTED_PG ? "virtual" : "",
193                  get_addr_linear(info,info->rip,&(info->segments.cs)));
194
195       // OK, now we will read the instruction
196       // The only difference between PROTECTED and PROTECTED_PG is whether we read
197       // from guest_pa or guest_va
198       if (info->cpu_mode==PROTECTED) { 
199         // The real rip address is actually a combination of the rip + CS base 
200         ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
201       } else { //PROTECTED_PG
202         ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
203       }
204         
205       if (ret != 15) {
206         // I think we should inject a GPF into the guest
207         PrintDebug("Could not read instruction (ret=%d)\n", ret);
208         return -1;
209       }
210
211       while (is_prefix_byte(instr[index])) {
212         index++; 
213       }
214
215       struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
216
217       struct cr0_32 * real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
218
219       if ((instr[index] == cr_access_byte) && 
220           (instr[index + 1] == mov_to_cr_byte)) {
221
222         // MOV to CR0
223     
224         addr_t first_operand;
225         addr_t second_operand;
226         struct cr0_32 *new_cr0;
227         operand_type_t addr_type;
228
229         index += 2;
230  
231
232         addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
233
234         if (addr_type != REG_OPERAND) {
235           PrintDebug("Non-register operand in write to CR0\n");
236           return -1;
237         }
238
239         new_cr0 = (struct cr0_32 *)first_operand;
240
241
242
243         if (info->page_mode == SHADOW_PAGING) {
244           struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
245
246           if (new_cr0->pg == 1){
247             // This should be new_cr0->pg && !(old_cr->pg), right?
248             // and then a case for turning paging off?
249
250             struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
251
252             info->cpu_mode = PROTECTED_PG;
253           
254             *shadow_cr0 = *new_cr0;
255             *real_cr0 = *new_cr0;
256
257             //
258             // Activate Shadow Paging
259             //
260             PrintDebug("Turning on paging in the guest\n");
261
262             info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
263           
264
265           } else if (new_cr0->pe == 0) {
266             info->cpu_mode = REAL;
267
268             *shadow_cr0 = *new_cr0;
269             *real_cr0 = *new_cr0;
270             real_cr0->pg = 1;
271           }
272
273
274         } else {
275           *real_cr0 = *new_cr0;
276         }
277
278         info->rip += index;
279
280       } else if ((instr[index] == 0x0f) &&
281                  (instr[index + 1] == 0x06)) { 
282         // CLTS instruction
283         PrintDebug("CLTS instruction - clearing TS flag of real and shadow CR0\n");
284         shadow_cr0->ts=0;
285         real_cr0->ts=0;
286         
287         index+=2;
288         
289         info->rip+=index;
290
291       } else {
292         PrintDebug("Unkown instruction: \n");
293         SerialMemDump(instr,15);
294         return -1;
295       }
296     }
297     break;
298     
299   case PROTECTED_PAE:
300     PrintDebug("Protected PAE Mode write to CR0 is UNIMPLEMENTED\n");
301     return -1;
302
303   case PROTECTED_PAE_PG:
304     PrintDebug("Protected PAE Paged Mode write to CR0 is UNIMPLEMENTED\n");
305     return -1;
306
307   case LONG:
308     PrintDebug("Protected Long Mode write to CR0 is UNIMPLEMENTED\n");
309     return -1;
310
311   case LONG_PG:
312     PrintDebug("Protected Long Paged Mode write to CR0 is UNIMPLEMENTED\n");
313     return -1;
314
315   default: 
316     {
317       PrintDebug("Unknown Mode write to CR0 (info->cpu_mode=0x%x\n)",info->cpu_mode);
318       return -1;
319     }
320     break;
321
322   }
323
324   return 0;
325 }
326
327
328 int handle_cr0_read(struct guest_info * info) {
329   char instr[15];
330
331   switch (info->cpu_mode) { 
332
333   case REAL: 
334     {
335
336       int index = 0;
337       int ret;
338
339       PrintDebug("Real Mode read from CR0 at linear guest pa 0x%x\n",get_addr_linear(info,info->rip,&(info->segments.cs)));
340
341       // The real rip address is actually a combination of the rip + CS base 
342       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
343       if (ret != 15) {
344         // I think we should inject a GPF into the guest
345         PrintDebug("Could not read Real Mode instruction (ret=%d)\n", ret);
346         return -1;
347       }
348
349
350       while (is_prefix_byte(instr[index])) {
351         index++; 
352       }
353
354       if ((instr[index] == cr_access_byte) && 
355           (instr[index + 1] == smsw_byte) && 
356           (MODRM_REG(instr[index + 2]) == smsw_reg_byte)) {
357
358         // SMSW (store machine status word)
359
360         addr_t first_operand;
361         addr_t second_operand;
362         struct cr0_real *cr0;
363         operand_type_t addr_type;
364         char cr0_val = 0;
365
366         index += 2;
367       
368         cr0 = (struct cr0_real*)&(info->ctrl_regs.cr0);
369       
370       
371         addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
372       
373         if (addr_type == MEM_OPERAND) {
374           addr_t host_addr;
375         
376           if (guest_pa_to_host_va(info, first_operand + (info->segments.ds.base << 4), &host_addr) == -1) {
377             // gpf the guest
378             PrintDebug("Could not convert guest physical address to host virtual address\n");
379             return -1;
380           }
381         
382           first_operand = host_addr;
383         } else {
384           // Register operand
385           // Should be ok??
386         }
387
388         cr0_val = *(char*)cr0 & 0x0f;
389
390         *(char *)first_operand &= 0xf0;
391         *(char *)first_operand |= cr0_val;
392
393         PrintDebug("index = %d, rip = %x\n", index, (ulong_t)(info->rip));
394         info->rip += index;
395         PrintDebug("new_rip = %x\n", (ulong_t)(info->rip));
396         // success
397
398       } else if ((instr[index] == cr_access_byte) &&
399                  (instr[index+1] == mov_from_cr_byte)) {
400         /* Mov from CR0
401          * This can only take a 32 bit register argument in anything less than 64 bit mode.
402          */
403         addr_t first_operand;
404         addr_t second_operand;
405         operand_type_t addr_type;
406
407         struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
408
409         index += 2;
410
411         addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
412      
413         struct cr0_32 * virt_cr0 = (struct cr0_32 *)first_operand;
414   
415         if (addr_type != REG_OPERAND) {
416           // invalid opcode to guest
417           PrintDebug("Invalid operand type in mov from CR0\n");
418           return -1;
419         }
420
421         if (info->page_mode == SHADOW_PAGING) {
422           *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
423         } else {
424           *virt_cr0 = *real_cr0;
425         }
426
427         info->rip += index;
428
429       } else {
430         PrintDebug("Unknown read instr from CR0\n");
431         return -1;
432       }
433
434     } 
435
436     break;
437
438   case PROTECTED:
439   case PROTECTED_PG:
440     {
441     
442       int index = 0;
443       int ret;
444
445       PrintDebug("Protected %s Mode read from CR0 at guest %s linear rip 0x%x\n", 
446                  info->cpu_mode==PROTECTED_PG ? "Paged" : "",
447                  info->cpu_mode==PROTECTED_PG ? "virtual" : "",
448                  get_addr_linear(info,info->rip,&(info->segments.cs)));
449
450       // We need to read the instruction, which is at CS:IP, but that 
451       // linear address is guest physical without PG and guest virtual with PG
452       if (info->cpu_mode==PROTECTED) { 
453         // The real rip address is actually a combination of the rip + CS base 
454         ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
455       } else { // PROTECTED_PG
456         // The real rip address is actually a combination of the rip + CS base 
457         ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
458       }
459
460       if (ret != 15) {
461         // I think we should inject a GPF into the guest
462         PrintDebug("Could not read Protected %s mode instruction (ret=%d)\n", 
463                    info->cpu_mode==PROTECTED_PG ? "Paged" : "", ret);
464         return -1;
465       }
466
467       while (is_prefix_byte(instr[index])) {
468         index++; 
469       }
470
471
472       if ((instr[index] == cr_access_byte) &&
473           (instr[index+1] == mov_from_cr_byte)) {
474         
475         // MOV from CR0 to register
476
477         addr_t first_operand;
478         addr_t second_operand;
479         operand_type_t addr_type;
480         struct cr0_32 * virt_cr0;
481         struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
482
483         index += 2;
484
485         addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
486
487         if (addr_type != REG_OPERAND) {
488           PrintDebug("Invalid operand type in mov from CR0\n");
489           return -1;
490         }
491       
492         virt_cr0 = (struct cr0_32 *)first_operand;
493
494         if (info->page_mode == SHADOW_PAGING) {
495           *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
496         } else {
497           *virt_cr0 = *real_cr0;
498         }
499       
500         info->rip += index;
501
502       } else { 
503         PrintDebug("Unknown read instruction from CR0\n");
504         return -1;
505       }
506     }
507     break;
508
509   case PROTECTED_PAE:
510     PrintDebug("Protected PAE Mode read to CR0 is UNIMPLEMENTED\n");
511     return -1;
512
513   case PROTECTED_PAE_PG:
514     PrintDebug("Protected PAE Paged Mode read to CR0 is UNIMPLEMENTED\n");
515     return -1;
516
517   case LONG:
518     PrintDebug("Protected Long Mode read to CR0 is UNIMPLEMENTED\n");
519     return -1;
520
521   case LONG_PG:
522     PrintDebug("Protected Long Paged Mode read to CR0 is UNIMPLEMENTED\n");
523     return -1;
524   default:
525     {
526       PrintDebug("Unknown Mode read from CR0 (info->cpu_mode=0x%x)\n",info->cpu_mode);
527       return -1;
528     }
529     break;
530   }
531
532
533   return 0;
534 }
535
536
537
538
539 int handle_cr3_write(struct guest_info * info) {
540   if ((info->cpu_mode == PROTECTED) || (info->cpu_mode == PROTECTED_PG)) {
541     int index = 0;
542     int ret;
543     char instr[15];
544
545
546     /* Isn't the RIP a Guest Virtual Address???????? */
547     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
548     if (ret != 15) {
549       PrintDebug("Could not read instruction (ret=%d)\n", ret);
550       return -1;
551     }
552     
553     while (is_prefix_byte(instr[index])) {
554       index++;
555     }
556
557     if ((instr[index] == cr_access_byte) && 
558         (instr[index + 1] == mov_to_cr_byte)) {
559
560       addr_t first_operand;
561       addr_t second_operand;
562       struct cr3_32 * new_cr3;
563       //      struct cr3_32 * real_cr3;
564       operand_type_t addr_type;
565
566       index += 2;
567
568       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
569
570       if (addr_type != REG_OPERAND) {
571         /* Mov to CR3 can only be a 32 bit register */
572         return -1;
573       }
574
575       new_cr3 = (struct cr3_32 *)first_operand;
576
577       if (info->page_mode == SHADOW_PAGING) {
578         addr_t shadow_pt;
579         struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
580         struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
581
582         PrintDebug("fooo1\n");
583
584         /* Delete the current Page Tables */
585         delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
586
587         PrintDebug("fooo2\n");
588         *guest_cr3 = *new_cr3;
589
590         // Something like this
591         shadow_pt =  create_new_shadow_pt32(info);
592         //shadow_pt = setup_shadow_pt32(info, CR3_TO_PDE32(*(addr_t *)new_cr3));
593
594
595         /* Copy Various flags */
596         *shadow_cr3 = *new_cr3;
597         
598         shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);
599
600         if (info->cpu_mode == PROTECTED_PG) {
601           // If we aren't in paged mode then we have to preserve the identity mapped CR3
602           info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
603         }
604       }
605
606       info->rip += index;
607
608     } else {
609       PrintDebug("Unknown Instruction\n");
610       return -1;
611     }
612   } else {
613     PrintDebug("Invalid operating Mode\n");
614     return -1;
615   }
616
617   return 0;
618 }
619
620
621
622
623 int handle_cr3_read(struct guest_info * info) {
624   if ((info->cpu_mode == PROTECTED) || (info->cpu_mode == PROTECTED_PG)) {
625     int index = 0;
626     int ret;
627     char instr[15];
628
629     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
630     if (ret != 15) {
631       PrintDebug("Could not read instruction (ret=%d)\n", ret);
632       return -1;
633     }
634     
635     while (is_prefix_byte(instr[index])) {
636       index++;
637     }
638
639     if ((instr[index] == cr_access_byte) && 
640         (instr[index + 1] == mov_from_cr_byte)) {
641       addr_t first_operand;
642       addr_t second_operand;
643       struct cr3_32 * virt_cr3;
644       struct cr3_32 * real_cr3 = (struct cr3_32 *)&(info->ctrl_regs.cr3);
645       operand_type_t addr_type;
646
647       index += 2;
648
649       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
650
651       if (addr_type != REG_OPERAND) {
652         /* Mov to CR3 can only be a 32 bit register */
653         return -1;
654       }
655
656       virt_cr3 = (struct cr3_32 *)first_operand;
657
658       if (info->page_mode == SHADOW_PAGING) {
659         *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
660       } else {
661         *virt_cr3 = *real_cr3;
662       }
663       
664       info->rip += index;
665     } else {
666       PrintDebug("Unknown Instruction\n");
667       return -1;
668     }
669   } else {
670     PrintDebug("Invalid operating Mode\n");
671     return -1;
672   }
673
674   return 0;
675 }