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 decoder support for cr0 write handler
[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 /* 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 #ifndef DEBUG_CTRL_REGS
18 #undef PrintDebug
19 #define PrintDebug(fmt, args...)
20 #endif
21
22
23
24
25
26
27
28 int handle_cr0_write(struct guest_info * info) {
29   char instr[15];
30   int ret;
31   struct x86_instr dec_instr;
32
33   if (info->mem_mode == PHYSICAL_MEM) { 
34     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
35   } else { 
36     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
37   }
38
39   if (ret != 15) {
40     // I think we should inject a GPF into the guest
41     PrintError("Could not read instruction (ret=%d)\n", ret);
42     return -1;
43   }
44
45   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
46     PrintError("Could not decode instruction\n");
47     return -1;
48   }
49
50
51   if (opcode_cmp(V3_OPCODE_LMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
52     struct cr0_real *real_cr0  = (struct cr0_real*)&(info->ctrl_regs.cr0);
53     struct cr0_real *new_cr0 = (struct cr0_real *)(dec_instr.first_operand.operand);    
54     uchar_t new_cr0_val;
55
56     PrintDebug("LMSW\n");
57
58     new_cr0_val = (*(char*)(new_cr0)) & 0x0f;
59     
60     PrintDebug("OperandVal = %x\n", new_cr0_val);
61
62     PrintDebug("Old CR0=%x\n", *real_cr0);      
63     *(uchar_t*)real_cr0 &= 0xf0;
64     *(uchar_t*)real_cr0 |= new_cr0_val;
65     PrintDebug("New CR0=%x\n", *real_cr0);      
66       
67
68     if (info->shdw_pg_mode == SHADOW_PAGING) {
69       struct cr0_real * shadow_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
70       
71       PrintDebug(" Old Shadow CR0=%x\n", *shadow_cr0);  
72       *(uchar_t*)shadow_cr0 &= 0xf0;
73       *(uchar_t*)shadow_cr0 |= new_cr0_val;
74       PrintDebug("New Shadow CR0=%x\n", *shadow_cr0);   
75     }
76   } else if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
77     PrintDebug("MOV2CR0\n");
78
79     if (info->cpu_mode == LONG) {
80       // 64 bit registers
81     } else {
82       // 32 bit registers
83         struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
84         struct cr0_32 *new_cr0= (struct cr0_32 *)(dec_instr.second_operand.operand);
85
86         PrintDebug("OperandVal = %x, length=%d\n", *new_cr0, dec_instr.first_operand.size);
87
88
89         PrintDebug("Old CR0=%x\n", *real_cr0);
90         *real_cr0 = *new_cr0;
91         
92
93         if (info->shdw_pg_mode == SHADOW_PAGING) {
94           struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
95           
96           PrintDebug("Old Shadow CR0=%x\n", *shadow_cr0);       
97           
98           real_cr0->et = 1;
99           
100           *shadow_cr0 = *new_cr0;
101           shadow_cr0->et = 1;
102           
103           if (get_mem_mode(info) == VIRTUAL_MEM) {
104             struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
105             
106             info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
107           } else  {
108             info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
109             real_cr0->pg = 1;
110           }
111           
112           PrintDebug("New Shadow CR0=%x\n",*shadow_cr0);
113         }
114         PrintDebug("New CR0=%x\n", *real_cr0);
115     }
116
117   } else if (opcode_cmp(V3_OPCODE_CLTS, (const uchar_t *)(dec_instr.opcode)) == 0) {
118     // CLTS
119     struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
120         
121     real_cr0->ts = 0;
122
123     if (info->shdw_pg_mode == SHADOW_PAGING) {
124       struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
125       shadow_cr0->ts = 0;
126     }
127   }
128
129   info->rip += dec_instr.instr_length;
130
131   return 0;
132 }
133
134
135 int handle_cr0_read(struct guest_info * info) {
136   char instr[15];
137
138   switch (info->cpu_mode) { 
139
140   case REAL: 
141     {
142
143       int index = 0;
144       int ret;
145
146       PrintDebug("Real Mode read from CR0 at linear guest pa 0x%x\n",get_addr_linear(info,info->rip,&(info->segments.cs)));
147       //PrintV3Segments(info);
148
149       // The real rip address is actually a combination of the rip + CS base 
150       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
151       if (ret != 15) {
152         // I think we should inject a GPF into the guest
153         PrintDebug("Could not read Real Mode instruction (ret=%d)\n", ret);
154         return -1;
155       }
156
157
158       while (is_prefix_byte(instr[index])) {
159         switch(instr[index]) {
160         case PREFIX_CS_OVERRIDE:
161         case PREFIX_SS_OVERRIDE:
162         case PREFIX_DS_OVERRIDE:
163         case PREFIX_ES_OVERRIDE:
164         case PREFIX_FS_OVERRIDE:
165         case PREFIX_GS_OVERRIDE:
166           PrintDebug("Segment Override!!\n");
167           return -1;
168           break;
169         default:
170           break;
171         }
172         index++; 
173       }
174
175       /*
176         while (is_prefix_byte(instr[index])) {
177         index++; 
178         }
179       */
180
181       if ((instr[index] == cr_access_byte) && 
182           (instr[index + 1] == smsw_byte) && 
183           (MODRM_REG(instr[index + 2]) == smsw_reg_byte)) {
184
185         // SMSW (store machine status word)
186
187         addr_t first_operand;
188         addr_t second_operand;
189         struct cr0_real *cr0;
190         operand_type_t addr_type;
191         char cr0_val = 0;
192
193         index += 2;
194       
195         cr0 = (struct cr0_real*)&(info->ctrl_regs.cr0);
196       
197       
198         addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG16);
199       
200         if (addr_type == MEM_OPERAND) {
201           addr_t host_addr;
202         
203           if (guest_pa_to_host_va(info, first_operand + (info->segments.ds.base << 4), &host_addr) == -1) {
204             // gpf the guest
205             PrintDebug("Could not convert guest physical address to host virtual address\n");
206             return -1;
207           }
208         
209           first_operand = host_addr;
210         } else {
211           // Register operand
212           // Should be ok??
213         }
214
215         cr0_val = *(char*)cr0 & 0x0f;
216
217         *(char *)first_operand &= 0xf0;
218         *(char *)first_operand |= cr0_val;
219
220         PrintDebug("index = %d, rip = %x\n", index, (ulong_t)(info->rip));
221         info->rip += index;
222         PrintDebug("new_rip = %x\n", (ulong_t)(info->rip));
223         // success
224
225       } else if ((instr[index] == cr_access_byte) &&
226                  (instr[index+1] == mov_from_cr_byte)) {
227         /* Mov from CR0
228          * This can only take a 32 bit register argument in anything less than 64 bit mode.
229          */
230         addr_t first_operand;
231         addr_t second_operand;
232         operand_type_t addr_type;
233
234         struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
235
236         index += 2;
237
238         addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
239      
240         struct cr0_32 * virt_cr0 = (struct cr0_32 *)first_operand;
241   
242         if (addr_type != REG_OPERAND) {
243           // invalid opcode to guest
244           PrintDebug("Invalid operand type in mov from CR0\n");
245           return -1;
246         }
247
248         if (info->shdw_pg_mode == SHADOW_PAGING) {
249           *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
250         } else {
251           *virt_cr0 = *real_cr0;
252         }
253
254         PrintDebug("Returning CR0: %x\n", *virt_cr0);
255
256         info->rip += index;
257
258       } else {
259         PrintDebug("Unknown read instr from CR0\n");
260         return -1;
261       }
262
263     } 
264
265     break;
266
267   case PROTECTED:
268     {
269     
270       int index = 0;
271       int ret;
272
273       PrintDebug("Protected %s Mode read from CR0 at guest %s linear rip 0x%x\n", 
274                  info->mem_mode == VIRTUAL_MEM ? "Paged" : "",
275                  info->mem_mode == VIRTUAL_MEM ? "virtual" : "",
276                  get_addr_linear(info, info->rip, &(info->segments.cs)));
277
278       // We need to read the instruction, which is at CS:IP, but that 
279       // linear address is guest physical without PG and guest virtual with PG
280       if (info->cpu_mode == PHYSICAL_MEM) { 
281         // The real rip address is actually a combination of the rip + CS base 
282         ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
283       } else { 
284         // The real rip address is actually a combination of the rip + CS base 
285         ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
286       }
287
288
289       /*
290         PrintDebug("Instr (15 bytes) at %x:\n", instr);
291         PrintTraceMemDump((char*)instr, 15);
292       */
293
294       if (ret != 15) {
295         // I think we should inject a GPF into the guest
296         PrintDebug("Could not read Protected %s mode instruction (ret=%d)\n", 
297                    info->cpu_mode == VIRTUAL_MEM ? "Paged" : "", ret);
298         return -1;
299       }
300
301
302       while (is_prefix_byte(instr[index])) {
303         switch(instr[index]) {
304         case PREFIX_CS_OVERRIDE:
305         case PREFIX_SS_OVERRIDE:
306         case PREFIX_DS_OVERRIDE:
307         case PREFIX_ES_OVERRIDE:
308         case PREFIX_FS_OVERRIDE:
309         case PREFIX_GS_OVERRIDE:
310           PrintDebug("Segment Override!!\n");
311           return -1;
312           break;
313         default:
314           break;
315         }
316         index++; 
317       }
318
319
320       /*
321         while (is_prefix_byte(instr[index])) {
322         index++; 
323         }
324       */
325
326       if ((instr[index] == cr_access_byte) &&
327           (instr[index+1] == mov_from_cr_byte)) {
328         
329         // MOV from CR0 to register
330
331         addr_t first_operand;
332         addr_t second_operand;
333         operand_type_t addr_type;
334         struct cr0_32 * virt_cr0;
335         struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
336
337         index += 2;
338
339         addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
340
341         if (addr_type != REG_OPERAND) {
342           PrintDebug("Invalid operand type in mov from CR0\n");
343           return -1;
344         }
345       
346         virt_cr0 = (struct cr0_32 *)first_operand;
347
348         if (info->shdw_pg_mode == SHADOW_PAGING) {
349           *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
350           
351           if (info->mem_mode == PHYSICAL_MEM) {
352             virt_cr0->pg = 0; // clear the pg bit because guest doesn't think it's on
353           }
354           
355         } else {
356           *virt_cr0 = *real_cr0;
357         }
358
359           PrintDebug("real CR0: %x\n", *(uint_t*)real_cr0);
360           PrintDebug("returned CR0: %x\n", *(uint_t*)virt_cr0);
361       
362         info->rip += index;
363
364       } else { 
365         PrintDebug("Unknown read instruction from CR0\n");
366         return -1;
367       }
368     }
369     break;
370
371   case PROTECTED_PAE:
372     PrintDebug("Protected PAE Mode read to CR0 is UNIMPLEMENTED\n");
373     return -1;
374
375   case LONG:
376     PrintDebug("Protected Long Mode read to CR0 is UNIMPLEMENTED\n");
377     return -1;
378
379
380   default:
381     {
382       PrintDebug("Unknown Mode read from CR0 (info->cpu_mode=0x%x)\n",info->cpu_mode);
383       return -1;
384     }
385     break;
386   }
387
388
389   return 0;
390 }
391
392
393
394
395 int handle_cr3_write(struct guest_info * info) {
396   if (info->cpu_mode == REAL) {
397     // WHAT THE HELL DOES THIS EVEN MEAN?????
398
399     int index = 0;
400     int ret;
401     char instr[15];
402
403     PrintDebug("Real Mode Write to CR3.\n");
404     // We need to read the instruction, which is at CS:IP, but that 
405     // linear address is guest physical without PG and guest virtual with PG
406
407     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
408
409     if (ret != 15) {
410       PrintDebug("Could not read instruction (ret=%d)\n", ret);
411       return -1;
412     }
413
414     while (is_prefix_byte(instr[index])) {
415       switch(instr[index]) {
416       case PREFIX_CS_OVERRIDE:
417       case PREFIX_SS_OVERRIDE:
418       case PREFIX_DS_OVERRIDE:
419       case PREFIX_ES_OVERRIDE:
420       case PREFIX_FS_OVERRIDE:
421       case PREFIX_GS_OVERRIDE:
422         PrintDebug("Segment Override!!\n");
423         return -1;
424         break;
425       default:
426         break;
427       }
428       index++; 
429     }
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_operands16(&(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->shdw_pg_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
459           if (CR3_TO_PDE32(*(uint_t*)shadow_cr3) != 0) {
460             PrintDebug("Shadow Page Table\n");
461             PrintDebugPageTables((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
462           }
463         */
464
465         /* Delete the current Page Tables */
466         delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
467
468         PrintDebug("Old Shadow CR3=%x; Old Guest CR3=%x\n", 
469                    *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
470
471
472         *guest_cr3 = *new_cr3;
473
474
475
476         // Something like this
477         shadow_pt =  create_new_shadow_pt32(info);
478         //shadow_pt = setup_shadow_pt32(info, CR3_TO_PDE32(*(addr_t *)new_cr3));
479
480         /* Copy Various flags */
481         *shadow_cr3 = *new_cr3;
482
483         /*
484         {
485           addr_t tmp_addr;
486           guest_pa_to_host_va(info, ((*(uint_t*)guest_cr3) & 0xfffff000), &tmp_addr);
487           PrintDebug("Guest PD\n");
488           PrintPD32((pde32_t *)tmp_addr);
489
490         }
491         */
492
493         
494         shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);
495
496         PrintDebug("New Shadow CR3=%x; New Guest CR3=%x\n", 
497                    *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
498
499
500
501
502       }
503       info->rip += index;
504
505     } else {
506       PrintDebug("Unknown Instruction\n");
507       PrintTraceMemDump(instr,15);
508       return -1;
509     }
510
511
512
513   } else if (info->cpu_mode == PROTECTED) {
514     int index = 0;
515     int ret;
516     char instr[15];
517
518     PrintDebug("Protected %s mode write to CR3 at %s 0x%x\n",
519                info->cpu_mode==PROTECTED ? "" : "Paged", 
520                info->cpu_mode==PROTECTED ? "guest physical" : "guest virtual",
521                get_addr_linear(info,info->rip,&(info->segments.cs)));
522
523     // We need to read the instruction, which is at CS:IP, but that 
524     // linear address is guest physical without PG and guest virtual with PG
525     if (info->mem_mode == PHYSICAL_MEM) { 
526       // The real rip address is actually a combination of the rip + CS base 
527       //PrintDebug("Writing Guest CR3 Write (Physical Address)\n");
528       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
529     } else { 
530       //PrintDebug("Writing Guest CR3 Write (Virtual Address)\n");
531       // The real rip address is actually a combination of the rip + CS base 
532       ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
533     }
534
535     if (ret != 15) {
536       PrintDebug("Could not read instruction (ret=%d)\n", ret);
537       return -1;
538     }
539
540     while (is_prefix_byte(instr[index])) {
541       switch(instr[index]) {
542       case PREFIX_CS_OVERRIDE:
543       case PREFIX_SS_OVERRIDE:
544       case PREFIX_DS_OVERRIDE:
545       case PREFIX_ES_OVERRIDE:
546       case PREFIX_FS_OVERRIDE:
547       case PREFIX_GS_OVERRIDE:
548         PrintDebug("Segment Override!!\n");
549         return -1;
550         break;
551       default:
552         break;
553       }
554       index++; 
555     }
556     
557     /*    
558           while (is_prefix_byte(instr[index])) {
559           index++;
560           }
561     */
562
563     if ((instr[index] == cr_access_byte) && 
564         (instr[index + 1] == mov_to_cr_byte)) {
565
566       addr_t first_operand;
567       addr_t second_operand;
568       struct cr3_32 * new_cr3;
569       //      struct cr3_32 * real_cr3;
570       operand_type_t addr_type;
571
572       index += 2;
573
574       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
575
576       if (addr_type != REG_OPERAND) {
577         /* Mov to CR3 can only be a 32 bit register */
578         return -1;
579       }
580
581       new_cr3 = (struct cr3_32 *)first_operand;
582
583       if (info->shdw_pg_mode == SHADOW_PAGING) {
584         addr_t shadow_pt;
585         struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
586         struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
587
588
589         /*
590           if (CR3_TO_PDE32(*(uint_t*)shadow_cr3) != 0) {
591             PrintDebug("Shadow Page Table\n");
592             PrintDebugPageTables((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
593           }
594         */
595
596         /* Delete the current Page Tables */
597         delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
598
599         PrintDebug("Old Shadow CR3=%x; Old Guest CR3=%x\n", 
600                    *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
601
602
603         *guest_cr3 = *new_cr3;
604
605
606
607         // Something like this
608         shadow_pt =  create_new_shadow_pt32(info);
609         //shadow_pt = setup_shadow_pt32(info, CR3_TO_PDE32(*(addr_t *)new_cr3));
610
611         /* Copy Various flags */
612         *shadow_cr3 = *new_cr3;
613
614         /*
615         {
616           addr_t tmp_addr;
617           guest_pa_to_host_va(info, ((*(uint_t*)guest_cr3) & 0xfffff000), &tmp_addr);
618           PrintDebug("Guest PD\n");
619           PrintPD32((pde32_t *)tmp_addr);
620
621         }
622         */
623
624         
625         shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);
626
627         PrintDebug("New Shadow CR3=%x; New Guest CR3=%x\n", 
628                    *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
629
630
631
632         if (info->mem_mode == VIRTUAL_MEM) {
633           // If we aren't in paged mode then we have to preserve the identity mapped CR3
634           info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
635         }
636       }
637
638       info->rip += index;
639
640     } else {
641       PrintDebug("Unknown Instruction\n");
642       PrintTraceMemDump(instr,15);
643       return -1;
644     }
645   } else {
646     PrintDebug("Invalid operating Mode (0x%x)\n", info->cpu_mode);
647     return -1;
648   }
649
650   return 0;
651 }
652
653
654
655
656 int handle_cr3_read(struct guest_info * info) {
657
658   if (info->cpu_mode == REAL) {
659     char instr[15];
660     int ret;
661     int index = 0;
662     addr_t linear_addr = 0;
663
664     linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
665
666     
667     //PrintDebug("RIP Linear: %x\n", linear_addr);
668     //PrintV3Segments(info);
669     
670     ret = read_guest_pa_memory(info, linear_addr, 15, instr);
671
672     if (ret != 15) {
673       PrintDebug("Could not read instruction (ret=%d)\n", ret);
674       return -1;
675     }
676     
677     while (is_prefix_byte(instr[index])) {
678       switch(instr[index]) {
679       case PREFIX_CS_OVERRIDE:
680       case PREFIX_SS_OVERRIDE:
681       case PREFIX_DS_OVERRIDE:
682       case PREFIX_ES_OVERRIDE:
683       case PREFIX_FS_OVERRIDE:
684       case PREFIX_GS_OVERRIDE:
685         PrintDebug("Segment Override!!\n");
686         return -1;
687         break;
688       default:
689         break;
690       }
691       index++; 
692     }
693
694
695     if ((instr[index] == cr_access_byte) && 
696         (instr[index + 1] == mov_from_cr_byte)) {
697       addr_t first_operand;
698       addr_t second_operand;
699       struct cr3_32 * virt_cr3;
700       struct cr3_32 * real_cr3 = (struct cr3_32 *)&(info->ctrl_regs.cr3);
701       operand_type_t addr_type;
702
703       index += 2;
704
705       addr_type = decode_operands16(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
706
707       if (addr_type != REG_OPERAND) {
708         /* Mov to CR3 can only be a 32 bit register */
709         return -1;
710       }
711
712       virt_cr3 = (struct cr3_32 *)first_operand;
713
714       if (info->shdw_pg_mode == SHADOW_PAGING) {
715         *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
716       } else {
717         *virt_cr3 = *real_cr3;
718       }
719       
720       info->rip += index;
721     } else {
722       PrintDebug("Unknown Instruction\n");
723       PrintTraceMemDump(instr,15);
724       return -1;
725     }
726
727
728     return 0;
729   } else if (info->cpu_mode == PROTECTED) {
730
731     int index = 0;
732     int ret;
733     char instr[15];
734
735    
736     // We need to read the instruction, which is at CS:IP, but that 
737     // linear address is guest physical without PG and guest virtual with PG
738     if (info->cpu_mode == PHYSICAL_MEM) { 
739       // The real rip address is actually a combination of the rip + CS base 
740       ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
741     } else { 
742       // The real rip address is actually a combination of the rip + CS base 
743       ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
744     }
745
746     if (ret != 15) {
747       PrintDebug("Could not read instruction (ret=%d)\n", ret);
748       return -1;
749     }
750     
751     while (is_prefix_byte(instr[index])) {
752       switch(instr[index]) {
753       case PREFIX_CS_OVERRIDE:
754       case PREFIX_SS_OVERRIDE:
755       case PREFIX_DS_OVERRIDE:
756       case PREFIX_ES_OVERRIDE:
757       case PREFIX_FS_OVERRIDE:
758       case PREFIX_GS_OVERRIDE:
759         PrintDebug("Segment Override!!\n");
760         return -1;
761         break;
762       default:
763         break;
764       }
765       index++; 
766     }
767
768     /*
769       while (is_prefix_byte(instr[index])) {
770       index++;
771       }
772     */
773
774     if ((instr[index] == cr_access_byte) && 
775         (instr[index + 1] == mov_from_cr_byte)) {
776       addr_t first_operand;
777       addr_t second_operand;
778       struct cr3_32 * virt_cr3;
779       struct cr3_32 * real_cr3 = (struct cr3_32 *)&(info->ctrl_regs.cr3);
780       operand_type_t addr_type;
781
782       index += 2;
783
784       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
785
786       if (addr_type != REG_OPERAND) {
787         /* Mov to CR3 can only be a 32 bit register */
788         return -1;
789       }
790
791       virt_cr3 = (struct cr3_32 *)first_operand;
792
793       if (info->shdw_pg_mode == SHADOW_PAGING) {
794         *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
795       } else {
796         *virt_cr3 = *real_cr3;
797       }
798       
799       info->rip += index;
800     } else {
801       PrintDebug("Unknown Instruction\n");
802       PrintTraceMemDump(instr,15);
803       return -1;
804     }
805   } else {
806     PrintDebug("Invalid operating Mode (0x%x), control registers follow\n", info->cpu_mode);
807     PrintV3CtrlRegs(info);
808     return -1;
809   }
810
811   return 0;
812 }