KVM: x86 emulator: Hoist modrm and abs decoding into separate functions
Signed-off-by: Avi Kivity <avi@qumranet.com>
This commit is contained in:
Родитель
3b6fff198c
Коммит
1c73ef6650
|
@ -548,14 +548,182 @@ static void decode_register_operand(struct operand *op,
|
|||
op->orig_val = op->val;
|
||||
}
|
||||
|
||||
static int decode_modrm(struct x86_emulate_ctxt *ctxt,
|
||||
struct x86_emulate_ops *ops)
|
||||
{
|
||||
struct decode_cache *c = &ctxt->decode;
|
||||
u8 sib;
|
||||
int index_reg = 0, base_reg = 0, scale, rip_relative = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (c->rex_prefix) {
|
||||
c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */
|
||||
index_reg = (c->rex_prefix & 2) << 2; /* REX.X */
|
||||
c->modrm_rm = base_reg = (c->rex_prefix & 1) << 3; /* REG.B */
|
||||
}
|
||||
|
||||
c->modrm = insn_fetch(u8, 1, c->eip);
|
||||
c->modrm_mod |= (c->modrm & 0xc0) >> 6;
|
||||
c->modrm_reg |= (c->modrm & 0x38) >> 3;
|
||||
c->modrm_rm |= (c->modrm & 0x07);
|
||||
c->modrm_ea = 0;
|
||||
c->use_modrm_ea = 1;
|
||||
|
||||
if (c->modrm_mod == 3) {
|
||||
c->modrm_val = *(unsigned long *)
|
||||
decode_register(c->modrm_rm, c->regs, c->d & ByteOp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (c->ad_bytes == 2) {
|
||||
unsigned bx = c->regs[VCPU_REGS_RBX];
|
||||
unsigned bp = c->regs[VCPU_REGS_RBP];
|
||||
unsigned si = c->regs[VCPU_REGS_RSI];
|
||||
unsigned di = c->regs[VCPU_REGS_RDI];
|
||||
|
||||
/* 16-bit ModR/M decode. */
|
||||
switch (c->modrm_mod) {
|
||||
case 0:
|
||||
if (c->modrm_rm == 6)
|
||||
c->modrm_ea += insn_fetch(u16, 2, c->eip);
|
||||
break;
|
||||
case 1:
|
||||
c->modrm_ea += insn_fetch(s8, 1, c->eip);
|
||||
break;
|
||||
case 2:
|
||||
c->modrm_ea += insn_fetch(u16, 2, c->eip);
|
||||
break;
|
||||
}
|
||||
switch (c->modrm_rm) {
|
||||
case 0:
|
||||
c->modrm_ea += bx + si;
|
||||
break;
|
||||
case 1:
|
||||
c->modrm_ea += bx + di;
|
||||
break;
|
||||
case 2:
|
||||
c->modrm_ea += bp + si;
|
||||
break;
|
||||
case 3:
|
||||
c->modrm_ea += bp + di;
|
||||
break;
|
||||
case 4:
|
||||
c->modrm_ea += si;
|
||||
break;
|
||||
case 5:
|
||||
c->modrm_ea += di;
|
||||
break;
|
||||
case 6:
|
||||
if (c->modrm_mod != 0)
|
||||
c->modrm_ea += bp;
|
||||
break;
|
||||
case 7:
|
||||
c->modrm_ea += bx;
|
||||
break;
|
||||
}
|
||||
if (c->modrm_rm == 2 || c->modrm_rm == 3 ||
|
||||
(c->modrm_rm == 6 && c->modrm_mod != 0))
|
||||
if (!c->override_base)
|
||||
c->override_base = &ctxt->ss_base;
|
||||
c->modrm_ea = (u16)c->modrm_ea;
|
||||
} else {
|
||||
/* 32/64-bit ModR/M decode. */
|
||||
switch (c->modrm_rm) {
|
||||
case 4:
|
||||
case 12:
|
||||
sib = insn_fetch(u8, 1, c->eip);
|
||||
index_reg |= (sib >> 3) & 7;
|
||||
base_reg |= sib & 7;
|
||||
scale = sib >> 6;
|
||||
|
||||
switch (base_reg) {
|
||||
case 5:
|
||||
if (c->modrm_mod != 0)
|
||||
c->modrm_ea += c->regs[base_reg];
|
||||
else
|
||||
c->modrm_ea +=
|
||||
insn_fetch(s32, 4, c->eip);
|
||||
break;
|
||||
default:
|
||||
c->modrm_ea += c->regs[base_reg];
|
||||
}
|
||||
switch (index_reg) {
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
c->modrm_ea += c->regs[index_reg] << scale;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (c->modrm_mod != 0)
|
||||
c->modrm_ea += c->regs[c->modrm_rm];
|
||||
else if (ctxt->mode == X86EMUL_MODE_PROT64)
|
||||
rip_relative = 1;
|
||||
break;
|
||||
default:
|
||||
c->modrm_ea += c->regs[c->modrm_rm];
|
||||
break;
|
||||
}
|
||||
switch (c->modrm_mod) {
|
||||
case 0:
|
||||
if (c->modrm_rm == 5)
|
||||
c->modrm_ea += insn_fetch(s32, 4, c->eip);
|
||||
break;
|
||||
case 1:
|
||||
c->modrm_ea += insn_fetch(s8, 1, c->eip);
|
||||
break;
|
||||
case 2:
|
||||
c->modrm_ea += insn_fetch(s32, 4, c->eip);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rip_relative) {
|
||||
c->modrm_ea += c->eip;
|
||||
switch (c->d & SrcMask) {
|
||||
case SrcImmByte:
|
||||
c->modrm_ea += 1;
|
||||
break;
|
||||
case SrcImm:
|
||||
if (c->d & ByteOp)
|
||||
c->modrm_ea += 1;
|
||||
else
|
||||
if (c->op_bytes == 8)
|
||||
c->modrm_ea += 4;
|
||||
else
|
||||
c->modrm_ea += c->op_bytes;
|
||||
}
|
||||
}
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int decode_abs(struct x86_emulate_ctxt *ctxt,
|
||||
struct x86_emulate_ops *ops)
|
||||
{
|
||||
struct decode_cache *c = &ctxt->decode;
|
||||
int rc = 0;
|
||||
|
||||
switch (c->ad_bytes) {
|
||||
case 2:
|
||||
c->modrm_ea = insn_fetch(u16, 2, c->eip);
|
||||
break;
|
||||
case 4:
|
||||
c->modrm_ea = insn_fetch(u32, 4, c->eip);
|
||||
break;
|
||||
case 8:
|
||||
c->modrm_ea = insn_fetch(u64, 8, c->eip);
|
||||
break;
|
||||
}
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
||||
{
|
||||
struct decode_cache *c = &ctxt->decode;
|
||||
u8 sib;
|
||||
int rc = 0;
|
||||
int mode = ctxt->mode;
|
||||
int index_reg = 0, base_reg = 0, scale, rip_relative = 0;
|
||||
|
||||
/* Shadow copy of register state. Committed on successful emulation. */
|
||||
|
||||
|
@ -637,13 +805,9 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
|
|||
done_prefixes:
|
||||
|
||||
/* REX prefix. */
|
||||
if (c->rex_prefix) {
|
||||
if (c->rex_prefix)
|
||||
if (c->rex_prefix & 8)
|
||||
c->op_bytes = 8; /* REX.W */
|
||||
c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */
|
||||
index_reg = (c->rex_prefix & 2) << 2; /* REX.X */
|
||||
c->modrm_rm = base_reg = (c->rex_prefix & 1) << 3; /* REG.B */
|
||||
}
|
||||
|
||||
/* Opcode byte(s). */
|
||||
c->d = opcode_table[c->b];
|
||||
|
@ -663,159 +827,12 @@ done_prefixes:
|
|||
}
|
||||
|
||||
/* ModRM and SIB bytes. */
|
||||
if (c->d & ModRM) {
|
||||
c->modrm = insn_fetch(u8, 1, c->eip);
|
||||
c->modrm_mod |= (c->modrm & 0xc0) >> 6;
|
||||
c->modrm_reg |= (c->modrm & 0x38) >> 3;
|
||||
c->modrm_rm |= (c->modrm & 0x07);
|
||||
c->modrm_ea = 0;
|
||||
c->use_modrm_ea = 1;
|
||||
|
||||
if (c->modrm_mod == 3) {
|
||||
c->modrm_val = *(unsigned long *)
|
||||
decode_register(c->modrm_rm, c->regs, c->d & ByteOp);
|
||||
goto modrm_done;
|
||||
}
|
||||
|
||||
if (c->ad_bytes == 2) {
|
||||
unsigned bx = c->regs[VCPU_REGS_RBX];
|
||||
unsigned bp = c->regs[VCPU_REGS_RBP];
|
||||
unsigned si = c->regs[VCPU_REGS_RSI];
|
||||
unsigned di = c->regs[VCPU_REGS_RDI];
|
||||
|
||||
/* 16-bit ModR/M decode. */
|
||||
switch (c->modrm_mod) {
|
||||
case 0:
|
||||
if (c->modrm_rm == 6)
|
||||
c->modrm_ea +=
|
||||
insn_fetch(u16, 2, c->eip);
|
||||
break;
|
||||
case 1:
|
||||
c->modrm_ea += insn_fetch(s8, 1, c->eip);
|
||||
break;
|
||||
case 2:
|
||||
c->modrm_ea += insn_fetch(u16, 2, c->eip);
|
||||
break;
|
||||
}
|
||||
switch (c->modrm_rm) {
|
||||
case 0:
|
||||
c->modrm_ea += bx + si;
|
||||
break;
|
||||
case 1:
|
||||
c->modrm_ea += bx + di;
|
||||
break;
|
||||
case 2:
|
||||
c->modrm_ea += bp + si;
|
||||
break;
|
||||
case 3:
|
||||
c->modrm_ea += bp + di;
|
||||
break;
|
||||
case 4:
|
||||
c->modrm_ea += si;
|
||||
break;
|
||||
case 5:
|
||||
c->modrm_ea += di;
|
||||
break;
|
||||
case 6:
|
||||
if (c->modrm_mod != 0)
|
||||
c->modrm_ea += bp;
|
||||
break;
|
||||
case 7:
|
||||
c->modrm_ea += bx;
|
||||
break;
|
||||
}
|
||||
if (c->modrm_rm == 2 || c->modrm_rm == 3 ||
|
||||
(c->modrm_rm == 6 && c->modrm_mod != 0))
|
||||
if (!c->override_base)
|
||||
c->override_base = &ctxt->ss_base;
|
||||
c->modrm_ea = (u16)c->modrm_ea;
|
||||
} else {
|
||||
/* 32/64-bit ModR/M decode. */
|
||||
switch (c->modrm_rm) {
|
||||
case 4:
|
||||
case 12:
|
||||
sib = insn_fetch(u8, 1, c->eip);
|
||||
index_reg |= (sib >> 3) & 7;
|
||||
base_reg |= sib & 7;
|
||||
scale = sib >> 6;
|
||||
|
||||
switch (base_reg) {
|
||||
case 5:
|
||||
if (c->modrm_mod != 0)
|
||||
c->modrm_ea +=
|
||||
c->regs[base_reg];
|
||||
else
|
||||
c->modrm_ea +=
|
||||
insn_fetch(s32, 4, c->eip);
|
||||
break;
|
||||
default:
|
||||
c->modrm_ea += c->regs[base_reg];
|
||||
}
|
||||
switch (index_reg) {
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
c->modrm_ea +=
|
||||
c->regs[index_reg] << scale;
|
||||
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (c->modrm_mod != 0)
|
||||
c->modrm_ea += c->regs[c->modrm_rm];
|
||||
else if (mode == X86EMUL_MODE_PROT64)
|
||||
rip_relative = 1;
|
||||
break;
|
||||
default:
|
||||
c->modrm_ea += c->regs[c->modrm_rm];
|
||||
break;
|
||||
}
|
||||
switch (c->modrm_mod) {
|
||||
case 0:
|
||||
if (c->modrm_rm == 5)
|
||||
c->modrm_ea +=
|
||||
insn_fetch(s32, 4, c->eip);
|
||||
break;
|
||||
case 1:
|
||||
c->modrm_ea += insn_fetch(s8, 1, c->eip);
|
||||
break;
|
||||
case 2:
|
||||
c->modrm_ea += insn_fetch(s32, 4, c->eip);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rip_relative) {
|
||||
c->modrm_ea += c->eip;
|
||||
switch (c->d & SrcMask) {
|
||||
case SrcImmByte:
|
||||
c->modrm_ea += 1;
|
||||
break;
|
||||
case SrcImm:
|
||||
if (c->d & ByteOp)
|
||||
c->modrm_ea += 1;
|
||||
else
|
||||
if (c->op_bytes == 8)
|
||||
c->modrm_ea += 4;
|
||||
else
|
||||
c->modrm_ea += c->op_bytes;
|
||||
}
|
||||
}
|
||||
modrm_done:
|
||||
;
|
||||
} else if (c->d & MemAbs) {
|
||||
switch (c->ad_bytes) {
|
||||
case 2:
|
||||
c->modrm_ea = insn_fetch(u16, 2, c->eip);
|
||||
break;
|
||||
case 4:
|
||||
c->modrm_ea = insn_fetch(u32, 4, c->eip);
|
||||
break;
|
||||
case 8:
|
||||
c->modrm_ea = insn_fetch(u64, 8, c->eip);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (c->d & ModRM)
|
||||
rc = decode_modrm(ctxt, ops);
|
||||
else if (c->d & MemAbs)
|
||||
rc = decode_abs(ctxt, ops);
|
||||
if (rc)
|
||||
goto done;
|
||||
|
||||
if (!c->override_base)
|
||||
c->override_base = &ctxt->ds_base;
|
||||
|
|
Загрузка…
Ссылка в новой задаче