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);
49 // I think we should inject a GPF into the guest
50 PrintError("Could not read instruction (ret=%d)\n", ret);
54 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
55 PrintError("Could not decode instruction\n");
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);
67 new_cr0_val = (*(char*)(new_cr0)) & 0x0f;
69 PrintDebug("OperandVal = %x\n", new_cr0_val);
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);
77 if (info->shdw_pg_mode == SHADOW_PAGING) {
78 struct cr0_real * shadow_cr0 = (struct cr0_real*)&(info->shdw_pg_state.guest_cr0);
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);
85 } else if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
86 PrintDebug("MOV2CR0\n");
88 if (info->cpu_mode == LONG) {
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);
95 PrintDebug("OperandVal = %x, length=%d\n", *new_cr0, dec_instr.dst_operand.size);
98 PrintDebug("Old CR0=%x\n", *real_cr0);
102 if (info->shdw_pg_mode == SHADOW_PAGING) {
103 struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
105 PrintDebug("Old Shadow CR0=%x\n", *shadow_cr0);
109 *shadow_cr0 = *new_cr0;
112 if (get_mem_mode(info) == VIRTUAL_MEM) {
113 struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
115 info->ctrl_regs.cr3 = *(addr_t*)shadow_cr3;
117 info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
121 PrintDebug("New Shadow CR0=%x\n",*shadow_cr0);
123 PrintDebug("New CR0=%x\n", *real_cr0);
126 } else if (opcode_cmp(V3_OPCODE_CLTS, (const uchar_t *)(dec_instr.opcode)) == 0) {
128 struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
132 if (info->shdw_pg_mode == SHADOW_PAGING) {
133 struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
137 PrintError("Unhandled opcode in handle_cr0_write\n");
141 info->rip += dec_instr.instr_length;
147 // First attempt = 253 lines
148 // current = 51 lines
149 int handle_cr0_read(struct guest_info * info) {
152 struct x86_instr dec_instr;
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);
157 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
161 // I think we should inject a GPF into the guest
162 PrintError("Could not read instruction (ret=%d)\n", ret);
166 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
167 PrintError("Could not decode instruction\n");
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);
175 PrintDebug("MOVCR2\n");
176 PrintDebug("CR0 at 0x%x\n", real_cr0);
178 if (info->shdw_pg_mode == SHADOW_PAGING) {
179 *virt_cr0 = *(struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
181 *virt_cr0 = *real_cr0;
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;
191 PrintDebug("SMSW\n");
193 PrintDebug("CR0 at 0x%x\n", real_cr0);
195 *(char *)virt_cr0 &= 0xf0;
196 *(char *)virt_cr0 |= cr0_val;
199 PrintError("Unhandled opcode in handle_cr0_read\n");
203 info->rip += dec_instr.instr_length;
210 // First Attemp = 256 lines
211 // current = 65 lines
212 int handle_cr3_write(struct guest_info * info) {
215 struct x86_instr dec_instr;
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);
220 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
224 // I think we should inject a GPF into the guest
225 PrintError("Could not read instruction (ret=%d)\n", ret);
229 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
230 PrintError("Could not decode instruction\n");
234 if (opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) == 0) {
236 PrintDebug("MOV2CR3\n");
238 PrintDebug("CR3 at 0x%x\n", &(info->ctrl_regs.cr3));
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);
245 PrintDebug("Old Shadow CR3=%x; Old Guest CR3=%x\n",
246 *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
248 if (!CR3_RELOAD_OPTIMIZATION || !CR3_32_SAME_BASE(new_cr3, guest_cr3)) {
252 PrintDebug("New CR3 is different - flushing shadow page table\n");
254 delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
256 shadow_pt = create_new_shadow_pt32(info);
258 shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);
261 shadow_cr3->pwt = new_cr3->pwt;
262 shadow_cr3->pcd = new_cr3->pcd;
265 *guest_cr3 = *new_cr3;
267 PrintDebug("New Shadow CR3=%x; New Guest CR3=%x\n",
268 *(uint_t*)shadow_cr3, *(uint_t*)guest_cr3);
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;
276 PrintError("Unhandled opcode in handle_cr3_write\n");
280 info->rip += dec_instr.instr_length;
287 // first attempt = 156 lines
288 // current = 36 lines
289 int handle_cr3_read(struct guest_info * info) {
292 struct x86_instr dec_instr;
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);
297 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
301 // I think we should inject a GPF into the guest
302 PrintError("Could not read instruction (ret=%d)\n", ret);
306 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
307 PrintError("Could not decode instruction\n");
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);
315 PrintDebug("CR3 at 0x%x\n", &(info->ctrl_regs.cr3));
317 if (info->shdw_pg_mode == SHADOW_PAGING) {
318 *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
320 *virt_cr3 = *(struct cr3_32 *)&(info->ctrl_regs.cr3);
323 PrintError("Unhandled opcode in handle_cr3_read\n");
328 info->rip += dec_instr.instr_length;