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.


modified copyright tags
[palacios.git] / palacios / src / palacios / vmm_ctrl_regs.c
1 /* (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> */
2 /* (c) 2008, The V3VEE Project <http://www.v3vee.org> */
3
4
5 #include <palacios/vmm_mem.h>
6 #include <palacios/vmm.h>
7 #include <palacios/vmcb.h>
8 #include <palacios/vmm_decoder.h>
9 #include <palacios/vm_guest_mem.h>
10 #include <palacios/vmm_ctrl_regs.h>
11
12
13
14 /* Segmentation is a problem here...
15  *
16  * When we get a memory operand, presumably we use the default segment (which is?) 
17  * unless an alternate segment was specfied in the prefix...
18  */
19
20
21 #ifndef DEBUG_CTRL_REGS
22 #undef PrintDebug
23 #define PrintDebug(fmt, args...)
24 #endif
25
26
27 // First Attempt = 494 lines
28 // current = 106 lines
29 int handle_cr0_write(struct guest_info * info) {
30   char instr[15];
31   int ret;
32   struct x86_instr dec_instr;
33
34   if (info->mem_mode == PHYSICAL_MEM) { 
35     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
36   } else { 
37     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
38   }
39
40   /* The IFetch will already have faulted in the necessary bytes for the full instruction
41     if (ret != 15) {
42     // I think we should inject a GPF into the guest
43     PrintError("Could not read instruction (ret=%d)\n", ret);
44     return -1;
45     }
46   */
47
48   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
49     PrintError("Could not decode instruction\n");
50     return -1;
51   }
52
53
54   if (opcode_cmp(V3_OPCODE_LMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
55     struct cr0_real *real_cr0  = (struct cr0_real*)&(info->ctrl_regs.cr0);
56     struct cr0_real *new_cr0 = (struct cr0_real *)(dec_instr.src_operand.operand);      
57     uchar_t new_cr0_val;
58
59     PrintDebug("LMSW\n");
60
61     new_cr0_val = (*(char*)(new_cr0)) & 0x0f;
62     
63     PrintDebug("OperandVal = %x\n", new_cr0_val);
64
65     PrintDebug("Old CR0=%x\n", *real_cr0);      
66     *(uchar_t*)real_cr0 &= 0xf0;
67     *(uchar_t*)real_cr0 |= new_cr0_val;
68     PrintDebug("New CR0=%x\n", *real_cr0);      
69       
70
71     if (info->shdw_pg_mode == SHADOW_PAGING) {
72       struct cr0_real * shadow_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
73       
74       PrintDebug(" Old Shadow CR0=%x\n", *shadow_cr0);  
75       *(uchar_t*)shadow_cr0 &= 0xf0;
76       *(uchar_t*)shadow_cr0 |= new_cr0_val;
77       PrintDebug("New Shadow CR0=%x\n", *shadow_cr0);   
78     }
79   } else if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
80     PrintDebug("MOV2CR0\n");
81
82     if (info->cpu_mode == LONG) {
83       // 64 bit registers
84     } else {
85       // 32 bit registers
86         struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
87         struct cr0_32 *new_cr0= (struct cr0_32 *)(dec_instr.src_operand.operand);
88
89         PrintDebug("OperandVal = %x, length=%d\n", *new_cr0, dec_instr.src_operand.size);
90
91
92         PrintDebug("Old CR0=%x\n", *real_cr0);
93         *real_cr0 = *new_cr0;
94         
95
96         if (info->shdw_pg_mode == SHADOW_PAGING) {
97           struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
98           
99           PrintDebug("Old Shadow CR0=%x\n", *shadow_cr0);       
100           
101           real_cr0->et = 1;
102           
103           *shadow_cr0 = *new_cr0;
104           shadow_cr0->et = 1;
105           
106           if (get_mem_mode(info) == VIRTUAL_MEM) {
107             struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
108             
109             info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
110           } else  {
111             info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
112             real_cr0->pg = 1;
113           }
114           
115           PrintDebug("New Shadow CR0=%x\n",*shadow_cr0);
116         }
117         PrintDebug("New CR0=%x\n", *real_cr0);
118     }
119
120   } else if (opcode_cmp(V3_OPCODE_CLTS, (const uchar_t *)(dec_instr.opcode)) == 0) {
121     // CLTS
122     struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
123         
124     real_cr0->ts = 0;
125
126     if (info->shdw_pg_mode == SHADOW_PAGING) {
127       struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
128       shadow_cr0->ts = 0;
129     }
130   } else {
131     PrintError("Unhandled opcode in handle_cr0_write\n");
132     return -1;
133   }
134
135   info->rip += dec_instr.instr_length;
136
137   return 0;
138 }
139
140
141 // First attempt = 253 lines
142 // current = 51 lines
143 int handle_cr0_read(struct guest_info * info) {
144   char instr[15];
145   int ret;
146   struct x86_instr dec_instr;
147
148   if (info->mem_mode == PHYSICAL_MEM) { 
149     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
150   } else { 
151     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
152   }
153
154   /* The IFetch will already have faulted in the necessary bytes for the full instruction
155      if (ret != 15) {
156      // I think we should inject a GPF into the guest
157      PrintError("Could not read instruction (ret=%d)\n", ret);
158      return -1;
159      }
160   */
161
162   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
163     PrintError("Could not decode instruction\n");
164     return -1;
165   }
166   
167   if (opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
168     struct cr0_32 * virt_cr0 = (struct cr0_32 *)(dec_instr.dst_operand.operand);
169     struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
170     
171     PrintDebug("MOVCR2\n");
172     PrintDebug("CR0 at 0x%x\n", real_cr0);
173
174     if (info->shdw_pg_mode == SHADOW_PAGING) {
175       *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
176     } else {
177       *virt_cr0 = *real_cr0;
178     }
179     
180     PrintDebug("real CR0: %x\n", *(uint_t*)real_cr0);
181     PrintDebug("returned CR0: %x\n", *(uint_t*)virt_cr0);
182   } else if (opcode_cmp(V3_OPCODE_SMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
183     struct cr0_real *real_cr0= (struct cr0_real*)&(info->ctrl_regs.cr0);
184     struct cr0_real *virt_cr0 = (struct cr0_real *)(dec_instr.dst_operand.operand);
185     char cr0_val = *(char*)real_cr0 & 0x0f;
186     
187     PrintDebug("SMSW\n");
188
189     PrintDebug("CR0 at 0x%x\n", real_cr0);
190
191     *(char *)virt_cr0 &= 0xf0;
192     *(char *)virt_cr0 |= cr0_val;
193     
194   } else {
195     PrintError("Unhandled opcode in handle_cr0_read\n");
196     return -1;
197   }
198
199   info->rip += dec_instr.instr_length;
200
201   return 0;
202 }
203
204
205
206 // First Attempt = 256 lines
207 // current = 65 lines
208 int handle_cr3_write(struct guest_info * info) {
209   int ret;
210   char instr[15];
211   struct x86_instr dec_instr;
212
213   if (info->mem_mode == PHYSICAL_MEM) { 
214     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
215   } else { 
216     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
217   }
218
219   /* The IFetch will already have faulted in the necessary bytes for the full instruction
220      if (ret != 15) {
221      // I think we should inject a GPF into the guest
222      PrintError("Could not read instruction (ret=%d)\n", ret);
223      return -1;
224      }
225   */
226
227   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
228     PrintError("Could not decode instruction\n");
229     return -1;
230   }
231
232   if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
233
234     PrintDebug("MOV2CR3\n");
235
236     PrintDebug("CR3 at 0x%x\n", &(info->ctrl_regs.cr3));
237
238     if (info->shdw_pg_mode == SHADOW_PAGING) {
239       struct cr3_32 * new_cr3 = (struct cr3_32 *)(dec_instr.src_operand.operand);       
240       struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
241       struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
242       int cached = 0;
243       
244
245       PrintDebug("Old Shadow CR3=%x; Old Guest CR3=%x\n", 
246                  *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
247       
248
249       cached = cache_page_tables32(info, CR3_TO_PDE32(*(addr_t *)new_cr3));
250
251       if (cached == -1) {
252         PrintError("CR3 Cache failed\n");
253         return -1;
254       } else if (cached == 0) {
255         addr_t shadow_pt;
256         
257         PrintDebug("New CR3 is different - flushing shadow page table\n");      
258         
259         delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
260         
261         shadow_pt =  create_new_shadow_pt32();
262         
263         shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);    
264       } else {
265         PrintDebug("Reusing cached shadow Page table\n");
266       }
267       
268       shadow_cr3->pwt = new_cr3->pwt;
269       shadow_cr3->pcd = new_cr3->pcd;
270       
271       // What the hell...
272       *guest_cr3 = *new_cr3;
273       
274       PrintDebug("New Shadow CR3=%x; New Guest CR3=%x\n", 
275                  *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
276
277       if (info->mem_mode == VIRTUAL_MEM) {
278         // If we aren't in paged mode then we have to preserve the identity mapped CR3
279         info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
280       }
281     }
282   } else {
283     PrintError("Unhandled opcode in handle_cr3_write\n");
284     return -1;
285   }
286
287   info->rip += dec_instr.instr_length;
288
289   return 0;
290 }
291
292
293
294 // first attempt = 156 lines
295 // current = 36 lines
296 int handle_cr3_read(struct guest_info * info) {
297   char instr[15];
298   int ret;
299   struct x86_instr dec_instr;
300
301   if (info->mem_mode == PHYSICAL_MEM) { 
302     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
303   } else { 
304     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
305   }
306
307   /* The IFetch will already have faulted in the necessary bytes for the full instruction
308      if (ret != 15) {
309      // I think we should inject a GPF into the guest
310      PrintError("Could not read instruction (ret=%d)\n", ret);
311      return -1;
312      }
313   */
314
315   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
316     PrintError("Could not decode instruction\n");
317     return -1;
318   }
319
320   if (opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
321     PrintDebug("MOVCR32\n");
322     struct cr3_32 * virt_cr3 = (struct cr3_32 *)(dec_instr.dst_operand.operand);
323
324     PrintDebug("CR3 at 0x%x\n", &(info->ctrl_regs.cr3));
325
326     if (info->shdw_pg_mode == SHADOW_PAGING) {
327       *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
328     } else {
329       *virt_cr3 = *(struct cr3_32 *)&(info->ctrl_regs.cr3);
330     }
331   } else {
332     PrintError("Unhandled opcode in handle_cr3_read\n");
333     return -1;
334   }
335
336   info->rip += dec_instr.instr_length;
337
338   return 0;
339 }