From: Jack Lange Date: Mon, 23 Feb 2009 22:06:33 +0000 (-0600) Subject: added stos instruction to the emulator X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=0733f93d0fc8a20528a9ab2f21704bee5562b302 added stos instruction to the emulator --- diff --git a/palacios/include/palacios/vmm_decoder.h b/palacios/include/palacios/vmm_decoder.h index 4c3df0b..009fc58 100644 --- a/palacios/include/palacios/vmm_decoder.h +++ b/palacios/include/palacios/vmm_decoder.h @@ -34,7 +34,7 @@ typedef enum { V3_INVALID_OP, V3_OP_SETB, V3_OP_SETBE, V3_OP_SETL, V3_OP_SETLE, V3_OP_SETNB, V3_OP_SETNBE, V3_OP_SETNL, V3_OP_SETNLE, V3_OP_SETNO, V3_OP_SETNP, V3_OP_SETNS, V3_OP_SETNZ, V3_OP_SETO, V3_OP_SETP, V3_OP_SETS, - V3_OP_SETZ, V3_OP_MOVS, V3_OP_MOVZX, V3_OP_MOVSX} v3_op_type_t; + V3_OP_SETZ, V3_OP_MOVS, V3_OP_STOS, V3_OP_MOVZX, V3_OP_MOVSX} v3_op_type_t; typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND, IMM_OPERAND} v3_operand_type_t; diff --git a/palacios/include/palacios/vmm_instr_emulator.h b/palacios/include/palacios/vmm_instr_emulator.h index aef325a..f8738f4 100644 --- a/palacios/include/palacios/vmm_instr_emulator.h +++ b/palacios/include/palacios/vmm_instr_emulator.h @@ -349,6 +349,98 @@ +#define MAKE_1OP_64STR_INST(iname) static inline void iname##64(addr_t * dst, \ + addr_t * src, \ + addr_t * ecx, addr_t * flags) { \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushfq; " \ + "pushq %4; " \ + "popfq; " \ + "rep; " \ + #iname"q; " \ + "pushfq; " \ + "popq %0; " \ + "popfq; " \ + : "=q"(*flags) \ + : "D"(*dst),"a"(*src),"c"(*ecx),"q"(*flags) \ + ); \ + \ + *flags |= flags_rsvd; \ + } + + +#define MAKE_1OP_32STR_INST(iname) static inline void iname##32(addr_t * dst, \ + addr_t * src, \ + addr_t * ecx, addr_t * flags) { \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %4; " \ + "popf; " \ + "rep; " \ + #iname"l; " \ + "pushf; " \ + "pop %0; " \ + "popf; " \ + : "=q"(*flags) \ + : "D"(*(uint32_t *)dst),"a"(*(uint32_t *)src),"c"(*(uint32_t *)ecx),"q"(*flags) \ + ); \ + \ + *flags |= flags_rsvd; \ + } + +#define MAKE_1OP_16STR_INST(iname) static inline void iname##16(addr_t * dst, \ + addr_t * src, \ + addr_t * ecx, addr_t * flags) { \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %4; " \ + "popf; " \ + "rep; " \ + #iname"w; " \ + "pushf; " \ + "pop %0; " \ + "popf; " \ + : "=q"(*flags) \ + : "D"(*dst),"a"(*src),"c"(*ecx),"q"(*flags) \ + ); \ + *flags |= flags_rsvd; \ + } + + + +#define MAKE_1OP_8STR_INST(iname) static inline void iname##8(addr_t * dst, \ + addr_t * src, \ + addr_t * ecx, addr_t * flags) { \ + /* Some of the flags values are not copied out in a pushf, we save them here */ \ + addr_t flags_rsvd = *flags & ~0xfffe7fff; \ + \ + asm volatile ( \ + "pushf; " \ + "push %4; " \ + "popf; " \ + "rep; " \ + #iname"b; " \ + "pushf; " \ + "pop %0; " \ + "popf; " \ + : "=q"(*flags) \ + : "D"(*dst),"a"(*src),"c"(*ecx),"q"(*flags) \ + ); \ + *flags |= flags_rsvd; \ + } + + + + #define MAKE_2OP_64_INST(iname) static inline void iname##64(addr_t * dst, addr_t * src) { \ uint64_t tmp_dst = *dst, tmp_src = *src; \ \ @@ -438,6 +530,41 @@ +#define MAKE_2OUT_64_INST(iname) static inline void iname##64(addr_t * dst, addr_t * src) { \ + asm volatile ( \ + #iname"q %1, %0; " \ + : "=q"(*(uint64_t *)dst), "=q"(*(uint64_t *)src) \ + : "0"(*(uint64_t *)dst), "1"(*(uint64_t *)src) \ + ); \ + } + +#define MAKE_2OUT_32_INST(iname) static inline void iname##32(addr_t * dst, addr_t * src) { \ + asm volatile ( \ + #iname"l %1, %0; " \ + : "=q"(*(uint32_t *)dst), "=q"(*(uint32_t *)src) \ + : "0"(*(uint32_t *)dst), "1"(*(uint32_t *)src) \ + ); \ + } + +#define MAKE_2OUT_16_INST(iname) static inline void iname##16(addr_t * dst, addr_t * src) { \ + asm volatile ( \ + #iname"w %1, %0; " \ + : "=q"(*(uint16_t *)dst), "=q"(*(uint16_t *)src) \ + : "0"(*(uint16_t *)dst), "1"(*(uint16_t *)src) \ + ); \ + } + +#define MAKE_2OUT_8_INST(iname) static inline void iname##8(addr_t * dst, addr_t * src) { \ + asm volatile ( \ + #iname"b %1, %0; " \ + : "=q"(*(uint8_t *)dst), "=q"(*(uint8_t *)src) \ + : "0"(*(uint8_t *)dst), "1"(*(uint8_t *)src) \ + ); \ + } + + + + /****************************/ @@ -479,9 +606,11 @@ MAKE_2OP_8_INST(mov); MAKE_2OP_8EXT_INST(movzx); MAKE_2OP_8EXT_INST(movsx); -MAKE_2OP_8_INST(xchg); +MAKE_2OUT_8_INST(xchg); MAKE_2OP_8STR_INST(movs); +MAKE_1OP_8STR_INST(stos); +MAKE_1OP_8STR_INST(scas); /****************************/ @@ -504,9 +633,12 @@ MAKE_1OP_16_INST(not); MAKE_2OP_16_INST(mov); MAKE_2OP_16EXT_INST(movzx); MAKE_2OP_16EXT_INST(movsx); -MAKE_2OP_16_INST(xchg); +MAKE_2OUT_16_INST(xchg); MAKE_2OP_16STR_INST(movs); +MAKE_1OP_16STR_INST(stos); +MAKE_1OP_16STR_INST(scas); + /****************************/ /* 32 Bit instruction forms */ @@ -527,11 +659,15 @@ MAKE_1OP_32_INST(not); MAKE_2OP_32_INST(mov); -MAKE_2OP_32_INST(xchg); +MAKE_2OUT_32_INST(xchg); MAKE_2OP_32STR_INST(movs); +MAKE_1OP_32STR_INST(stos); +MAKE_1OP_32STR_INST(scas); + + #ifdef __V3_64BIT__ @@ -553,9 +689,11 @@ MAKE_1OP_64_INST(not); MAKE_2OP_64_INST(mov); +MAKE_2OP_64STR_INST(movs); +MAKE_1OP_64STR_INST(stos); +MAKE_1OP_64STR_INST(scas); - -MAKE_2OP_64_INST(xchg); +MAKE_2OUT_64_INST(xchg); #endif diff --git a/palacios/src/palacios/vmm_config.c b/palacios/src/palacios/vmm_config.c index 32e3862..c572871 100644 --- a/palacios/src/palacios/vmm_config.c +++ b/palacios/src/palacios/vmm_config.c @@ -158,7 +158,7 @@ static int setup_memory_map(struct guest_info * info, struct v3_vm_config * conf #define ROMBIOS_START 0x000f0000 // VGA frame buffer - if (1) { + if (0) { if (v3_add_shadow_mem(info, 0xa0000, 0xc0000, 0xa0000) == -1) { PrintError("Could not map VGA framebuffer\n"); return -1; diff --git a/palacios/src/palacios/vmm_emulator.c b/palacios/src/palacios/vmm_emulator.c index a040c3c..735b997 100644 --- a/palacios/src/palacios/vmm_emulator.c +++ b/palacios/src/palacios/vmm_emulator.c @@ -43,99 +43,104 @@ static int emulate_string_write_op(struct guest_info * info, struct x86_instr * addr_t tmp_rcx = 0; addr_t src_addr = 0; - if (dec_instr->op_type == V3_OP_MOVS) { - // PrintError("MOVS emulation\n"); - - if (dec_instr->dst_operand.operand != write_gva) { - PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n", - (void *)dec_instr->dst_operand.operand, (void *)write_gva); - return -1; - } - - emulation_length = ( (dec_instr->str_op_length < (0x1000 - PAGE_OFFSET_4KB(write_gva))) ? - dec_instr->str_op_length : - (0x1000 - PAGE_OFFSET_4KB(write_gva))); - /* ** Fix emulation length so that it doesn't overrun over the src page either ** */ + if (dec_instr->dst_operand.operand != write_gva) { + PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n", + (void *)dec_instr->dst_operand.operand, (void *)write_gva); + return -1; + } + + emulation_length = ( (dec_instr->str_op_length < (0x1000 - PAGE_OFFSET_4KB(write_gva))) ? + dec_instr->str_op_length : + (0x1000 - PAGE_OFFSET_4KB(write_gva))); + + /* ** Fix emulation length so that it doesn't overrun over the src page either ** */ + tmp_rcx = emulation_length; + - PrintDebug("STR_OP_LEN: %d, Page Len: %d\n", - (uint_t)dec_instr->str_op_length, - (uint_t)(0x1000 - PAGE_OFFSET_4KB(write_gva))); - PrintDebug("Emulation length: %d\n", emulation_length); - tmp_rcx = emulation_length; - + if (dec_instr->op_type == V3_OP_MOVS) { - // figure out addresses here.... - if (info->mem_mode == PHYSICAL_MEM) { - if (guest_pa_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) { - PrintError("Could not translate write Source (Physical) to host VA\n"); - return -1; - } - } else { - if (guest_va_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) { - PrintError("Could not translate write Source (Virtual) to host VA\n"); - return -1; - } + // figure out addresses here.... + if (info->mem_mode == PHYSICAL_MEM) { + if (guest_pa_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) { + PrintError("Could not translate write Source (Physical) to host VA\n"); + return -1; } - - - PrintDebug("Dst Operand: %p (size=%d), Src Operand: %p\n", - (void *)dec_instr->dst_operand.operand, - dec_instr->dst_operand.size, - (void *)dec_instr->src_operand.operand); - PrintDebug("Dst Addr: %p, Src Addr: %p\n", (void *)dst_addr, (void *)src_addr); - - //return -1; - - - - + } else { + if (guest_va_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) { + PrintError("Could not translate write Source (Virtual) to host VA\n"); + return -1; + } + } if (dec_instr->dst_operand.size == 1) { movs8((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); } else if (dec_instr->dst_operand.size == 2) { movs16((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); } else if (dec_instr->dst_operand.size == 4) { - movs32((addr_t*)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + movs32((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); +#ifdef __V3_64BIT__ + } else if (dec_instr->dst_operand.size == 8) { + movs64((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); +#endif } else { PrintError("Invalid operand length\n"); return -1; } - PrintDebug("Calling Write function\n"); + info->vm_regs.rdi += emulation_length; + info->vm_regs.rsi += emulation_length; - if (write_fn(write_gpa, (void *)dst_addr, emulation_length, priv_data) != emulation_length) { - PrintError("Did not fully read hooked data\n"); - return -1; + // RCX is only modified if the rep prefix is present + if (dec_instr->prefixes.rep == 1) { + info->vm_regs.rcx -= emulation_length; } + } else if (dec_instr->op_type == V3_OP_STOS) { - PrintDebug("RDI=%p, RSI=%p, RCX=%p\n", - (void *)*(addr_t *)&(info->vm_regs.rdi), - (void *)*(addr_t *)&(info->vm_regs.rsi), - (void *)*(addr_t *)&(info->vm_regs.rcx)); + if (dec_instr->dst_operand.size == 1) { + stos8((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + } else if (dec_instr->dst_operand.size == 2) { + stos16((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); + } else if (dec_instr->dst_operand.size == 4) { + stos32((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); +#ifdef __V3_64BIT__ + } else if (dec_instr->dst_operand.size == 8) { + stos64((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags)); +#endif + } else { + PrintError("Invalid operand length\n"); + return -1; + } info->vm_regs.rdi += emulation_length; - info->vm_regs.rsi += emulation_length; - info->vm_regs.rcx -= emulation_length; - PrintDebug("RDI=%p, RSI=%p, RCX=%p\n", - (void *)*(addr_t *)&(info->vm_regs.rdi), - (void *)*(addr_t *)&(info->vm_regs.rsi), - (void *)*(addr_t *)&(info->vm_regs.rcx)); - - if (emulation_length == dec_instr->str_op_length) { - info->rip += dec_instr->instr_length; + // RCX is only modified if the rep prefix is present + if (dec_instr->prefixes.rep == 1) { + info->vm_regs.rcx -= emulation_length; } - return emulation_length; + } else { + PrintError("Unimplemented String operation\n"); + return -1; + } + + if (write_fn(write_gpa, (void *)dst_addr, emulation_length, priv_data) != emulation_length) { + PrintError("Did not fully read hooked data\n"); + return -1; } + if (emulation_length == dec_instr->str_op_length) { + info->rip += dec_instr->instr_length; + } + + return emulation_length; + + - return -1; } diff --git a/palacios/src/palacios/vmm_xed.c b/palacios/src/palacios/vmm_xed.c index 68e39b0..25103cc 100644 --- a/palacios/src/palacios/vmm_xed.c +++ b/palacios/src/palacios/vmm_xed.c @@ -259,6 +259,33 @@ static int decode_string_op(struct guest_info * info, instr->str_op_length = 1; } + } else if (instr->op_type == V3_OP_STOS) { + instr->num_operands = 2; + + if (get_memory_operand(info, xed_instr, 0, &(instr->dst_operand)) == -1) { + PrintError("Could not get Destination memory operand\n"); + return -1; + } + + // STOS reads from rax + xed_reg_to_v3_reg(info, xed_decoded_inst_get_reg(xed_instr, XED_OPERAND_REG0), + &(instr->src_operand.operand), + &(instr->src_operand.size)); + instr->src_operand.type = REG_OPERAND; + + if (instr->prefixes.rep == 1) { + addr_t reg_addr = 0; + uint_t reg_length = 0; + + xed_reg_to_v3_reg(info, xed_decoded_inst_get_reg(xed_instr, XED_OPERAND_REG1), ®_addr, ®_length); + instr->str_op_length = MASK(*(addr_t *)reg_addr, reg_length); + } else { + instr->str_op_length = 1; + } + + } else { + PrintError("Unhandled String OP\n"); + return -1; } return 0; @@ -605,8 +632,8 @@ static int get_memory_operand(struct guest_info * info, xed_decoded_inst_t * xe - PrintDebug("Struct: Seg=%p, base=%p, index=%p, scale=%p, displacement=%p (size=%d)\n", - (void *)mem_op.segment, (void*)mem_op.base, (void *)mem_op.index, + PrintDebug("Struct: Seg=%p (size=%d), base=%p, index=%p, scale=%p, displacement=%p (size=%d)\n", + (void *)mem_op.segment, mem_op.segment_size, (void*)mem_op.base, (void *)mem_op.index, (void *)mem_op.scale, (void *)(addr_t)mem_op.displacement, mem_op.displacement_size); @@ -1008,21 +1035,27 @@ static int xed_reg_to_v3_reg(struct guest_info * info, xed_reg_enum_t xed_reg, a */ case XED_REG_CS: *v3_reg = (addr_t)&(info->segments.cs); + *reg_len = 8; return SEGMENT_REGISTER; case XED_REG_DS: *v3_reg = (addr_t)&(info->segments.ds); + *reg_len = 8; return SEGMENT_REGISTER; case XED_REG_ES: *v3_reg = (addr_t)&(info->segments.es); + *reg_len = 8; return SEGMENT_REGISTER; case XED_REG_SS: *v3_reg = (addr_t)&(info->segments.ss); + *reg_len = 8; return SEGMENT_REGISTER; case XED_REG_FS: *v3_reg = (addr_t)&(info->segments.fs); + *reg_len = 8; return SEGMENT_REGISTER; case XED_REG_GS: *v3_reg = (addr_t)&(info->segments.gs); + *reg_len = 8; return SEGMENT_REGISTER; @@ -1236,6 +1269,7 @@ static v3_op_type_t get_opcode(xed_iform_enum_t iform) { return V3_OP_MOVSX; + case XED_IFORM_DEC_MEMv: case XED_IFORM_DEC_MEMb: return V3_OP_DEC; @@ -1324,13 +1358,19 @@ static v3_op_type_t get_opcode(xed_iform_enum_t iform) { case XED_IFORM_SETZ_MEMb: return V3_OP_SETZ; - case XED_IFORM_MOVSB: case XED_IFORM_MOVSW: case XED_IFORM_MOVSD: case XED_IFORM_MOVSQ: return V3_OP_MOVS; + case XED_IFORM_STOSB: + case XED_IFORM_STOSW: + case XED_IFORM_STOSD: + case XED_IFORM_STOSQ: + return V3_OP_STOS; + + default: return V3_INVALID_OP; }