diff options
author | Avi Kivity <avi@qumranet.com> | 2007-10-31 05:15:56 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:52:59 -0500 |
commit | 33615aa956521923eab0552994b5961cd3034042 (patch) | |
tree | dae9983159614d9bdfed6d60201e60f1a72105f0 /drivers/kvm/x86_emulate.c | |
parent | 3c118e24af821d68dca0ba81e9499820c840c133 (diff) |
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: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/x86_emulate.c')
-rw-r--r-- | drivers/kvm/x86_emulate.c | 103 |
1 files changed, 46 insertions, 57 deletions
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 58ceb6616364..884e4a2e47e6 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c | |||
@@ -99,17 +99,13 @@ static u16 opcode_table[256] = { | |||
99 | ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, | 99 | ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, |
100 | 0, 0, 0, 0, | 100 | 0, 0, 0, 0, |
101 | /* 0x40 - 0x47 */ | 101 | /* 0x40 - 0x47 */ |
102 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | 102 | DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, |
103 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | ||
104 | /* 0x48 - 0x4F */ | 103 | /* 0x48 - 0x4F */ |
105 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | 104 | DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, |
106 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | ||
107 | /* 0x50 - 0x57 */ | 105 | /* 0x50 - 0x57 */ |
108 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | 106 | SrcReg, SrcReg, SrcReg, SrcReg, SrcReg, SrcReg, SrcReg, SrcReg, |
109 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | ||
110 | /* 0x58 - 0x5F */ | 107 | /* 0x58 - 0x5F */ |
111 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | 108 | DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, |
112 | ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, | ||
113 | /* 0x60 - 0x67 */ | 109 | /* 0x60 - 0x67 */ |
114 | 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , | 110 | 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , |
115 | 0, 0, 0, 0, | 111 | 0, 0, 0, 0, |
@@ -525,13 +521,17 @@ static void decode_register_operand(struct operand *op, | |||
525 | int highbyte_regs, | 521 | int highbyte_regs, |
526 | int inhibit_bytereg) | 522 | int inhibit_bytereg) |
527 | { | 523 | { |
524 | unsigned reg = c->modrm_reg; | ||
525 | |||
526 | if (!(c->d & ModRM)) | ||
527 | reg = (c->b & 7) | ((c->rex_prefix & 1) << 3); | ||
528 | op->type = OP_REG; | 528 | op->type = OP_REG; |
529 | if ((c->d & ByteOp) && !inhibit_bytereg) { | 529 | if ((c->d & ByteOp) && !inhibit_bytereg) { |
530 | op->ptr = decode_register(c->modrm_reg, c->regs, highbyte_regs); | 530 | op->ptr = decode_register(reg, c->regs, highbyte_regs); |
531 | op->val = *(u8 *)op->ptr; | 531 | op->val = *(u8 *)op->ptr; |
532 | op->bytes = 1; | 532 | op->bytes = 1; |
533 | } else { | 533 | } else { |
534 | op->ptr = decode_register(c->modrm_reg, c->regs, 0); | 534 | op->ptr = decode_register(reg, c->regs, 0); |
535 | op->bytes = c->op_bytes; | 535 | op->bytes = c->op_bytes; |
536 | switch (op->bytes) { | 536 | switch (op->bytes) { |
537 | case 2: | 537 | case 2: |
@@ -552,7 +552,7 @@ int | |||
552 | x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | 552 | x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) |
553 | { | 553 | { |
554 | struct decode_cache *c = &ctxt->decode; | 554 | struct decode_cache *c = &ctxt->decode; |
555 | u8 sib, rex_prefix = 0; | 555 | u8 sib; |
556 | int rc = 0; | 556 | int rc = 0; |
557 | int mode = ctxt->mode; | 557 | int mode = ctxt->mode; |
558 | int index_reg = 0, base_reg = 0, scale, rip_relative = 0; | 558 | 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 | case 0x40 ... 0x4f: /* REX */ | 616 | case 0x40 ... 0x4f: /* REX */ |
617 | if (mode != X86EMUL_MODE_PROT64) | 617 | if (mode != X86EMUL_MODE_PROT64) |
618 | goto done_prefixes; | 618 | goto done_prefixes; |
619 | rex_prefix = c->b; | 619 | c->rex_prefix = c->b; |
620 | continue; | 620 | continue; |
621 | case 0xf0: /* LOCK */ | 621 | case 0xf0: /* LOCK */ |
622 | c->lock_prefix = 1; | 622 | c->lock_prefix = 1; |
@@ -631,18 +631,18 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
631 | 631 | ||
632 | /* Any legacy prefix after a REX prefix nullifies its effect. */ | 632 | /* Any legacy prefix after a REX prefix nullifies its effect. */ |
633 | 633 | ||
634 | rex_prefix = 0; | 634 | c->rex_prefix = 0; |
635 | } | 635 | } |
636 | 636 | ||
637 | done_prefixes: | 637 | done_prefixes: |
638 | 638 | ||
639 | /* REX prefix. */ | 639 | /* REX prefix. */ |
640 | if (rex_prefix) { | 640 | if (c->rex_prefix) { |
641 | if (rex_prefix & 8) | 641 | if (c->rex_prefix & 8) |
642 | c->op_bytes = 8; /* REX.W */ | 642 | c->op_bytes = 8; /* REX.W */ |
643 | c->modrm_reg = (rex_prefix & 4) << 1; /* REX.R */ | 643 | c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */ |
644 | index_reg = (rex_prefix & 2) << 2; /* REX.X */ | 644 | index_reg = (c->rex_prefix & 2) << 2; /* REX.X */ |
645 | c->modrm_rm = base_reg = (rex_prefix & 1) << 3; /* REG.B */ | 645 | c->modrm_rm = base_reg = (c->rex_prefix & 1) << 3; /* REG.B */ |
646 | } | 646 | } |
647 | 647 | ||
648 | /* Opcode byte(s). */ | 648 | /* Opcode byte(s). */ |
@@ -837,7 +837,7 @@ modrm_done: | |||
837 | case SrcNone: | 837 | case SrcNone: |
838 | break; | 838 | break; |
839 | case SrcReg: | 839 | case SrcReg: |
840 | decode_register_operand(&c->src, c, rex_prefix == 0, 0); | 840 | decode_register_operand(&c->src, c, c->rex_prefix == 0, 0); |
841 | break; | 841 | break; |
842 | case SrcMem16: | 842 | case SrcMem16: |
843 | c->src.bytes = 2; | 843 | c->src.bytes = 2; |
@@ -895,7 +895,7 @@ modrm_done: | |||
895 | /* Special instructions do their own operand decoding. */ | 895 | /* Special instructions do their own operand decoding. */ |
896 | return 0; | 896 | return 0; |
897 | case DstReg: | 897 | case DstReg: |
898 | decode_register_operand(&c->dst, c, rex_prefix == 0, | 898 | decode_register_operand(&c->dst, c, c->rex_prefix == 0, |
899 | c->twobyte && (c->b == 0xb6 || c->b == 0xb7)); | 899 | c->twobyte && (c->b == 0xb6 || c->b == 0xb7)); |
900 | break; | 900 | break; |
901 | case DstMem: | 901 | case DstMem: |
@@ -1258,6 +1258,32 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
1258 | cmp: /* cmp */ | 1258 | cmp: /* cmp */ |
1259 | emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); | 1259 | emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); |
1260 | break; | 1260 | break; |
1261 | case 0x40 ... 0x47: /* inc r16/r32 */ | ||
1262 | emulate_1op("inc", c->dst, ctxt->eflags); | ||
1263 | break; | ||
1264 | case 0x48 ... 0x4f: /* dec r16/r32 */ | ||
1265 | emulate_1op("dec", c->dst, ctxt->eflags); | ||
1266 | break; | ||
1267 | case 0x50 ... 0x57: /* push reg */ | ||
1268 | c->dst.type = OP_MEM; | ||
1269 | c->dst.bytes = c->op_bytes; | ||
1270 | c->dst.val = c->src.val; | ||
1271 | register_address_increment(c->regs[VCPU_REGS_RSP], | ||
1272 | -c->op_bytes); | ||
1273 | c->dst.ptr = (void *) register_address( | ||
1274 | ctxt->ss_base, c->regs[VCPU_REGS_RSP]); | ||
1275 | break; | ||
1276 | case 0x58 ... 0x5f: /* pop reg */ | ||
1277 | pop_instruction: | ||
1278 | if ((rc = ops->read_std(register_address(ctxt->ss_base, | ||
1279 | c->regs[VCPU_REGS_RSP]), c->dst.ptr, | ||
1280 | c->op_bytes, ctxt->vcpu)) != 0) | ||
1281 | goto done; | ||
1282 | |||
1283 | register_address_increment(c->regs[VCPU_REGS_RSP], | ||
1284 | c->op_bytes); | ||
1285 | c->dst.type = OP_NONE; /* Disable writeback. */ | ||
1286 | break; | ||
1261 | case 0x63: /* movsxd */ | 1287 | case 0x63: /* movsxd */ |
1262 | if (ctxt->mode != X86EMUL_MODE_PROT64) | 1288 | if (ctxt->mode != X86EMUL_MODE_PROT64) |
1263 | goto cannot_emulate; | 1289 | goto cannot_emulate; |
@@ -1373,43 +1399,6 @@ special_insn: | |||
1373 | if (c->twobyte) | 1399 | if (c->twobyte) |
1374 | goto twobyte_special_insn; | 1400 | goto twobyte_special_insn; |
1375 | switch (c->b) { | 1401 | switch (c->b) { |
1376 | case 0x40 ... 0x47: /* inc r16/r32 */ | ||
1377 | c->dst.bytes = c->op_bytes; | ||
1378 | c->dst.ptr = (unsigned long *)&c->regs[c->b & 0x7]; | ||
1379 | c->dst.val = *c->dst.ptr; | ||
1380 | emulate_1op("inc", c->dst, ctxt->eflags); | ||
1381 | break; | ||
1382 | case 0x48 ... 0x4f: /* dec r16/r32 */ | ||
1383 | c->dst.bytes = c->op_bytes; | ||
1384 | c->dst.ptr = (unsigned long *)&c->regs[c->b & 0x7]; | ||
1385 | c->dst.val = *c->dst.ptr; | ||
1386 | emulate_1op("dec", c->dst, ctxt->eflags); | ||
1387 | break; | ||
1388 | case 0x50 ... 0x57: /* push reg */ | ||
1389 | if (c->op_bytes == 2) | ||
1390 | c->src.val = (u16) c->regs[c->b & 0x7]; | ||
1391 | else | ||
1392 | c->src.val = (u32) c->regs[c->b & 0x7]; | ||
1393 | c->dst.type = OP_MEM; | ||
1394 | c->dst.bytes = c->op_bytes; | ||
1395 | c->dst.val = c->src.val; | ||
1396 | register_address_increment(c->regs[VCPU_REGS_RSP], | ||
1397 | -c->op_bytes); | ||
1398 | c->dst.ptr = (void *) register_address( | ||
1399 | ctxt->ss_base, c->regs[VCPU_REGS_RSP]); | ||
1400 | break; | ||
1401 | case 0x58 ... 0x5f: /* pop reg */ | ||
1402 | c->dst.ptr = (unsigned long *)&c->regs[c->b & 0x7]; | ||
1403 | pop_instruction: | ||
1404 | if ((rc = ops->read_std(register_address(ctxt->ss_base, | ||
1405 | c->regs[VCPU_REGS_RSP]), c->dst.ptr, | ||
1406 | c->op_bytes, ctxt->vcpu)) != 0) | ||
1407 | goto done; | ||
1408 | |||
1409 | register_address_increment(c->regs[VCPU_REGS_RSP], | ||
1410 | c->op_bytes); | ||
1411 | c->dst.type = OP_NONE; /* Disable writeback. */ | ||
1412 | break; | ||
1413 | case 0x6a: /* push imm8 */ | 1402 | case 0x6a: /* push imm8 */ |
1414 | c->src.val = 0L; | 1403 | c->src.val = 0L; |
1415 | c->src.val = insn_fetch(s8, 1, c->eip); | 1404 | c->src.val = insn_fetch(s8, 1, c->eip); |