Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel' of ssh://newskysaw.cs.northwestern.edu/home/palacios/palacios...
[palacios.git] / palacios / src / palacios / vmm_v3dec.c
index 78cb8b6..343be38 100644 (file)
  */
 
 #include <palacios/vmm_decoder.h>
+#include <palacios/vmm_instr_decoder.h>
+
+#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;
+int v3_encode(struct guest_info * info, struct x86_instr * instr, uint8_t * instr_buf) {
+    return -1;
+}
 
-    //  PrintDebug("ModRM mod=%d\n", modrm->mod);
 
-    instr_cursor += 1;
+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;
 
-    if (modrm->mod == 3) {
-       mod_mode = REG;
-       addr_type = REG_OPERAND;
-       //PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
 
-       *first_operand = decode_register(gprs, modrm->rm, reg_size);
+    PrintDebug("Decoding Instruction at %p\n", (void *)instr_ptr);
 
-    } else {
+    memset(instr, 0, sizeof(struct x86_instr));
 
-       addr_type = MEM_OPERAND;
+    // scan for prefixes
+    length = v3_get_prefixes((uint8_t *)instr_ptr, &(instr->prefixes));
 
-       if (modrm->mod == 0) {
-           mod_mode = DISP0;
-       } else if (modrm->mod == 1) {
-           mod_mode = DISP8;
-       } else if (modrm->mod == 2) {
-           mod_mode = DISP16;
-       }
 
-       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;
 
+           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);
 
-       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;
+           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("\t decoded as (%s)\n", op_form_to_str(form));
 
-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;
+    if (form == INVALID_INSTR) {
+       PrintError("Could not find instruction form (%x)\n", *(uint32_t *)(instr_ptr + length));
+       return -1;
+    }
 
+    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("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("Decoding Instr at %p\n", (void *)core->rip);
+    v3_print_instr(instr);
+    V3_Print("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("\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), &reg_code);
+
+           if (ret == -1) {
+               PrintError("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("Illegal operand width (%d)\n", operand_width);
+               return -1;
            }
 
+           instr->src_operand.read = 1;
+           instr->dst_operand.write = 1;
+
+           instr_ptr += operand_width;
 
-           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->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), &reg_code);
+
+           if (ret == -1) {
+               PrintError("Error decoding operand\n");
+               return -1;
            }
 
-           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_ptr += ret;
+
+           instr->src_operand.type = REG_OPERAND;
+           instr->src_operand.size = operand_width;
+
+           instr->src_operand.read = 1;
+           instr->dst_operand.write = 1;
+
+
+           decode_gpr(core, reg_code, &(instr->src_operand));
+
+           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), &reg_code);
+
+           if (ret == -1) {
+               PrintError("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;
 
-       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;
+           break;
        }
-    
+       case MOVSX_8:
+       case MOVZX_8: {
+           uint8_t reg_code = 0;
 
-       *first_operand = base_addr;
-    }
+           ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand), &reg_code);
+           instr->src_operand.size = 1;
+
+           if (ret == -1) {
+               PrintError("Error decoding operand\n");
+               return -1;
+           }
 
-    *offset += (instr_cursor - modrm_instr);
+           instr_ptr += ret;
 
-    *second_operand = decode_register(gprs, modrm->reg, reg_size);
+           instr->dst_operand.size = operand_width;
+           instr->dst_operand.type = REG_OPERAND;
+           decode_gpr(core, reg_code, &(instr->dst_operand));
 
-    return addr_type;
-}
+           instr->src_operand.read = 1;
+           instr->dst_operand.write = 1;
 
+           instr->num_operands = 2;
 
+           break;
+       }
+       case MOVSX:
+       case MOVZX: {
+           uint8_t reg_code = 0;
 
-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]);
+           ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand), &reg_code);
+           instr->src_operand.size = 2;
 
-           switch (modrm->reg) {
-               case 4:
-                   return SMSW;
-               case 6:
-                   return LMSW;
-               case 7:
-                   return INVLPG;
-               default:
-                   return INVALID_INSTR;
+           if (ret == -1) {
+               PrintError("Error decoding operand\n");
+               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_ptr += ret;
 
-       default:
-           return INVALID_INSTR;
-    }
-}
+           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 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;
+           instr->num_operands = 2;
+
+           break;
+       }
+       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), &reg_code);
+
+           if (ret == -1) {
+               PrintError("Error decoding operand\n");
+               return -1;
            }
+
+           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 0x81: {
-           struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
+       case MOVS:
+       case MOVS_8: {
+           instr->is_str_op = 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;
+           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 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 MOV_2CR: {
+           uint8_t reg_code = 0;
+           
+           ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand),
+                                   &reg_code);
+
+           if (ret == -1) {
+               PrintError("Error decoding operand for (%s)\n", op_form_to_str(form));
+               return -1;
            }
-       }
+               
+           instr_ptr += ret;
 
-       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->dst_operand.type = REG_OPERAND;
+           instr->dst_operand.size = operand_width;
+           decode_cr(core, reg_code, &(instr->dst_operand));
            
-       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;
-           }
+           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_CR2: {
+           uint8_t reg_code = 0;
+           
+           ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand),
+                                   &reg_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));
 
-       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;
+
+           break;
        }
+       case INVLPG: {
+           uint8_t reg_code = 0;
 
-       case 0xff: {
-           struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
+           ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), &reg_code);
 
-           switch (modrm->reg) {
-               case 0:
-                   return INC;
-               case 1:
-                   return DEC;
-               default:
-                   return INVALID_INSTR;
+           if (ret == -1) {
+               PrintError("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), &reg_code);
 
+           if (ret == -1) {
+               PrintError("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("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;
+
+    }
 }