mirror of https://gitee.com/openkylin/linux.git
KVM: x86 emulator: move x86_decode_insn() downwards
No code changes. Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
parent
ef65c88912
commit
dde7e6d12a
|
@ -945,378 +945,6 @@ static int decode_abs(struct x86_emulate_ctxt *ctxt,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
x86_decode_insn(struct x86_emulate_ctxt *ctxt)
|
|
||||||
{
|
|
||||||
struct x86_emulate_ops *ops = ctxt->ops;
|
|
||||||
struct decode_cache *c = &ctxt->decode;
|
|
||||||
int rc = X86EMUL_CONTINUE;
|
|
||||||
int mode = ctxt->mode;
|
|
||||||
int def_op_bytes, def_ad_bytes, dual, goffset;
|
|
||||||
struct opcode opcode, *g_mod012, *g_mod3;
|
|
||||||
|
|
||||||
/* we cannot decode insn before we complete previous rep insn */
|
|
||||||
WARN_ON(ctxt->restart);
|
|
||||||
|
|
||||||
c->eip = ctxt->eip;
|
|
||||||
c->fetch.start = c->fetch.end = c->eip;
|
|
||||||
ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
|
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case X86EMUL_MODE_REAL:
|
|
||||||
case X86EMUL_MODE_VM86:
|
|
||||||
case X86EMUL_MODE_PROT16:
|
|
||||||
def_op_bytes = def_ad_bytes = 2;
|
|
||||||
break;
|
|
||||||
case X86EMUL_MODE_PROT32:
|
|
||||||
def_op_bytes = def_ad_bytes = 4;
|
|
||||||
break;
|
|
||||||
#ifdef CONFIG_X86_64
|
|
||||||
case X86EMUL_MODE_PROT64:
|
|
||||||
def_op_bytes = 4;
|
|
||||||
def_ad_bytes = 8;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->op_bytes = def_op_bytes;
|
|
||||||
c->ad_bytes = def_ad_bytes;
|
|
||||||
|
|
||||||
/* Legacy prefixes. */
|
|
||||||
for (;;) {
|
|
||||||
switch (c->b = insn_fetch(u8, 1, c->eip)) {
|
|
||||||
case 0x66: /* operand-size override */
|
|
||||||
/* switch between 2/4 bytes */
|
|
||||||
c->op_bytes = def_op_bytes ^ 6;
|
|
||||||
break;
|
|
||||||
case 0x67: /* address-size override */
|
|
||||||
if (mode == X86EMUL_MODE_PROT64)
|
|
||||||
/* switch between 4/8 bytes */
|
|
||||||
c->ad_bytes = def_ad_bytes ^ 12;
|
|
||||||
else
|
|
||||||
/* switch between 2/4 bytes */
|
|
||||||
c->ad_bytes = def_ad_bytes ^ 6;
|
|
||||||
break;
|
|
||||||
case 0x26: /* ES override */
|
|
||||||
case 0x2e: /* CS override */
|
|
||||||
case 0x36: /* SS override */
|
|
||||||
case 0x3e: /* DS override */
|
|
||||||
set_seg_override(c, (c->b >> 3) & 3);
|
|
||||||
break;
|
|
||||||
case 0x64: /* FS override */
|
|
||||||
case 0x65: /* GS override */
|
|
||||||
set_seg_override(c, c->b & 7);
|
|
||||||
break;
|
|
||||||
case 0x40 ... 0x4f: /* REX */
|
|
||||||
if (mode != X86EMUL_MODE_PROT64)
|
|
||||||
goto done_prefixes;
|
|
||||||
c->rex_prefix = c->b;
|
|
||||||
continue;
|
|
||||||
case 0xf0: /* LOCK */
|
|
||||||
c->lock_prefix = 1;
|
|
||||||
break;
|
|
||||||
case 0xf2: /* REPNE/REPNZ */
|
|
||||||
c->rep_prefix = REPNE_PREFIX;
|
|
||||||
break;
|
|
||||||
case 0xf3: /* REP/REPE/REPZ */
|
|
||||||
c->rep_prefix = REPE_PREFIX;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto done_prefixes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Any legacy prefix after a REX prefix nullifies its effect. */
|
|
||||||
|
|
||||||
c->rex_prefix = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
done_prefixes:
|
|
||||||
|
|
||||||
/* REX prefix. */
|
|
||||||
if (c->rex_prefix)
|
|
||||||
if (c->rex_prefix & 8)
|
|
||||||
c->op_bytes = 8; /* REX.W */
|
|
||||||
|
|
||||||
/* Opcode byte(s). */
|
|
||||||
opcode = opcode_table[c->b];
|
|
||||||
if (opcode.flags == 0) {
|
|
||||||
/* Two-byte opcode? */
|
|
||||||
if (c->b == 0x0f) {
|
|
||||||
c->twobyte = 1;
|
|
||||||
c->b = insn_fetch(u8, 1, c->eip);
|
|
||||||
opcode = twobyte_table[c->b];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c->d = opcode.flags;
|
|
||||||
|
|
||||||
if (c->d & Group) {
|
|
||||||
dual = c->d & GroupDual;
|
|
||||||
c->modrm = insn_fetch(u8, 1, c->eip);
|
|
||||||
--c->eip;
|
|
||||||
|
|
||||||
if (c->d & GroupDual) {
|
|
||||||
g_mod012 = opcode.u.gdual->mod012;
|
|
||||||
g_mod3 = opcode.u.gdual->mod3;
|
|
||||||
} else
|
|
||||||
g_mod012 = g_mod3 = opcode.u.group;
|
|
||||||
|
|
||||||
c->d &= ~(Group | GroupDual);
|
|
||||||
|
|
||||||
goffset = (c->modrm >> 3) & 7;
|
|
||||||
|
|
||||||
if ((c->modrm >> 6) == 3)
|
|
||||||
opcode = g_mod3[goffset];
|
|
||||||
else
|
|
||||||
opcode = g_mod012[goffset];
|
|
||||||
c->d |= opcode.flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->execute = opcode.u.execute;
|
|
||||||
|
|
||||||
/* Unrecognised? */
|
|
||||||
if (c->d == 0 || (c->d & Undefined)) {
|
|
||||||
DPRINTF("Cannot emulate %02x\n", c->b);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack))
|
|
||||||
c->op_bytes = 8;
|
|
||||||
|
|
||||||
/* ModRM and SIB bytes. */
|
|
||||||
if (c->d & ModRM)
|
|
||||||
rc = decode_modrm(ctxt, ops);
|
|
||||||
else if (c->d & MemAbs)
|
|
||||||
rc = decode_abs(ctxt, ops);
|
|
||||||
if (rc != X86EMUL_CONTINUE)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (!c->has_seg_override)
|
|
||||||
set_seg_override(c, VCPU_SREG_DS);
|
|
||||||
|
|
||||||
if (!(!c->twobyte && c->b == 0x8d))
|
|
||||||
c->modrm_ea += seg_override_base(ctxt, ops, c);
|
|
||||||
|
|
||||||
if (c->ad_bytes != 8)
|
|
||||||
c->modrm_ea = (u32)c->modrm_ea;
|
|
||||||
|
|
||||||
if (c->rip_relative)
|
|
||||||
c->modrm_ea += c->eip;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decode and fetch the source operand: register, memory
|
|
||||||
* or immediate.
|
|
||||||
*/
|
|
||||||
switch (c->d & SrcMask) {
|
|
||||||
case SrcNone:
|
|
||||||
break;
|
|
||||||
case SrcReg:
|
|
||||||
decode_register_operand(&c->src, c, 0);
|
|
||||||
break;
|
|
||||||
case SrcMem16:
|
|
||||||
c->src.bytes = 2;
|
|
||||||
goto srcmem_common;
|
|
||||||
case SrcMem32:
|
|
||||||
c->src.bytes = 4;
|
|
||||||
goto srcmem_common;
|
|
||||||
case SrcMem:
|
|
||||||
c->src.bytes = (c->d & ByteOp) ? 1 :
|
|
||||||
c->op_bytes;
|
|
||||||
/* Don't fetch the address for invlpg: it could be unmapped. */
|
|
||||||
if (c->twobyte && c->b == 0x01 && c->modrm_reg == 7)
|
|
||||||
break;
|
|
||||||
srcmem_common:
|
|
||||||
/*
|
|
||||||
* For instructions with a ModR/M byte, switch to register
|
|
||||||
* access if Mod = 3.
|
|
||||||
*/
|
|
||||||
if ((c->d & ModRM) && c->modrm_mod == 3) {
|
|
||||||
c->src.type = OP_REG;
|
|
||||||
c->src.val = c->modrm_val;
|
|
||||||
c->src.ptr = c->modrm_ptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
c->src.type = OP_MEM;
|
|
||||||
c->src.ptr = (unsigned long *)c->modrm_ea;
|
|
||||||
c->src.val = 0;
|
|
||||||
break;
|
|
||||||
case SrcImm:
|
|
||||||
case SrcImmU:
|
|
||||||
c->src.type = OP_IMM;
|
|
||||||
c->src.ptr = (unsigned long *)c->eip;
|
|
||||||
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
|
||||||
if (c->src.bytes == 8)
|
|
||||||
c->src.bytes = 4;
|
|
||||||
/* NB. Immediates are sign-extended as necessary. */
|
|
||||||
switch (c->src.bytes) {
|
|
||||||
case 1:
|
|
||||||
c->src.val = insn_fetch(s8, 1, c->eip);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
c->src.val = insn_fetch(s16, 2, c->eip);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
c->src.val = insn_fetch(s32, 4, c->eip);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((c->d & SrcMask) == SrcImmU) {
|
|
||||||
switch (c->src.bytes) {
|
|
||||||
case 1:
|
|
||||||
c->src.val &= 0xff;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
c->src.val &= 0xffff;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
c->src.val &= 0xffffffff;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SrcImmByte:
|
|
||||||
case SrcImmUByte:
|
|
||||||
c->src.type = OP_IMM;
|
|
||||||
c->src.ptr = (unsigned long *)c->eip;
|
|
||||||
c->src.bytes = 1;
|
|
||||||
if ((c->d & SrcMask) == SrcImmByte)
|
|
||||||
c->src.val = insn_fetch(s8, 1, c->eip);
|
|
||||||
else
|
|
||||||
c->src.val = insn_fetch(u8, 1, c->eip);
|
|
||||||
break;
|
|
||||||
case SrcAcc:
|
|
||||||
c->src.type = OP_REG;
|
|
||||||
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
|
||||||
c->src.ptr = &c->regs[VCPU_REGS_RAX];
|
|
||||||
switch (c->src.bytes) {
|
|
||||||
case 1:
|
|
||||||
c->src.val = *(u8 *)c->src.ptr;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
c->src.val = *(u16 *)c->src.ptr;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
c->src.val = *(u32 *)c->src.ptr;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
c->src.val = *(u64 *)c->src.ptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SrcOne:
|
|
||||||
c->src.bytes = 1;
|
|
||||||
c->src.val = 1;
|
|
||||||
break;
|
|
||||||
case SrcSI:
|
|
||||||
c->src.type = OP_MEM;
|
|
||||||
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
|
||||||
c->src.ptr = (unsigned long *)
|
|
||||||
register_address(c, seg_override_base(ctxt, ops, c),
|
|
||||||
c->regs[VCPU_REGS_RSI]);
|
|
||||||
c->src.val = 0;
|
|
||||||
break;
|
|
||||||
case SrcImmFAddr:
|
|
||||||
c->src.type = OP_IMM;
|
|
||||||
c->src.ptr = (unsigned long *)c->eip;
|
|
||||||
c->src.bytes = c->op_bytes + 2;
|
|
||||||
insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
|
|
||||||
break;
|
|
||||||
case SrcMemFAddr:
|
|
||||||
c->src.type = OP_MEM;
|
|
||||||
c->src.ptr = (unsigned long *)c->modrm_ea;
|
|
||||||
c->src.bytes = c->op_bytes + 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decode and fetch the second source operand: register, memory
|
|
||||||
* or immediate.
|
|
||||||
*/
|
|
||||||
switch (c->d & Src2Mask) {
|
|
||||||
case Src2None:
|
|
||||||
break;
|
|
||||||
case Src2CL:
|
|
||||||
c->src2.bytes = 1;
|
|
||||||
c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8;
|
|
||||||
break;
|
|
||||||
case Src2ImmByte:
|
|
||||||
c->src2.type = OP_IMM;
|
|
||||||
c->src2.ptr = (unsigned long *)c->eip;
|
|
||||||
c->src2.bytes = 1;
|
|
||||||
c->src2.val = insn_fetch(u8, 1, c->eip);
|
|
||||||
break;
|
|
||||||
case Src2One:
|
|
||||||
c->src2.bytes = 1;
|
|
||||||
c->src2.val = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decode and fetch the destination operand: register or memory. */
|
|
||||||
switch (c->d & DstMask) {
|
|
||||||
case ImplicitOps:
|
|
||||||
/* Special instructions do their own operand decoding. */
|
|
||||||
return 0;
|
|
||||||
case DstReg:
|
|
||||||
decode_register_operand(&c->dst, c,
|
|
||||||
c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
|
|
||||||
break;
|
|
||||||
case DstMem:
|
|
||||||
case DstMem64:
|
|
||||||
if ((c->d & ModRM) && c->modrm_mod == 3) {
|
|
||||||
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
|
||||||
c->dst.type = OP_REG;
|
|
||||||
c->dst.val = c->dst.orig_val = c->modrm_val;
|
|
||||||
c->dst.ptr = c->modrm_ptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
c->dst.type = OP_MEM;
|
|
||||||
c->dst.ptr = (unsigned long *)c->modrm_ea;
|
|
||||||
if ((c->d & DstMask) == DstMem64)
|
|
||||||
c->dst.bytes = 8;
|
|
||||||
else
|
|
||||||
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
|
||||||
c->dst.val = 0;
|
|
||||||
if (c->d & BitOp) {
|
|
||||||
unsigned long mask = ~(c->dst.bytes * 8 - 1);
|
|
||||||
|
|
||||||
c->dst.ptr = (void *)c->dst.ptr +
|
|
||||||
(c->src.val & mask) / 8;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DstAcc:
|
|
||||||
c->dst.type = OP_REG;
|
|
||||||
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
|
||||||
c->dst.ptr = &c->regs[VCPU_REGS_RAX];
|
|
||||||
switch (c->dst.bytes) {
|
|
||||||
case 1:
|
|
||||||
c->dst.val = *(u8 *)c->dst.ptr;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
c->dst.val = *(u16 *)c->dst.ptr;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
c->dst.val = *(u32 *)c->dst.ptr;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
c->dst.val = *(u64 *)c->dst.ptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
c->dst.orig_val = c->dst.val;
|
|
||||||
break;
|
|
||||||
case DstDI:
|
|
||||||
c->dst.type = OP_MEM;
|
|
||||||
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
|
||||||
c->dst.ptr = (unsigned long *)
|
|
||||||
register_address(c, es_base(ctxt, ops),
|
|
||||||
c->regs[VCPU_REGS_RDI]);
|
|
||||||
c->dst.val = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_emulated(struct x86_emulate_ctxt *ctxt,
|
static int read_emulated(struct x86_emulate_ctxt *ctxt,
|
||||||
struct x86_emulate_ops *ops,
|
struct x86_emulate_ops *ops,
|
||||||
unsigned long addr, void *dest, unsigned size)
|
unsigned long addr, void *dest, unsigned size)
|
||||||
|
@ -2624,6 +2252,378 @@ static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned long base,
|
||||||
op->ptr = (unsigned long *)register_address(c, base, c->regs[reg]);
|
op->ptr = (unsigned long *)register_address(c, base, c->regs[reg]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
x86_decode_insn(struct x86_emulate_ctxt *ctxt)
|
||||||
|
{
|
||||||
|
struct x86_emulate_ops *ops = ctxt->ops;
|
||||||
|
struct decode_cache *c = &ctxt->decode;
|
||||||
|
int rc = X86EMUL_CONTINUE;
|
||||||
|
int mode = ctxt->mode;
|
||||||
|
int def_op_bytes, def_ad_bytes, dual, goffset;
|
||||||
|
struct opcode opcode, *g_mod012, *g_mod3;
|
||||||
|
|
||||||
|
/* we cannot decode insn before we complete previous rep insn */
|
||||||
|
WARN_ON(ctxt->restart);
|
||||||
|
|
||||||
|
c->eip = ctxt->eip;
|
||||||
|
c->fetch.start = c->fetch.end = c->eip;
|
||||||
|
ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case X86EMUL_MODE_REAL:
|
||||||
|
case X86EMUL_MODE_VM86:
|
||||||
|
case X86EMUL_MODE_PROT16:
|
||||||
|
def_op_bytes = def_ad_bytes = 2;
|
||||||
|
break;
|
||||||
|
case X86EMUL_MODE_PROT32:
|
||||||
|
def_op_bytes = def_ad_bytes = 4;
|
||||||
|
break;
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
case X86EMUL_MODE_PROT64:
|
||||||
|
def_op_bytes = 4;
|
||||||
|
def_ad_bytes = 8;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->op_bytes = def_op_bytes;
|
||||||
|
c->ad_bytes = def_ad_bytes;
|
||||||
|
|
||||||
|
/* Legacy prefixes. */
|
||||||
|
for (;;) {
|
||||||
|
switch (c->b = insn_fetch(u8, 1, c->eip)) {
|
||||||
|
case 0x66: /* operand-size override */
|
||||||
|
/* switch between 2/4 bytes */
|
||||||
|
c->op_bytes = def_op_bytes ^ 6;
|
||||||
|
break;
|
||||||
|
case 0x67: /* address-size override */
|
||||||
|
if (mode == X86EMUL_MODE_PROT64)
|
||||||
|
/* switch between 4/8 bytes */
|
||||||
|
c->ad_bytes = def_ad_bytes ^ 12;
|
||||||
|
else
|
||||||
|
/* switch between 2/4 bytes */
|
||||||
|
c->ad_bytes = def_ad_bytes ^ 6;
|
||||||
|
break;
|
||||||
|
case 0x26: /* ES override */
|
||||||
|
case 0x2e: /* CS override */
|
||||||
|
case 0x36: /* SS override */
|
||||||
|
case 0x3e: /* DS override */
|
||||||
|
set_seg_override(c, (c->b >> 3) & 3);
|
||||||
|
break;
|
||||||
|
case 0x64: /* FS override */
|
||||||
|
case 0x65: /* GS override */
|
||||||
|
set_seg_override(c, c->b & 7);
|
||||||
|
break;
|
||||||
|
case 0x40 ... 0x4f: /* REX */
|
||||||
|
if (mode != X86EMUL_MODE_PROT64)
|
||||||
|
goto done_prefixes;
|
||||||
|
c->rex_prefix = c->b;
|
||||||
|
continue;
|
||||||
|
case 0xf0: /* LOCK */
|
||||||
|
c->lock_prefix = 1;
|
||||||
|
break;
|
||||||
|
case 0xf2: /* REPNE/REPNZ */
|
||||||
|
c->rep_prefix = REPNE_PREFIX;
|
||||||
|
break;
|
||||||
|
case 0xf3: /* REP/REPE/REPZ */
|
||||||
|
c->rep_prefix = REPE_PREFIX;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto done_prefixes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Any legacy prefix after a REX prefix nullifies its effect. */
|
||||||
|
|
||||||
|
c->rex_prefix = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
done_prefixes:
|
||||||
|
|
||||||
|
/* REX prefix. */
|
||||||
|
if (c->rex_prefix)
|
||||||
|
if (c->rex_prefix & 8)
|
||||||
|
c->op_bytes = 8; /* REX.W */
|
||||||
|
|
||||||
|
/* Opcode byte(s). */
|
||||||
|
opcode = opcode_table[c->b];
|
||||||
|
if (opcode.flags == 0) {
|
||||||
|
/* Two-byte opcode? */
|
||||||
|
if (c->b == 0x0f) {
|
||||||
|
c->twobyte = 1;
|
||||||
|
c->b = insn_fetch(u8, 1, c->eip);
|
||||||
|
opcode = twobyte_table[c->b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c->d = opcode.flags;
|
||||||
|
|
||||||
|
if (c->d & Group) {
|
||||||
|
dual = c->d & GroupDual;
|
||||||
|
c->modrm = insn_fetch(u8, 1, c->eip);
|
||||||
|
--c->eip;
|
||||||
|
|
||||||
|
if (c->d & GroupDual) {
|
||||||
|
g_mod012 = opcode.u.gdual->mod012;
|
||||||
|
g_mod3 = opcode.u.gdual->mod3;
|
||||||
|
} else
|
||||||
|
g_mod012 = g_mod3 = opcode.u.group;
|
||||||
|
|
||||||
|
c->d &= ~(Group | GroupDual);
|
||||||
|
|
||||||
|
goffset = (c->modrm >> 3) & 7;
|
||||||
|
|
||||||
|
if ((c->modrm >> 6) == 3)
|
||||||
|
opcode = g_mod3[goffset];
|
||||||
|
else
|
||||||
|
opcode = g_mod012[goffset];
|
||||||
|
c->d |= opcode.flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->execute = opcode.u.execute;
|
||||||
|
|
||||||
|
/* Unrecognised? */
|
||||||
|
if (c->d == 0 || (c->d & Undefined)) {
|
||||||
|
DPRINTF("Cannot emulate %02x\n", c->b);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack))
|
||||||
|
c->op_bytes = 8;
|
||||||
|
|
||||||
|
/* ModRM and SIB bytes. */
|
||||||
|
if (c->d & ModRM)
|
||||||
|
rc = decode_modrm(ctxt, ops);
|
||||||
|
else if (c->d & MemAbs)
|
||||||
|
rc = decode_abs(ctxt, ops);
|
||||||
|
if (rc != X86EMUL_CONTINUE)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (!c->has_seg_override)
|
||||||
|
set_seg_override(c, VCPU_SREG_DS);
|
||||||
|
|
||||||
|
if (!(!c->twobyte && c->b == 0x8d))
|
||||||
|
c->modrm_ea += seg_override_base(ctxt, ops, c);
|
||||||
|
|
||||||
|
if (c->ad_bytes != 8)
|
||||||
|
c->modrm_ea = (u32)c->modrm_ea;
|
||||||
|
|
||||||
|
if (c->rip_relative)
|
||||||
|
c->modrm_ea += c->eip;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode and fetch the source operand: register, memory
|
||||||
|
* or immediate.
|
||||||
|
*/
|
||||||
|
switch (c->d & SrcMask) {
|
||||||
|
case SrcNone:
|
||||||
|
break;
|
||||||
|
case SrcReg:
|
||||||
|
decode_register_operand(&c->src, c, 0);
|
||||||
|
break;
|
||||||
|
case SrcMem16:
|
||||||
|
c->src.bytes = 2;
|
||||||
|
goto srcmem_common;
|
||||||
|
case SrcMem32:
|
||||||
|
c->src.bytes = 4;
|
||||||
|
goto srcmem_common;
|
||||||
|
case SrcMem:
|
||||||
|
c->src.bytes = (c->d & ByteOp) ? 1 :
|
||||||
|
c->op_bytes;
|
||||||
|
/* Don't fetch the address for invlpg: it could be unmapped. */
|
||||||
|
if (c->twobyte && c->b == 0x01 && c->modrm_reg == 7)
|
||||||
|
break;
|
||||||
|
srcmem_common:
|
||||||
|
/*
|
||||||
|
* For instructions with a ModR/M byte, switch to register
|
||||||
|
* access if Mod = 3.
|
||||||
|
*/
|
||||||
|
if ((c->d & ModRM) && c->modrm_mod == 3) {
|
||||||
|
c->src.type = OP_REG;
|
||||||
|
c->src.val = c->modrm_val;
|
||||||
|
c->src.ptr = c->modrm_ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c->src.type = OP_MEM;
|
||||||
|
c->src.ptr = (unsigned long *)c->modrm_ea;
|
||||||
|
c->src.val = 0;
|
||||||
|
break;
|
||||||
|
case SrcImm:
|
||||||
|
case SrcImmU:
|
||||||
|
c->src.type = OP_IMM;
|
||||||
|
c->src.ptr = (unsigned long *)c->eip;
|
||||||
|
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
||||||
|
if (c->src.bytes == 8)
|
||||||
|
c->src.bytes = 4;
|
||||||
|
/* NB. Immediates are sign-extended as necessary. */
|
||||||
|
switch (c->src.bytes) {
|
||||||
|
case 1:
|
||||||
|
c->src.val = insn_fetch(s8, 1, c->eip);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
c->src.val = insn_fetch(s16, 2, c->eip);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
c->src.val = insn_fetch(s32, 4, c->eip);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((c->d & SrcMask) == SrcImmU) {
|
||||||
|
switch (c->src.bytes) {
|
||||||
|
case 1:
|
||||||
|
c->src.val &= 0xff;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
c->src.val &= 0xffff;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
c->src.val &= 0xffffffff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SrcImmByte:
|
||||||
|
case SrcImmUByte:
|
||||||
|
c->src.type = OP_IMM;
|
||||||
|
c->src.ptr = (unsigned long *)c->eip;
|
||||||
|
c->src.bytes = 1;
|
||||||
|
if ((c->d & SrcMask) == SrcImmByte)
|
||||||
|
c->src.val = insn_fetch(s8, 1, c->eip);
|
||||||
|
else
|
||||||
|
c->src.val = insn_fetch(u8, 1, c->eip);
|
||||||
|
break;
|
||||||
|
case SrcAcc:
|
||||||
|
c->src.type = OP_REG;
|
||||||
|
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
||||||
|
c->src.ptr = &c->regs[VCPU_REGS_RAX];
|
||||||
|
switch (c->src.bytes) {
|
||||||
|
case 1:
|
||||||
|
c->src.val = *(u8 *)c->src.ptr;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
c->src.val = *(u16 *)c->src.ptr;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
c->src.val = *(u32 *)c->src.ptr;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
c->src.val = *(u64 *)c->src.ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SrcOne:
|
||||||
|
c->src.bytes = 1;
|
||||||
|
c->src.val = 1;
|
||||||
|
break;
|
||||||
|
case SrcSI:
|
||||||
|
c->src.type = OP_MEM;
|
||||||
|
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
||||||
|
c->src.ptr = (unsigned long *)
|
||||||
|
register_address(c, seg_override_base(ctxt, ops, c),
|
||||||
|
c->regs[VCPU_REGS_RSI]);
|
||||||
|
c->src.val = 0;
|
||||||
|
break;
|
||||||
|
case SrcImmFAddr:
|
||||||
|
c->src.type = OP_IMM;
|
||||||
|
c->src.ptr = (unsigned long *)c->eip;
|
||||||
|
c->src.bytes = c->op_bytes + 2;
|
||||||
|
insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
|
||||||
|
break;
|
||||||
|
case SrcMemFAddr:
|
||||||
|
c->src.type = OP_MEM;
|
||||||
|
c->src.ptr = (unsigned long *)c->modrm_ea;
|
||||||
|
c->src.bytes = c->op_bytes + 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode and fetch the second source operand: register, memory
|
||||||
|
* or immediate.
|
||||||
|
*/
|
||||||
|
switch (c->d & Src2Mask) {
|
||||||
|
case Src2None:
|
||||||
|
break;
|
||||||
|
case Src2CL:
|
||||||
|
c->src2.bytes = 1;
|
||||||
|
c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8;
|
||||||
|
break;
|
||||||
|
case Src2ImmByte:
|
||||||
|
c->src2.type = OP_IMM;
|
||||||
|
c->src2.ptr = (unsigned long *)c->eip;
|
||||||
|
c->src2.bytes = 1;
|
||||||
|
c->src2.val = insn_fetch(u8, 1, c->eip);
|
||||||
|
break;
|
||||||
|
case Src2One:
|
||||||
|
c->src2.bytes = 1;
|
||||||
|
c->src2.val = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode and fetch the destination operand: register or memory. */
|
||||||
|
switch (c->d & DstMask) {
|
||||||
|
case ImplicitOps:
|
||||||
|
/* Special instructions do their own operand decoding. */
|
||||||
|
return 0;
|
||||||
|
case DstReg:
|
||||||
|
decode_register_operand(&c->dst, c,
|
||||||
|
c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
|
||||||
|
break;
|
||||||
|
case DstMem:
|
||||||
|
case DstMem64:
|
||||||
|
if ((c->d & ModRM) && c->modrm_mod == 3) {
|
||||||
|
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
||||||
|
c->dst.type = OP_REG;
|
||||||
|
c->dst.val = c->dst.orig_val = c->modrm_val;
|
||||||
|
c->dst.ptr = c->modrm_ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c->dst.type = OP_MEM;
|
||||||
|
c->dst.ptr = (unsigned long *)c->modrm_ea;
|
||||||
|
if ((c->d & DstMask) == DstMem64)
|
||||||
|
c->dst.bytes = 8;
|
||||||
|
else
|
||||||
|
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
||||||
|
c->dst.val = 0;
|
||||||
|
if (c->d & BitOp) {
|
||||||
|
unsigned long mask = ~(c->dst.bytes * 8 - 1);
|
||||||
|
|
||||||
|
c->dst.ptr = (void *)c->dst.ptr +
|
||||||
|
(c->src.val & mask) / 8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DstAcc:
|
||||||
|
c->dst.type = OP_REG;
|
||||||
|
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
||||||
|
c->dst.ptr = &c->regs[VCPU_REGS_RAX];
|
||||||
|
switch (c->dst.bytes) {
|
||||||
|
case 1:
|
||||||
|
c->dst.val = *(u8 *)c->dst.ptr;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
c->dst.val = *(u16 *)c->dst.ptr;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
c->dst.val = *(u32 *)c->dst.ptr;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
c->dst.val = *(u64 *)c->dst.ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c->dst.orig_val = c->dst.val;
|
||||||
|
break;
|
||||||
|
case DstDI:
|
||||||
|
c->dst.type = OP_MEM;
|
||||||
|
c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
|
||||||
|
c->dst.ptr = (unsigned long *)
|
||||||
|
register_address(c, es_base(ctxt, ops),
|
||||||
|
c->regs[VCPU_REGS_RDI]);
|
||||||
|
c->dst.val = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
|
x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue