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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
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>
29 /* Segmentation is a problem here...
31 * When we get a memory operand, presumably we use the default segment (which is?)
32 * unless an alternate segment was specfied in the prefix...
36 #ifndef DEBUG_CTRL_REGS
38 #define PrintDebug(fmt, args...)
42 // First Attempt = 494 lines
43 // current = 106 lines
44 int v3_handle_cr0_write(struct guest_info * info) {
47 struct x86_instr dec_instr;
49 if (info->mem_mode == PHYSICAL_MEM) {
50 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
52 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
55 /* The IFetch will already have faulted in the necessary bytes for the full instruction
57 // I think we should inject a GPF into the guest
58 PrintError("Could not read instruction (ret=%d)\n", ret);
63 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
64 PrintError("Could not decode instruction\n");
69 if (v3_opcode_cmp(V3_OPCODE_LMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
70 struct cr0_real *real_cr0 = (struct cr0_real*)&(info->ctrl_regs.cr0);
71 struct cr0_real *new_cr0 = (struct cr0_real *)(dec_instr.src_operand.operand);
76 new_cr0_val = (*(char*)(new_cr0)) & 0x0f;
78 PrintDebug("OperandVal = %x\n", new_cr0_val);
80 PrintDebug("Old CR0=%x\n", *(uint_t *)real_cr0);
81 *(uchar_t*)real_cr0 &= 0xf0;
82 *(uchar_t*)real_cr0 |= new_cr0_val;
83 PrintDebug("New CR0=%x\n", *(uint_t *)real_cr0);
86 if (info->shdw_pg_mode == SHADOW_PAGING) {
87 struct cr0_real * shadow_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
89 PrintDebug(" Old Shadow CR0=%x\n", *(uint_t *)shadow_cr0);
90 *(uchar_t*)shadow_cr0 &= 0xf0;
91 *(uchar_t*)shadow_cr0 |= new_cr0_val;
92 PrintDebug("New Shadow CR0=%x\n", *(uint_t *)shadow_cr0);
94 } else if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
95 PrintDebug("MOV2CR0\n");
97 if (info->cpu_mode == LONG) {
101 struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
102 struct cr0_32 *new_cr0= (struct cr0_32 *)(dec_instr.src_operand.operand);
104 PrintDebug("OperandVal = %x, length=%d\n", *(uint_t *)new_cr0, dec_instr.src_operand.size);
107 PrintDebug("Old CR0=%x\n", *(uint_t *)real_cr0);
108 *real_cr0 = *new_cr0;
111 if (info->shdw_pg_mode == SHADOW_PAGING) {
112 struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
114 PrintDebug("Old Shadow CR0=%x\n", *(uint_t *)shadow_cr0);
118 *shadow_cr0 = *new_cr0;
121 if (v3_get_mem_mode(info) == VIRTUAL_MEM) {
122 struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
123 PrintDebug("Setting up Shadow Page Table\n");
124 info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
126 info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
130 PrintDebug("New Shadow CR0=%x\n",*(uint_t *)shadow_cr0);
132 PrintDebug("New CR0=%x\n", *(uint_t *)real_cr0);
135 } else if (v3_opcode_cmp(V3_OPCODE_CLTS, (const uchar_t *)(dec_instr.opcode)) == 0) {
137 struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
141 if (info->shdw_pg_mode == SHADOW_PAGING) {
142 struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
146 PrintError("Unhandled opcode in handle_cr0_write\n");
150 info->rip += dec_instr.instr_length;
156 // First attempt = 253 lines
157 // current = 51 lines
158 int v3_handle_cr0_read(struct guest_info * info) {
161 struct x86_instr dec_instr;
163 if (info->mem_mode == PHYSICAL_MEM) {
164 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
166 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
169 /* The IFetch will already have faulted in the necessary bytes for the full instruction
171 // I think we should inject a GPF into the guest
172 PrintError("Could not read instruction (ret=%d)\n", ret);
177 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
178 PrintError("Could not decode instruction\n");
182 if (v3_opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
183 struct cr0_32 * virt_cr0 = (struct cr0_32 *)(dec_instr.dst_operand.operand);
184 struct cr0_32 * real_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
186 PrintDebug("MOVCR2\n");
187 PrintDebug("CR0 at 0x%p\n", (void *)real_cr0);
189 if (info->shdw_pg_mode == SHADOW_PAGING) {
190 *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
192 *virt_cr0 = *real_cr0;
195 PrintDebug("real CR0: %x\n", *(uint_t*)real_cr0);
196 PrintDebug("returned CR0: %x\n", *(uint_t*)virt_cr0);
197 } else if (v3_opcode_cmp(V3_OPCODE_SMSW, (const uchar_t *)(dec_instr.opcode)) == 0) {
198 struct cr0_real *real_cr0= (struct cr0_real*)&(info->ctrl_regs.cr0);
199 struct cr0_real *virt_cr0 = (struct cr0_real *)(dec_instr.dst_operand.operand);
200 char cr0_val = *(char*)real_cr0 & 0x0f;
202 PrintDebug("SMSW\n");
204 PrintDebug("CR0 at 0x%p\n", real_cr0);
206 *(char *)virt_cr0 &= 0xf0;
207 *(char *)virt_cr0 |= cr0_val;
210 PrintError("Unhandled opcode in handle_cr0_read\n");
214 info->rip += dec_instr.instr_length;
221 // First Attempt = 256 lines
222 // current = 65 lines
223 int v3_handle_cr3_write(struct guest_info * info) {
226 struct x86_instr dec_instr;
228 if (info->mem_mode == PHYSICAL_MEM) {
229 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
231 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
234 /* The IFetch will already have faulted in the necessary bytes for the full instruction
236 // I think we should inject a GPF into the guest
237 PrintError("Could not read instruction (ret=%d)\n", ret);
242 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
243 PrintError("Could not decode instruction\n");
247 if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
249 PrintDebug("MOV2CR3\n");
251 PrintDebug("CR3 at 0x%p\n", &(info->ctrl_regs.cr3));
253 if (info->shdw_pg_mode == SHADOW_PAGING) {
254 struct cr3_32 * new_cr3 = (struct cr3_32 *)(dec_instr.src_operand.operand);
255 struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
256 struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
260 PrintDebug("Old Shadow CR3=%x; Old Guest CR3=%x\n",
261 *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
265 cached = v3_cache_page_tables32(info, (addr_t)V3_PAddr((void *)(addr_t)CR3_TO_PDE32((void *)*(addr_t *)new_cr3)));
268 PrintError("CR3 Cache failed\n");
270 } else if (cached == 0) {
273 if( info->mem_mode == VIRTUAL_MEM )
275 PrintDebug("New CR3 is different - flushing shadow page table %p\n", shadow_cr3 );
277 delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
280 shadow_pt = v3_create_new_shadow_pt32();
282 shadow_cr3->pdt_base_addr = (addr_t)V3_PAddr((void *)(addr_t)PD32_BASE_ADDR(shadow_pt));
283 PrintDebug( "Created new shadow page table %p\n", shadow_cr3->pdt_base_addr );
284 //PrintDebugPageTables( (pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3) );
288 PrintDebug("Reusing cached shadow Page table\n");
292 shadow_cr3->pwt = new_cr3->pwt;
293 shadow_cr3->pcd = new_cr3->pcd;
296 *guest_cr3 = *new_cr3;
298 PrintDebug("New Shadow CR3=%x; New Guest CR3=%x\n",
299 *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
301 if (info->mem_mode == VIRTUAL_MEM) {
302 // If we aren't in paged mode then we have to preserve the identity mapped CR3
303 info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
307 PrintError("Unhandled opcode in handle_cr3_write\n");
311 info->rip += dec_instr.instr_length;
318 // first attempt = 156 lines
319 // current = 36 lines
320 int v3_handle_cr3_read(struct guest_info * info) {
323 struct x86_instr dec_instr;
325 if (info->mem_mode == PHYSICAL_MEM) {
326 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
328 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
331 /* The IFetch will already have faulted in the necessary bytes for the full instruction
333 // I think we should inject a GPF into the guest
334 PrintError("Could not read instruction (ret=%d)\n", ret);
339 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
340 PrintError("Could not decode instruction\n");
344 if (v3_opcode_cmp(V3_OPCODE_MOVCR2, (const uchar_t *)(dec_instr.opcode)) == 0) {
345 PrintDebug("MOVCR32\n");
346 struct cr3_32 * virt_cr3 = (struct cr3_32 *)(dec_instr.dst_operand.operand);
348 PrintDebug("CR3 at 0x%p\n", &(info->ctrl_regs.cr3));
350 if (info->shdw_pg_mode == SHADOW_PAGING) {
351 *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
353 *virt_cr3 = *(struct cr3_32 *)&(info->ctrl_regs.cr3);
356 PrintError("Unhandled opcode in handle_cr3_read\n");
360 info->rip += dec_instr.instr_length;