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.


2a3ebbda811e4880081a08b8523399aed861329b
[palacios.git] / palacios / src / palacios / vmm_ctrl_regs.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm_mem.h>
21 #include <palacios/vmm.h>
22 #include <palacios/vmcb.h>
23 #include <palacios/vmm_decoder.h>
24 #include <palacios/vm_guest_mem.h>
25 #include <palacios/vmm_ctrl_regs.h>
26 #include <palacios/vmm_direct_paging.h>
27 #include <palacios/svm.h>
28
29 #ifndef V3_CONFIG_DEBUG_CTRL_REGS
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34
35 static int handle_lmsw(struct guest_info * info, struct x86_instr * dec_instr);
36 static int handle_clts(struct guest_info * info, struct x86_instr * dec_instr);
37 static int handle_mov_to_cr0(struct guest_info * info, struct x86_instr * dec_instr);
38
39
40 // First Attempt = 494 lines
41 // current = 106 lines
42 int v3_handle_cr0_write(struct guest_info * info) {
43     uchar_t instr[15];
44     int ret;
45     struct x86_instr dec_instr;
46     
47     if (info->mem_mode == PHYSICAL_MEM) { 
48         ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
49     } else { 
50         ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
51     }
52     
53     if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
54         PrintError(info->vm_info, info, "Could not decode instruction\n");
55         return -1;
56     }
57
58     
59     if (dec_instr.op_type == V3_OP_LMSW) {
60         if (handle_lmsw(info, &dec_instr) == -1) {
61             return -1;
62         }
63     } else if (dec_instr.op_type == V3_OP_MOV2CR) {
64         if (handle_mov_to_cr0(info, &dec_instr) == -1) {
65             return -1;
66         }
67     } else if (dec_instr.op_type == V3_OP_CLTS) {
68         if (handle_clts(info, &dec_instr) == -1) {
69             return -1;
70         }
71     } else {
72         PrintError(info->vm_info, info, "Unhandled opcode in handle_cr0_write\n");
73         return -1;
74     }
75     
76     info->rip += dec_instr.instr_length;
77     
78     return 0;
79 }
80
81
82
83
84 // The CR0 register only has flags in the low 32 bits
85 // The hardware does a format check to make sure the high bits are zero
86 // Because of this we can ignore the high 32 bits here
87 static int handle_mov_to_cr0(struct guest_info * info, struct x86_instr * dec_instr) {
88     // 32 bit registers
89     struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
90     struct cr0_32 * new_cr0 = (struct cr0_32 *)(dec_instr->src_operand.operand);
91     struct cr0_32 * guest_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
92     uint_t paging_transition = 0;
93     
94     PrintDebug(info->vm_info, info, "MOV2CR0 (MODE=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
95     
96     PrintDebug(info->vm_info, info, "OperandVal = %x, length=%d\n", *(uint_t *)new_cr0, dec_instr->src_operand.size);
97     
98     PrintDebug(info->vm_info, info, "Old CR0=%x\n", *(uint_t *)shadow_cr0);
99     PrintDebug(info->vm_info, info, "Old Guest CR0=%x\n", *(uint_t *)guest_cr0);        
100     
101     
102     // We detect if this is a paging transition
103     if (guest_cr0->pg != new_cr0->pg) {
104         paging_transition = 1;
105     }  
106     
107     // Guest always sees the value they wrote
108     *guest_cr0 = *new_cr0;
109     
110     // This value must always be set to 1 
111     guest_cr0->et = 1;
112     
113     // Set the shadow register to catch non-virtualized flags
114     *shadow_cr0 = *guest_cr0;
115     
116     // Paging is always enabled
117     shadow_cr0->pg = 1;
118
119     if (guest_cr0->pg == 0) {
120         // If paging is not enabled by the guest, then we always enable write-protect to catch memory hooks
121         shadow_cr0->wp = 1;
122     }
123     
124     // Was there a paging transition
125     // Meaning we need to change the page tables
126     if (paging_transition) {
127         if (v3_get_vm_mem_mode(info) == VIRTUAL_MEM) {
128             
129             struct efer_64 * guest_efer  = (struct efer_64 *)&(info->shdw_pg_state.guest_efer);
130             struct efer_64 * shadow_efer = (struct efer_64 *)&(info->ctrl_regs.efer);
131             
132             // Check long mode LME to set LME
133             if (guest_efer->lme == 1) {
134                 PrintDebug(info->vm_info, info, "Enabing Long Mode\n");
135                 guest_efer->lma = 1;
136                 
137                 shadow_efer->lma = 1;
138                 shadow_efer->lme = 1;
139                 
140                 PrintDebug(info->vm_info, info, "New EFER %p\n", (void *)*(addr_t *)(shadow_efer));
141             }
142             
143             PrintDebug(info->vm_info, info, "Activating Shadow Page Tables\n");
144             
145             if (v3_activate_shadow_pt(info) == -1) {
146                 PrintError(info->vm_info, info, "Failed to activate shadow page tables\n");
147                 return -1;
148             }
149         } else {
150
151             shadow_cr0->wp = 1;
152             
153             if (v3_activate_passthrough_pt(info) == -1) {
154                 PrintError(info->vm_info, info, "Failed to activate passthrough page tables\n");
155                 return -1;
156             }
157         }
158     }
159     
160     
161     PrintDebug(info->vm_info, info, "New Guest CR0=%x\n",*(uint_t *)guest_cr0);  
162     PrintDebug(info->vm_info, info, "New CR0=%x\n", *(uint_t *)shadow_cr0);
163     
164     return 0;
165 }
166
167
168
169
170 static int handle_clts(struct guest_info * info, struct x86_instr * dec_instr) {
171     // CLTS
172     struct cr0_32 * real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
173     
174     real_cr0->ts = 0;
175     
176     if (info->shdw_pg_mode == SHADOW_PAGING) {
177         struct cr0_32 * guest_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
178         guest_cr0->ts = 0;
179     }
180     return 0;
181 }
182
183
184 static int handle_lmsw(struct guest_info * info, struct x86_instr * dec_instr) {
185     struct cr0_real * real_cr0  = (struct cr0_real *)&(info->ctrl_regs.cr0);
186     // XED is a mess, and basically reverses the operand order for an LMSW
187     struct cr0_real * new_cr0 = (struct cr0_real *)(dec_instr->dst_operand.operand);    
188     uchar_t new_cr0_val;
189     
190     PrintDebug(info->vm_info, info, "LMSW\n");
191     
192     new_cr0_val = (*(char*)(new_cr0)) & 0x0f;
193     
194     PrintDebug(info->vm_info, info, "OperandVal = %x\n", new_cr0_val);
195     
196     // We can just copy the new value through
197     // we don't need to virtualize the lower 4 bits
198     PrintDebug(info->vm_info, info, "Old CR0=%x\n", *(uint_t *)real_cr0);       
199     *(uchar_t*)real_cr0 &= 0xf0;
200     *(uchar_t*)real_cr0 |= new_cr0_val;
201     PrintDebug(info->vm_info, info, "New CR0=%x\n", *(uint_t *)real_cr0);       
202     
203     
204     // If Shadow paging is enabled we push the changes to the virtualized copy of cr0
205     if (info->shdw_pg_mode == SHADOW_PAGING) {
206         struct cr0_real * guest_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
207         
208         PrintDebug(info->vm_info, info, "Old Guest CR0=%x\n", *(uint_t *)guest_cr0);    
209         *(uchar_t*)guest_cr0 &= 0xf0;
210         *(uchar_t*)guest_cr0 |= new_cr0_val;
211         PrintDebug(info->vm_info, info, "New Guest CR0=%x\n", *(uint_t *)guest_cr0);    
212     }
213     return 0;
214 }
215
216
217
218
219
220 // First attempt = 253 lines
221 // current = 51 lines
222 int v3_handle_cr0_read(struct guest_info * info) {
223     uchar_t instr[15];
224     int ret;
225     struct x86_instr dec_instr;
226     
227     if (info->mem_mode == PHYSICAL_MEM) { 
228         ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
229     } else { 
230         ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
231     }
232     
233     
234     if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
235         PrintError(info->vm_info, info, "Could not decode instruction\n");
236         return -1;
237     }
238     
239     if (dec_instr.op_type == V3_OP_MOVCR2) {
240         PrintDebug(info->vm_info, info, "MOVCR2 (mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
241
242         if ((v3_get_vm_cpu_mode(info) == LONG) || 
243             (v3_get_vm_cpu_mode(info) == LONG_32_COMPAT)) {
244             struct cr0_64 * dst_reg = (struct cr0_64 *)(dec_instr.dst_operand.operand);
245         
246             if (info->shdw_pg_mode == SHADOW_PAGING) {
247                 struct cr0_64 * guest_cr0 = (struct cr0_64 *)&(info->shdw_pg_state.guest_cr0);
248                 *dst_reg = *guest_cr0;
249             } else {
250                 struct cr0_64 * shadow_cr0 = (struct cr0_64 *)&(info->ctrl_regs.cr0);
251                 *dst_reg = *shadow_cr0;
252             }
253
254             PrintDebug(info->vm_info, info, "returned CR0: %p\n", (void *)*(addr_t *)dst_reg);
255         } else {
256             struct cr0_32 * dst_reg = (struct cr0_32 *)(dec_instr.dst_operand.operand);
257         
258             if (info->shdw_pg_mode == SHADOW_PAGING) {
259                 struct cr0_32 * guest_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
260                 *dst_reg = *guest_cr0;
261             } else {
262                 struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
263                 *dst_reg = *shadow_cr0;
264             }
265
266             PrintDebug(info->vm_info, info, "returned CR0: %x\n", *(uint_t*)dst_reg);
267         }
268
269     } else if (dec_instr.op_type == V3_OP_SMSW) {
270         struct cr0_real * shadow_cr0 = (struct cr0_real *)&(info->ctrl_regs.cr0);
271         struct cr0_real * dst_reg = (struct cr0_real *)(dec_instr.dst_operand.operand);
272         char cr0_val = *(char*)shadow_cr0 & 0x0f;
273         
274         PrintDebug(info->vm_info, info, "SMSW\n");
275         
276         // The lower 4 bits of the guest/shadow CR0 are mapped through
277         // We can treat nested and shadow paging the same here
278         *(char *)dst_reg &= 0xf0;
279         *(char *)dst_reg |= cr0_val;
280         
281     } else {
282         PrintError(info->vm_info, info, "Unhandled opcode in handle_cr0_read\n");
283         return -1;
284     }
285     
286     info->rip += dec_instr.instr_length;
287
288     return 0;
289 }
290
291
292
293
294 // First Attempt = 256 lines
295 // current = 65 lines
296 int v3_handle_cr3_write(struct guest_info * info) {
297     int ret;
298     uchar_t instr[15];
299     struct x86_instr dec_instr;
300     
301     if (info->mem_mode == PHYSICAL_MEM) { 
302         ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
303     } else { 
304         ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
305     }
306     
307     if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
308         PrintError(info->vm_info, info, "Could not decode instruction\n");
309         return -1;
310     }
311     
312     if (dec_instr.op_type == V3_OP_MOV2CR) {
313         PrintDebug(info->vm_info, info, "MOV2CR3 (cpu_mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
314         
315         if (info->shdw_pg_mode == SHADOW_PAGING) {
316             PrintDebug(info->vm_info, info, "Old Shadow CR3=%p; Old Guest CR3=%p\n", 
317                        (void *)(addr_t)(info->ctrl_regs.cr3), 
318                        (void*)(addr_t)(info->shdw_pg_state.guest_cr3));
319             
320             
321             // We update the guest CR3    
322             if (info->cpu_mode == LONG) {
323                 struct cr3_64 * new_cr3 = (struct cr3_64 *)(dec_instr.src_operand.operand);
324                 struct cr3_64 * guest_cr3 = (struct cr3_64 *)&(info->shdw_pg_state.guest_cr3);
325                 *guest_cr3 = *new_cr3;
326             } else {
327                 struct cr3_32 * new_cr3 = (struct cr3_32 *)(dec_instr.src_operand.operand);
328                 struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
329                 *guest_cr3 = *new_cr3;
330             }
331
332
333             // If Paging is enabled in the guest then we need to change the shadow page tables
334             if (info->mem_mode == VIRTUAL_MEM) {
335                 if (v3_activate_shadow_pt(info) == -1) {
336                     PrintError(info->vm_info, info, "Failed to activate 32 bit shadow page table\n");
337                     return -1;
338                 }
339             }
340             
341             PrintDebug(info->vm_info, info, "New Shadow CR3=%p; New Guest CR3=%p\n", 
342                        (void *)(addr_t)(info->ctrl_regs.cr3), 
343                        (void*)(addr_t)(info->shdw_pg_state.guest_cr3));
344             
345         } else if (info->shdw_pg_mode == NESTED_PAGING) {
346             
347             // This is just a passthrough operation which we probably don't need here
348             if (info->cpu_mode == LONG) {
349                 struct cr3_64 * new_cr3 = (struct cr3_64 *)(dec_instr.src_operand.operand);
350                 struct cr3_64 * guest_cr3 = (struct cr3_64 *)&(info->ctrl_regs.cr3);
351                 *guest_cr3 = *new_cr3;
352             } else {
353                 struct cr3_32 * new_cr3 = (struct cr3_32 *)(dec_instr.src_operand.operand);
354                 struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->ctrl_regs.cr3);
355                 *guest_cr3 = *new_cr3;
356             }
357             
358         }
359     } else {
360         PrintError(info->vm_info, info, "Unhandled opcode in handle_cr3_write\n");
361         return -1;
362     }
363     
364     info->rip += dec_instr.instr_length;
365     
366     return 0;
367 }
368
369
370
371 // first attempt = 156 lines
372 // current = 36 lines
373 int v3_handle_cr3_read(struct guest_info * info) {
374     uchar_t instr[15];
375     int ret;
376     struct x86_instr dec_instr;
377     
378     if (info->mem_mode == PHYSICAL_MEM) { 
379         ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
380     } else { 
381         ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
382     }
383     
384     if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
385         PrintError(info->vm_info, info, "Could not decode instruction\n");
386         return -1;
387     }
388     
389     if (dec_instr.op_type == V3_OP_MOVCR2) {
390         PrintDebug(info->vm_info, info, "MOVCR32 (mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
391         
392         if (info->shdw_pg_mode == SHADOW_PAGING) {
393             
394             if ((v3_get_vm_cpu_mode(info) == LONG) || 
395                 (v3_get_vm_cpu_mode(info) == LONG_32_COMPAT)) {
396                 struct cr3_64 * dst_reg = (struct cr3_64 *)(dec_instr.dst_operand.operand);
397                 struct cr3_64 * guest_cr3 = (struct cr3_64 *)&(info->shdw_pg_state.guest_cr3);
398                 *dst_reg = *guest_cr3;
399             } else {
400                 struct cr3_32 * dst_reg = (struct cr3_32 *)(dec_instr.dst_operand.operand);
401                 struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
402                 *dst_reg = *guest_cr3;
403             }
404             
405         } else if (info->shdw_pg_mode == NESTED_PAGING) {
406             
407             // This is just a passthrough operation which we probably don't need here
408             if ((v3_get_vm_cpu_mode(info) == LONG) || 
409                 (v3_get_vm_cpu_mode(info) == LONG_32_COMPAT)) {
410                 struct cr3_64 * dst_reg = (struct cr3_64 *)(dec_instr.dst_operand.operand);
411                 struct cr3_64 * guest_cr3 = (struct cr3_64 *)&(info->ctrl_regs.cr3);
412                 *dst_reg = *guest_cr3;
413             } else {
414                 struct cr3_32 * dst_reg = (struct cr3_32 *)(dec_instr.dst_operand.operand);
415                 struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->ctrl_regs.cr3);
416                 *dst_reg = *guest_cr3;
417             }
418         }
419         
420     } else {
421         PrintError(info->vm_info, info, "Unhandled opcode in handle_cr3_read\n");
422         return -1;
423     }
424     
425     info->rip += dec_instr.instr_length;
426     
427     return 0;
428 }
429
430
431 //return guest cr4 - shadow PAE is always on
432 int v3_handle_cr4_read(struct guest_info * info) {
433     uchar_t instr[15];
434     int ret;
435     struct x86_instr dec_instr;
436     
437     if (info->mem_mode == PHYSICAL_MEM) { 
438         ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
439     } else { 
440         ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
441     }
442     
443     if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
444         PrintError(info->vm_info, info, "Could not decode instruction\n");
445         return -1;
446     }
447     if (dec_instr.op_type != V3_OP_MOVCR2) {
448         PrintError(info->vm_info, info, "Invalid opcode in read CR4\n");
449         return -1;
450     }
451         
452         if (info->shdw_pg_mode == SHADOW_PAGING) {
453             
454             if ((v3_get_vm_cpu_mode(info) == LONG) || 
455                 (v3_get_vm_cpu_mode(info) == LONG_32_COMPAT)) {
456                 struct cr4_64 * dst_reg = (struct cr4_64 *)(dec_instr.dst_operand.operand);
457                 struct cr4_64 * guest_cr4 = (struct cr4_64 *)&(info->ctrl_regs.cr4);
458                 *dst_reg = *guest_cr4;
459             } 
460             else {
461                 struct cr4_32 * dst_reg = (struct cr4_32 *)(dec_instr.dst_operand.operand);
462                 struct cr4_32 * guest_cr4 = (struct cr4_32 *)&(info->shdw_pg_state.guest_cr4);
463                 *dst_reg = *guest_cr4;
464             }
465             
466         } else if (info->shdw_pg_mode == NESTED_PAGING) {
467             
468             
469             if ((v3_get_vm_cpu_mode(info) == LONG) || 
470                 (v3_get_vm_cpu_mode(info) == LONG_32_COMPAT)) {
471                 struct cr4_64 * dst_reg = (struct cr4_64 *)(dec_instr.dst_operand.operand);
472                 struct cr4_64 * guest_cr4 = (struct cr4_64 *)&(info->ctrl_regs.cr4);
473                 *dst_reg = *guest_cr4;
474             } else {
475                 struct cr4_32 * dst_reg = (struct cr4_32 *)(dec_instr.dst_operand.operand);
476                 struct cr4_32 * guest_cr4 = (struct cr4_32 *)&(info->ctrl_regs.cr4);
477                 *dst_reg = *guest_cr4;
478             }
479         }
480         
481         info->rip += dec_instr.instr_length;
482     return 0;
483 }
484
485
486 int v3_handle_cr4_write(struct guest_info * info) {
487     uchar_t instr[15];
488     int ret;
489     int flush_tlb=0;
490     struct x86_instr dec_instr;
491     v3_cpu_mode_t cpu_mode = v3_get_vm_cpu_mode(info);
492     
493     if (info->mem_mode == PHYSICAL_MEM) { 
494         ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
495     } else { 
496         ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
497     }
498     
499     if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
500         PrintError(info->vm_info, info, "Could not decode instruction\n");
501         return -1;
502     }
503     
504     if (dec_instr.op_type != V3_OP_MOV2CR) {
505         PrintError(info->vm_info, info, "Invalid opcode in write to CR4\n");
506         return -1;
507     }
508     
509     // Check to see if we need to flush the tlb
510     
511
512     if (v3_get_vm_mem_mode(info) == VIRTUAL_MEM) { 
513         struct cr4_32 * new_cr4 = (struct cr4_32 *)(dec_instr.src_operand.operand);
514         struct cr4_32 * cr4 = (struct cr4_32 *)&(info->shdw_pg_state.guest_cr4);
515         
516         // if pse, pge, or pae have changed while PG (in any mode) is on
517         // the side effect is a TLB flush, which means we need to
518         // toss the current shadow page tables too
519         //
520         // 
521         // TODO - PAE FLAG needs to be special cased
522         if ((cr4->pse != new_cr4->pse) || 
523             (cr4->pge != new_cr4->pge) || 
524             (cr4->pae != new_cr4->pae)) { 
525             PrintDebug(info->vm_info, info, "Handling PSE/PGE/PAE -> TLBFlush case, flag set\n");
526             flush_tlb = 1;
527             
528         }
529     }
530     
531
532     if ((cpu_mode == PROTECTED) || (cpu_mode == PROTECTED_PAE)) {
533         struct cr4_32 * new_cr4 = (struct cr4_32 *)(dec_instr.src_operand.operand);
534         struct cr4_32 * shadow_cr4 = (struct cr4_32 *)&(info->ctrl_regs.cr4);
535         struct cr4_32 * guest_cr4 = (struct cr4_32 *)&(info->shdw_pg_state.guest_cr4);
536         PrintDebug(info->vm_info, info, "OperandVal = %x, length = %d\n", *(uint_t *)new_cr4, dec_instr.src_operand.size);
537         PrintDebug(info->vm_info, info, "Old guest CR4=%x\n", *(uint_t *)guest_cr4);
538         
539         if ((info->shdw_pg_mode == SHADOW_PAGING)) { 
540             if (v3_get_vm_mem_mode(info) == PHYSICAL_MEM) {
541                 
542                 if ((guest_cr4->pae == 0) && (new_cr4->pae == 1)) {
543                     PrintDebug(info->vm_info, info, "Creating PAE passthrough tables\n");
544                     
545                     // create 32 bit PAE direct map page table
546                     if (v3_reset_passthrough_pts(info) == -1) {
547                         PrintError(info->vm_info, info, "Could not create 32 bit PAE passthrough pages tables\n");
548                         return -1;
549                     }
550
551                     // reset cr3 to new page tables
552                     info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
553                     
554                 } else if ((guest_cr4->pae == 1) && (new_cr4->pae == 0)) {
555                     // Create passthrough standard 32bit pagetables
556                     PrintError(info->vm_info, info, "Switching From PAE to Protected mode not supported\n");
557                     return -1;
558                 } 
559             }
560         }
561         
562         *guest_cr4 = *new_cr4;
563         *shadow_cr4 = *guest_cr4;
564         shadow_cr4->pae = 1;   // always on for the shadow pager
565         PrintDebug(info->vm_info, info, "New guest CR4=%x and shadow CR4=%x\n", *(uint_t *)guest_cr4,*(uint_t*)shadow_cr4);
566         
567     } else if ((cpu_mode == LONG) || (cpu_mode == LONG_32_COMPAT)) {
568         struct cr4_64 * new_cr4 = (struct cr4_64 *)(dec_instr.src_operand.operand);
569         struct cr4_64 * cr4 = (struct cr4_64 *)&(info->ctrl_regs.cr4);
570         
571         PrintDebug(info->vm_info, info, "Old CR4=%p\n", (void *)*(addr_t *)cr4);
572         PrintDebug(info->vm_info, info, "New CR4=%p\n", (void *)*(addr_t *)new_cr4);
573         
574         if (new_cr4->pae == 0) {
575             // cannot turn off PAE in long mode GPF the guest
576             PrintError(info->vm_info, info, "Cannot disable PAE in long mode, should send GPF\n");
577             return -1;
578         }
579         
580         *cr4 = *new_cr4;
581         
582     } else {
583         PrintError(info->vm_info, info, "CR4 write not supported in CPU_MODE: %s\n", v3_cpu_mode_to_str(cpu_mode));
584         return -1;
585     }
586     
587     if (info->shdw_pg_mode == SHADOW_PAGING) {
588         if (flush_tlb) {
589             PrintDebug(info->vm_info, info, "Handling PSE/PGE/PAE -> TLBFlush (doing flush now!)\n");
590             if (v3_activate_shadow_pt(info) == -1) {
591                 PrintError(info->vm_info, info, "Failed to activate shadow page tables when emulating TLB flush in handling cr4 write\n");
592                 return -1;
593             }
594         }
595     }
596     
597     info->rip += dec_instr.instr_length;
598     return 0;
599 }
600
601
602 /*
603   The CR8 and APIC TPR interaction are kind of crazy.
604
605   CR8 mandates that the priority class is in bits 3:0
606
607   The interaction of CR8 and an actual APIC is somewhat implementation dependent, but
608   a basic current APIC has the priority class at 7:4 and the *subclass* at 3:0
609
610   The APIC TPR (both fields) can be written as the APIC register
611   A write to CR8 sets the priority class field, and should zero the subclass
612   A read from CR8 gets just the priority class field
613
614   In the apic_tpr storage location, we have:
615
616      zeros [class] [subclass]
617
618   Because of this, an APIC implementation should use apic_tpr to store its TPR
619   In fact, it *should* do this, otherwise its TPR may get out of sync with the architected TPR
620
621   On a CR8 read, we return just 
622
623      zeros 0000  [class]
624
625   On a CR8 write, we set the register to
626
627      zeros [class] 0000
628
629 */
630
631 int v3_handle_cr8_write(struct guest_info * info) {
632     int ret;
633     uchar_t instr[15];
634     struct x86_instr dec_instr;
635     
636     if (info->mem_mode == PHYSICAL_MEM) { 
637         ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
638     } else { 
639         ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
640     }
641     
642     if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
643         PrintError(info->vm_info, info, "Could not decode instruction\n");
644         return -1;
645     }
646     
647     if (dec_instr.op_type == V3_OP_MOV2CR) {
648         PrintDebug(info->vm_info, info, "MOV2CR8 (cpu_mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
649         
650         if ((info->cpu_mode == LONG) ||
651             (info->cpu_mode == LONG_32_COMPAT)) {
652             uint64_t *val = (uint64_t *)(dec_instr.src_operand.operand);
653
654             info->ctrl_regs.apic_tpr = (*val & 0xf) << 4;
655
656             V3_Print(info->vm_info, info, "Write of CR8 sets apic_tpr to 0x%llx\n",info->ctrl_regs.apic_tpr);
657
658         }  else {
659             // probably should raise exception here
660         }
661     } else {
662         PrintError(info->vm_info, info, "Unhandled opcode in handle_cr8_write\n");
663         return -1;
664     }
665     
666     info->rip += dec_instr.instr_length;
667     
668     return 0;
669 }
670
671
672
673 int v3_handle_cr8_read(struct guest_info * info) {
674     uchar_t instr[15];
675     int ret;
676     struct x86_instr dec_instr;
677     
678     if (info->mem_mode == PHYSICAL_MEM) { 
679         ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
680     } else { 
681         ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
682     }
683     
684     if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
685         PrintError(info->vm_info, info, "Could not decode instruction\n");
686         return -1;
687     }
688     
689     if (dec_instr.op_type == V3_OP_MOVCR2) {
690         PrintDebug(info->vm_info, info, "MOVCR82 (mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
691         
692         if ((info->cpu_mode == LONG) || 
693             (info->cpu_mode == LONG_32_COMPAT)) {
694             uint64_t *dst_reg = (uint64_t *)(dec_instr.dst_operand.operand);
695
696             *dst_reg = (info->ctrl_regs.apic_tpr >> 4) & 0xf;
697
698             V3_Print(info->vm_info, info, "Read of CR8 (apic_tpr) returns 0x%llx\n",*dst_reg);
699
700         } else {
701             // probably should raise exception
702         }
703             
704     } else {
705         PrintError(info->vm_info, info, "Unhandled opcode in handle_cr8_read\n");
706         return -1;
707     }
708     
709     info->rip += dec_instr.instr_length;
710     
711     return 0;
712 }
713
714
715 int v3_handle_efer_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data) {
716     PrintDebug(core->vm_info, core, "EFER Read HI=%x LO=%x\n", core->shdw_pg_state.guest_efer.hi, core->shdw_pg_state.guest_efer.lo);
717     
718     dst->value = core->shdw_pg_state.guest_efer.value;
719     
720     return 0;
721 }
722
723
724 int v3_handle_efer_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data) {
725     struct v3_msr *  vm_efer     = &(core->shdw_pg_state.guest_efer);
726     struct efer_64 * hw_efer     = (struct efer_64 *)&(core->ctrl_regs.efer);
727     struct efer_64   old_hw_efer = *((struct efer_64 *)&core->ctrl_regs.efer);
728     
729     PrintDebug(core->vm_info, core, "EFER Write HI=%x LO=%x\n", src.hi, src.lo);
730
731     // Set EFER value seen by guest if it reads EFER
732     vm_efer->value = src.value;
733
734     // Set EFER value seen by hardware while the guest is running
735     *(uint64_t *)hw_efer = src.value;
736
737     // We have gotten here either because we are using
738     // shadow paging, or we are using nested paging on SVM
739     // In the latter case, we don't need to do anything
740     // like the following
741     if (core->shdw_pg_mode == SHADOW_PAGING) { 
742       // Catch unsupported features
743       if ((old_hw_efer.lme == 1) && (hw_efer->lme == 0)) {
744         PrintError(core->vm_info, core, "Disabling long mode once it has been enabled is not supported\n");
745         return -1;
746       }
747       
748       // Set LME and LMA bits seen by hardware
749       if (old_hw_efer.lme == 0) {
750         // Long mode was not previously enabled, so the lme bit cannot
751         // be set yet. It will be set later when the guest sets CR0.PG
752         // to enable paging.
753         hw_efer->lme = 0;
754       } else {
755         // Long mode was previously enabled. Ensure LMA bit is set.
756         // VMX does not automatically set LMA, and this should not affect SVM.
757         hw_efer->lma = 1;
758       }
759     }
760       
761       
762     PrintDebug(core->vm_info, core, "RIP=%p\n", (void *)core->rip);
763     PrintDebug(core->vm_info, core, "New EFER value HW(hi=%p), VM(hi=%p)\n", (void *)*(uint64_t *)hw_efer, (void *)vm_efer->value); 
764
765
766     return 0;
767 }
768
769 int v3_handle_vm_cr_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data) {
770     /* tell the guest that the BIOS disabled SVM, that way it doesn't get 
771      * confused by the fact that CPUID reports SVM as available but it still
772      * cannot be used 
773      */
774     dst->value = SVM_VM_CR_MSR_lock | SVM_VM_CR_MSR_svmdis;
775     PrintDebug(core->vm_info, core, "VM_CR Read HI=%x LO=%x\n", dst->hi, dst->lo);
776     return 0;
777 }
778
779 int v3_handle_vm_cr_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data) {
780     PrintDebug(core->vm_info, core, "VM_CR Write\n");
781     PrintDebug(core->vm_info, core, "VM_CR Write Values: HI=%x LO=%x\n", src.hi, src.lo);
782
783     /* writes to LOCK and SVMDIS are silently ignored (according to the spec), 
784      * other writes indicate the guest wants to use some feature we haven't
785      * implemented
786      */
787     if (src.value & ~(SVM_VM_CR_MSR_lock | SVM_VM_CR_MSR_svmdis)) {
788         PrintDebug(core->vm_info, core, "VM_CR write sets unsupported bits: HI=%x LO=%x\n", src.hi, src.lo);
789         return -1;
790     }
791     
792     return 0;
793 }