From: Jack Lange <jacklange@cs.pitt.edu>
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),
+					&reg_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),
+					&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));
+
+		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), &reg_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;
     }