Commit 33615aa9 authored by Avi Kivity's avatar Avi Kivity

KVM: x86 emulator: centralize decoding of one-byte register access insns

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: default avatarAvi Kivity <avi@qumranet.com>
parent 3c118e24
...@@ -99,17 +99,13 @@ static u16 opcode_table[256] = { ...@@ -99,17 +99,13 @@ static u16 opcode_table[256] = {
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
0, 0, 0, 0, 0, 0, 0, 0,
/* 0x40 - 0x47 */ /* 0x40 - 0x47 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x48 - 0x4F */ /* 0x48 - 0x4F */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x50 - 0x57 */ /* 0x50 - 0x57 */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, SrcReg, SrcReg, SrcReg, SrcReg, SrcReg, SrcReg, SrcReg, SrcReg,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x58 - 0x5F */ /* 0x58 - 0x5F */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x60 - 0x67 */ /* 0x60 - 0x67 */
0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
0, 0, 0, 0, 0, 0, 0, 0,
...@@ -525,13 +521,17 @@ static void decode_register_operand(struct operand *op, ...@@ -525,13 +521,17 @@ static void decode_register_operand(struct operand *op,
int highbyte_regs, int highbyte_regs,
int inhibit_bytereg) 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; op->type = OP_REG;
if ((c->d & ByteOp) && !inhibit_bytereg) { 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->val = *(u8 *)op->ptr;
op->bytes = 1; op->bytes = 1;
} else { } else {
op->ptr = decode_register(c->modrm_reg, c->regs, 0); op->ptr = decode_register(reg, c->regs, 0);
op->bytes = c->op_bytes; op->bytes = c->op_bytes;
switch (op->bytes) { switch (op->bytes) {
case 2: case 2:
...@@ -552,7 +552,7 @@ int ...@@ -552,7 +552,7 @@ int
x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{ {
struct decode_cache *c = &ctxt->decode; struct decode_cache *c = &ctxt->decode;
u8 sib, rex_prefix = 0; u8 sib;
int rc = 0; int rc = 0;
int mode = ctxt->mode; int mode = ctxt->mode;
int index_reg = 0, base_reg = 0, scale, rip_relative = 0; int index_reg = 0, base_reg = 0, scale, rip_relative = 0;
...@@ -616,7 +616,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) ...@@ -616,7 +616,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
case 0x40 ... 0x4f: /* REX */ case 0x40 ... 0x4f: /* REX */
if (mode != X86EMUL_MODE_PROT64) if (mode != X86EMUL_MODE_PROT64)
goto done_prefixes; goto done_prefixes;
rex_prefix = c->b; c->rex_prefix = c->b;
continue; continue;
case 0xf0: /* LOCK */ case 0xf0: /* LOCK */
c->lock_prefix = 1; c->lock_prefix = 1;
...@@ -631,18 +631,18 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) ...@@ -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. */ /* Any legacy prefix after a REX prefix nullifies its effect. */
rex_prefix = 0; c->rex_prefix = 0;
} }
done_prefixes: done_prefixes:
/* REX prefix. */ /* REX prefix. */
if (rex_prefix) { if (c->rex_prefix) {
if (rex_prefix & 8) if (c->rex_prefix & 8)
c->op_bytes = 8; /* REX.W */ c->op_bytes = 8; /* REX.W */
c->modrm_reg = (rex_prefix & 4) << 1; /* REX.R */ c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */
index_reg = (rex_prefix & 2) << 2; /* REX.X */ index_reg = (c->rex_prefix & 2) << 2; /* REX.X */
c->modrm_rm = base_reg = (rex_prefix & 1) << 3; /* REG.B */ c->modrm_rm = base_reg = (c->rex_prefix & 1) << 3; /* REG.B */
} }
/* Opcode byte(s). */ /* Opcode byte(s). */
...@@ -837,7 +837,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) ...@@ -837,7 +837,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
case SrcNone: case SrcNone:
break; break;
case SrcReg: case SrcReg:
decode_register_operand(&c->src, c, rex_prefix == 0, 0); decode_register_operand(&c->src, c, c->rex_prefix == 0, 0);
break; break;
case SrcMem16: case SrcMem16:
c->src.bytes = 2; c->src.bytes = 2;
...@@ -895,7 +895,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) ...@@ -895,7 +895,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
/* Special instructions do their own operand decoding. */ /* Special instructions do their own operand decoding. */
return 0; return 0;
case DstReg: 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)); c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
break; break;
case DstMem: case DstMem:
...@@ -1258,6 +1258,32 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) ...@@ -1258,6 +1258,32 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
cmp: /* cmp */ cmp: /* cmp */
emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags);
break; 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 */ case 0x63: /* movsxd */
if (ctxt->mode != X86EMUL_MODE_PROT64) if (ctxt->mode != X86EMUL_MODE_PROT64)
goto cannot_emulate; goto cannot_emulate;
...@@ -1373,43 +1399,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) ...@@ -1373,43 +1399,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
if (c->twobyte) if (c->twobyte)
goto twobyte_special_insn; goto twobyte_special_insn;
switch (c->b) { 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 */ case 0x6a: /* push imm8 */
c->src.val = 0L; c->src.val = 0L;
c->src.val = insn_fetch(s8, 1, c->eip); c->src.val = insn_fetch(s8, 1, c->eip);
......
...@@ -126,6 +126,7 @@ struct decode_cache { ...@@ -126,6 +126,7 @@ struct decode_cache {
u8 rep_prefix; u8 rep_prefix;
u8 op_bytes; u8 op_bytes;
u8 ad_bytes; u8 ad_bytes;
u8 rex_prefix;
struct operand src; struct operand src;
struct operand dst; struct operand dst;
unsigned long *override_base; unsigned long *override_base;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment