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>
10 /* Segmentation is a problem here...
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...
17 #ifndef DEBUG_CTRL_REGS
19 #define PrintDebug(fmt, args...)
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
35 // First Attempt = 494 lines
36 // current = 106 lines
37 int handle_cr0_write(struct guest_info * info) {
40 struct x86_instr dec_instr;
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);
45 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
48 /* The IFetch will already have faulted in the necessary bytes for the full instruction
50 // I think we should inject a GPF into the guest
51 PrintError("Could not read instruction (ret=%d)\n", ret);
56 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
57 PrintError("Could not decode instruction\n");
62 if (opcode_cmp(V3_OPCODE_LMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
63 struct cr0_real *real_cr0 = (struct cr0_real*)&(info->ctrl_regs.cr0);
64 struct cr0_real *new_cr0 = (struct cr0_real *)(dec_instr.src_operand.operand);
69 new_cr0_val = (*(char*)(new_cr0)) & 0x0f;
71 PrintDebug("OperandVal = %x\n", new_cr0_val);
73 PrintDebug("Old CR0=%x\n", *real_cr0);
74 *(uchar_t*)real_cr0 &= 0xf0;
75 *(uchar_t*)real_cr0 |= new_cr0_val;
76 PrintDebug("New CR0=%x\n", *real_cr0);
79 if (info->shdw_pg_mode == SHADOW_PAGING) {
80 struct cr0_real * shadow_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
82 PrintDebug(" Old Shadow CR0=%x\n", *shadow_cr0);
83 *(uchar_t*)shadow_cr0 &= 0xf0;
84 *(uchar_t*)shadow_cr0 |= new_cr0_val;
85 PrintDebug("New Shadow CR0=%x\n", *shadow_cr0);
87 } else if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
88 PrintDebug("MOV2CR0\n");
90 if (info->cpu_mode == LONG) {
94 struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
95 struct cr0_32 *new_cr0= (struct cr0_32 *)(dec_instr.src_operand.operand);
97 PrintDebug("OperandVal = %x, length=%d\n", *new_cr0, dec_instr_src_operand.size);
100 PrintDebug("Old CR0=%x\n", *real_cr0);
101 *real_cr0 = *new_cr0;
104 if (info->shdw_pg_mode == SHADOW_PAGING) {
105 struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
107 PrintDebug("Old Shadow CR0=%x\n", *shadow_cr0);
111 *shadow_cr0 = *new_cr0;
114 if (get_mem_mode(info) == VIRTUAL_MEM) {
115 struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
117 info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
119 info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
123 PrintDebug("New Shadow CR0=%x\n",*shadow_cr0);
125 PrintDebug("New CR0=%x\n", *real_cr0);
128 } else if (opcode_cmp(V3_OPCODE_CLTS, (const uchar_t *)(dec_instr.opcode)) == 0) {
130 struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
134 if (info->shdw_pg_mode == SHADOW_PAGING) {
135 struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
139 PrintError("Unhandled opcode in handle_cr0_write\n");
143 info->rip += dec_instr.instr_length;
149 // First attempt = 253 lines
150 // current = 51 lines
151 int handle_cr0_read(struct guest_info * info) {
154 struct x86_instr dec_instr;
156 if (info->mem_mode == PHYSICAL_MEM) {
157 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
159 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
162 /* The IFetch will already have faulted in the necessary bytes for the full instruction
164 // I think we should inject a GPF into the guest
165 PrintError("Could not read instruction (ret=%d)\n", ret);
170 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
171 PrintError("Could not decode instruction\n");
175 if (opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
176 struct cr0_32 * virt_cr0 = (struct cr0_32 *)(dec_instr.dst_operand.operand);
177 struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
179 PrintDebug("MOVCR2\n");
180 PrintDebug("CR0 at 0x%x\n", real_cr0);
182 if (info->shdw_pg_mode == SHADOW_PAGING) {
183 *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
185 *virt_cr0 = *real_cr0;
188 PrintDebug("real CR0: %x\n", *(uint_t*)real_cr0);
189 PrintDebug("returned CR0: %x\n", *(uint_t*)virt_cr0);
190 } else if (opcode_cmp(V3_OPCODE_SMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
191 struct cr0_real *real_cr0= (struct cr0_real*)&(info->ctrl_regs.cr0);
192 struct cr0_real *virt_cr0 = (struct cr0_real *)(dec_instr.dst_operand.operand);
193 char cr0_val = *(char*)real_cr0 & 0x0f;
195 PrintDebug("SMSW\n");
197 PrintDebug("CR0 at 0x%x\n", real_cr0);
199 *(char *)virt_cr0 &= 0xf0;
200 *(char *)virt_cr0 |= cr0_val;
203 PrintError("Unhandled opcode in handle_cr0_read\n");
207 info->rip += dec_instr.instr_length;
214 // First Attemp = 256 lines
215 // current = 65 lines
216 int handle_cr3_write(struct guest_info * info) {
219 struct x86_instr dec_instr;
221 if (info->mem_mode == PHYSICAL_MEM) {
222 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
224 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
227 /* The IFetch will already have faulted in the necessary bytes for the full instruction
229 // I think we should inject a GPF into the guest
230 PrintError("Could not read instruction (ret=%d)\n", ret);
235 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
236 PrintError("Could not decode instruction\n");
240 if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
242 PrintDebug("MOV2CR3\n");
244 PrintDebug("CR3 at 0x%x\n", &(info->ctrl_regs.cr3));
246 if (info->shdw_pg_mode == SHADOW_PAGING) {
247 struct cr3_32 * new_cr3 = (struct cr3_32 *)(dec_instr.src_operand.operand);
248 struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
249 struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
251 PrintDebug("Old Shadow CR3=%x; Old Guest CR3=%x\n",
252 *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
254 if (!CR3_RELOAD_OPTIMIZATION || !CR3_32_SAME_BASE(new_cr3, guest_cr3)) {
258 PrintDebug("New CR3 is different - flushing shadow page table\n");
260 delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
262 shadow_pt = create_new_shadow_pt32();
264 shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);
267 shadow_cr3->pwt = new_cr3->pwt;
268 shadow_cr3->pcd = new_cr3->pcd;
271 *guest_cr3 = *new_cr3;
273 PrintDebug("New Shadow CR3=%x; New Guest CR3=%x\n",
274 *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
276 if (info->mem_mode == VIRTUAL_MEM) {
277 // If we aren't in paged mode then we have to preserve the identity mapped CR3
278 info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
282 PrintError("Unhandled opcode in handle_cr3_write\n");
286 info->rip += dec_instr.instr_length;
293 // first attempt = 156 lines
294 // current = 36 lines
295 int handle_cr3_read(struct guest_info * info) {
298 struct x86_instr dec_instr;
300 if (info->mem_mode == PHYSICAL_MEM) {
301 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
303 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
306 /* The IFetch will already have faulted in the necessary bytes for the full instruction
308 // I think we should inject a GPF into the guest
309 PrintError("Could not read instruction (ret=%d)\n", ret);
314 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
315 PrintError("Could not decode instruction\n");
319 if (opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
320 PrintDebug("MOVCR32\n");
321 struct cr3_32 * virt_cr3 = (struct cr3_32 *)(dec_instr.dst_operand.operand);
323 PrintDebug("CR3 at 0x%x\n", &(info->ctrl_regs.cr3));
325 if (info->shdw_pg_mode == SHADOW_PAGING) {
326 *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
328 *virt_cr3 = *(struct cr3_32 *)&(info->ctrl_regs.cr3);
331 PrintError("Unhandled opcode in handle_cr3_read\n");
336 info->rip += dec_instr.instr_length;