Mailing List Archive

Fix SVM instruction decode, fixing problem with gfxboot package.
# HG changeset patch
# User kaf24@firebug.cl.cam.ac.uk
# Node ID 5abf652c4c52ae39c232bde1c298949210b36dfb
# Parent e9d5563c08beee69a3228b0410edc64fe8723b8a
Fix SVM instruction decode, fixing problem with gfxboot package.

Signed-off-by: Tom Woller <thomas.woller@amd.com>

diff -r e9d5563c08be -r 5abf652c4c52 xen/arch/x86/hvm/svm/instrlen.c
--- a/xen/arch/x86/hvm/svm/instrlen.c Tue Feb 21 18:35:34 2006
+++ b/xen/arch/x86/hvm/svm/instrlen.c Tue Feb 21 18:36:00 2006
@@ -2,17 +2,19 @@
* instrlen.c - calculates the instruction length for all operating modes
*
* Travis Betak, travis.betak@amd.com
- * Copyright (c) 2005 AMD
+ * Copyright (c) 2005,2006 AMD
+ * Copyright (c) 2005 Keir Fraser
*
- * Essentially a very, very stripped version of Keir Fraser's work in
- * x86_emulate.c. Used primarily for MMIO.
+ * Essentially a very, very stripped version of Keir Fraser's work in
+ * x86_emulate.c. Used for MMIO.
*/

/*
- * TODO: the way in which we use svm_instrlen is very inefficient as is now
- * stands. it will be worth while to return the actual instruction buffer
- * along with the instruction length since we are getting the instruction length
- * so we know how much of the buffer we need to fetch.
+ * TODO: the way in which we use svm_instrlen is very inefficient as is now
+ * stands. It will be worth while to return the actual instruction buffer
+ * along with the instruction length since one of the reasons we are getting
+ * the instruction length is to know how many instruction bytes we need to
+ * fetch.
*/

#include <xen/config.h>
@@ -22,6 +24,11 @@
#include <asm/regs.h>
#define DPRINTF DPRINTK
#include <asm-x86/x86_emulate.h>
+
+/* read from guest memory */
+extern int inst_copy_from_guest(unsigned char *buf, unsigned long eip,
+ int length);
+extern void svm_dump_inst(unsigned long eip);

/*
* Opcode effective-address decode tables.
@@ -33,98 +40,101 @@
*/

/* Operand sizes: 8-bit operands or specified/overridden size. */
-#define BYTE_OP (1<<0) /* 8-bit operands. */
+#define ByteOp (1<<0) /* 8-bit operands. */
/* Destination operand type. */
-#define IMPLICIT_OPS (1<<1) /* Implicit in opcode. No generic decode. */
-#define DST_REG (2<<1) /* Register operand. */
-#define DST_MEM (3<<1) /* Memory operand. */
-#define DST_MASK (3<<1)
+#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */
+#define DstReg (2<<1) /* Register operand. */
+#define DstMem (3<<1) /* Memory operand. */
+#define DstMask (3<<1)
/* Source operand type. */
-#define SRC_NONE (0<<3) /* No source operand. */
-#define SRC_IMPLICIT (0<<3) /* Source operand is implicit in the opcode. */
-#define SRC_REG (1<<3) /* Register operand. */
-#define SRC_MEM (2<<3) /* Memory operand. */
-#define SRC_IMM (3<<3) /* Immediate operand. */
-#define SRC_IMMBYTE (4<<3) /* 8-bit sign-extended immediate operand. */
-#define SRC_MASK (7<<3)
-/* Generic MODRM decode. */
-#define MODRM (1<<6)
+#define SrcNone (0<<3) /* No source operand. */
+#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */
+#define SrcReg (1<<3) /* Register operand. */
+#define SrcMem (2<<3) /* Memory operand. */
+#define SrcMem16 (3<<3) /* Memory operand (16-bit). */
+#define SrcMem32 (4<<3) /* Memory operand (32-bit). */
+#define SrcImm (5<<3) /* Immediate operand. */
+#define SrcImmByte (6<<3) /* 8-bit sign-extended immediate operand. */
+#define SrcMask (7<<3)
+/* Generic ModRM decode. */
+#define ModRM (1<<6)
/* Destination is only written; never read. */
#define Mov (1<<7)

-static u8 opcode_table[256] = {
+static uint8_t opcode_table[256] = {
/* 0x00 - 0x07 */
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
- BYTE_OP | DST_REG | SRC_MEM | MODRM, DST_REG | SRC_MEM | MODRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
0, 0, 0, 0,
/* 0x08 - 0x0F */
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
- BYTE_OP | DST_REG | SRC_MEM | MODRM, DST_REG | SRC_MEM | MODRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
0, 0, 0, 0,
/* 0x10 - 0x17 */
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
- BYTE_OP | DST_REG | SRC_MEM | MODRM, DST_REG | SRC_MEM | MODRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
0, 0, 0, 0,
/* 0x18 - 0x1F */
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
- BYTE_OP | DST_REG | SRC_MEM | MODRM, DST_REG | SRC_MEM | MODRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
0, 0, 0, 0,
/* 0x20 - 0x27 */
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
- BYTE_OP | DST_REG | SRC_MEM | MODRM, DST_REG | SRC_MEM | MODRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
0, 0, 0, 0,
/* 0x28 - 0x2F */
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
- BYTE_OP | DST_REG | SRC_MEM | MODRM, DST_REG | SRC_MEM | MODRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
0, 0, 0, 0,
/* 0x30 - 0x37 */
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
- BYTE_OP | DST_REG | SRC_MEM | MODRM, DST_REG | SRC_MEM | MODRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
0, 0, 0, 0,
/* 0x38 - 0x3F */
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
- BYTE_OP | DST_REG | SRC_MEM | MODRM, DST_REG | SRC_MEM | MODRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
0, 0, 0, 0,
/* 0x40 - 0x4F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x50 - 0x5F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x60 - 0x6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, DstReg|SrcMem32|ModRM|Mov /* movsxd (x86/64) */,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x70 - 0x7F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x80 - 0x87 */
- BYTE_OP | DST_MEM | SRC_IMM | MODRM, DST_MEM | SRC_IMM | MODRM,
- BYTE_OP | DST_MEM | SRC_IMM | MODRM, DST_MEM | SRC_IMMBYTE | MODRM,
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
+ ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
+ ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
/* 0x88 - 0x8F */
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM,
- BYTE_OP | DST_REG | SRC_MEM | MODRM, DST_REG | SRC_MEM | MODRM,
- 0, 0, 0, DST_MEM | SRC_NONE | MODRM | Mov,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ 0, 0, 0, DstMem|SrcNone|ModRM|Mov,
/* 0x90 - 0x9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xA0 - 0xA7 */
- BYTE_OP | DST_REG | SRC_MEM | Mov, DST_REG | SRC_MEM | Mov,
- BYTE_OP | DST_MEM | SRC_REG | Mov, DST_MEM | SRC_REG | Mov,
- BYTE_OP | IMPLICIT_OPS | Mov, IMPLICIT_OPS | Mov,
- BYTE_OP | IMPLICIT_OPS, IMPLICIT_OPS,
+ ByteOp|DstReg|SrcMem|Mov, DstReg|SrcMem|Mov,
+ ByteOp|DstMem|SrcReg|Mov, DstMem|SrcReg|Mov,
+ ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
+ ByteOp|ImplicitOps, ImplicitOps,
/* 0xA8 - 0xAF */
- 0, 0, BYTE_OP | IMPLICIT_OPS | Mov, IMPLICIT_OPS | Mov,
- BYTE_OP | IMPLICIT_OPS | Mov, IMPLICIT_OPS | Mov,
- BYTE_OP | IMPLICIT_OPS, IMPLICIT_OPS,
+ 0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
+ ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
+ ByteOp|ImplicitOps, ImplicitOps,
/* 0xB0 - 0xBF */
- SRC_IMMBYTE, SRC_IMMBYTE, SRC_IMMBYTE, SRC_IMMBYTE,
- SRC_IMMBYTE, SRC_IMMBYTE, SRC_IMMBYTE, SRC_IMMBYTE,
+ SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
+ SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
0, 0, 0, 0, 0, 0, 0, 0,
/* 0xC0 - 0xC7 */
- BYTE_OP | DST_MEM | SRC_IMM | MODRM, DST_MEM | SRC_IMMBYTE | MODRM, 0, 0,
- 0, 0, BYTE_OP | DST_MEM | SRC_IMM | MODRM, DST_MEM | SRC_IMM | MODRM,
+ ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, 0, 0,
+ 0, 0, ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
/* 0xC8 - 0xCF */
0, 0, 0, 0, 0, 0, 0, 0,
/* 0xD0 - 0xD7 */
- BYTE_OP | DST_MEM | SRC_IMPLICIT | MODRM, DST_MEM | SRC_IMPLICIT | MODRM,
- BYTE_OP | DST_MEM | SRC_IMPLICIT | MODRM, DST_MEM | SRC_IMPLICIT | MODRM,
+ ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
+ ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
0, 0, 0, 0,
/* 0xD8 - 0xDF */
0, 0, 0, 0, 0, 0, 0, 0,
@@ -132,31 +142,31 @@
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xF0 - 0xF7 */
0, 0, 0, 0,
- 0, 0, BYTE_OP | DST_MEM | SRC_NONE | MODRM, DST_MEM | SRC_NONE | MODRM,
+ 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
/* 0xF8 - 0xFF */
0, 0, 0, 0,
- 0, 0, BYTE_OP | DST_MEM | SRC_NONE | MODRM, DST_MEM | SRC_NONE | MODRM
+ 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
};

-static u8 twobyte_table[256] = {
+static uint8_t twobyte_table[256] = {
/* 0x00 - 0x0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IMPLICIT_OPS | MODRM, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0,
/* 0x10 - 0x1F */
- 0, 0, 0, 0, 0, 0, 0, 0, IMPLICIT_OPS | MODRM, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0,
/* 0x20 - 0x2F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x30 - 0x3F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x40 - 0x47 */
- DST_REG | SRC_MEM | MODRM | Mov, DST_REG | SRC_MEM | MODRM | Mov,
- DST_REG | SRC_MEM | MODRM | Mov, DST_REG | SRC_MEM | MODRM | Mov,
- DST_REG | SRC_MEM | MODRM | Mov, DST_REG | SRC_MEM | MODRM | Mov,
- DST_REG | SRC_MEM | MODRM | Mov, DST_REG | SRC_MEM | MODRM | Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
/* 0x48 - 0x4F */
- DST_REG | SRC_MEM | MODRM | Mov, DST_REG | SRC_MEM | MODRM | Mov,
- DST_REG | SRC_MEM | MODRM | Mov, DST_REG | SRC_MEM | MODRM | Mov,
- DST_REG | SRC_MEM | MODRM | Mov, DST_REG | SRC_MEM | MODRM | Mov,
- DST_REG | SRC_MEM | MODRM | Mov, DST_REG | SRC_MEM | MODRM | Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
/* 0x50 - 0x5F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x60 - 0x6F */
@@ -168,20 +178,17 @@
/* 0x90 - 0x9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xA0 - 0xA7 */
- 0, 0, 0, DST_MEM | SRC_REG | MODRM, 0, 0, 0, 0,
+ 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
/* 0xA8 - 0xAF */
- 0, 0, 0, DST_MEM | SRC_REG | MODRM, 0, 0, 0, 0,
+ 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
/* 0xB0 - 0xB7 */
- BYTE_OP | DST_MEM | SRC_REG | MODRM, DST_MEM | SRC_REG | MODRM, 0,
- DST_MEM | SRC_REG | MODRM,
- 0, 0,
- DST_REG | SRC_MEM | MODRM,
- DST_REG | SRC_REG | MODRM,
-
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstMem|SrcReg|ModRM,
+ 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
/* 0xB8 - 0xBF */
- 0, 0, DST_MEM | SRC_IMMBYTE | MODRM, DST_MEM | SRC_REG | MODRM, 0, 0, 0, 0,
+ 0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM,
+ 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
/* 0xC0 - 0xCF */
- 0, 0, 0, 0, 0, 0, 0, IMPLICIT_OPS | MODRM, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xD0 - 0xDF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xE0 - 0xEF */
@@ -189,11 +196,6 @@
/* 0xF0 - 0xFF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
-
-/* read from guest memory */
-extern int inst_copy_from_guest(unsigned char *buf, unsigned long eip,
- int length);
-extern void svm_dump_inst(unsigned long eip);

/*
* insn_fetch - fetch the next 1 to 4 bytes from instruction stream
@@ -219,206 +221,250 @@
(_type)_x; \
})

+
/**
- * get_instruction_length - returns the current instructions length
+ * svn_instrlen - returns the current instructions length
*
* @regs: guest register state
- * @cr2: target address
- * @ops: guest memory operations
* @mode: guest operating mode
*
* EXTERNAL this routine calculates the length of the current instruction
* pointed to by eip. The guest state is _not_ changed by this routine.
*/
-unsigned long svm_instrlen(struct cpu_user_regs *regs, int mode)
+int svm_instrlen(struct cpu_user_regs *regs, int mode)
{
- u8 b, d, twobyte = 0;
- u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
- unsigned int op_bytes = (mode == 8) ? 4 : mode, ad_bytes = mode;
- unsigned int i;
+ uint8_t b, d, twobyte = 0, rex_prefix = 0;
+ uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
+ unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
int rc = 0;
- u32 length = 0;
- u8 tmp;
-
- /* Copy the registers so we don't alter the guest's present state */
- volatile struct cpu_user_regs _regs = *regs;
-
- /* Check for Real Mode */
- if (mode == 2)
- _regs.eip += (_regs.cs << 4);
-
- /* Legacy prefix check */
- for (i = 0; i < 8; i++) {
- switch (b = insn_fetch(u8, 1, _regs.eip, length)) {
- case 0x66: /* operand-size override */
- op_bytes ^= 6; /* switch between 2/4 bytes */
- break;
- case 0x67: /* address-size override */
- ad_bytes ^= (mode == 8) ? 12 : 6; /* 2/4/8 bytes */
- break;
- case 0x2e: /* CS override */
- case 0x3e: /* DS override */
- case 0x26: /* ES override */
- case 0x64: /* FS override */
- case 0x65: /* GS override */
- case 0x36: /* SS override */
- case 0xf0: /* LOCK */
- case 0xf3: /* REP/REPE/REPZ */
- case 0xf2: /* REPNE/REPNZ */
+ int length = 0;
+ unsigned int tmp;
+
+ /* Shadow copy of register state. Committed on successful emulation. */
+ struct cpu_user_regs _regs = *regs;
+
+ /* include CS for 16-bit modes */
+ if (mode == X86EMUL_MODE_REAL || mode == X86EMUL_MODE_PROT16)
+ _regs.eip += (_regs.cs << 4);
+
+ switch ( mode )
+ {
+ case X86EMUL_MODE_REAL:
+ case X86EMUL_MODE_PROT16:
+ op_bytes = ad_bytes = 2;
+ break;
+ case X86EMUL_MODE_PROT32:
+ op_bytes = ad_bytes = 4;
+ break;
+#ifdef __x86_64__
+ case X86EMUL_MODE_PROT64:
+ op_bytes = 4;
+ ad_bytes = 8;
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ /* Legacy prefixes. */
+ for ( i = 0; i < 8; i++ )
+ {
+ switch ( b = insn_fetch(uint8_t, 1, _regs.eip, length) )
+ {
+ case 0x66: /* operand-size override */
+ op_bytes ^= 6; /* switch between 2/4 bytes */
+ break;
+ case 0x67: /* address-size override */
+ if ( mode == X86EMUL_MODE_PROT64 )
+ ad_bytes ^= 12; /* switch between 4/8 bytes */
+ else
+ ad_bytes ^= 6; /* switch between 2/4 bytes */
+ break;
+ case 0x2e: /* CS override */
+ case 0x3e: /* DS override */
+ case 0x26: /* ES override */
+ case 0x64: /* FS override */
+ case 0x65: /* GS override */
+ case 0x36: /* SS override */
+ break;
+ case 0xf0: /* LOCK */
+ lock_prefix = 1;
+ break;
+ case 0xf3: /* REP/REPE/REPZ */
+ rep_prefix = 1;
+ break;
+ case 0xf2: /* REPNE/REPNZ */
break;
default:
goto done_prefixes;
}
}
-
done_prefixes:

- /* REX prefix check */
- if ((mode == 8) && ((b & 0xf0) == 0x40))
- {
- if (b & 8)
- op_bytes = 8; /* REX.W */
- modrm_reg = (b & 4) << 1; /* REX.R */
+ /* Note quite the same as 80386 real mode, but hopefully good enough. */
+ if ( (mode == X86EMUL_MODE_REAL) && (ad_bytes != 2) ) {
+ printf("sonofabitch!! we don't support 32-bit addresses in realmode\n");
+ goto cannot_emulate;
+ }
+
+ /* REX prefix. */
+ if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) )
+ {
+ rex_prefix = b;
+ if ( b & 8 )
+ op_bytes = 8; /* REX.W */
+ modrm_reg = (b & 4) << 1; /* REX.R */
/* REX.B and REX.X do not need to be decoded. */
- b = insn_fetch(u8, 1, _regs.eip, length);
+ b = insn_fetch(uint8_t, 1, _regs.eip, length);
}

/* Opcode byte(s). */
d = opcode_table[b];
- if (d == 0)
+ if ( d == 0 )
{
/* Two-byte opcode? */
- if (b == 0x0f) {
+ if ( b == 0x0f )
+ {
twobyte = 1;
- b = insn_fetch(u8, 1, _regs.eip, length);
+ b = insn_fetch(uint8_t, 1, _regs.eip, length);
d = twobyte_table[b];
}

/* Unrecognised? */
- if (d == 0)
+ if ( d == 0 )
goto cannot_emulate;
}

- /* MODRM and SIB bytes. */
- if (d & MODRM)
- {
- modrm = insn_fetch(u8, 1, _regs.eip, length);
+ /* ModRM and SIB bytes. */
+ if ( d & ModRM )
+ {
+ modrm = insn_fetch(uint8_t, 1, _regs.eip, length);
modrm_mod |= (modrm & 0xc0) >> 6;
modrm_reg |= (modrm & 0x38) >> 3;
- modrm_rm |= (modrm & 0x07);
- switch (modrm_mod)
- {
- case 0:
- if ((modrm_rm == 4) &&
- (((insn_fetch(u8, 1, _regs.eip,
- length)) & 7) == 5))
+ modrm_rm |= (modrm & 0x07);
+
+ if ( modrm_mod == 3 )
+ {
+ DPRINTF("Cannot parse ModRM.mod == 3.\n");
+ goto cannot_emulate;
+ }
+
+ if ( ad_bytes == 2 )
+ {
+ /* 16-bit ModR/M decode. */
+ switch ( modrm_mod )
{
- length += 4;
- _regs.eip += 4; /* skip SIB.base disp32 */
- }
- else if (modrm_rm == 5)
+ case 0:
+ if ( modrm_rm == 6 )
+ {
+ length += 2;
+ _regs.eip += 2; /* skip disp16 */
+ }
+ break;
+ case 1:
+ length += 1;
+ _regs.eip += 1; /* skip disp8 */
+ break;
+ case 2:
+ length += 2;
+ _regs.eip += 2; /* skip disp16 */
+ break;
+ }
+ }
+ else
+ {
+ /* 32/64-bit ModR/M decode. */
+ switch ( modrm_mod )
{
+ case 0:
+ if ( (modrm_rm == 4) &&
+ (((insn_fetch(uint8_t, 1, _regs.eip, length)) & 7)
+ == 5) )
+ {
+ length += 4;
+ _regs.eip += 4; /* skip disp32 specified by SIB.base */
+ }
+ else if ( modrm_rm == 5 )
+ {
+ length += 4;
+ _regs.eip += 4; /* skip disp32 */
+ }
+ break;
+ case 1:
+ if ( modrm_rm == 4 )
+ {
+ insn_fetch(uint8_t, 1, _regs.eip, length);
+ }
+ length += 1;
+ _regs.eip += 1; /* skip disp8 */
+ break;
+ case 2:
+ if ( modrm_rm == 4 )
+ {
+ insn_fetch(uint8_t, 1, _regs.eip, length);
+ }
length += 4;
_regs.eip += 4; /* skip disp32 */
+ break;
}
- break;
- case 1:
- if (modrm_rm == 4)
- {
- insn_fetch(u8, 1, _regs.eip, length);
- }
- length += 1;
- _regs.eip += 1; /* skip disp8 */
- break;
- case 2:
- if (modrm_rm == 4)
- {
- insn_fetch(u8, 1, _regs.eip, length);
- }
- length += 4;
- _regs.eip += 4; /* skip disp32 */
- break;
- case 3:
- DPRINTF("Cannot parse ModRM.mod == 3.\n");
- goto cannot_emulate;
}
}

/* Decode and fetch the destination operand: register or memory. */
- switch (d & DST_MASK)
- {
- case IMPLICIT_OPS:
+ switch ( d & DstMask )
+ {
+ case ImplicitOps:
/* Special instructions do their own operand decoding. */
goto done;
}

- /* Decode and fetch the source operand: register, memory or immediate */
- switch (d & SRC_MASK)
- {
- case SRC_IMM:
- tmp = (d & BYTE_OP) ? 1 : op_bytes;
- if (tmp == 8)
- tmp = 4;
+ /* Decode and fetch the source operand: register, memory or immediate. */
+ switch ( d & SrcMask )
+ {
+ case SrcImm:
+ tmp = (d & ByteOp) ? 1 : op_bytes;
+ if ( tmp == 8 ) tmp = 4;
/* NB. Immediates are sign-extended as necessary. */
- switch (tmp) {
- case 1:
- insn_fetch(s8, 1, _regs.eip, length);
- break;
- case 2:
- insn_fetch(s16, 2, _regs.eip, length);
- break;
- case 4:
- insn_fetch(s32, 4, _regs.eip, length);
- break;
- }
- break;
- case SRC_IMMBYTE:
- insn_fetch(s8, 1, _regs.eip, length);
- break;
- }
-
- if (twobyte)
+ switch ( tmp )
+ {
+ case 1: insn_fetch(int8_t, 1, _regs.eip, length); break;
+ case 2: insn_fetch(int16_t, 2, _regs.eip, length); break;
+ case 4: insn_fetch(int32_t, 4, _regs.eip, length); break;
+ }
+ break;
+ case SrcImmByte:
+ insn_fetch(int8_t, 1, _regs.eip, length);
+ break;
+ }
+
+ if ( twobyte )
goto done;

- switch (b)
- {
- case 0xa0:
- case 0xa1: /* mov */
+ switch ( b )
+ {
+ case 0xa0 ... 0xa1: /* mov */
length += ad_bytes;
- _regs.eip += ad_bytes; /* skip src displacement */
- break;
- case 0xa2:
- case 0xa3: /* mov */
+ _regs.eip += ad_bytes; /* skip src displacement */
+ break;
+ case 0xa2 ... 0xa3: /* mov */
length += ad_bytes;
- _regs.eip += ad_bytes; /* skip dst displacement */
- break;
- case 0xf6:
- case 0xf7: /* Grp3 */
- switch (modrm_reg)
- {
- case 0:
- case 1: /* test */
- /*
- * Special case in Grp3: test has an
- * immediate source operand.
- */
- tmp = (d & BYTE_OP) ? 1 : op_bytes;
- if (tmp == 8)
- tmp = 4;
- switch (tmp)
+ _regs.eip += ad_bytes; /* skip dst displacement */
+ break;
+ case 0xf6 ... 0xf7: /* Grp3 */
+ switch ( modrm_reg )
+ {
+ case 0 ... 1: /* test */
+ /* Special case in Grp3: test has an immediate source operand. */
+ tmp = (d & ByteOp) ? 1 : op_bytes;
+ if ( tmp == 8 ) tmp = 4;
+ switch ( tmp )
{
- case 1:
- insn_fetch(s8, 1, _regs.eip, length);
- break;
- case 2:
- insn_fetch(s16, 2, _regs.eip, length);
- break;
- case 4:
- insn_fetch(s32, 4, _regs.eip, length);
- break;
+ case 1: insn_fetch(int8_t, 1, _regs.eip, length); break;
+ case 2: insn_fetch(int16_t, 2, _regs.eip, length); break;
+ case 4: insn_fetch(int32_t, 4, _regs.eip, length); break;
}
goto done;
- }
+ }
break;
}

@@ -429,5 +475,5 @@
DPRINTF("Cannot emulate %02x at address %lx (eip %lx, mode %d)\n",
b, (unsigned long)_regs.eip, (unsigned long)regs->eip, mode);
svm_dump_inst(_regs.eip);
- return (unsigned long)-1;
+ return -1;
}

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xensource.com
http://lists.xensource.com/xen-changelog