mirror of
https://github.com/xen-project/xen.git
synced 2026-10-30 03:00:05 +01:00
[XEN] Emulator extensions to decode ModRM.MOD == 3.
This allows emulation of register-only instructions. Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
c35c69faae
commit
0a967eccec
3 files changed
+151
-119
No files matched your search
@@ -15,8 +15,6 @@ typedef int64_t s64;
|
||||
#include <asm-x86/x86_emulate.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define PFEC_write_access (1U<<1)
|
||||
|
||||
static int read(
|
||||
unsigned int seg,
|
||||
unsigned long offset,
|
||||
@@ -119,7 +117,6 @@ int main(int argc, char **argv)
|
||||
regs.eflags = 0x200;
|
||||
regs.eip = (unsigned long)&instr[0];
|
||||
regs.ecx = 0x12345678;
|
||||
regs.error_code = PFEC_write_access;
|
||||
regs.eax = (unsigned long)res;
|
||||
*res = 0x7FFFFFFF;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
@@ -130,6 +127,21 @@ int main(int argc, char **argv)
|
||||
goto fail;
|
||||
printf("okay\n");
|
||||
|
||||
printf("%-40s", "Testing addl %%ecx,%%eax...");
|
||||
instr[0] = 0x01; instr[1] = 0xc8;
|
||||
regs.eflags = 0x200;
|
||||
regs.eip = (unsigned long)&instr[0];
|
||||
regs.ecx = 0x12345678;
|
||||
regs.eax = 0x7FFFFFFF;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(regs.ecx != 0x12345678) ||
|
||||
(regs.eax != 0x92345677) ||
|
||||
(regs.eflags != 0xa94) ||
|
||||
(regs.eip != (unsigned long)&instr[2]) )
|
||||
goto fail;
|
||||
printf("okay\n");
|
||||
|
||||
printf("%-40s", "Testing xorl (%%eax),%%ecx...");
|
||||
instr[0] = 0x33; instr[1] = 0x08;
|
||||
regs.eflags = 0x200;
|
||||
@@ -140,7 +152,6 @@ int main(int argc, char **argv)
|
||||
regs.ecx = 0x12345678UL;
|
||||
#endif
|
||||
regs.eax = (unsigned long)res;
|
||||
regs.error_code = 0;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x92345677) ||
|
||||
@@ -155,7 +166,6 @@ int main(int argc, char **argv)
|
||||
regs.eip = (unsigned long)&instr[0];
|
||||
regs.ecx = ~0UL;
|
||||
regs.eax = (unsigned long)res;
|
||||
regs.error_code = 0;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x92345677) ||
|
||||
@@ -171,7 +181,6 @@ int main(int argc, char **argv)
|
||||
regs.eax = 0x92345677UL;
|
||||
regs.ecx = 0xAA;
|
||||
regs.ebx = (unsigned long)res;
|
||||
regs.error_code = PFEC_write_access;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x923456AA) ||
|
||||
@@ -188,7 +197,6 @@ int main(int argc, char **argv)
|
||||
regs.eax = 0xAABBCC77UL;
|
||||
regs.ecx = 0xFF;
|
||||
regs.ebx = (unsigned long)res;
|
||||
regs.error_code = PFEC_write_access;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x923456AA) ||
|
||||
@@ -205,7 +213,6 @@ int main(int argc, char **argv)
|
||||
regs.eip = (unsigned long)&instr[0];
|
||||
regs.ecx = 0x12345678;
|
||||
regs.eax = (unsigned long)res;
|
||||
regs.error_code = PFEC_write_access;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x12345678) ||
|
||||
@@ -223,7 +230,6 @@ int main(int argc, char **argv)
|
||||
regs.eax = 0x923456AAUL;
|
||||
regs.ecx = 0xDDEEFF00L;
|
||||
regs.ebx = (unsigned long)res;
|
||||
regs.error_code = PFEC_write_access;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0xDDEEFF00) ||
|
||||
@@ -241,7 +247,6 @@ int main(int argc, char **argv)
|
||||
regs.eip = (unsigned long)&instr[0];
|
||||
regs.esi = (unsigned long)res + 0;
|
||||
regs.edi = (unsigned long)res + 2;
|
||||
regs.error_code = 0; /* read fault */
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x44554455) ||
|
||||
@@ -259,9 +264,8 @@ int main(int argc, char **argv)
|
||||
regs.eflags = 0x200;
|
||||
regs.eip = (unsigned long)&instr[0];
|
||||
regs.edi = (unsigned long)res;
|
||||
regs.error_code = PFEC_write_access;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x2233445D) ||
|
||||
((regs.eflags&0x201) != 0x201) ||
|
||||
(regs.eip != (unsigned long)&instr[4]) )
|
||||
@@ -275,9 +279,8 @@ int main(int argc, char **argv)
|
||||
regs.eip = (unsigned long)&instr[0];
|
||||
regs.eax = -32;
|
||||
regs.edi = (unsigned long)(res+1);
|
||||
regs.error_code = PFEC_write_access;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x2233445E) ||
|
||||
((regs.eflags&0x201) != 0x201) ||
|
||||
(regs.eip != (unsigned long)&instr[3]) )
|
||||
@@ -296,9 +299,8 @@ int main(int argc, char **argv)
|
||||
regs.ecx = 0xCCCCFFFF;
|
||||
regs.eip = (unsigned long)&instr[0];
|
||||
regs.edi = (unsigned long)res;
|
||||
regs.error_code = PFEC_write_access;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
if ( (rc != 0) ||
|
||||
(res[0] != 0x9999AAAA) ||
|
||||
(res[1] != 0xCCCCFFFF) ||
|
||||
((regs.eflags&0x240) != 0x240) ||
|
||||
@@ -311,7 +313,6 @@ int main(int argc, char **argv)
|
||||
regs.eflags = 0x200;
|
||||
regs.eip = (unsigned long)&instr[0];
|
||||
regs.edi = (unsigned long)res;
|
||||
regs.error_code = PFEC_write_access;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(res[0] != 0x9999AAAA) ||
|
||||
@@ -330,7 +331,6 @@ int main(int argc, char **argv)
|
||||
regs.ecx = 0x12345678;
|
||||
regs.eax = (unsigned long)res;
|
||||
*res = 0x82;
|
||||
regs.error_code = 0;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x82) ||
|
||||
@@ -347,7 +347,6 @@ int main(int argc, char **argv)
|
||||
regs.ecx = 0x12345678;
|
||||
regs.eax = (unsigned long)res;
|
||||
*res = 0x1234aa82;
|
||||
regs.error_code = 0;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x1234aa82) ||
|
||||
@@ -364,7 +363,6 @@ int main(int argc, char **argv)
|
||||
regs.ecx = (unsigned long)res;
|
||||
regs.eax = 0x12345678;
|
||||
*res = 0x11111111;
|
||||
regs.error_code = 0;
|
||||
rc = x86_emulate_memop(&ctxt, &emulops);
|
||||
if ( (rc != 0) ||
|
||||
(*res != 0x11116789) ||
|
||||
|
||||
@@ -268,7 +268,7 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
|
||||
struct trap_info *ti;
|
||||
struct trap_bounce *tb;
|
||||
u8 modrm, mod, reg, rm, decode;
|
||||
void *memreg, *regreg;
|
||||
void *memreg;
|
||||
unsigned long offset;
|
||||
u8 disp8;
|
||||
u32 disp32 = 0;
|
||||
@@ -384,8 +384,7 @@ int gpf_emulate_4gb(struct cpu_user_regs *regs)
|
||||
goto fixme;
|
||||
}
|
||||
|
||||
/* Decode Reg and R/M fields. */
|
||||
regreg = decode_register(reg, regs, 0);
|
||||
/* Decode R/M field. */
|
||||
memreg = decode_register(rm, regs, 0);
|
||||
|
||||
/* Decode Mod field. */
|
||||
|
||||
+131
-96
@@ -192,11 +192,15 @@ struct operand {
|
||||
enum { OP_REG, OP_MEM, OP_IMM } type;
|
||||
unsigned int bytes;
|
||||
unsigned long val, orig_val;
|
||||
/* OP_REG: Pointer to register field. */
|
||||
unsigned long *reg;
|
||||
/* OP_MEM: Segment and offset. */
|
||||
enum x86_segment mem_seg;
|
||||
unsigned long mem_off;
|
||||
union {
|
||||
/* OP_REG: Pointer to register field. */
|
||||
unsigned long *reg;
|
||||
/* OP_MEM: Segment and offset. */
|
||||
struct {
|
||||
enum x86_segment seg;
|
||||
unsigned long off;
|
||||
} mem;
|
||||
};
|
||||
};
|
||||
|
||||
/* EFLAGS bit definitions. */
|
||||
@@ -451,8 +455,13 @@ x86_emulate_memop(
|
||||
struct operand src, dst;
|
||||
int mode = ctxt->mode;
|
||||
|
||||
enum x86_segment ea_seg = x86_seg_ds;
|
||||
unsigned long ea_off = 0;
|
||||
/* Data operand effective address (usually computed from ModRM). */
|
||||
struct operand ea;
|
||||
|
||||
/* Default is a memory operand relative to segment DS. */
|
||||
ea.type = OP_MEM;
|
||||
ea.mem.seg = x86_seg_ds;
|
||||
ea.mem.off = 0;
|
||||
|
||||
switch ( mode )
|
||||
{
|
||||
@@ -488,22 +497,22 @@ x86_emulate_memop(
|
||||
ad_bytes ^= 6; /* switch between 2/4 bytes */
|
||||
break;
|
||||
case 0x2e: /* CS override */
|
||||
ea_seg = x86_seg_cs;
|
||||
ea.mem.seg = x86_seg_cs;
|
||||
break;
|
||||
case 0x3e: /* DS override */
|
||||
ea_seg = x86_seg_ds;
|
||||
ea.mem.seg = x86_seg_ds;
|
||||
break;
|
||||
case 0x26: /* ES override */
|
||||
ea_seg = x86_seg_es;
|
||||
ea.mem.seg = x86_seg_es;
|
||||
break;
|
||||
case 0x64: /* FS override */
|
||||
ea_seg = x86_seg_fs;
|
||||
ea.mem.seg = x86_seg_fs;
|
||||
break;
|
||||
case 0x65: /* GS override */
|
||||
ea_seg = x86_seg_gs;
|
||||
ea.mem.seg = x86_seg_gs;
|
||||
break;
|
||||
case 0x36: /* SS override */
|
||||
ea_seg = x86_seg_ss;
|
||||
ea.mem.seg = x86_seg_ss;
|
||||
break;
|
||||
case 0xf0: /* LOCK */
|
||||
lock_prefix = 1;
|
||||
@@ -554,35 +563,39 @@ x86_emulate_memop(
|
||||
modrm_rm = modrm & 0x07;
|
||||
|
||||
if ( modrm_mod == 3 )
|
||||
goto cannot_emulate;
|
||||
|
||||
if ( ad_bytes == 2 )
|
||||
{
|
||||
ea.type = OP_REG;
|
||||
ea.reg = decode_register(
|
||||
modrm_rm, &_regs, (d & ByteOp) && (rex_prefix == 0));
|
||||
}
|
||||
else if ( ad_bytes == 2 )
|
||||
{
|
||||
/* 16-bit ModR/M decode. */
|
||||
switch ( modrm_rm )
|
||||
{
|
||||
case 0: ea_off = _regs.ebx + _regs.esi; break;
|
||||
case 1: ea_off = _regs.ebx + _regs.edi; break;
|
||||
case 2: ea_off = _regs.ebp + _regs.esi; break;
|
||||
case 3: ea_off = _regs.ebp + _regs.edi; break;
|
||||
case 4: ea_off = _regs.esi; break;
|
||||
case 5: ea_off = _regs.edi; break;
|
||||
case 6: ea_off = _regs.ebp; break;
|
||||
case 7: ea_off = _regs.ebx; break;
|
||||
case 0: ea.mem.off = _regs.ebx + _regs.esi; break;
|
||||
case 1: ea.mem.off = _regs.ebx + _regs.edi; break;
|
||||
case 2: ea.mem.off = _regs.ebp + _regs.esi; break;
|
||||
case 3: ea.mem.off = _regs.ebp + _regs.edi; break;
|
||||
case 4: ea.mem.off = _regs.esi; break;
|
||||
case 5: ea.mem.off = _regs.edi; break;
|
||||
case 6: ea.mem.off = _regs.ebp; break;
|
||||
case 7: ea.mem.off = _regs.ebx; break;
|
||||
}
|
||||
switch ( modrm_mod )
|
||||
{
|
||||
case 0:
|
||||
if ( modrm_rm == 6 )
|
||||
ea_off = insn_fetch_type(int16_t);
|
||||
ea.mem.off = insn_fetch_type(int16_t);
|
||||
break;
|
||||
case 1:
|
||||
ea_off += insn_fetch_type(int8_t);
|
||||
ea.mem.off += insn_fetch_type(int8_t);
|
||||
break;
|
||||
case 2:
|
||||
ea_off += insn_fetch_type(int16_t);
|
||||
ea.mem.off += insn_fetch_type(int16_t);
|
||||
break;
|
||||
}
|
||||
ea.mem.off = truncate_ea(ea.mem.off);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -593,49 +606,48 @@ x86_emulate_memop(
|
||||
sib_index = ((sib >> 3) & 7) | ((rex_prefix << 2) & 8);
|
||||
sib_base = (sib & 7) | ((rex_prefix << 3) & 8);
|
||||
if ( sib_index != 4 )
|
||||
ea_off = *(long *)decode_register(sib_index, &_regs, 0);
|
||||
ea_off <<= (sib >> 6) & 3;
|
||||
ea.mem.off = *(long*)decode_register(sib_index, &_regs, 0);
|
||||
ea.mem.off <<= (sib >> 6) & 3;
|
||||
if ( (modrm_mod == 0) && ((sib_base & 7) == 5) )
|
||||
ea_off += insn_fetch_type(int32_t);
|
||||
ea.mem.off += insn_fetch_type(int32_t);
|
||||
else
|
||||
ea_off += *(long *)decode_register(sib_base, &_regs, 0);
|
||||
ea.mem.off += *(long*)decode_register(sib_base, &_regs, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
modrm_rm |= (rex_prefix & 1) << 3;
|
||||
ea_off = *(long *)decode_register(modrm_rm, &_regs, 0);
|
||||
ea.mem.off = *(long *)decode_register(modrm_rm, &_regs, 0);
|
||||
}
|
||||
switch ( modrm_mod )
|
||||
{
|
||||
case 0:
|
||||
if ( (modrm_rm & 7) != 5 )
|
||||
break;
|
||||
ea_off = insn_fetch_type(int32_t);
|
||||
ea.mem.off = insn_fetch_type(int32_t);
|
||||
if ( mode != X86EMUL_MODE_PROT64 )
|
||||
break;
|
||||
/* Relative to RIP of next instruction. Argh! */
|
||||
ea_off += _regs.eip;
|
||||
ea.mem.off += _regs.eip;
|
||||
if ( (d & SrcMask) == SrcImm )
|
||||
ea_off += (d & ByteOp) ? 1 :
|
||||
ea.mem.off += (d & ByteOp) ? 1 :
|
||||
((op_bytes == 8) ? 4 : op_bytes);
|
||||
else if ( (d & SrcMask) == SrcImmByte )
|
||||
ea_off += 1;
|
||||
ea.mem.off += 1;
|
||||
else if ( ((b == 0xf6) || (b == 0xf7)) &&
|
||||
((modrm_reg & 7) <= 1) )
|
||||
/* Special case in Grp3: test has immediate operand. */
|
||||
ea_off += (d & ByteOp) ? 1
|
||||
ea.mem.off += (d & ByteOp) ? 1
|
||||
: ((op_bytes == 8) ? 4 : op_bytes);
|
||||
break;
|
||||
case 1:
|
||||
ea_off += insn_fetch_type(int8_t);
|
||||
ea.mem.off += insn_fetch_type(int8_t);
|
||||
break;
|
||||
case 2:
|
||||
ea_off += insn_fetch_type(int32_t);
|
||||
ea.mem.off += insn_fetch_type(int32_t);
|
||||
break;
|
||||
}
|
||||
ea.mem.off = truncate_ea(ea.mem.off);
|
||||
}
|
||||
|
||||
ea_off = truncate_ea(ea_off);
|
||||
}
|
||||
|
||||
/* Special instructions do their own operand decoding. */
|
||||
@@ -652,7 +664,7 @@ x86_emulate_memop(
|
||||
if ( d & ByteOp )
|
||||
{
|
||||
src.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
|
||||
src.val = src.orig_val = *(uint8_t *)src.reg;
|
||||
src.val = *(uint8_t *)src.reg;
|
||||
src.bytes = 1;
|
||||
}
|
||||
else
|
||||
@@ -660,28 +672,35 @@ x86_emulate_memop(
|
||||
src.reg = decode_register(modrm_reg, &_regs, 0);
|
||||
switch ( (src.bytes = op_bytes) )
|
||||
{
|
||||
case 2: src.val = src.orig_val = *(uint16_t *)src.reg; break;
|
||||
case 4: src.val = src.orig_val = *(uint32_t *)src.reg; break;
|
||||
case 8: src.val = src.orig_val = *(uint64_t *)src.reg; break;
|
||||
case 2: src.val = *(uint16_t *)src.reg; break;
|
||||
case 4: src.val = *(uint32_t *)src.reg; break;
|
||||
case 8: src.val = *(uint64_t *)src.reg; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SrcMem16:
|
||||
src.bytes = 2;
|
||||
ea.bytes = 2;
|
||||
goto srcmem_common;
|
||||
case SrcMem32:
|
||||
src.bytes = 4;
|
||||
ea.bytes = 4;
|
||||
goto srcmem_common;
|
||||
case SrcMem:
|
||||
src.bytes = (d & ByteOp) ? 1 : op_bytes;
|
||||
ea.bytes = (d & ByteOp) ? 1 : op_bytes;
|
||||
srcmem_common:
|
||||
src.type = OP_MEM;
|
||||
src.mem_seg = ea_seg;
|
||||
src.mem_off = ea_off;
|
||||
if ( (rc = ops->read(src.mem_seg, src.mem_off,
|
||||
&src.val, src.bytes, ctxt)) != 0 )
|
||||
src = ea;
|
||||
if ( src.type == OP_REG )
|
||||
{
|
||||
switch ( src.bytes )
|
||||
{
|
||||
case 1: src.val = *(uint8_t *)src.reg; break;
|
||||
case 2: src.val = *(uint16_t *)src.reg; break;
|
||||
case 4: src.val = *(uint32_t *)src.reg; break;
|
||||
case 8: src.val = *(uint64_t *)src.reg; break;
|
||||
}
|
||||
}
|
||||
else if ( (rc = ops->read(src.mem.seg, src.mem.off,
|
||||
&src.val, src.bytes, ctxt)) )
|
||||
goto done;
|
||||
src.orig_val = src.val;
|
||||
break;
|
||||
case SrcImm:
|
||||
src.type = OP_IMM;
|
||||
@@ -725,8 +744,7 @@ x86_emulate_memop(
|
||||
}
|
||||
break;
|
||||
case DstBitBase:
|
||||
dst.mem_off = ea_off;
|
||||
if ( (d & SrcMask) == SrcImmByte )
|
||||
if ( ((d & SrcMask) == SrcImmByte) || (ea.type == OP_REG) )
|
||||
{
|
||||
src.val &= (op_bytes << 3) - 1;
|
||||
}
|
||||
@@ -746,28 +764,34 @@ x86_emulate_memop(
|
||||
{
|
||||
unsigned long byte_offset;
|
||||
byte_offset = op_bytes + (((-src.val-1) >> 3) & ~(op_bytes-1));
|
||||
dst.mem_off -= byte_offset;
|
||||
ea.mem.off -= byte_offset;
|
||||
src.val = (byte_offset << 3) + src.val;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst.mem_off += (src.val >> 3) & ~(op_bytes - 1);
|
||||
ea.mem.off += (src.val >> 3) & ~(op_bytes - 1);
|
||||
src.val &= (op_bytes << 3) - 1;
|
||||
}
|
||||
}
|
||||
/* Becomes a normal DstMem operation from here on. */
|
||||
d = (d & ~DstMask) | DstMem;
|
||||
goto dstmem_common;
|
||||
case DstMem:
|
||||
dst.mem_off = ea_off;
|
||||
dstmem_common:
|
||||
dst.mem_seg = ea_seg;
|
||||
dst.type = OP_MEM;
|
||||
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
|
||||
if ( !(d & Mov) && /* optimisation - avoid slow emulated read */
|
||||
((rc = ops->read(dst.mem_seg, dst.mem_off,
|
||||
&dst.val, dst.bytes, ctxt)) != 0) )
|
||||
goto done;
|
||||
ea.bytes = (d & ByteOp) ? 1 : op_bytes;
|
||||
dst = ea;
|
||||
if ( dst.type == OP_REG )
|
||||
{
|
||||
switch ( dst.bytes )
|
||||
{
|
||||
case 1: dst.val = *(uint8_t *)dst.reg; break;
|
||||
case 2: dst.val = *(uint16_t *)dst.reg; break;
|
||||
case 4: dst.val = *(uint32_t *)dst.reg; break;
|
||||
case 8: dst.val = *(uint64_t *)dst.reg; break;
|
||||
}
|
||||
}
|
||||
else if ( !(d & Mov) && /* optimisation - avoid slow emulated read */
|
||||
(rc = ops->read(dst.mem.seg, dst.mem.off,
|
||||
&dst.val, dst.bytes, ctxt)) )
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
dst.orig_val = dst.val;
|
||||
@@ -920,7 +944,7 @@ x86_emulate_memop(
|
||||
if ( mode == X86EMUL_MODE_PROT64 )
|
||||
{
|
||||
dst.bytes = 8;
|
||||
if ( (rc = ops->read(dst.mem_seg, dst.mem_off,
|
||||
if ( (rc = ops->read(dst.mem.seg, dst.mem.off,
|
||||
&dst.val, 8, ctxt)) != 0 )
|
||||
goto done;
|
||||
}
|
||||
@@ -954,11 +978,11 @@ x86_emulate_memop(
|
||||
case OP_MEM:
|
||||
if ( lock_prefix )
|
||||
rc = ops->cmpxchg(
|
||||
dst.mem_seg, dst.mem_off, dst.orig_val,
|
||||
dst.mem.seg, dst.mem.off, dst.orig_val,
|
||||
dst.val, dst.bytes, ctxt);
|
||||
else
|
||||
rc = ops->write(
|
||||
dst.mem_seg, dst.mem_off, dst.val, dst.bytes, ctxt);
|
||||
dst.mem.seg, dst.mem.off, dst.val, dst.bytes, ctxt);
|
||||
if ( rc != 0 )
|
||||
goto done;
|
||||
default:
|
||||
@@ -987,29 +1011,29 @@ x86_emulate_memop(
|
||||
}
|
||||
switch ( b )
|
||||
{
|
||||
case 0xa0 ... 0xa1: /* mov moffs,{%al,%ax,%eax,%rax} */
|
||||
case 0xa0 ... 0xa1: /* mov mem.offs,{%al,%ax,%eax,%rax} */
|
||||
/* Source EA is not encoded via ModRM. */
|
||||
dst.type = OP_REG;
|
||||
dst.reg = (unsigned long *)&_regs.eax;
|
||||
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
|
||||
if ( (rc = ops->read(ea_seg, insn_fetch_bytes(ad_bytes),
|
||||
if ( (rc = ops->read(ea.mem.seg, insn_fetch_bytes(ad_bytes),
|
||||
&dst.val, dst.bytes, ctxt)) != 0 )
|
||||
goto done;
|
||||
break;
|
||||
case 0xa2 ... 0xa3: /* mov {%al,%ax,%eax,%rax},moffs */
|
||||
case 0xa2 ... 0xa3: /* mov {%al,%ax,%eax,%rax},mem.offs */
|
||||
/* Destination EA is not encoded via ModRM. */
|
||||
dst.type = OP_MEM;
|
||||
dst.mem_seg = ea_seg;
|
||||
dst.mem_off = insn_fetch_bytes(ad_bytes);
|
||||
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
|
||||
dst.val = (unsigned long)_regs.eax;
|
||||
dst.type = OP_MEM;
|
||||
dst.mem.seg = ea.mem.seg;
|
||||
dst.mem.off = insn_fetch_bytes(ad_bytes);
|
||||
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
|
||||
dst.val = (unsigned long)_regs.eax;
|
||||
break;
|
||||
case 0xa4 ... 0xa5: /* movs */
|
||||
dst.type = OP_MEM;
|
||||
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
|
||||
dst.mem_seg = x86_seg_es;
|
||||
dst.mem_off = truncate_ea(_regs.edi);
|
||||
if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi),
|
||||
dst.mem.seg = x86_seg_es;
|
||||
dst.mem.off = truncate_ea(_regs.edi);
|
||||
if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
|
||||
&dst.val, dst.bytes, ctxt)) != 0 )
|
||||
goto done;
|
||||
register_address_increment(
|
||||
@@ -1020,8 +1044,8 @@ x86_emulate_memop(
|
||||
case 0xaa ... 0xab: /* stos */
|
||||
dst.type = OP_MEM;
|
||||
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
|
||||
dst.mem_seg = x86_seg_es;
|
||||
dst.mem_off = truncate_ea(_regs.edi);
|
||||
dst.mem.seg = x86_seg_es;
|
||||
dst.mem.off = truncate_ea(_regs.edi);
|
||||
dst.val = _regs.eax;
|
||||
register_address_increment(
|
||||
_regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
|
||||
@@ -1030,7 +1054,7 @@ x86_emulate_memop(
|
||||
dst.type = OP_REG;
|
||||
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
|
||||
dst.reg = (unsigned long *)&_regs.eax;
|
||||
if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi),
|
||||
if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
|
||||
&dst.val, dst.bytes, ctxt)) != 0 )
|
||||
goto done;
|
||||
register_address_increment(
|
||||
@@ -1105,9 +1129,14 @@ x86_emulate_memop(
|
||||
case 0xab: bts: /* bts */
|
||||
emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags);
|
||||
break;
|
||||
case 0xb6 ... 0xb7: /* movzx */
|
||||
case 0xb6: /* movzx rm8,r{16,32,64} */
|
||||
/* Recompute DstReg as we may have decoded AH/BH/CH/DH. */
|
||||
dst.reg = decode_register(modrm_reg, &_regs, 0);
|
||||
dst.bytes = op_bytes;
|
||||
dst.val = (d & ByteOp) ? (uint8_t)src.val : (uint16_t)src.val;
|
||||
dst.val = (uint8_t)src.val;
|
||||
break;
|
||||
case 0xb7: /* movzx rm16,r{16,32,64} */
|
||||
dst.val = (uint16_t)src.val;
|
||||
break;
|
||||
case 0xbb: btc: /* btc */
|
||||
emulate_2op_SrcV_nobyte("btc", src, dst, _regs.eflags);
|
||||
@@ -1121,9 +1150,14 @@ x86_emulate_memop(
|
||||
case 3: goto btc;
|
||||
}
|
||||
break;
|
||||
case 0xbe ... 0xbf: /* movsx */
|
||||
case 0xbe: /* movsx rm8,r{16,32,64} */
|
||||
/* Recompute DstReg as we may have decoded AH/BH/CH/DH. */
|
||||
dst.reg = decode_register(modrm_reg, &_regs, 0);
|
||||
dst.bytes = op_bytes;
|
||||
dst.val = (d & ByteOp) ? (int8_t)src.val : (int16_t)src.val;
|
||||
dst.val = (int8_t)src.val;
|
||||
break;
|
||||
case 0xbf: /* movsx rm16,r{16,32,64} */
|
||||
dst.val = (int16_t)src.val;
|
||||
break;
|
||||
case 0xc0 ... 0xc1: /* xadd */
|
||||
/* Write back the register source. */
|
||||
@@ -1150,8 +1184,8 @@ x86_emulate_memop(
|
||||
#if defined(__i386__)
|
||||
{
|
||||
unsigned long old_lo, old_hi;
|
||||
if ( ((rc = ops->read(ea_seg, ea_off+0, &old_lo, 4, ctxt)) != 0) ||
|
||||
((rc = ops->read(ea_seg, ea_off+4, &old_hi, 4, ctxt)) != 0) )
|
||||
if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, &old_lo, 4, ctxt)) ||
|
||||
(rc = ops->read(ea.mem.seg, ea.mem.off+4, &old_hi, 4, ctxt)) )
|
||||
goto done;
|
||||
if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) )
|
||||
{
|
||||
@@ -1166,7 +1200,7 @@ x86_emulate_memop(
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (rc = ops->cmpxchg8b(ea_seg, ea_off, old_lo, old_hi,
|
||||
if ( (rc = ops->cmpxchg8b(ea.mem.seg, ea.mem.off, old_lo, old_hi,
|
||||
_regs.ebx, _regs.ecx, ctxt)) != 0 )
|
||||
goto done;
|
||||
_regs.eflags |= EFLG_ZF;
|
||||
@@ -1176,7 +1210,7 @@ x86_emulate_memop(
|
||||
#elif defined(__x86_64__)
|
||||
{
|
||||
unsigned long old, new;
|
||||
if ( (rc = ops->read(ea_seg, ea_off, &old, 8, ctxt)) != 0 )
|
||||
if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &old, 8, ctxt)) != 0 )
|
||||
goto done;
|
||||
if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) ||
|
||||
((uint32_t)(old>>32) != (uint32_t)_regs.edx) )
|
||||
@@ -1188,7 +1222,8 @@ x86_emulate_memop(
|
||||
else
|
||||
{
|
||||
new = (_regs.ecx<<32)|(uint32_t)_regs.ebx;
|
||||
if ( (rc = ops->cmpxchg(ea_seg, ea_off, old, new, 8, ctxt)) != 0 )
|
||||
if ( (rc = ops->cmpxchg(ea.mem.seg, ea.mem.off, old,
|
||||
new, 8, ctxt)) != 0 )
|
||||
goto done;
|
||||
_regs.eflags |= EFLG_ZF;
|
||||
}
|
||||
@@ -1201,10 +1236,10 @@ x86_emulate_memop(
|
||||
cannot_emulate:
|
||||
#ifdef __XEN__
|
||||
gdprintk(XENLOG_DEBUG, "Instr:");
|
||||
for ( ea_off = ctxt->regs->eip; ea_off < _regs.eip; ea_off++ )
|
||||
for ( ea.mem.off = ctxt->regs->eip; ea.mem.off < _regs.eip; ea.mem.off++ )
|
||||
{
|
||||
unsigned long x;
|
||||
ops->insn_fetch(x86_seg_cs, ea_off, &x, 1, ctxt);
|
||||
ops->insn_fetch(x86_seg_cs, ea.mem.off, &x, 1, ctxt);
|
||||
printk(" %02x", (uint8_t)x);
|
||||
}
|
||||
printk("\n");
|
||||
|
||||