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.


large change to break apart the guest operation mode parameters
[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->shdw_pg_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->shdw_pg_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     {
185
186       int index = 0;
187       int ret;
188
189       PrintDebug("Protected %s Mode write to CR0 at guest %s linear rip 0x%x\n", 
190                  info->mem_mode == VIRTUAL_MEM ? "Paged" : "",
191                  info->mem_mode == VIRTUAL_MEM ? "virtual" : "",
192                  get_addr_linear(info, info->rip, &(info->segments.cs)));
193
194       // OK, now we will read the instruction
195       // The only difference between PROTECTED and PROTECTED_PG is whether we read
196       // from guest_pa or guest_va
197       if (info->mem_mode == PHYSICAL_MEM) { 
198         // The real rip address is actually a combination of the rip + CS base 
199         ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
200       } else { 
201         ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
202       }
203         
204       if (ret != 15) {
205         // I think we should inject a GPF into the guest
206         PrintDebug("Could not read instruction (ret=%d)\n", ret);
207         return -1;
208       }
209
210       while (is_prefix_byte(instr[index])) {
211         index++; 
212       }
213
214       struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
215
216       struct cr0_32 * real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
217
218       if ((instr[index] == cr_access_byte) && 
219           (instr[index + 1] == mov_to_cr_byte)) {
220
221         // MOV to CR0
222     
223         addr_t first_operand;
224         addr_t second_operand;
225         struct cr0_32 *new_cr0;
226         operand_type_t addr_type;
227
228         index += 2;
229  
230
231         addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
232
233         if (addr_type != REG_OPERAND) {
234           PrintDebug("Non-register operand in write to CR0\n");
235           return -1;
236         }
237
238         new_cr0 = (struct cr0_32 *)first_operand;
239
240
241
242         if (info->shdw_pg_mode == SHADOW_PAGING) {
243           struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
244
245           if (new_cr0->pg == 1){
246             // This should be new_cr0->pg && !(old_cr->pg), right?
247             // and then a case for turning paging off?
248
249             struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
250
251             info->mem_mode = VIRTUAL_MEM;
252           
253             *shadow_cr0 = *new_cr0;
254             *real_cr0 = *new_cr0;
255
256             //
257             // Activate Shadow Paging
258             //
259             PrintDebug("Turning on paging in the guest\n");
260
261             info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
262           
263
264           } else if (new_cr0->pe == 0) {
265             info->cpu_mode = REAL;
266
267             *shadow_cr0 = *new_cr0;
268             *real_cr0 = *new_cr0;
269             real_cr0->pg = 1;
270           }
271
272
273         } else {
274           *real_cr0 = *new_cr0;
275         }
276
277         info->rip += index;
278
279       } else if ((instr[index] == 0x0f) &&
280                  (instr[index + 1] == 0x06)) { 
281         // CLTS instruction
282         PrintDebug("CLTS instruction - clearing TS flag of real and shadow CR0\n");
283         shadow_cr0->ts=0;
284         real_cr0->ts=0;
285         
286         index+=2;
287         
288         info->rip+=index;
289
290       } else {
291         PrintDebug("Unkown instruction: \n");
292         SerialMemDump(instr,15);
293         return -1;
294       }
295     }
296     break;
297     
298   case PROTECTED_PAE:
299     PrintDebug("Protected PAE Mode write to CR0 is UNIMPLEMENTED\n");
300     return -1;
301
302   case LONG:
303     PrintDebug("Protected Long Mode write to CR0 is UNIMPLEMENTED\n");
304     return -1;
305
306   default: 
307     {
308       PrintDebug("Unknown Mode write to CR0 (info->cpu_mode=0x%x\n)",info->cpu_mode);
309       return -1;
310     }
311     break;
312
313   }
314
315   return 0;
316 }
317
318
319 int handle_cr0_read(struct guest_info * info) {
320   char instr[15];
321
322   switch (info->cpu_mode) { 
323
324   case REAL: 
325     {
326
327       int index = 0;
328       int ret;
329
330       PrintDebug("Real Mode read from CR0 at linear guest pa 0x%x\n",get_addr_linear(info,info->rip,&(info->segments.cs)));
331
332       // The real rip address is actually a combination of the rip + CS base 
333       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
334       if (ret != 15) {
335         // I think we should inject a GPF into the guest
336         PrintDebug("Could not read Real Mode instruction (ret=%d)\n", ret);
337         return -1;
338       }
339
340
341       while (is_prefix_byte(instr[index])) {
342         index++; 
343       }
344
345       if ((instr[index] == cr_access_byte) && 
346           (instr[index + 1] == smsw_byte) && 
347           (MODRM_REG(instr[index + 2]) == smsw_reg_byte)) {
348
349         // SMSW (store machine status word)
350
351         addr_t first_operand;
352         addr_t second_operand;
353         struct cr0_real *cr0;
354         operand_type_t addr_type;
355         char cr0_val = 0;
356
357         index += 2;
358       
359         cr0 = (struct cr0_real*)&(info->ctrl_regs.cr0);
360       
361       
362         addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
363       
364         if (addr_type == MEM_OPERAND) {
365           addr_t host_addr;
366         
367           if (guest_pa_to_host_va(info, first_operand + (info->segments.ds.base << 4), &host_addr) == -1) {
368             // gpf the guest
369             PrintDebug("Could not convert guest physical address to host virtual address\n");
370             return -1;
371           }
372         
373           first_operand = host_addr;
374         } else {
375           // Register operand
376           // Should be ok??
377         }
378
379         cr0_val = *(char*)cr0 & 0x0f;
380
381         *(char *)first_operand &= 0xf0;
382         *(char *)first_operand |= cr0_val;
383
384         PrintDebug("index = %d, rip = %x\n", index, (ulong_t)(info->rip));
385         info->rip += index;
386         PrintDebug("new_rip = %x\n", (ulong_t)(info->rip));
387         // success
388
389       } else if ((instr[index] == cr_access_byte) &&
390                  (instr[index+1] == mov_from_cr_byte)) {
391         /* Mov from CR0
392          * This can only take a 32 bit register argument in anything less than 64 bit mode.
393          */
394         addr_t first_operand;
395         addr_t second_operand;
396         operand_type_t addr_type;
397
398         struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
399
400         index += 2;
401
402         addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
403      
404         struct cr0_32 * virt_cr0 = (struct cr0_32 *)first_operand;
405   
406         if (addr_type != REG_OPERAND) {
407           // invalid opcode to guest
408           PrintDebug("Invalid operand type in mov from CR0\n");
409           return -1;
410         }
411
412         if (info->shdw_pg_mode == SHADOW_PAGING) {
413           *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
414         } else {
415           *virt_cr0 = *real_cr0;
416         }
417
418         info->rip += index;
419
420       } else {
421         PrintDebug("Unknown read instr from CR0\n");
422         return -1;
423       }
424
425     } 
426
427     break;
428
429   case PROTECTED:
430     {
431     
432       int index = 0;
433       int ret;
434
435       PrintDebug("Protected %s Mode read from CR0 at guest %s linear rip 0x%x\n", 
436                  info->mem_mode == VIRTUAL_MEM ? "Paged" : "",
437                  info->mem_mode == VIRTUAL_MEM ? "virtual" : "",
438                  get_addr_linear(info, info->rip, &(info->segments.cs)));
439
440       // We need to read the instruction, which is at CS:IP, but that 
441       // linear address is guest physical without PG and guest virtual with PG
442       if (info->cpu_mode == PHYSICAL_MEM) { 
443         // The real rip address is actually a combination of the rip + CS base 
444         ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
445       } else { 
446         // The real rip address is actually a combination of the rip + CS base 
447         ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
448       }
449
450       if (ret != 15) {
451         // I think we should inject a GPF into the guest
452         PrintDebug("Could not read Protected %s mode instruction (ret=%d)\n", 
453                    info->cpu_mode == VIRTUAL_MEM ? "Paged" : "", ret);
454         return -1;
455       }
456
457       while (is_prefix_byte(instr[index])) {
458         index++; 
459       }
460
461
462       if ((instr[index] == cr_access_byte) &&
463           (instr[index+1] == mov_from_cr_byte)) {
464         
465         // MOV from CR0 to register
466
467         addr_t first_operand;
468         addr_t second_operand;
469         operand_type_t addr_type;
470         struct cr0_32 * virt_cr0;
471         struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
472
473         index += 2;
474
475         addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
476
477         if (addr_type != REG_OPERAND) {
478           PrintDebug("Invalid operand type in mov from CR0\n");
479           return -1;
480         }
481       
482         virt_cr0 = (struct cr0_32 *)first_operand;
483
484         if (info->shdw_pg_mode == SHADOW_PAGING) {
485           *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
486         } else {
487           *virt_cr0 = *real_cr0;
488         }
489       
490         info->rip += index;
491
492       } else { 
493         PrintDebug("Unknown read instruction from CR0\n");
494         return -1;
495       }
496     }
497     break;
498
499   case PROTECTED_PAE:
500     PrintDebug("Protected PAE Mode read to CR0 is UNIMPLEMENTED\n");
501     return -1;
502
503   case LONG:
504     PrintDebug("Protected Long Mode read to CR0 is UNIMPLEMENTED\n");
505     return -1;
506
507
508   default:
509     {
510       PrintDebug("Unknown Mode read from CR0 (info->cpu_mode=0x%x)\n",info->cpu_mode);
511       return -1;
512     }
513     break;
514   }
515
516
517   return 0;
518 }
519
520
521
522
523 int handle_cr3_write(struct guest_info * info) {
524   if (info->cpu_mode == PROTECTED) {
525     int index = 0;
526     int ret;
527     char instr[15];
528
529
530     // We need to read the instruction, which is at CS:IP, but that 
531     // linear address is guest physical without PG and guest virtual with PG
532     if (info->cpu_mode == PHYSICAL_MEM) { 
533       // The real rip address is actually a combination of the rip + CS base 
534       PrintDebug("Writing Guest CR3 Write (Physical Address)\n");
535       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
536     } else { 
537       PrintDebug("Writing Guest CR3 Write (Virtual Address)\n");
538       // The real rip address is actually a combination of the rip + CS base 
539       ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
540     }
541
542
543     if (ret != 15) {
544       PrintDebug("Could not read instruction (ret=%d)\n", ret);
545       return -1;
546     }
547     
548     while (is_prefix_byte(instr[index])) {
549       index++;
550     }
551
552     if ((instr[index] == cr_access_byte) && 
553         (instr[index + 1] == mov_to_cr_byte)) {
554
555       addr_t first_operand;
556       addr_t second_operand;
557       struct cr3_32 * new_cr3;
558       //      struct cr3_32 * real_cr3;
559       operand_type_t addr_type;
560
561       index += 2;
562
563       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
564
565       if (addr_type != REG_OPERAND) {
566         /* Mov to CR3 can only be a 32 bit register */
567         return -1;
568       }
569
570       new_cr3 = (struct cr3_32 *)first_operand;
571
572       if (info->shdw_pg_mode == SHADOW_PAGING) {
573         addr_t shadow_pt;
574         struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
575         struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
576
577
578         /* Delete the current Page Tables */
579         delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
580
581
582         *guest_cr3 = *new_cr3;
583
584         // Something like this
585         shadow_pt =  create_new_shadow_pt32(info);
586         //shadow_pt = setup_shadow_pt32(info, CR3_TO_PDE32(*(addr_t *)new_cr3));
587
588
589         /* Copy Various flags */
590         *shadow_cr3 = *new_cr3;
591         
592         shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);
593
594         if (info->mem_mode == VIRTUAL_MEM) {
595           // If we aren't in paged mode then we have to preserve the identity mapped CR3
596           info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
597         }
598       }
599
600       info->rip += index;
601
602     } else {
603       PrintDebug("Unknown Instruction\n");
604       return -1;
605     }
606   } else {
607     PrintDebug("Invalid operating Mode\n");
608     return -1;
609   }
610
611   return 0;
612 }
613
614
615
616
617 int handle_cr3_read(struct guest_info * info) {
618   if (info->cpu_mode == PROTECTED) {
619     int index = 0;
620     int ret;
621     char instr[15];
622
623    
624     // We need to read the instruction, which is at CS:IP, but that 
625     // linear address is guest physical without PG and guest virtual with PG
626     if (info->cpu_mode == PHYSICAL_MEM) { 
627       // The real rip address is actually a combination of the rip + CS base 
628       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
629     } else { 
630       // The real rip address is actually a combination of the rip + CS base 
631       ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
632     }
633
634     if (ret != 15) {
635       PrintDebug("Could not read instruction (ret=%d)\n", ret);
636       return -1;
637     }
638     
639     while (is_prefix_byte(instr[index])) {
640       index++;
641     }
642
643     if ((instr[index] == cr_access_byte) && 
644         (instr[index + 1] == mov_from_cr_byte)) {
645       addr_t first_operand;
646       addr_t second_operand;
647       struct cr3_32 * virt_cr3;
648       struct cr3_32 * real_cr3 = (struct cr3_32 *)&(info->ctrl_regs.cr3);
649       operand_type_t addr_type;
650
651       index += 2;
652
653       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
654
655       if (addr_type != REG_OPERAND) {
656         /* Mov to CR3 can only be a 32 bit register */
657         return -1;
658       }
659
660       virt_cr3 = (struct cr3_32 *)first_operand;
661
662       if (info->shdw_pg_mode == SHADOW_PAGING) {
663         *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
664       } else {
665         *virt_cr3 = *real_cr3;
666       }
667       
668       info->rip += index;
669     } else {
670       PrintDebug("Unknown Instruction\n");
671       return -1;
672     }
673   } else {
674     PrintDebug("Invalid operating Mode\n");
675     return -1;
676   }
677
678   return 0;
679 }