Skip to content

Commit

Permalink
KVM: x86 emulator: centralize decoding of one-byte register access insns
Browse files Browse the repository at this point in the history
Instructions like 'inc reg' that have the register operand encoded
in the opcode are currently specially decoded.  Extend
decode_register_operand() to handle that case, indicated by having
DstReg or SrcReg without ModRM.

Signed-off-by: Avi Kivity <avi@qumranet.com>
  • Loading branch information
Avi Kivity committed Jan 30, 2008
1 parent 3c118e2 commit 33615aa
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 57 deletions.
103 changes: 46 additions & 57 deletions drivers/kvm/x86_emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,13 @@ static u16 opcode_table[256] = {
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
0, 0, 0, 0,
/* 0x40 - 0x47 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
/* 0x48 - 0x4F */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
/* 0x50 - 0x57 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
SrcReg, SrcReg, SrcReg, SrcReg, SrcReg, SrcReg, SrcReg, SrcReg,
/* 0x58 - 0x5F */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
/* 0x60 - 0x67 */
0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
0, 0, 0, 0,
Expand Down Expand Up @@ -525,13 +521,17 @@ static void decode_register_operand(struct operand *op,
int highbyte_regs,
int inhibit_bytereg)
{
unsigned reg = c->modrm_reg;

if (!(c->d & ModRM))
reg = (c->b & 7) | ((c->rex_prefix & 1) << 3);
op->type = OP_REG;
if ((c->d & ByteOp) && !inhibit_bytereg) {
op->ptr = decode_register(c->modrm_reg, c->regs, highbyte_regs);
op->ptr = decode_register(reg, c->regs, highbyte_regs);
op->val = *(u8 *)op->ptr;
op->bytes = 1;
} else {
op->ptr = decode_register(c->modrm_reg, c->regs, 0);
op->ptr = decode_register(reg, c->regs, 0);
op->bytes = c->op_bytes;
switch (op->bytes) {
case 2:
Expand All @@ -552,7 +552,7 @@ int
x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{
struct decode_cache *c = &ctxt->decode;
u8 sib, rex_prefix = 0;
u8 sib;
int rc = 0;
int mode = ctxt->mode;
int index_reg = 0, base_reg = 0, scale, rip_relative = 0;
Expand Down Expand Up @@ -616,7 +616,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
case 0x40 ... 0x4f: /* REX */
if (mode != X86EMUL_MODE_PROT64)
goto done_prefixes;
rex_prefix = c->b;
c->rex_prefix = c->b;
continue;
case 0xf0: /* LOCK */
c->lock_prefix = 1;
Expand All @@ -631,18 +631,18 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)

/* Any legacy prefix after a REX prefix nullifies its effect. */

rex_prefix = 0;
c->rex_prefix = 0;
}

done_prefixes:

/* REX prefix. */
if (rex_prefix) {
if (rex_prefix & 8)
if (c->rex_prefix) {
if (c->rex_prefix & 8)
c->op_bytes = 8; /* REX.W */
c->modrm_reg = (rex_prefix & 4) << 1; /* REX.R */
index_reg = (rex_prefix & 2) << 2; /* REX.X */
c->modrm_rm = base_reg = (rex_prefix & 1) << 3; /* REG.B */
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). */
Expand Down Expand Up @@ -837,7 +837,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
case SrcNone:
break;
case SrcReg:
decode_register_operand(&c->src, c, rex_prefix == 0, 0);
decode_register_operand(&c->src, c, c->rex_prefix == 0, 0);
break;
case SrcMem16:
c->src.bytes = 2;
Expand Down Expand Up @@ -895,7 +895,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
/* Special instructions do their own operand decoding. */
return 0;
case DstReg:
decode_register_operand(&c->dst, c, rex_prefix == 0,
decode_register_operand(&c->dst, c, c->rex_prefix == 0,
c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
break;
case DstMem:
Expand Down Expand Up @@ -1258,6 +1258,32 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
cmp: /* cmp */
emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags);
break;
case 0x40 ... 0x47: /* inc r16/r32 */
emulate_1op("inc", c->dst, ctxt->eflags);
break;
case 0x48 ... 0x4f: /* dec r16/r32 */
emulate_1op("dec", c->dst, ctxt->eflags);
break;
case 0x50 ... 0x57: /* push reg */
c->dst.type = OP_MEM;
c->dst.bytes = c->op_bytes;
c->dst.val = c->src.val;
register_address_increment(c->regs[VCPU_REGS_RSP],
-c->op_bytes);
c->dst.ptr = (void *) register_address(
ctxt->ss_base, c->regs[VCPU_REGS_RSP]);
break;
case 0x58 ... 0x5f: /* pop reg */
pop_instruction:
if ((rc = ops->read_std(register_address(ctxt->ss_base,
c->regs[VCPU_REGS_RSP]), c->dst.ptr,
c->op_bytes, ctxt->vcpu)) != 0)
goto done;

register_address_increment(c->regs[VCPU_REGS_RSP],
c->op_bytes);
c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0x63: /* movsxd */
if (ctxt->mode != X86EMUL_MODE_PROT64)
goto cannot_emulate;
Expand Down Expand Up @@ -1373,43 +1399,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
if (c->twobyte)
goto twobyte_special_insn;
switch (c->b) {
case 0x40 ... 0x47: /* inc r16/r32 */
c->dst.bytes = c->op_bytes;
c->dst.ptr = (unsigned long *)&c->regs[c->b & 0x7];
c->dst.val = *c->dst.ptr;
emulate_1op("inc", c->dst, ctxt->eflags);
break;
case 0x48 ... 0x4f: /* dec r16/r32 */
c->dst.bytes = c->op_bytes;
c->dst.ptr = (unsigned long *)&c->regs[c->b & 0x7];
c->dst.val = *c->dst.ptr;
emulate_1op("dec", c->dst, ctxt->eflags);
break;
case 0x50 ... 0x57: /* push reg */
if (c->op_bytes == 2)
c->src.val = (u16) c->regs[c->b & 0x7];
else
c->src.val = (u32) c->regs[c->b & 0x7];
c->dst.type = OP_MEM;
c->dst.bytes = c->op_bytes;
c->dst.val = c->src.val;
register_address_increment(c->regs[VCPU_REGS_RSP],
-c->op_bytes);
c->dst.ptr = (void *) register_address(
ctxt->ss_base, c->regs[VCPU_REGS_RSP]);
break;
case 0x58 ... 0x5f: /* pop reg */
c->dst.ptr = (unsigned long *)&c->regs[c->b & 0x7];
pop_instruction:
if ((rc = ops->read_std(register_address(ctxt->ss_base,
c->regs[VCPU_REGS_RSP]), c->dst.ptr,
c->op_bytes, ctxt->vcpu)) != 0)
goto done;

register_address_increment(c->regs[VCPU_REGS_RSP],
c->op_bytes);
c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0x6a: /* push imm8 */
c->src.val = 0L;
c->src.val = insn_fetch(s8, 1, c->eip);
Expand Down
1 change: 1 addition & 0 deletions drivers/kvm/x86_emulate.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ struct decode_cache {
u8 rep_prefix;
u8 op_bytes;
u8 ad_bytes;
u8 rex_prefix;
struct operand src;
struct operand dst;
unsigned long *override_base;
Expand Down

0 comments on commit 33615aa

Please sign in to comment.