]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
KVM: x86 emulator: centralize decoding of one-byte register access insns
authorAvi Kivity <avi@qumranet.com>
Wed, 31 Oct 2007 09:15:56 +0000 (11:15 +0200)
committerAvi Kivity <avi@qumranet.com>
Wed, 30 Jan 2008 15:52:59 +0000 (17:52 +0200)
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>
drivers/kvm/x86_emulate.c
drivers/kvm/x86_emulate.h

index 58ceb66163645c55595261804345eab5acb000c0..884e4a2e47e66dbba5db8e11b4bd2877d6095fd4 100644 (file)
@@ -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,
@@ -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:
@@ -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;
@@ -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;
@@ -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). */
@@ -837,7 +837,7 @@ modrm_done:
        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;
@@ -895,7 +895,7 @@ modrm_done:
                /* 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:
@@ -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;
@@ -1373,43 +1399,6 @@ special_insn:
        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);
index f03b1287700a6e9877e0cc394713721f82cfec2e..e34868b42c334c051dd2ffb4b1d12a074b78859e 100644 (file)
@@ -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;