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.h>
21 #include <palacios/vmm_emulator.h>
22 #include <palacios/vm_guest_mem.h>
23 #include <palacios/vmm_decoder.h>
24 #include <palacios/vmm_paging.h>
25 #include <palacios/vmm_instr_emulator.h>
27 #ifndef DEBUG_EMULATOR
29 #define PrintDebug(fmt, args...)
35 static int run_op(struct guest_info * info, v3_op_type_t op_type, addr_t src_addr, addr_t dst_addr, int src_op_size, int dst_op_size);
37 // We emulate up to the next 4KB page boundry
38 static int emulate_string_write_op(struct guest_info * info, struct x86_instr * dec_instr,
39 addr_t write_gva, addr_t write_gpa, addr_t dst_addr,
40 int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
42 uint_t emulation_length = 0;
46 if (dec_instr->dst_operand.operand != write_gva) {
47 PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
48 (void *)dec_instr->dst_operand.operand, (void *)write_gva);
52 emulation_length = ( (dec_instr->str_op_length < (0x1000 - PAGE_OFFSET_4KB(write_gva))) ?
53 dec_instr->str_op_length :
54 (0x1000 - PAGE_OFFSET_4KB(write_gva)));
56 /* ** Fix emulation length so that it doesn't overrun over the src page either ** */
57 tmp_rcx = emulation_length;
62 if (dec_instr->op_type == V3_OP_MOVS) {
64 // figure out addresses here....
65 if (info->mem_mode == PHYSICAL_MEM) {
66 if (guest_pa_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) {
67 PrintError("Could not translate write Source (Physical) to host VA\n");
71 if (guest_va_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) {
72 PrintError("Could not translate write Source (Virtual) to host VA\n");
77 if (dec_instr->dst_operand.size == 1) {
78 movs8((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
79 } else if (dec_instr->dst_operand.size == 2) {
80 movs16((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
81 } else if (dec_instr->dst_operand.size == 4) {
82 movs32((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
84 } else if (dec_instr->dst_operand.size == 8) {
85 movs64((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
88 PrintError("Invalid operand length\n");
92 info->vm_regs.rdi += emulation_length;
93 info->vm_regs.rsi += emulation_length;
95 // RCX is only modified if the rep prefix is present
96 if (dec_instr->prefixes.rep == 1) {
97 info->vm_regs.rcx -= emulation_length;
100 } else if (dec_instr->op_type == V3_OP_STOS) {
102 if (dec_instr->dst_operand.size == 1) {
103 stos8((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
104 } else if (dec_instr->dst_operand.size == 2) {
105 stos16((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
106 } else if (dec_instr->dst_operand.size == 4) {
107 stos32((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
109 } else if (dec_instr->dst_operand.size == 8) {
110 stos64((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
113 PrintError("Invalid operand length\n");
117 info->vm_regs.rdi += emulation_length;
119 // RCX is only modified if the rep prefix is present
120 if (dec_instr->prefixes.rep == 1) {
121 info->vm_regs.rcx -= emulation_length;
125 PrintError("Unimplemented String operation\n");
129 if (write_fn(write_gpa, (void *)dst_addr, emulation_length, priv_data) != emulation_length) {
130 PrintError("Did not fully read hooked data\n");
134 if (emulation_length == dec_instr->str_op_length) {
135 info->rip += dec_instr->instr_length;
138 return emulation_length;
150 int v3_emulate_write_op(struct guest_info * info, addr_t write_gva, addr_t write_gpa, addr_t dst_addr,
151 int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
153 struct x86_instr dec_instr;
160 PrintDebug("Emulating Write for instruction at %p\n", (void *)(addr_t)(info->rip));
161 PrintDebug("GVA=%p\n", (void *)write_gva);
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);
173 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
174 PrintError("Decoding Error\n");
175 // Kick off single step emulator
179 if (dec_instr.is_str_op) {
180 return emulate_string_write_op(info, &dec_instr, write_gva, write_gpa, dst_addr, write_fn, priv_data);
184 if ((dec_instr.dst_operand.type != MEM_OPERAND) ||
185 (dec_instr.dst_operand.operand != write_gva)) {
186 PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
187 (void *)dec_instr.dst_operand.operand, (void *)write_gva);
192 if (dec_instr.src_operand.type == MEM_OPERAND) {
193 if (info->mem_mode == PHYSICAL_MEM) {
194 if (guest_pa_to_host_va(info, dec_instr.src_operand.operand, &src_addr) == -1) {
195 PrintError("Could not translate write Source (Physical) to host VA\n");
199 if (guest_va_to_host_va(info, dec_instr.src_operand.operand, &src_addr) == -1) {
200 PrintError("Could not translate write Source (Virtual) to host VA\n");
204 } else if (dec_instr.src_operand.type == REG_OPERAND) {
205 src_addr = dec_instr.src_operand.operand;
207 src_addr = (addr_t)&(dec_instr.src_operand.operand);
210 dst_op_len = dec_instr.dst_operand.size;
211 src_op_len = dec_instr.src_operand.size;
213 PrintDebug("Dst_Addr = %p, SRC operand = %p\n",
214 (void *)dst_addr, (void *)src_addr);
217 if (run_op(info, dec_instr.op_type, src_addr, dst_addr, src_op_len, dst_op_len) == -1) {
218 PrintError("Instruction Emulation Failed\n");
222 if (write_fn(write_gpa, (void *)dst_addr, dst_op_len, priv_data) != dst_op_len) {
223 PrintError("Did not fully write hooked data\n");
227 info->rip += dec_instr.instr_length;
233 int v3_emulate_read_op(struct guest_info * info, addr_t read_gva, addr_t read_gpa, addr_t src_addr,
234 int (*read_fn)(addr_t guest_addr, void * dst, uint_t length, void * priv_data),
236 struct x86_instr dec_instr;
243 PrintDebug("Emulating Read for instruction at %p\n", (void *)(addr_t)(info->rip));
244 PrintDebug("GVA=%p\n", (void *)read_gva);
246 if (info->mem_mode == PHYSICAL_MEM) {
247 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
249 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
256 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
257 PrintError("Decoding Error\n");
258 // Kick off single step emulator
262 if (dec_instr.is_str_op) {
263 PrintError("String operations not implemented on fully hooked regions\n");
268 if ((dec_instr.src_operand.type != MEM_OPERAND) ||
269 (dec_instr.src_operand.operand != read_gva)) {
270 PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
271 (void *)dec_instr.src_operand.operand, (void *)read_gva);
276 if (dec_instr.dst_operand.type == MEM_OPERAND) {
277 if (info->mem_mode == PHYSICAL_MEM) {
278 if (guest_pa_to_host_va(info, dec_instr.dst_operand.operand, &dst_addr) == -1) {
279 PrintError("Could not translate Read Destination (Physical) to host VA\n");
283 if (guest_va_to_host_va(info, dec_instr.dst_operand.operand, &dst_addr) == -1) {
284 PrintError("Could not translate Read Destination (Virtual) to host VA\n");
288 } else if (dec_instr.dst_operand.type == REG_OPERAND) {
289 dst_addr = dec_instr.dst_operand.operand;
291 dst_addr = (addr_t)&(dec_instr.dst_operand.operand);
294 src_op_len = dec_instr.src_operand.size;
295 dst_op_len = dec_instr.dst_operand.size;
297 PrintDebug("Dst_Addr = %p, SRC Addr = %p\n",
298 (void *)dst_addr, (void *)src_addr);
300 if (read_fn(read_gpa, (void *)src_addr, src_op_len, priv_data) != src_op_len) {
301 PrintError("Did not fully read hooked data\n");
305 if (run_op(info, dec_instr.op_type, src_addr, dst_addr, src_op_len, dst_op_len) == -1) {
306 PrintError("Instruction Emulation Failed\n");
310 info->rip += dec_instr.instr_length;
320 static int run_op(struct guest_info * info, v3_op_type_t op_type, addr_t src_addr, addr_t dst_addr, int src_op_size, int dst_op_size) {
322 if (src_op_size == 1) {
323 PrintDebug("Executing 8 bit instruction\n");
327 adc8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
330 add8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
333 and8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
336 or8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
339 xor8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
342 sub8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
346 mov8((addr_t *)dst_addr, (addr_t *)src_addr);
350 movzx8((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
353 movsx8((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
357 not8((addr_t *)dst_addr);
360 xchg8((addr_t *)dst_addr, (addr_t *)src_addr);
365 inc8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
368 dec8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
371 neg8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
374 setb8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
377 setbe8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
380 setl8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
383 setle8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
386 setnb8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
389 setnbe8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
392 setnl8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
395 setnle8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
398 setno8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
401 setnp8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
404 setns8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
407 setnz8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
410 seto8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
413 setp8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
416 sets8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
419 setz8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
423 PrintError("Unknown 8 bit instruction\n");
427 } else if (src_op_size == 2) {
428 PrintDebug("Executing 16 bit instruction\n");
432 adc16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
435 add16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
438 and16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
441 or16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
444 xor16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
447 sub16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
452 inc16((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
455 dec16((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
458 neg16((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
462 mov16((addr_t *)dst_addr, (addr_t *)src_addr);
465 movzx16((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
468 movsx16((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
471 not16((addr_t *)dst_addr);
474 xchg16((addr_t *)dst_addr, (addr_t *)src_addr);
478 PrintError("Unknown 16 bit instruction\n");
482 } else if (src_op_size == 4) {
483 PrintDebug("Executing 32 bit instruction\n");
487 adc32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
490 add32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
493 and32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
496 or32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
499 xor32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
502 sub32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
506 inc32((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
509 dec32((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
512 neg32((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
516 mov32((addr_t *)dst_addr, (addr_t *)src_addr);
520 not32((addr_t *)dst_addr);
523 xchg32((addr_t *)dst_addr, (addr_t *)src_addr);
527 PrintError("Unknown 32 bit instruction\n");
532 } else if (src_op_size == 8) {
533 PrintDebug("Executing 64 bit instruction\n");
537 adc64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
540 add64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
543 and64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
546 or64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
549 xor64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
552 sub64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
556 inc64((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
559 dec64((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
562 neg64((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
566 mov64((addr_t *)dst_addr, (addr_t *)src_addr);
570 not64((addr_t *)dst_addr);
573 xchg64((addr_t *)dst_addr, (addr_t *)src_addr);
577 PrintError("Unknown 64 bit instruction\n");
583 PrintError("Invalid Operation Size\n");