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.


write_cr3 optimization to reuse page table if cr3 is unchanged is now
[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 // Set to 1 if CR3 reload with same value shall not
24 // force a shadow page table flush
25 // It makes windows loading MUCH faster. 
26 // Note that this optimization appears to fail with a 2.6 linux kernel
27 #define CR3_RELOAD_OPTIMIZATION 0
28
29
30
31
32
33
34
35 // First Attempt = 494 lines
36 // current = 106 lines
37 int handle_cr0_write(struct guest_info * info) {
38   char instr[15];
39   int ret;
40   struct x86_instr dec_instr;
41
42   if (info->mem_mode == PHYSICAL_MEM) { 
43     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
44   } else { 
45     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
46   }
47
48   if (ret != 15) {
49     // I think we should inject a GPF into the guest
50     PrintError("Could not read instruction (ret=%d)\n", ret);
51     return -1;
52   }
53
54   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
55     PrintError("Could not decode instruction\n");
56     return -1;
57   }
58
59
60   if (opcode_cmp(V3_OPCODE_LMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
61     struct cr0_real *real_cr0  = (struct cr0_real*)&(info->ctrl_regs.cr0);
62     struct cr0_real *new_cr0 = (struct cr0_real *)(dec_instr.src_operand.operand);      
63     uchar_t new_cr0_val;
64
65     PrintDebug("LMSW\n");
66
67     new_cr0_val = (*(char*)(new_cr0)) & 0x0f;
68     
69     PrintDebug("OperandVal = %x\n", new_cr0_val);
70
71     PrintDebug("Old CR0=%x\n", *real_cr0);      
72     *(uchar_t*)real_cr0 &= 0xf0;
73     *(uchar_t*)real_cr0 |= new_cr0_val;
74     PrintDebug("New CR0=%x\n", *real_cr0);      
75       
76
77     if (info->shdw_pg_mode == SHADOW_PAGING) {
78       struct cr0_real * shadow_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
79       
80       PrintDebug(" Old Shadow CR0=%x\n", *shadow_cr0);  
81       *(uchar_t*)shadow_cr0 &= 0xf0;
82       *(uchar_t*)shadow_cr0 |= new_cr0_val;
83       PrintDebug("New Shadow CR0=%x\n", *shadow_cr0);   
84     }
85   } else if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
86     PrintDebug("MOV2CR0\n");
87
88     if (info->cpu_mode == LONG) {
89       // 64 bit registers
90     } else {
91       // 32 bit registers
92         struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
93         struct cr0_32 *new_cr0= (struct cr0_32 *)(dec_instr.src_operand.operand);
94
95         PrintDebug("OperandVal = %x, length=%d\n", *new_cr0, dec_instr.dst_operand.size);
96
97
98         PrintDebug("Old CR0=%x\n", *real_cr0);
99         *real_cr0 = *new_cr0;
100         
101
102         if (info->shdw_pg_mode == SHADOW_PAGING) {
103           struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
104           
105           PrintDebug("Old Shadow CR0=%x\n", *shadow_cr0);       
106           
107           real_cr0->et = 1;
108           
109           *shadow_cr0 = *new_cr0;
110           shadow_cr0->et = 1;
111           
112           if (get_mem_mode(info) == VIRTUAL_MEM) {
113             struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
114             
115             info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
116           } else  {
117             info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
118             real_cr0->pg = 1;
119           }
120           
121           PrintDebug("New Shadow CR0=%x\n",*shadow_cr0);
122         }
123         PrintDebug("New CR0=%x\n", *real_cr0);
124     }
125
126   } else if (opcode_cmp(V3_OPCODE_CLTS, (const uchar_t *)(dec_instr.opcode)) == 0) {
127     // CLTS
128     struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
129         
130     real_cr0->ts = 0;
131
132     if (info->shdw_pg_mode == SHADOW_PAGING) {
133       struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
134       shadow_cr0->ts = 0;
135     }
136   } else {
137     PrintError("Unhandled opcode in handle_cr0_write\n");
138     return -1;
139   }
140
141   info->rip += dec_instr.instr_length;
142
143   return 0;
144 }
145
146
147 // First attempt = 253 lines
148 // current = 51 lines
149 int handle_cr0_read(struct guest_info * info) {
150   char instr[15];
151   int ret;
152   struct x86_instr dec_instr;
153
154   if (info->mem_mode == PHYSICAL_MEM) { 
155     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
156   } else { 
157     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
158   }
159
160   if (ret != 15) {
161     // I think we should inject a GPF into the guest
162     PrintError("Could not read instruction (ret=%d)\n", ret);
163     return -1;
164   }
165
166   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
167     PrintError("Could not decode instruction\n");
168     return -1;
169   }
170   
171   if (opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
172     struct cr0_32 * virt_cr0 = (struct cr0_32 *)(dec_instr.dst_operand.operand);
173     struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
174     
175     PrintDebug("MOVCR2\n");
176     PrintDebug("CR0 at 0x%x\n", real_cr0);
177
178     if (info->shdw_pg_mode == SHADOW_PAGING) {
179       *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
180     } else {
181       *virt_cr0 = *real_cr0;
182     }
183     
184     PrintDebug("real CR0: %x\n", *(uint_t*)real_cr0);
185     PrintDebug("returned CR0: %x\n", *(uint_t*)virt_cr0);
186   } else if (opcode_cmp(V3_OPCODE_SMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
187     struct cr0_real *real_cr0= (struct cr0_real*)&(info->ctrl_regs.cr0);
188     struct cr0_real *virt_cr0 = (struct cr0_real *)(dec_instr.dst_operand.operand);
189     char cr0_val = *(char*)real_cr0 & 0x0f;
190     
191     PrintDebug("SMSW\n");
192
193     PrintDebug("CR0 at 0x%x\n", real_cr0);
194
195     *(char *)virt_cr0 &= 0xf0;
196     *(char *)virt_cr0 |= cr0_val;
197     
198   } else {
199     PrintError("Unhandled opcode in handle_cr0_read\n");
200     return -1;
201   }
202
203   info->rip += dec_instr.instr_length;
204
205   return 0;
206 }
207
208
209
210 // First Attemp = 256 lines
211 // current = 65 lines
212 int handle_cr3_write(struct guest_info * info) {
213   int ret;
214   char instr[15];
215   struct x86_instr dec_instr;
216
217   if (info->mem_mode == PHYSICAL_MEM) { 
218     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
219   } else { 
220     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
221   }
222
223   if (ret != 15) {
224     // I think we should inject a GPF into the guest
225     PrintError("Could not read instruction (ret=%d)\n", ret);
226     return -1;
227   }
228
229   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
230     PrintError("Could not decode instruction\n");
231     return -1;
232   }
233
234   if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
235
236     PrintDebug("MOV2CR3\n");
237
238     PrintDebug("CR3 at 0x%x\n", &(info->ctrl_regs.cr3));
239
240     if (info->shdw_pg_mode == SHADOW_PAGING) {
241       struct cr3_32 * new_cr3 = (struct cr3_32 *)(dec_instr.src_operand.operand);       
242       struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
243       struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
244       
245       PrintDebug("Old Shadow CR3=%x; Old Guest CR3=%x\n", 
246                  *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
247       
248       if (!CR3_RELOAD_OPTIMIZATION || !CR3_32_SAME_BASE(new_cr3, guest_cr3)) { 
249         addr_t shadow_pt;
250
251         
252         PrintDebug("New CR3 is different - flushing shadow page table\n");      
253         
254         delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
255         
256         shadow_pt =  create_new_shadow_pt32(info);
257         
258         shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);    
259       } 
260       
261       shadow_cr3->pwt = new_cr3->pwt;
262       shadow_cr3->pcd = new_cr3->pcd;
263       
264       // What the hell...
265       *guest_cr3 = *new_cr3;
266       
267       PrintDebug("New Shadow CR3=%x; New Guest CR3=%x\n", 
268                  *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
269
270       if (info->mem_mode == VIRTUAL_MEM) {
271         // If we aren't in paged mode then we have to preserve the identity mapped CR3
272         info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
273       }
274     }
275   } else {
276     PrintError("Unhandled opcode in handle_cr3_write\n");
277     return -1;
278   }
279
280   info->rip += dec_instr.instr_length;
281
282   return 0;
283 }
284
285
286
287 // first attempt = 156 lines
288 // current = 36 lines
289 int handle_cr3_read(struct guest_info * info) {
290   char instr[15];
291   int ret;
292   struct x86_instr dec_instr;
293
294   if (info->mem_mode == PHYSICAL_MEM) { 
295     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
296   } else { 
297     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
298   }
299
300   if (ret != 15) {
301     // I think we should inject a GPF into the guest
302     PrintError("Could not read instruction (ret=%d)\n", ret);
303     return -1;
304   }
305
306   if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
307     PrintError("Could not decode instruction\n");
308     return -1;
309   }
310
311   if (opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
312     PrintDebug("MOVCR32\n");
313     struct cr3_32 * virt_cr3 = (struct cr3_32 *)(dec_instr.dst_operand.operand);
314
315     PrintDebug("CR3 at 0x%x\n", &(info->ctrl_regs.cr3));
316
317     if (info->shdw_pg_mode == SHADOW_PAGING) {
318       *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
319     } else {
320       *virt_cr3 = *(struct cr3_32 *)&(info->ctrl_regs.cr3);
321     }
322   } else {
323     PrintError("Unhandled opcode in handle_cr3_read\n");
324     return -1;
325   }
326
327
328   info->rip += dec_instr.instr_length;
329
330   return 0;
331 }