X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fvmm_v3dec.c;h=c05aef163cfeea85dafe526f2be35de8a61ee84c;hb=d13fa71cb7a372c39ea92aaa69d74d63d9e0ed8e;hp=78cb8b61292805f6f18bb3598aa0b65ca38079fb;hpb=b3e5aa263c35961c74e0b7ed96b8510e8c6d7d0d;p=palacios.git diff --git a/palacios/src/palacios/vmm_v3dec.c b/palacios/src/palacios/vmm_v3dec.c index 78cb8b6..c05aef1 100644 --- a/palacios/src/palacios/vmm_v3dec.c +++ b/palacios/src/palacios/vmm_v3dec.c @@ -18,802 +18,731 @@ */ #include +#include + +#ifndef V3_CONFIG_DEBUG_DECODER +#undef PrintDebug +#define PrintDebug(fmt, args...) +#endif + + +#define MASK(val, length) ({ \ + uint64_t mask = 0x0LL; \ + switch (length) { \ + case 1: \ + mask = 0x00000000000000ffLL; \ + break; \ + case 2: \ + mask = 0x000000000000ffffLL; \ + break; \ + case 4: \ + mask = 0x00000000ffffffffLL; \ + break; \ + case 8: \ + mask = 0xffffffffffffffffLL; \ + break; \ + } \ + val & mask; \ + }) + +static v3_op_type_t op_form_to_type(op_form_t form); +static int parse_operands(struct guest_info * core, uint8_t * instr_ptr, struct x86_instr * instr, op_form_t form); -/* .... Giant fucking switch tables */ - - - -#define MODRM_MOD(x) (((x) >> 6) & 0x3) -#define MODRM_REG(x) (((x) >> 3) & 0x7) -#define MODRM_RM(x) ((x) & 0x7) - -struct modrm_byte { - uint_t rm : 3; - uint_t reg : 3; - uint_t mod : 2; -} __attribute__((packed)); - - -#define SIB_BASE(x) (((x) >> 6) & 0x3) -#define SIB_INDEX(x) (((x) >> 3) & 0x7) -#define SIB_SCALE(x) ((x) & 0x7) - -struct sib_byte { - uint_t base : 3; - uint_t index : 3; - uint_t scale : 2; -} __attribute__((packed)); - - - - -typedef enum { - INVALID_INSTR, - LMSW, - SMSW, - CLTS, - INVLPG, - - MOV_CR2, - MOV_2CR, - MOV_DR2, - MOV_2DR, - MOV_SR2, - MOV_2SR, - - MOV_2GPR_8, - MOV_2GPR, - MOV_GPR2_8, - MOV_GPR2, - MOV_MEM2AL_8, - MOV_MEM2AX, - MOV_AL2MEM_8, - MOV_AX2MEM, - MOV_IMM2_8, - MOV_IMM2, - - MOVS_8, - MOVS, - MOVSX_8, - MOVSX, - MOVZX_8, - MOVZX, - - HLT, - PUSHF, - POPF, - - ADC_2MEM_8, - ADC_2MEM, - ADC_MEM2_8, - ADC_MEM2, - ADC_IMM2_8, - ADC_IMM2, - ADC_IMM2SX_8, - ADD_IMM2_8, - ADD_IMM2, - ADD_IMM2SX_8, - ADD_2MEM_8, - ADD_2MEM, - ADD_MEM2_8, - ADD_MEM2, - AND_MEM2_8, - AND_MEM2, - AND_2MEM_8, - AND_2MEM, - AND_IMM2_8, - AND_IMM2, - AND_IMM2SX_8, - OR_2MEM_8, - OR_2MEM, - OR_MEM2_8, - OR_MEM2, - OR_IMM2_8, - OR_IMM2, - OR_IMM2SX_8, - SUB_2MEM_8, - SUB_2MEM, - SUB_MEM2_8, - SUB_MEM2, - SUB_IMM2_8, - SUB_IMM2, - SUB_IMM2SX_8, - XOR_2MEM_8, - XOR_2MEM, - XOR_MEM2_8, - XOR_MEM2, - XOR_IMM2_8, - XOR_IMM2, - XOR_IMM2SX_8, - - INC_8, - INC, - DEC_8, - DEC, - NEG_8, - NEG, - NOT_8, - NOT, - XCHG_8, - XCHG, - - SETB, - SETBE, - SETL, - SETLE, - SETNB, - SETNBE, - SETNL, - SETNLE, - SETNO, - SETNP, - SETNS, - SETNZ, - SETP, - SETS, - SETZ, - SETO, - - STOS_8, - STOS -} op_form_t; - -static op_form_t op_code_to_form(uint8_t * instr); - - - -typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_mode_t; -typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t; - - -struct v3_gprs; - -static inline addr_t decode_register(struct v3_gprs * gprs, char reg_code, reg_size_t reg_size) { - addr_t reg_addr; - - switch (reg_code) { - case 0: - reg_addr = (addr_t)&(gprs->rax); - break; - case 1: - reg_addr = (addr_t)&(gprs->rcx); - break; - case 2: - reg_addr = (addr_t)&(gprs->rdx); - break; - case 3: - reg_addr = (addr_t)&(gprs->rbx); - break; - case 4: - if (reg_size == REG8) { - reg_addr = (addr_t)&(gprs->rax) + 1; - } else { - reg_addr = (addr_t)&(gprs->rsp); - } - break; - case 5: - if (reg_size == REG8) { - reg_addr = (addr_t)&(gprs->rcx) + 1; - } else { - reg_addr = (addr_t)&(gprs->rbp); - } - break; - case 6: - if (reg_size == REG8) { - reg_addr = (addr_t)&(gprs->rdx) + 1; - } else { - reg_addr = (addr_t)&(gprs->rsi); - } - break; - case 7: - if (reg_size == REG8) { - reg_addr = (addr_t)&(gprs->rbx) + 1; - } else { - reg_addr = (addr_t)&(gprs->rdi); - } - break; - default: - reg_addr = 0; - break; - } +int v3_disasm(struct guest_info * info, void *instr_ptr, addr_t * rip, int mark) { + return -1; +} + - return reg_addr; +int v3_init_decoder(struct guest_info * core) { + return 0; } +int v3_deinit_decoder(struct guest_info * core) { + return 0; +} -static inline v3_operand_type_t decode_operands16(struct v3_gprs * gprs, // input/output - char * modrm_instr, // input - int * offset, // output - addr_t * first_operand, // output - addr_t * second_operand, // output - reg_size_t reg_size) { // input - - struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr; - addr_t base_addr = 0; - modrm_mode_t mod_mode = 0; - v3_operand_type_t addr_type = INVALID_OPERAND; - char * instr_cursor = modrm_instr; - // PrintDebug("ModRM mod=%d\n", modrm->mod); +int v3_encode(struct guest_info * info, struct x86_instr * instr, uint8_t * instr_buf) { + return -1; +} - instr_cursor += 1; - if (modrm->mod == 3) { - mod_mode = REG; - addr_type = REG_OPERAND; - //PrintDebug("first operand = Register (RM=%d)\n",modrm->rm); +int v3_decode(struct guest_info * core, addr_t instr_ptr, struct x86_instr * instr) { + op_form_t form = INVALID_INSTR; + int ret = 0; + int length = 0; - *first_operand = decode_register(gprs, modrm->rm, reg_size); - } else { + PrintDebug(core->vm_info, core, "Decoding Instruction at %p\n", (void *)instr_ptr); - addr_type = MEM_OPERAND; + memset(instr, 0, sizeof(struct x86_instr)); - if (modrm->mod == 0) { - mod_mode = DISP0; - } else if (modrm->mod == 1) { - mod_mode = DISP8; - } else if (modrm->mod == 2) { - mod_mode = DISP16; - } + // scan for prefixes + length = v3_get_prefixes((uint8_t *)instr_ptr, &(instr->prefixes)); - switch (modrm->rm) { - case 0: - base_addr = gprs->rbx + gprs->rsi; - break; - case 1: - base_addr = gprs->rbx + gprs->rdi; - break; - case 2: - base_addr = gprs->rbp + gprs->rsi; - break; - case 3: - base_addr = gprs->rbp + gprs->rdi; - break; - case 4: - base_addr = gprs->rsi; - break; - case 5: - base_addr = gprs->rdi; - break; - case 6: - if (modrm->mod == 0) { - base_addr = 0; - mod_mode = DISP16; - } else { - base_addr = gprs->rbp; - } - break; - case 7: - base_addr = gprs->rbx; - break; - } + // REX prefix + if (v3_get_vm_cpu_mode(core) == LONG) { + uint8_t prefix = *(uint8_t *)(instr_ptr + length); + if ((prefix & 0xf0) == 0x40) { + instr->prefixes.rex = 1; - if (mod_mode == DISP8) { - base_addr += (uchar_t)*(instr_cursor); - instr_cursor += 1; - } else if (mod_mode == DISP16) { - base_addr += (ushort_t)*(instr_cursor); - instr_cursor += 2; + instr->prefixes.rex_rm = (prefix & 0x01); + instr->prefixes.rex_sib_idx = ((prefix & 0x02) >> 1); + instr->prefixes.rex_reg = ((prefix & 0x04) >> 2); + instr->prefixes.rex_op_size = ((prefix & 0x08) >> 3); + + length += 1; } - - *first_operand = base_addr; } - *offset += (instr_cursor - modrm_instr); - *second_operand = decode_register(gprs, modrm->reg, reg_size); - return addr_type; -} + form = op_code_to_form((uint8_t *)(instr_ptr + length), &length); + PrintDebug(core->vm_info, core, "\t decoded as (%s)\n", op_form_to_str(form)); + if (form == INVALID_INSTR) { + PrintError(core->vm_info, core, "Could not find instruction form (%x)\n", *(uint32_t *)(instr_ptr + length)); + return -1; + } -static inline v3_operand_type_t decode_operands32(struct v3_gprs * gprs, // input/output - uchar_t * modrm_instr, // input - int * offset, // output - addr_t * first_operand, // output - addr_t * second_operand, // output - reg_size_t reg_size) { // input - - uchar_t * instr_cursor = modrm_instr; - struct modrm_byte * modrm = (struct modrm_byte *)modrm_instr; - addr_t base_addr = 0; - modrm_mode_t mod_mode = 0; - uint_t has_sib_byte = 0; - v3_operand_type_t addr_type = INVALID_OPERAND; - + instr->op_type = op_form_to_type(form); + ret = parse_operands(core, (uint8_t *)(instr_ptr + length), instr, form); - instr_cursor += 1; + if (ret == -1) { + PrintError(core->vm_info, core, "Could not parse instruction operands\n"); + return -1; + } + length += ret; - if (modrm->mod == 3) { - mod_mode = REG; - addr_type = REG_OPERAND; - - // PrintDebug("first operand = Register (RM=%d)\n",modrm->rm); + instr->instr_length += length; - *first_operand = decode_register(gprs, modrm->rm, reg_size); +#ifdef V3_CONFIG_DEBUG_DECODER + V3_Print(core->vm_info, core, "Decoding Instr at %p\n", (void *)core->rip); + v3_print_instr(instr); + V3_Print(core->vm_info, core, "CS DB FLag=%x\n", core->segments.cs.db); +#endif - } else { + return 0; +} - addr_type = MEM_OPERAND; - if (modrm->mod == 0) { - mod_mode = DISP0; - } else if (modrm->mod == 1) { - mod_mode = DISP8; - } else if (modrm->mod == 2) { - mod_mode = DISP32; - } +static int parse_operands(struct guest_info * core, uint8_t * instr_ptr, + struct x86_instr * instr, op_form_t form) { + // get operational mode of the guest for operand width + uint8_t operand_width = get_operand_width(core, instr, form); + uint8_t addr_width = get_addr_width(core, instr); + int ret = 0; + uint8_t * instr_start = instr_ptr; - switch (modrm->rm) { - case 0: - base_addr = gprs->rax; - break; - case 1: - base_addr = gprs->rcx; - break; - case 2: - base_addr = gprs->rdx; - break; - case 3: - base_addr = gprs->rbx; - break; - case 4: - has_sib_byte = 1; - break; - case 5: - if (modrm->mod == 0) { - base_addr = 0; - mod_mode = DISP32; - } else { - base_addr = gprs->rbp; - } - break; - case 6: - base_addr = gprs->rsi; - break; - case 7: - base_addr = gprs->rdi; - break; - } - if (has_sib_byte) { - instr_cursor += 1; - struct sib_byte * sib = (struct sib_byte *)(instr_cursor); - int scale = 1; + PrintDebug(core->vm_info, core, "\tOperand width=%d, Addr width=%d\n", operand_width, addr_width); + + switch (form) { + case ADC_IMM2_8: + case ADD_IMM2_8: + case AND_IMM2_8: + case OR_IMM2_8: + case SUB_IMM2_8: + case XOR_IMM2_8: + case MOV_IMM2_8: + case ADC_IMM2: + case ADD_IMM2: + case AND_IMM2: + case OR_IMM2: + case SUB_IMM2: + case XOR_IMM2: + case MOV_IMM2: { + uint8_t reg_code = 0; + + ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), ®_code); + + if (ret == -1) { + PrintError(core->vm_info, core, "Error decoding operand\n"); + return -1; + } + + instr_ptr += ret; - instr_cursor += 1; + instr->src_operand.type = IMM_OPERAND; + instr->src_operand.size = operand_width; - if (sib->scale == 1) { - scale = 2; - } else if (sib->scale == 2) { - scale = 4; - } else if (sib->scale == 3) { - scale = 8; + if (operand_width == 1) { + instr->src_operand.operand = *(uint8_t *)instr_ptr; + } else if (operand_width == 2) { + instr->src_operand.operand = *(uint16_t *)instr_ptr; + } else if (operand_width == 4) { + instr->src_operand.operand = *(uint32_t *)instr_ptr; + } else if (operand_width == 8) { + instr->src_operand.operand = *(sint32_t *)instr_ptr; // This is a special case for sign extended 64bit ops + } else { + PrintError(core->vm_info, core, "Illegal operand width (%d)\n", operand_width); + return -1; } + instr->src_operand.read = 1; + instr->dst_operand.write = 1; - switch (sib->index) { - case 0: - base_addr = gprs->rax; - break; - case 1: - base_addr = gprs->rcx; - break; - case 2: - base_addr = gprs->rdx; - break; - case 3: - base_addr = gprs->rbx; - break; - case 4: - base_addr = 0; - break; - case 5: - base_addr = gprs->rbp; - break; - case 6: - base_addr = gprs->rsi; - break; - case 7: - base_addr = gprs->rdi; - break; - } + instr_ptr += operand_width; - base_addr *= scale; - - - switch (sib->base) { - case 0: - base_addr += gprs->rax; - break; - case 1: - base_addr += gprs->rcx; - break; - case 2: - base_addr += gprs->rdx; - break; - case 3: - base_addr += gprs->rbx; - break; - case 4: - base_addr += gprs->rsp; - break; - case 5: - if (modrm->mod != 0) { - base_addr += gprs->rbp; - } - break; - case 6: - base_addr += gprs->rsi; - break; - case 7: - base_addr += gprs->rdi; - break; + instr->num_operands = 2; + + break; + } + case ADC_2MEM_8: + case ADD_2MEM_8: + case AND_2MEM_8: + case OR_2MEM_8: + case SUB_2MEM_8: + case XOR_2MEM_8: + case MOV_2MEM_8: + case ADC_2MEM: + case ADD_2MEM: + case AND_2MEM: + case OR_2MEM: + case SUB_2MEM: + case XOR_2MEM: + case MOV_2MEM: { + uint8_t reg_code = 0; + + ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), ®_code); + + if (ret == -1) { + PrintError(core->vm_info, core, "Error decoding operand\n"); + return -1; } - } + instr_ptr += ret; + instr->src_operand.type = REG_OPERAND; + instr->src_operand.size = operand_width; - if (mod_mode == DISP8) { - base_addr += (uchar_t)*(instr_cursor); - instr_cursor += 1; - } else if (mod_mode == DISP32) { - base_addr += (uint_t)*(instr_cursor); - instr_cursor += 4; - } - + instr->src_operand.read = 1; + instr->dst_operand.write = 1; - *first_operand = base_addr; - } - *offset += (instr_cursor - modrm_instr); + decode_gpr(core, reg_code, &(instr->src_operand)); - *second_operand = decode_register(gprs, modrm->reg, reg_size); + instr->num_operands = 2; + break; + } + case ADC_MEM2_8: + case ADD_MEM2_8: + case AND_MEM2_8: + case OR_MEM2_8: + case SUB_MEM2_8: + case XOR_MEM2_8: + case MOV_MEM2_8: + case ADC_MEM2: + case ADD_MEM2: + case AND_MEM2: + case OR_MEM2: + case SUB_MEM2: + case XOR_MEM2: + case MOV_MEM2: { + uint8_t reg_code = 0; + + ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand), ®_code); + + if (ret == -1) { + PrintError(core->vm_info, core, "Error decoding operand\n"); + return -1; + } - return addr_type; -} + instr_ptr += ret; + instr->dst_operand.size = operand_width; + instr->dst_operand.type = REG_OPERAND; + decode_gpr(core, reg_code, &(instr->dst_operand)); + instr->src_operand.read = 1; + instr->dst_operand.write = 1; -static inline op_form_t op_code_to_form_0f(uint8_t * instr) { - switch (instr[1]) { - case 0x01: { - struct modrm_byte * modrm = (struct modrm_byte *)&(instr[2]); + instr->num_operands = 2; - switch (modrm->reg) { - case 4: - return SMSW; - case 6: - return LMSW; - case 7: - return INVLPG; - default: - return INVALID_INSTR; + break; + } + case MOV_MEM2AL_8: + case MOV_MEM2AX: { + + /* Use AX for destination operand */ + instr->dst_operand.size = operand_width; + instr->dst_operand.type = REG_OPERAND; + instr->dst_operand.operand = (addr_t)&(core->vm_regs.rax); + instr->dst_operand.write = 1; + + /* Get the correct offset -- (seg + offset) */ + struct v3_segment * src_reg = get_instr_segment(core, instr); + addr_t offset = 0; + + if (addr_width == 2) { + offset = *(uint16_t *)instr_ptr; + } else if (addr_width == 4) { + offset = *(uint32_t *)instr_ptr; + } else if (addr_width == 8) { + offset = *(uint64_t *)instr_ptr; + } else { + PrintError(core->vm_info, core, "illegal address width for %s (width=%d)\n", + op_form_to_str(form), addr_width); + return -1; } + + instr->src_operand.operand = ADDR_MASK(get_addr_linear(core, offset, src_reg), + get_addr_width(core, instr)); + + instr->src_operand.read = 1; + instr->src_operand.type = MEM_OPERAND; + instr->src_operand.size = addr_width; + + instr_ptr += addr_width; + instr->num_operands = 2; + + break; } + case MOV_AL2MEM_8: + case MOV_AX2MEM: { + + /* Use AX for src operand */ + instr->src_operand.size = operand_width; + instr->src_operand.type = REG_OPERAND; + instr->src_operand.operand = (addr_t)&(core->vm_regs.rax); + instr->src_operand.write = 1; + + /* Get the correct offset -- (seg + offset) */ + struct v3_segment * dst_reg = get_instr_segment(core, instr); + addr_t offset = 0; + + if (addr_width == 2) { + offset = *(uint16_t *)instr_ptr; + } else if (addr_width == 4) { + offset = *(uint32_t *)instr_ptr; + } else if (addr_width == 8) { + offset = *(uint64_t *)instr_ptr; + } else { + PrintError(core->vm_info, core, "illegal address width for %s (width=%d)\n", + op_form_to_str(form), addr_width); + return -1; + } - case 0x06: - return CLTS; - case 0x20: - return MOV_CR2; - case 0x21: - return MOV_DR2; - - case 0x22: - return MOV_2CR; - case 0x23: - return MOV_2DR; - - case 0x90: - return SETO; - case 0x91: - return SETNO; - case 0x92: - return SETB; - case 0x93: - return SETNB; - case 0x94: - return SETZ; - case 0x95: - return SETNZ; - case 0x96: - return SETBE; - case 0x97: - return SETNBE; - case 0x98: - return SETS; - case 0x99: - return SETNS; - case 0x9a: - return SETP; - case 0x9b: - return SETNP; - case 0x9c: - return SETL; - case 0x9d: - return SETNL; - case 0x9e: - return SETLE; - case 0x9f: - return SETNLE; - - case 0xb6: - return MOVZX_8; - case 0xb7: - return MOVZX; - - case 0xbe: - return MOVSX_8; - case 0xbf: - return MOVSX; + instr->dst_operand.operand = ADDR_MASK(get_addr_linear(core, offset, dst_reg), + get_addr_width(core, instr)); + instr->dst_operand.read = 1; + instr->dst_operand.type = MEM_OPERAND; + instr->dst_operand.size = addr_width; - default: - return INVALID_INSTR; - } -} + instr_ptr += addr_width; + instr->num_operands = 2; + + break; + } + case MOVSX_8: + case MOVZX_8: { + uint8_t reg_code = 0; + ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand), ®_code); + instr->src_operand.size = 1; -static op_form_t op_code_to_form(uint8_t * instr) { - switch (instr[0]) { - case 0x00: - return ADD_2MEM_8; - case 0x01: - return ADD_2MEM; - case 0x02: - return ADD_MEM2_8; - case 0x03: - return ADD_MEM2; - - case 0x08: - return OR_2MEM_8; - case 0x09: - return OR_2MEM; - case 0x0a: - return OR_MEM2_8; - case 0x0b: - return OR_MEM2; - - - case 0x0f: - return op_code_to_form_0f(instr); - - case 0x10: - return ADC_2MEM_8; - case 0x11: - return ADC_2MEM; - case 0x12: - return ADC_MEM2_8; - case 0x13: - return ADC_MEM2; - - case 0x20: - return AND_2MEM_8; - case 0x21: - return AND_2MEM; - case 0x22: - return AND_MEM2_8; - case 0x23: - return AND_MEM2; - - case 0x28: - return SUB_2MEM_8; - case 0x29: - return SUB_2MEM; - case 0x2a: - return SUB_MEM2_8; - case 0x2b: - return SUB_MEM2; - - - case 0x30: - return XOR_2MEM_8; - case 0x31: - return XOR_2MEM; - case 0x32: - return XOR_MEM2_8; - case 0x33: - return XOR_MEM2; - - case 0x80:{ - struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); - - switch (modrm->reg) { - case 0: - return ADD_IMM2_8; - case 1: - return OR_IMM2_8; - case 2: - return ADC_IMM2_8; - case 4: - return AND_IMM2_8; - case 5: - return SUB_IMM2_8; - case 6: - return XOR_IMM2_8; - default: - return INVALID_INSTR; + if (ret == -1) { + PrintError(core->vm_info, core, "Error decoding operand\n"); + return -1; } + + instr_ptr += ret; + + instr->dst_operand.size = operand_width; + instr->dst_operand.type = REG_OPERAND; + decode_gpr(core, reg_code, &(instr->dst_operand)); + + instr->src_operand.read = 1; + instr->dst_operand.write = 1; + + instr->num_operands = 2; + + break; } - case 0x81: { - struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); - - switch (modrm->reg) { - case 0: - return ADD_IMM2; - case 1: - return OR_IMM2; - case 2: - return ADC_IMM2; - case 4: - return AND_IMM2; - case 5: - return SUB_IMM2; - case 6: - return XOR_IMM2; - default: - return INVALID_INSTR; + case MOVSX: + case MOVZX: { + uint8_t reg_code = 0; + + ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand), ®_code); + instr->src_operand.size = 2; + + if (ret == -1) { + PrintError(core->vm_info, core, "Error decoding operand\n"); + return -1; } + + instr_ptr += ret; + + instr->dst_operand.size = operand_width; + instr->dst_operand.type = REG_OPERAND; + decode_gpr(core, reg_code, &(instr->dst_operand)); + + instr->src_operand.read = 1; + instr->dst_operand.write = 1; + + instr->num_operands = 2; + + break; } - case 0x83: { - struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); - - switch (modrm->reg) { - case 0: - return ADD_IMM2SX_8; - case 1: - return OR_IMM2SX_8; - case 2: - return ADC_IMM2SX_8; - case 4: - return AND_IMM2SX_8; - case 5: - return SUB_IMM2SX_8; - case 6: - return XOR_IMM2SX_8; - default: - return INVALID_INSTR; + case ADC_IMM2SX_8: + case ADD_IMM2SX_8: + case AND_IMM2SX_8: + case OR_IMM2SX_8: + case SUB_IMM2SX_8: + case XOR_IMM2SX_8: { + uint8_t reg_code = 0; + + ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), ®_code); + + if (ret == -1) { + PrintError(core->vm_info, core, "Error decoding operand\n"); + return -1; } - } - case 0x86: - return XCHG_8; - case 0x87: - return XCHG; - case 0x88: - return MOV_2GPR_8; - case 0x89: - return MOV_2GPR; - case 0x8a: - return MOV_GPR2_8; - case 0x8b: - return MOV_GPR2; + instr_ptr += ret; + + instr->src_operand.type = IMM_OPERAND; + instr->src_operand.size = operand_width; + instr->src_operand.operand = (addr_t)MASK((sint64_t)*(sint8_t *)instr_ptr, operand_width); // sign extend. + + instr->src_operand.read = 1; + instr->dst_operand.write = 1; + + instr_ptr += 1; + + instr->num_operands = 2; + + break; + } + case MOVS: + case MOVS_8: { + instr->is_str_op = 1; - case 0x8c: - return MOV_SR2; - case 0x8e: - return MOV_2SR; - - - case 0x9c: - return PUSHF; - case 0x9d: - return POPF; - - case 0xa0: - return MOV_MEM2AL_8; - case 0xa1: - return MOV_MEM2AX; - case 0xa2: - return MOV_AL2MEM_8; - case 0xa3: - return MOV_AX2MEM; - - case 0xa4: - return MOVS_8; - case 0xa5: - return MOVS; - - case 0xaa: - return STOS_8; - case 0xab: - return STOS; - - case 0xc6: - return MOV_IMM2_8; - case 0xc7: - return MOV_IMM2; - - case 0xf4: - return HLT; - - - case 0xf6: { - struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); - - switch (modrm->reg) { - case 2: - return NOT_8; - case 3: - return NEG_8; - default: - return INVALID_INSTR; + if (instr->prefixes.rep == 1) { + instr->str_op_length = MASK(core->vm_regs.rcx, addr_width); + } else { + instr->str_op_length = 1; } + + // Source: DS:(E)SI + // Destination: ES:(E)DI + + instr->src_operand.type = MEM_OPERAND; + instr->src_operand.size = operand_width; + instr->src_operand.operand = get_addr_linear(core, MASK(core->vm_regs.rsi, addr_width), &(core->segments.ds)); + + + instr->dst_operand.type = MEM_OPERAND; + instr->dst_operand.size = operand_width; + instr->dst_operand.operand = get_addr_linear(core, MASK(core->vm_regs.rdi, addr_width), &(core->segments.es)); + + + instr->src_operand.read = 1; + instr->dst_operand.write = 1; + + instr->num_operands = 2; + + break; } - case 0xf7: { - struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); - - switch (modrm->reg) { - case 2: - return NOT; - case 3: - return NEG; - default: - return INVALID_INSTR; + case MOV_2CR: { + uint8_t reg_code = 0; + + ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand), + ®_code); + + if (ret == -1) { + PrintError(core->vm_info, core, "Error decoding operand for (%s)\n", op_form_to_str(form)); + return -1; } + + instr_ptr += ret; + + instr->dst_operand.type = REG_OPERAND; + instr->dst_operand.size = operand_width; + decode_cr(core, reg_code, &(instr->dst_operand)); + + instr->src_operand.read = 1; + instr->dst_operand.write = 1; + + instr->num_operands = 2; + break; } + case MOV_CR2: { + uint8_t reg_code = 0; + + ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), + ®_code); + + if (ret == -1) { + PrintError(core->vm_info, core, "Error decoding operand for (%s)\n", op_form_to_str(form)); + return -1; + } + + instr_ptr += ret; + instr->src_operand.type = REG_OPERAND; + instr->src_operand.size = operand_width; + decode_cr(core, reg_code, &(instr->src_operand)); - case 0xfe: { - struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); + instr->src_operand.read = 1; + instr->dst_operand.write = 1; - switch (modrm->reg) { - case 0: - return INC_8; - case 1: - return DEC_8; - default: - return INVALID_INSTR; + instr->num_operands = 2; + break; + } + case STOS: + case STOS_8: { + instr->is_str_op = 1; + + if (instr->prefixes.rep == 1) { + instr->str_op_length = MASK(core->vm_regs.rcx, addr_width); + } else { + instr->str_op_length = 1; } + + instr->src_operand.size = operand_width; + instr->src_operand.type = REG_OPERAND; + instr->src_operand.operand = (addr_t)&(core->vm_regs.rax); + + instr->dst_operand.type = MEM_OPERAND; + instr->dst_operand.size = operand_width; + instr->dst_operand.operand = get_addr_linear(core, MASK(core->vm_regs.rdi, addr_width), &(core->segments.es)); + + instr->src_operand.read = 1; + instr->dst_operand.write = 1; + + instr->num_operands = 2; + + break; } + case INT: { + instr->dst_operand.type = IMM_OPERAND; + instr->dst_operand.size = operand_width; + instr->dst_operand.operand = *(uint8_t *)instr_ptr; + instr_ptr += operand_width; + instr->num_operands = 1; - case 0xff: { - struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]); + break; + } + case INVLPG: { + uint8_t reg_code = 0; + + ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), ®_code); - switch (modrm->reg) { - case 0: - return INC; - case 1: - return DEC; - default: - return INVALID_INSTR; + if (ret == -1) { + PrintError(core->vm_info, core, "Error decoding operand for (%s)\n", op_form_to_str(form)); + return -1; } - } - default: - return INVALID_INSTR; - } -} + instr_ptr += ret; -int v3_disasm(struct guest_info * info, void *instr_ptr, addr_t * rip, int mark) { - return 0; -} + instr->num_operands = 1; + break; + } + case LMSW: + case SMSW: { + uint8_t reg_code = 0; + ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), ®_code); + if (ret == -1) { + PrintError(core->vm_info, core, "Error decoding operand for (%s)\n", op_form_to_str(form)); + return -1; + } -int v3_init_decoder(struct guest_info * core) { - return 0; -} + instr_ptr += ret; + instr->dst_operand.read = 1; -int v3_deinit_decoder(struct guest_info * core) { - return 0; + instr->num_operands = 1; + break; + } + case CLTS: { + // no operands. + break; + } + default: + PrintError(core->vm_info, core, "Invalid Instruction form: %s\n", op_form_to_str(form)); + return -1; + } + + return (instr_ptr - instr_start); } -int v3_encode(struct guest_info * info, struct x86_instr * instr, char * instr_buf) { - return 0; -} +static v3_op_type_t op_form_to_type(op_form_t form) { + switch (form) { + case LMSW: + return V3_OP_LMSW; + case SMSW: + return V3_OP_SMSW; + case CLTS: + return V3_OP_CLTS; + case INVLPG: + return V3_OP_INVLPG; -int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * instr) { - op_code_to_form((void *)instr_ptr); + case INT: + return V3_OP_INT; + + case MOV_CR2: + return V3_OP_MOVCR2; + case MOV_2CR: + return V3_OP_MOV2CR; + + case MOV_MEM2_8: + case MOV_MEM2: + case MOV_2MEM_8: + case MOV_2MEM: + case MOV_MEM2AL_8: + case MOV_MEM2AX: + case MOV_AL2MEM_8: + case MOV_AX2MEM: + case MOV_IMM2_8: + case MOV_IMM2: + return V3_OP_MOV; + + case MOVS_8: + case MOVS: + return V3_OP_MOVS; + + case MOVSX_8: + case MOVSX: + return V3_OP_MOVSX; + + case MOVZX_8: + case MOVZX: + return V3_OP_MOVZX; + + + case ADC_2MEM_8: + case ADC_2MEM: + case ADC_MEM2_8: + case ADC_MEM2: + case ADC_IMM2_8: + case ADC_IMM2: + case ADC_IMM2SX_8: + return V3_OP_ADC; + + + case ADD_2MEM_8: + case ADD_2MEM: + case ADD_MEM2_8: + case ADD_MEM2: + case ADD_IMM2_8: + case ADD_IMM2: + case ADD_IMM2SX_8: + return V3_OP_ADD; + + case AND_MEM2_8: + case AND_MEM2: + case AND_2MEM_8: + case AND_2MEM: + case AND_IMM2_8: + case AND_IMM2: + case AND_IMM2SX_8: + return V3_OP_AND; + + case OR_2MEM_8: + case OR_2MEM: + case OR_MEM2_8: + case OR_MEM2: + case OR_IMM2_8: + case OR_IMM2: + case OR_IMM2SX_8: + return V3_OP_OR; + + case SUB_2MEM_8: + case SUB_2MEM: + case SUB_MEM2_8: + case SUB_MEM2: + case SUB_IMM2_8: + case SUB_IMM2: + case SUB_IMM2SX_8: + return V3_OP_SUB; + + case XOR_2MEM_8: + case XOR_2MEM: + case XOR_MEM2_8: + case XOR_MEM2: + case XOR_IMM2_8: + case XOR_IMM2: + case XOR_IMM2SX_8: + return V3_OP_XOR; + + case INC_8: + case INC: + return V3_OP_INC; + + case DEC_8: + case DEC: + return V3_OP_DEC; + + case NEG_8: + case NEG: + return V3_OP_NEG; + + case NOT_8: + case NOT: + return V3_OP_NOT; + + case XCHG_8: + case XCHG: + return V3_OP_XCHG; + + case SETB: + return V3_OP_SETB; + case SETBE: + return V3_OP_SETBE; + case SETL: + return V3_OP_SETL; + case SETLE: + return V3_OP_SETLE; + case SETNB: + return V3_OP_SETNB; + case SETNBE: + return V3_OP_SETNBE; + case SETNL: + return V3_OP_SETNL; + case SETNLE: + return V3_OP_SETNLE; + case SETNO: + return V3_OP_SETNO; + case SETNP: + return V3_OP_SETNP; + case SETNS: + return V3_OP_SETNS; + case SETNZ: + return V3_OP_SETNZ; + case SETP: + return V3_OP_SETP; + case SETS: + return V3_OP_SETS; + case SETZ: + return V3_OP_SETZ; + case SETO: + return V3_OP_SETO; + + case STOS_8: + case STOS: + return V3_OP_STOS; + + case HLT: + case PUSHF: + case POPF: + case MOV_DR2: + case MOV_2DR: + case MOV_SR2: + case MOV_2SR: - return 0; + default: + return V3_INVALID_OP; + + } }