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 | |
| 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')
| -rw-r--r-- | drivers/kvm/x86_emulate.c | 103 | ||||
| -rw-r--r-- | drivers/kvm/x86_emulate.h | 1 |
2 files changed, 47 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); |
diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h index f03b1287700a..e34868b42c33 100644 --- a/drivers/kvm/x86_emulate.h +++ b/drivers/kvm/x86_emulate.h | |||
| @@ -126,6 +126,7 @@ struct decode_cache { | |||
| 126 | u8 rep_prefix; | 126 | u8 rep_prefix; |
| 127 | u8 op_bytes; | 127 | u8 op_bytes; |
| 128 | u8 ad_bytes; | 128 | u8 ad_bytes; |
| 129 | u8 rex_prefix; | ||
| 129 | struct operand src; | 130 | struct operand src; |
| 130 | struct operand dst; | 131 | struct operand dst; |
| 131 | unsigned long *override_base; | 132 | unsigned long *override_base; |
