From: Jack Lange Date: Tue, 8 Mar 2011 22:31:39 +0000 (-0600) Subject: more decoder work X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=c44555f7fa9a90c1934f5b74c8fe1dee1c09d325;p=palacios.git more decoder work --- diff --git a/palacios/include/palacios/vmm_decoder.h b/palacios/include/palacios/vmm_decoder.h index a6bee03..7f05064 100644 --- a/palacios/include/palacios/vmm_decoder.h +++ b/palacios/include/palacios/vmm_decoder.h @@ -120,6 +120,8 @@ uint8_t v3_get_prefixes(uint8_t * instr, struct x86_prefixes * prefixes); +void v3_print_instr(struct x86_instr * instr); + #define PREFIX_LOCK 0xF0 #define PREFIX_REPNE 0xF2 diff --git a/palacios/include/palacios/vmm_instr_decoder.h b/palacios/include/palacios/vmm_instr_decoder.h index 207da43..15d6271 100644 --- a/palacios/include/palacios/vmm_instr_decoder.h +++ b/palacios/include/palacios/vmm_instr_decoder.h @@ -345,10 +345,12 @@ struct sib_byte { struct v3_gprs; -static inline int decode_gpr(struct v3_gprs * gprs, +static inline int decode_gpr(struct guest_info * core, uint8_t reg_code, struct x86_operand * reg) { + struct v3_gprs * gprs = &(core->vm_regs); + switch (reg_code) { case 0: reg->operand = (addr_t)&(gprs->rax); @@ -391,14 +393,47 @@ static inline int decode_gpr(struct v3_gprs * gprs, } break; default: + PrintError("Invalid Reg Code (%d)\n", reg_code); reg->operand = 0; - break; + return -1; } return 0; } + + +static inline int decode_cr(struct guest_info * core, + uint8_t reg_code, + struct x86_operand * reg) { + + struct v3_ctrl_regs * crs = &(core->ctrl_regs); + + PrintDebug("\t Ctrl regs %d\n", reg_code); + + switch (reg_code) { + case 0: + reg->operand = (addr_t)&(crs->cr0); + break; + case 2: + reg->operand = (addr_t)&(crs->cr2); + break; + case 3: + reg->operand = (addr_t)&(crs->cr3); + break; + case 4: + reg->operand = (addr_t)&(crs->cr4); + break; + default: + reg->operand = 0; + PrintError("Invalid Reg Code (%d)\n", reg_code); + return -1; + } + + return 0; +} + // This converts the displacement into the appropriate masked value /* QUESTION: Are the register Values signed ????? @@ -413,7 +448,7 @@ static inline int decode_gpr(struct v3_gprs * gprs, val = (sint32_t)(reg & 0xffffffff); \ } else { \ PrintError("Error invalid displacement size (%d)\n", mode); \ - V3_ASSERT(0); \ + /*V3_ASSERT(0);*/ \ } \ val; \ }) @@ -440,7 +475,7 @@ static int decode_rm_operand16(struct guest_info * core, //PrintDebug("first operand = Register (RM=%d)\n",modrm->rm); operand->type = REG_OPERAND; - decode_gpr(gprs, modrm->rm, operand); + decode_gpr(core, modrm->rm, operand); } else { struct v3_segment * seg = NULL; @@ -544,7 +579,7 @@ static int decode_rm_operand32(struct guest_info * core, operand->type = REG_OPERAND; // PrintDebug("first operand = Register (RM=%d)\n",modrm->rm); - decode_gpr(gprs, modrm->rm, operand); + decode_gpr(core, modrm->rm, operand); } else { struct v3_segment * seg = NULL; @@ -1027,3 +1062,114 @@ static op_form_t op_code_to_form(uint8_t * instr, int * length) { return INVALID_INSTR; } } + + + +static char * op_form_to_str(op_form_t form) { + + switch (form) { + case LMSW: return "LMSW"; + case SMSW: return "SMSW"; + case CLTS: return "CLTS"; + case INVLPG: return "INVLPG"; + case MOV_CR2: return "MOV_CR2"; + case MOV_2CR: return "MOV_2CR"; + case MOV_DR2: return "MOV_DR2"; + case MOV_2DR: return "MOV_2DR"; + case MOV_SR2: return "MOV_SR2"; + case MOV_2SR: return "MOV_2SR"; + case MOV_MEM2_8: return "MOV_MEM2_8"; + case MOV_MEM2: return "MOV_MEM2"; + case MOV_2MEM_8: return "MOV_2MEM_8"; + case MOV_2MEM: return "MOV_2MEM"; + case MOV_MEM2AL_8: return "MOV_MEM2AL_8"; + case MOV_MEM2AX: return "MOV_MEM2AX"; + case MOV_AL2MEM_8: return "MOV_AL2MEM_8"; + case MOV_AX2MEM: return "MOV_AX2MEM"; + case MOV_IMM2_8: return "MOV_IMM2_8"; + case MOV_IMM2: return "MOV_IMM2"; + case MOVS_8: return "MOVS_8"; + case MOVS: return "MOVS"; + case MOVSX_8: return "MOVSX_8"; + case MOVSX: return "MOVSX"; + case MOVZX_8: return "MOVZX_8"; + case MOVZX: return "MOVZX"; + case HLT: return "HLT"; + case PUSHF: return "PUSHF"; + case POPF: return "POPF"; + case ADC_2MEM_8: return "ADC_2MEM_8"; + case ADC_2MEM: return "ADC_2MEM"; + case ADC_MEM2_8: return "ADC_MEM2_8"; + case ADC_MEM2: return "ADC_MEM2"; + case ADC_IMM2_8: return "ADC_IMM2_8"; + case ADC_IMM2: return "ADC_IMM2"; + case ADC_IMM2SX_8: return "ADC_IMM2SX_8"; + case ADD_IMM2_8: return "ADD_IMM2_8"; + case ADD_IMM2: return "ADD_IMM2"; + case ADD_IMM2SX_8: return "ADD_IMM2SX_8"; + case ADD_2MEM_8: return "ADD_2MEM_8"; + case ADD_2MEM: return "ADD_2MEM"; + case ADD_MEM2_8: return "ADD_MEM2_8"; + case ADD_MEM2: return "ADD_MEM2"; + case AND_MEM2_8: return "AND_MEM2_8"; + case AND_MEM2: return "AND_MEM2"; + case AND_2MEM_8: return "AND_2MEM_8"; + case AND_2MEM: return "AND_2MEM"; + case AND_IMM2_8: return "AND_IMM2_8"; + case AND_IMM2: return "AND_IMM2"; + case AND_IMM2SX_8: return "AND_IMM2SX_8"; + case OR_2MEM_8: return "OR_2MEM_8"; + case OR_2MEM: return "OR_2MEM"; + case OR_MEM2_8: return "OR_MEM2_8"; + case OR_MEM2: return "OR_MEM2"; + case OR_IMM2_8: return "OR_IMM2_8"; + case OR_IMM2: return "OR_IMM2"; + case OR_IMM2SX_8: return "OR_IMM2SX_8"; + case SUB_2MEM_8: return "SUB_2MEM_8"; + case SUB_2MEM: return "SUB_2MEM"; + case SUB_MEM2_8: return "SUB_MEM2_8"; + case SUB_MEM2: return "SUB_MEM2"; + case SUB_IMM2_8: return "SUB_IMM2_8"; + case SUB_IMM2: return "SUB_IMM2"; + case SUB_IMM2SX_8: return "SUB_IMM2SX_8"; + case XOR_2MEM_8: return "XOR_2MEM_8"; + case XOR_2MEM: return "XOR_2MEM"; + case XOR_MEM2_8: return "XOR_MEM2_8"; + case XOR_MEM2: return "XOR_MEM2"; + case XOR_IMM2_8: return "XOR_IMM2_8"; + case XOR_IMM2: return "XOR_IMM2"; + case XOR_IMM2SX_8: return "XOR_IMM2SX_8"; + case INC_8: return "INC_8"; + case INC: return "INC"; + case DEC_8: return "DEC_8"; + case DEC: return "DEC"; + case NEG_8: return "NEG_8"; + case NEG: return "NEG"; + case NOT_8: return "NOT_8"; + case NOT: return "NOT"; + case XCHG_8: return "XCHG_8"; + case XCHG: return "XCHG"; + case SETB: return "SETB"; + case SETBE: return "SETBE"; + case SETL: return "SETL"; + case SETLE: return "SETLE"; + case SETNB: return "SETNB"; + case SETNBE: return "SETNBE"; + case SETNL: return "SETNL"; + case SETNLE: return "SETNLE"; + case SETNO: return "SETNO"; + case SETNP: return "SETNP"; + case SETNS: return "SETNS"; + case SETNZ: return "SETNZ"; + case SETP: return "SETP"; + case SETS: return "SETS"; + case SETZ: return "SETZ"; + case SETO: return "SETO"; + case STOS_8: return "STOS_8"; + case STOS: return "STOS"; + + case INVALID_INSTR: + default: + return "INVALID_INSTR"; + } +} diff --git a/palacios/src/palacios/vm_guest.c b/palacios/src/palacios/vm_guest.c index 73926cc..7a10e66 100644 --- a/palacios/src/palacios/vm_guest.c +++ b/palacios/src/palacios/vm_guest.c @@ -252,14 +252,14 @@ void v3_print_ctrl_regs(struct guest_info * info) { V3_Print("32 bit Ctrl Regs:\n"); for (i = 0; reg_names[i] != NULL; i++) { - V3_Print("\t%s=0x%p\n", reg_names[i], (void *)(addr_t)reg_ptr[i]); + V3_Print("\t%s=0x%p (at %p)\n", reg_names[i], (void *)(addr_t)reg_ptr[i], &(reg_ptr[i])); } V3_Print("\tEFER=0x%p\n", (void*)(addr_t)(guest_state->efer)); } - +#if 0 static int safe_gva_to_hva(struct guest_info * info, addr_t linear_addr, addr_t * host_addr) { /* select the proper translation based on guest mode */ if (info->mem_mode == PHYSICAL_MEM) { @@ -282,6 +282,8 @@ static int v3_print_disassembly(struct guest_info * info) { /* start disassembly 64 bytes before current RIP, continue 32 bytes after */ rip = (addr_t) info->rip - 64; while ((int) (rip - info->rip) < 32) { + V3_Print("disassembly step\n"); + /* always print RIP, even if the instructions before were bad */ if (!passed_rip && rip >= info->rip) { if (rip != info->rip) { @@ -303,11 +305,13 @@ static int v3_print_disassembly(struct guest_info * info) { rip++; continue; } + } return 0; } +#endif void v3_print_guest_state(struct guest_info * info) { addr_t linear_addr = 0; @@ -334,7 +338,7 @@ void v3_print_guest_state(struct guest_info * info) { v3_print_stack(info); - v3_print_disassembly(info); + // v3_print_disassembly(info); } void v3_print_guest_state_all(struct v3_vm_info * vm) { @@ -410,7 +414,7 @@ void v3_print_GPRs(struct guest_info * info) { V3_Print("32 bit GPRs:\n"); for (i = 0; reg_names[i] != NULL; i++) { - V3_Print("\t%s=0x%p\n", reg_names[i], (void *)(addr_t)reg_ptr[i]); + V3_Print("\t%s=0x%p (at %p)\n", reg_names[i], (void *)(addr_t)reg_ptr[i], &(reg_ptr[i])); } } @@ -428,7 +432,7 @@ void v3_print_GPRs(struct guest_info * info) { V3_Print("64 bit GPRs:\n"); for (i = 0; reg_names[i] != NULL; i++) { - V3_Print("\t%s=0x%p\n", reg_names[i], (void *)(addr_t)reg_ptr[i]); + V3_Print("\t%s=0x%p (at %p)\n", reg_names[i], (void *)(addr_t)reg_ptr[i], &(reg_ptr[i])); } } diff --git a/palacios/src/palacios/vmm_decoder.c b/palacios/src/palacios/vmm_decoder.c index 676fd6d..f70e784 100644 --- a/palacios/src/palacios/vmm_decoder.c +++ b/palacios/src/palacios/vmm_decoder.c @@ -104,3 +104,128 @@ void v3_strip_rep_prefix(uchar_t * instr, int length) { } } } + + +static char * op_type_to_str(v3_op_type_t type) { + switch (type) { + case V3_OP_MOVCR2: return "V3_OP_MOVCR2"; + case V3_OP_MOV2CR: return "V3_OP_MOV2CR"; + case V3_OP_SMSW: return "V3_OP_SMSW"; + case V3_OP_LMSW: return "V3_OP_LMSW"; + case V3_OP_CLTS: return "V3_OP_CLTS"; + case V3_OP_INVLPG: return "V3_OP_INVLPG"; + case V3_OP_ADC: return "V3_OP_ADC"; + case V3_OP_ADD: return "V3_OP_ADD"; + case V3_OP_AND: return "V3_OP_AND"; + case V3_OP_OR: return "V3_OP_OR"; + case V3_OP_XOR: return "V3_OP_XOR"; + case V3_OP_SUB: return "V3_OP_SUB"; + case V3_OP_INC: return "V3_OP_INC"; + case V3_OP_DEC: return "V3_OP_DEC"; + case V3_OP_NEG: return "V3_OP_NEG"; + case V3_OP_MOV: return "V3_OP_MOV"; + case V3_OP_NOT: return "V3_OP_NOT"; + case V3_OP_XCHG: return "V3_OP_XCHG"; + case V3_OP_SETB: return "V3_OP_SETB"; + case V3_OP_SETBE: return "V3_OP_SETBE"; + case V3_OP_SETL: return "V3_OP_SETL"; + case V3_OP_SETLE: return "V3_OP_SETLE"; + case V3_OP_SETNB: return "V3_OP_SETNB"; + case V3_OP_SETNBE: return "V3_OP_SETNBE"; + case V3_OP_SETNL: return "V3_OP_SETNL"; + case V3_OP_SETNLE: return "V3_OP_SETNLE"; + case V3_OP_SETNO: return "V3_OP_SETNO"; + case V3_OP_SETNP: return "V3_OP_SETNP"; + case V3_OP_SETNS: return "V3_OP_SETNS"; + case V3_OP_SETNZ: return "V3_OP_SETNZ"; + case V3_OP_SETO: return "V3_OP_SETO"; + case V3_OP_SETP: return "V3_OP_SETP"; + case V3_OP_SETS: return "V3_OP_SETS"; + case V3_OP_SETZ: return "V3_OP_SETZ"; + case V3_OP_MOVS: return "V3_OP_MOVS"; + case V3_OP_STOS: return "V3_OP_STOS"; + case V3_OP_MOVZX: return "V3_OP_MOVZX"; + case V3_OP_MOVSX: return "V3_OP_MOVSX"; + case V3_INVALID_OP: + default: + return "V3_INVALID_OP"; + } +} + + +static char * operand_type_to_str(v3_operand_type_t op) { + switch (op) { + case REG_OPERAND: return "REG_OPERAND"; + case MEM_OPERAND: return "MEM_OPERAND"; + case IMM_OPERAND: return "IMM_OPERAND"; + default: + return "INVALID_OPERAND"; + } +} + + +static const ullong_t mask_1 = 0x00000000000000ffLL; +static const ullong_t mask_2 = 0x000000000000ffffLL; +static const ullong_t mask_4 = 0x00000000ffffffffLL; +static const ullong_t mask_8 = 0xffffffffffffffffLL; + + +#define MASK(val, length) ({ \ + ullong_t mask = 0x0LL; \ + switch (length) { \ + case 1: \ + mask = mask_1; \ + break; \ + case 2: \ + mask = mask_2; \ + break; \ + case 4: \ + mask = mask_4; \ + break; \ + case 8: \ + mask = mask_8; \ + break; \ + } \ + val & mask; \ + }) + +void v3_print_instr(struct x86_instr * instr) { + V3_Print("Instr: %s (Len: %d)\n", op_type_to_str(instr->op_type), instr->instr_length); + + V3_Print("Prefixes= %x\n", *(uint32_t *)&(instr->prefixes)); + + if (instr->is_str_op) { + V3_Print("String OP (len=%d)\n", (uint32_t)instr->str_op_length); + } + + V3_Print("Number of operands: %d\n", instr->num_operands); + + if (instr->num_operands > 0) { + V3_Print("Src Operand (%s)\n", operand_type_to_str(instr->src_operand.type)); + V3_Print("\tLen=%d (Addr: %p)\n", instr->src_operand.size, + (void *)instr->src_operand.operand); + if (instr->src_operand.type == REG_OPERAND) { + V3_Print("\tVal: %p\n", (void *)MASK(*(uint64_t *)(instr->src_operand.operand), instr->src_operand.size)); + } + } + + if (instr->num_operands > 1) { + V3_Print("Dst Operand (%s)\n", operand_type_to_str(instr->dst_operand.type)); + V3_Print("\tLen=%d (Addr: %p)\n", instr->dst_operand.size, + (void *)instr->dst_operand.operand); + if (instr->dst_operand.type == REG_OPERAND) { + V3_Print("\tVal: %p\n", (void *)MASK(*(uint64_t *)(instr->dst_operand.operand), instr->dst_operand.size)); + } + } + + if (instr->num_operands > 2) { + V3_Print("Third Operand (%s)\n", operand_type_to_str(instr->third_operand.type)); + V3_Print("\tLen=%d (Addr: %p)\n", instr->third_operand.size, + (void *)instr->third_operand.operand); + if (instr->third_operand.type == REG_OPERAND) { + V3_Print("\tVal: %p\n", (void *)MASK(*(uint64_t *)(instr->third_operand.operand), instr->third_operand.size)); + } + } +} + + diff --git a/palacios/src/palacios/vmm_v3dec.c b/palacios/src/palacios/vmm_v3dec.c index d3a59d1..f02d04b 100644 --- a/palacios/src/palacios/vmm_v3dec.c +++ b/palacios/src/palacios/vmm_v3dec.c @@ -54,7 +54,7 @@ static int parse_operands(struct guest_info * core, uint8_t * instr_ptr, struct int v3_disasm(struct guest_info * info, void *instr_ptr, addr_t * rip, int mark) { - return 0; + return -1; } @@ -69,7 +69,7 @@ int v3_deinit_decoder(struct guest_info * core) { int v3_encode(struct guest_info * info, struct x86_instr * instr, uint8_t * instr_buf) { - return 0; + return -1; } @@ -78,6 +78,9 @@ int v3_decode(struct guest_info * core, addr_t instr_ptr, struct x86_instr * ins int ret = 0; int length = 0; + + V3_Print("Decoding Instruction at %p\n", (void *)instr_ptr); + memset(instr, 0, sizeof(struct x86_instr)); // scan for prefixes @@ -89,6 +92,9 @@ int v3_decode(struct guest_info * core, addr_t instr_ptr, struct x86_instr * ins form = op_code_to_form((uint8_t *)(instr_ptr + length), &length); + + V3_Print("\t decoded as (%s)\n", op_form_to_str(form)); + if (form == INVALID_INSTR) { PrintError("Could not find instruction form (%x)\n", *(uint32_t *)(instr_ptr + length)); return -1; @@ -108,6 +114,8 @@ int v3_decode(struct guest_info * core, addr_t instr_ptr, struct x86_instr * ins instr->instr_length += length; + v3_print_instr(instr); + return 0; } @@ -116,11 +124,13 @@ 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, form);; + uint8_t addr_width = get_addr_width(core, instr, form); int ret = 0; uint8_t * instr_start = instr_ptr; + PrintDebug("\tOperand width=%d, Addr width=%d\n", operand_width, addr_width); + switch (form) { case ADC_IMM2_8: case ADD_IMM2_8: @@ -199,7 +209,7 @@ static int parse_operands(struct guest_info * core, uint8_t * instr_ptr, instr->src_operand.type = REG_OPERAND; instr->src_operand.size = operand_width; - decode_gpr(&(core->vm_regs), reg_code, &(instr->src_operand)); + decode_gpr(core, reg_code, &(instr->src_operand)); instr->num_operands = 2; break; @@ -232,7 +242,7 @@ static int parse_operands(struct guest_info * core, uint8_t * instr_ptr, instr->dst_operand.size = operand_width; instr->dst_operand.type = REG_OPERAND; - decode_gpr(&(core->vm_regs), reg_code, &(instr->dst_operand)); + decode_gpr(core, reg_code, &(instr->dst_operand)); instr->num_operands = 2; @@ -277,22 +287,113 @@ static int parse_operands(struct guest_info * core, uint8_t * instr_ptr, } // Source: DS:(E)SI - // Source: ES:(E)DI + // 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->src_operand.type = MEM_OPERAND; - instr->src_operand.size = operand_width; - instr->src_operand.operand = get_addr_linear(core, MASK(core->vm_regs.rdi, addr_width), &(core->segments.es)); + 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->num_operands = 2; break; + + case MOV_2CR: { + uint8_t reg_code = 0; + + instr->src_operand.size = operand_width; + + ret = decode_rm_operand(core, instr_ptr, instr, &(instr->src_operand), + ®_code); + + if (ret == -1) { + PrintError("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->num_operands = 2; + break; + } + case MOV_CR2: { + uint8_t reg_code = 0; + + instr->dst_operand.size = operand_width; + + ret = decode_rm_operand(core, instr_ptr, instr, &(instr->dst_operand), + ®_code); + + if (ret == -1) { + PrintError("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)); + + 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, operand_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->num_operands = 2; + + break; + } + case INVLPG: { + uint8_t reg_code = 0; + + // We use the dst operand here to maintain bug-for-bug compatibility with XED + + instr->dst_operand.size = operand_width; + + ret = decode_rm_operand(core, instr_ptr, instr, &(instr->dst_operand), ®_code); + + if (ret == -1) { + PrintError("Error decoding operand for (%s)\n", op_form_to_str(form)); + return -1; + } + + instr_ptr += ret; + + instr->num_operands = 1; + break; + } + case CLTS: { + // no operands. + break; + + } } default: - PrintError("Invalid Instruction form: %d\n", form); + PrintError("Invalid Instruction form: %s\n", op_form_to_str(form)); return -1; }