diff options
author | Avi Kivity <avi@redhat.com> | 2010-08-01 08:40:19 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-10-24 04:50:40 -0400 |
commit | 2dbd0dd711e6c0ca6a2be9e6d93bbeb339386638 (patch) | |
tree | a4b4cd21579263b64c4287489a59f301d2c5e667 /arch | |
parent | 1f6f05800e2fdd815ac63e3264071d26d429f491 (diff) |
KVM: x86 emulator: Decode memory operands directly into a 'struct operand'
Since modrm operand can be either register or memory, decoding it into
a 'struct operand', which can represent both, is simpler.
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/kvm_emulate.h | 3 | ||||
-rw-r--r-- | arch/x86/kvm/emulate.c | 125 |
2 files changed, 57 insertions, 71 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index e425444658e8..1e4a72ce301a 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h | |||
@@ -203,9 +203,6 @@ struct decode_cache { | |||
203 | u8 modrm_rm; | 203 | u8 modrm_rm; |
204 | u8 modrm_seg; | 204 | u8 modrm_seg; |
205 | bool rip_relative; | 205 | bool rip_relative; |
206 | unsigned long modrm_ea; | ||
207 | void *modrm_ptr; | ||
208 | unsigned long modrm_val; | ||
209 | struct fetch_cache fetch; | 206 | struct fetch_cache fetch; |
210 | struct read_cache io_read; | 207 | struct read_cache io_read; |
211 | struct read_cache mem_read; | 208 | struct read_cache mem_read; |
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index eda69411d050..955d48074648 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -581,12 +581,14 @@ static void decode_register_operand(struct operand *op, | |||
581 | } | 581 | } |
582 | 582 | ||
583 | static int decode_modrm(struct x86_emulate_ctxt *ctxt, | 583 | static int decode_modrm(struct x86_emulate_ctxt *ctxt, |
584 | struct x86_emulate_ops *ops) | 584 | struct x86_emulate_ops *ops, |
585 | struct operand *op) | ||
585 | { | 586 | { |
586 | struct decode_cache *c = &ctxt->decode; | 587 | struct decode_cache *c = &ctxt->decode; |
587 | u8 sib; | 588 | u8 sib; |
588 | int index_reg = 0, base_reg = 0, scale; | 589 | int index_reg = 0, base_reg = 0, scale; |
589 | int rc = X86EMUL_CONTINUE; | 590 | int rc = X86EMUL_CONTINUE; |
591 | ulong modrm_ea = 0; | ||
590 | 592 | ||
591 | if (c->rex_prefix) { | 593 | if (c->rex_prefix) { |
592 | c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */ | 594 | c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */ |
@@ -598,16 +600,19 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, | |||
598 | c->modrm_mod |= (c->modrm & 0xc0) >> 6; | 600 | c->modrm_mod |= (c->modrm & 0xc0) >> 6; |
599 | c->modrm_reg |= (c->modrm & 0x38) >> 3; | 601 | c->modrm_reg |= (c->modrm & 0x38) >> 3; |
600 | c->modrm_rm |= (c->modrm & 0x07); | 602 | c->modrm_rm |= (c->modrm & 0x07); |
601 | c->modrm_ea = 0; | ||
602 | c->modrm_seg = VCPU_SREG_DS; | 603 | c->modrm_seg = VCPU_SREG_DS; |
603 | 604 | ||
604 | if (c->modrm_mod == 3) { | 605 | if (c->modrm_mod == 3) { |
605 | c->modrm_ptr = decode_register(c->modrm_rm, | 606 | op->type = OP_REG; |
607 | op->bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | ||
608 | op->addr.reg = decode_register(c->modrm_rm, | ||
606 | c->regs, c->d & ByteOp); | 609 | c->regs, c->d & ByteOp); |
607 | c->modrm_val = *(unsigned long *)c->modrm_ptr; | 610 | fetch_register_operand(op); |
608 | return rc; | 611 | return rc; |
609 | } | 612 | } |
610 | 613 | ||
614 | op->type = OP_MEM; | ||
615 | |||
611 | if (c->ad_bytes == 2) { | 616 | if (c->ad_bytes == 2) { |
612 | unsigned bx = c->regs[VCPU_REGS_RBX]; | 617 | unsigned bx = c->regs[VCPU_REGS_RBX]; |
613 | unsigned bp = c->regs[VCPU_REGS_RBP]; | 618 | unsigned bp = c->regs[VCPU_REGS_RBP]; |
@@ -618,46 +623,46 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, | |||
618 | switch (c->modrm_mod) { | 623 | switch (c->modrm_mod) { |
619 | case 0: | 624 | case 0: |
620 | if (c->modrm_rm == 6) | 625 | if (c->modrm_rm == 6) |
621 | c->modrm_ea += insn_fetch(u16, 2, c->eip); | 626 | modrm_ea += insn_fetch(u16, 2, c->eip); |
622 | break; | 627 | break; |
623 | case 1: | 628 | case 1: |
624 | c->modrm_ea += insn_fetch(s8, 1, c->eip); | 629 | modrm_ea += insn_fetch(s8, 1, c->eip); |
625 | break; | 630 | break; |
626 | case 2: | 631 | case 2: |
627 | c->modrm_ea += insn_fetch(u16, 2, c->eip); | 632 | modrm_ea += insn_fetch(u16, 2, c->eip); |
628 | break; | 633 | break; |
629 | } | 634 | } |
630 | switch (c->modrm_rm) { | 635 | switch (c->modrm_rm) { |
631 | case 0: | 636 | case 0: |
632 | c->modrm_ea += bx + si; | 637 | modrm_ea += bx + si; |
633 | break; | 638 | break; |
634 | case 1: | 639 | case 1: |
635 | c->modrm_ea += bx + di; | 640 | modrm_ea += bx + di; |
636 | break; | 641 | break; |
637 | case 2: | 642 | case 2: |
638 | c->modrm_ea += bp + si; | 643 | modrm_ea += bp + si; |
639 | break; | 644 | break; |
640 | case 3: | 645 | case 3: |
641 | c->modrm_ea += bp + di; | 646 | modrm_ea += bp + di; |
642 | break; | 647 | break; |
643 | case 4: | 648 | case 4: |
644 | c->modrm_ea += si; | 649 | modrm_ea += si; |
645 | break; | 650 | break; |
646 | case 5: | 651 | case 5: |
647 | c->modrm_ea += di; | 652 | modrm_ea += di; |
648 | break; | 653 | break; |
649 | case 6: | 654 | case 6: |
650 | if (c->modrm_mod != 0) | 655 | if (c->modrm_mod != 0) |
651 | c->modrm_ea += bp; | 656 | modrm_ea += bp; |
652 | break; | 657 | break; |
653 | case 7: | 658 | case 7: |
654 | c->modrm_ea += bx; | 659 | modrm_ea += bx; |
655 | break; | 660 | break; |
656 | } | 661 | } |
657 | if (c->modrm_rm == 2 || c->modrm_rm == 3 || | 662 | if (c->modrm_rm == 2 || c->modrm_rm == 3 || |
658 | (c->modrm_rm == 6 && c->modrm_mod != 0)) | 663 | (c->modrm_rm == 6 && c->modrm_mod != 0)) |
659 | c->modrm_seg = VCPU_SREG_SS; | 664 | c->modrm_seg = VCPU_SREG_SS; |
660 | c->modrm_ea = (u16)c->modrm_ea; | 665 | modrm_ea = (u16)modrm_ea; |
661 | } else { | 666 | } else { |
662 | /* 32/64-bit ModR/M decode. */ | 667 | /* 32/64-bit ModR/M decode. */ |
663 | if ((c->modrm_rm & 7) == 4) { | 668 | if ((c->modrm_rm & 7) == 4) { |
@@ -667,48 +672,51 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, | |||
667 | scale = sib >> 6; | 672 | scale = sib >> 6; |
668 | 673 | ||
669 | if ((base_reg & 7) == 5 && c->modrm_mod == 0) | 674 | if ((base_reg & 7) == 5 && c->modrm_mod == 0) |
670 | c->modrm_ea += insn_fetch(s32, 4, c->eip); | 675 | modrm_ea += insn_fetch(s32, 4, c->eip); |
671 | else | 676 | else |
672 | c->modrm_ea += c->regs[base_reg]; | 677 | modrm_ea += c->regs[base_reg]; |
673 | if (index_reg != 4) | 678 | if (index_reg != 4) |
674 | c->modrm_ea += c->regs[index_reg] << scale; | 679 | modrm_ea += c->regs[index_reg] << scale; |
675 | } else if ((c->modrm_rm & 7) == 5 && c->modrm_mod == 0) { | 680 | } else if ((c->modrm_rm & 7) == 5 && c->modrm_mod == 0) { |
676 | if (ctxt->mode == X86EMUL_MODE_PROT64) | 681 | if (ctxt->mode == X86EMUL_MODE_PROT64) |
677 | c->rip_relative = 1; | 682 | c->rip_relative = 1; |
678 | } else | 683 | } else |
679 | c->modrm_ea += c->regs[c->modrm_rm]; | 684 | modrm_ea += c->regs[c->modrm_rm]; |
680 | switch (c->modrm_mod) { | 685 | switch (c->modrm_mod) { |
681 | case 0: | 686 | case 0: |
682 | if (c->modrm_rm == 5) | 687 | if (c->modrm_rm == 5) |
683 | c->modrm_ea += insn_fetch(s32, 4, c->eip); | 688 | modrm_ea += insn_fetch(s32, 4, c->eip); |
684 | break; | 689 | break; |
685 | case 1: | 690 | case 1: |
686 | c->modrm_ea += insn_fetch(s8, 1, c->eip); | 691 | modrm_ea += insn_fetch(s8, 1, c->eip); |
687 | break; | 692 | break; |
688 | case 2: | 693 | case 2: |
689 | c->modrm_ea += insn_fetch(s32, 4, c->eip); | 694 | modrm_ea += insn_fetch(s32, 4, c->eip); |
690 | break; | 695 | break; |
691 | } | 696 | } |
692 | } | 697 | } |
698 | op->addr.mem = modrm_ea; | ||
693 | done: | 699 | done: |
694 | return rc; | 700 | return rc; |
695 | } | 701 | } |
696 | 702 | ||
697 | static int decode_abs(struct x86_emulate_ctxt *ctxt, | 703 | static int decode_abs(struct x86_emulate_ctxt *ctxt, |
698 | struct x86_emulate_ops *ops) | 704 | struct x86_emulate_ops *ops, |
705 | struct operand *op) | ||
699 | { | 706 | { |
700 | struct decode_cache *c = &ctxt->decode; | 707 | struct decode_cache *c = &ctxt->decode; |
701 | int rc = X86EMUL_CONTINUE; | 708 | int rc = X86EMUL_CONTINUE; |
702 | 709 | ||
710 | op->type = OP_MEM; | ||
703 | switch (c->ad_bytes) { | 711 | switch (c->ad_bytes) { |
704 | case 2: | 712 | case 2: |
705 | c->modrm_ea = insn_fetch(u16, 2, c->eip); | 713 | op->addr.mem = insn_fetch(u16, 2, c->eip); |
706 | break; | 714 | break; |
707 | case 4: | 715 | case 4: |
708 | c->modrm_ea = insn_fetch(u32, 4, c->eip); | 716 | op->addr.mem = insn_fetch(u32, 4, c->eip); |
709 | break; | 717 | break; |
710 | case 8: | 718 | case 8: |
711 | c->modrm_ea = insn_fetch(u64, 8, c->eip); | 719 | op->addr.mem = insn_fetch(u64, 8, c->eip); |
712 | break; | 720 | break; |
713 | } | 721 | } |
714 | done: | 722 | done: |
@@ -2280,6 +2288,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt) | |||
2280 | int mode = ctxt->mode; | 2288 | int mode = ctxt->mode; |
2281 | int def_op_bytes, def_ad_bytes, dual, goffset; | 2289 | int def_op_bytes, def_ad_bytes, dual, goffset; |
2282 | struct opcode opcode, *g_mod012, *g_mod3; | 2290 | struct opcode opcode, *g_mod012, *g_mod3; |
2291 | struct operand memop = { .type = OP_NONE }; | ||
2283 | 2292 | ||
2284 | /* we cannot decode insn before we complete previous rep insn */ | 2293 | /* we cannot decode insn before we complete previous rep insn */ |
2285 | WARN_ON(ctxt->restart); | 2294 | WARN_ON(ctxt->restart); |
@@ -2418,25 +2427,25 @@ done_prefixes: | |||
2418 | 2427 | ||
2419 | /* ModRM and SIB bytes. */ | 2428 | /* ModRM and SIB bytes. */ |
2420 | if (c->d & ModRM) { | 2429 | if (c->d & ModRM) { |
2421 | rc = decode_modrm(ctxt, ops); | 2430 | rc = decode_modrm(ctxt, ops, &memop); |
2422 | if (!c->has_seg_override) | 2431 | if (!c->has_seg_override) |
2423 | set_seg_override(c, c->modrm_seg); | 2432 | set_seg_override(c, c->modrm_seg); |
2424 | } else if (c->d & MemAbs) | 2433 | } else if (c->d & MemAbs) |
2425 | rc = decode_abs(ctxt, ops); | 2434 | rc = decode_abs(ctxt, ops, &memop); |
2426 | if (rc != X86EMUL_CONTINUE) | 2435 | if (rc != X86EMUL_CONTINUE) |
2427 | goto done; | 2436 | goto done; |
2428 | 2437 | ||
2429 | if (!c->has_seg_override) | 2438 | if (!c->has_seg_override) |
2430 | set_seg_override(c, VCPU_SREG_DS); | 2439 | set_seg_override(c, VCPU_SREG_DS); |
2431 | 2440 | ||
2432 | if (!(!c->twobyte && c->b == 0x8d)) | 2441 | if (memop.type == OP_MEM && !(!c->twobyte && c->b == 0x8d)) |
2433 | c->modrm_ea += seg_override_base(ctxt, ops, c); | 2442 | memop.addr.mem += seg_override_base(ctxt, ops, c); |
2434 | 2443 | ||
2435 | if (c->ad_bytes != 8) | 2444 | if (memop.type == OP_MEM && c->ad_bytes != 8) |
2436 | c->modrm_ea = (u32)c->modrm_ea; | 2445 | memop.addr.mem = (u32)memop.addr.mem; |
2437 | 2446 | ||
2438 | if (c->rip_relative) | 2447 | if (memop.type == OP_MEM && c->rip_relative) |
2439 | c->modrm_ea += c->eip; | 2448 | memop.addr.mem += c->eip; |
2440 | 2449 | ||
2441 | /* | 2450 | /* |
2442 | * Decode and fetch the source operand: register, memory | 2451 | * Decode and fetch the source operand: register, memory |
@@ -2449,31 +2458,16 @@ done_prefixes: | |||
2449 | decode_register_operand(&c->src, c, 0); | 2458 | decode_register_operand(&c->src, c, 0); |
2450 | break; | 2459 | break; |
2451 | case SrcMem16: | 2460 | case SrcMem16: |
2452 | c->src.bytes = 2; | 2461 | memop.bytes = 2; |
2453 | goto srcmem_common; | 2462 | goto srcmem_common; |
2454 | case SrcMem32: | 2463 | case SrcMem32: |
2455 | c->src.bytes = 4; | 2464 | memop.bytes = 4; |
2456 | goto srcmem_common; | 2465 | goto srcmem_common; |
2457 | case SrcMem: | 2466 | case SrcMem: |
2458 | c->src.bytes = (c->d & ByteOp) ? 1 : | 2467 | memop.bytes = (c->d & ByteOp) ? 1 : |
2459 | c->op_bytes; | 2468 | c->op_bytes; |
2460 | /* Don't fetch the address for invlpg: it could be unmapped. */ | ||
2461 | if (c->d & NoAccess) | ||
2462 | break; | ||
2463 | srcmem_common: | 2469 | srcmem_common: |
2464 | /* | 2470 | c->src = memop; |
2465 | * For instructions with a ModR/M byte, switch to register | ||
2466 | * access if Mod = 3. | ||
2467 | */ | ||
2468 | if ((c->d & ModRM) && c->modrm_mod == 3) { | ||
2469 | c->src.type = OP_REG; | ||
2470 | c->src.val = c->modrm_val; | ||
2471 | c->src.addr.reg = c->modrm_ptr; | ||
2472 | break; | ||
2473 | } | ||
2474 | c->src.type = OP_MEM; | ||
2475 | c->src.addr.mem = c->modrm_ea; | ||
2476 | c->src.val = 0; | ||
2477 | break; | 2471 | break; |
2478 | case SrcImm: | 2472 | case SrcImm: |
2479 | case SrcImmU: | 2473 | case SrcImmU: |
@@ -2543,9 +2537,8 @@ done_prefixes: | |||
2543 | insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip); | 2537 | insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip); |
2544 | break; | 2538 | break; |
2545 | case SrcMemFAddr: | 2539 | case SrcMemFAddr: |
2546 | c->src.type = OP_MEM; | 2540 | memop.bytes = c->op_bytes + 2; |
2547 | c->src.addr.mem = c->modrm_ea; | 2541 | goto srcmem_common; |
2548 | c->src.bytes = c->op_bytes + 2; | ||
2549 | break; | 2542 | break; |
2550 | } | 2543 | } |
2551 | 2544 | ||
@@ -2583,26 +2576,18 @@ done_prefixes: | |||
2583 | break; | 2576 | break; |
2584 | case DstMem: | 2577 | case DstMem: |
2585 | case DstMem64: | 2578 | case DstMem64: |
2586 | if ((c->d & ModRM) && c->modrm_mod == 3) { | 2579 | c->dst = memop; |
2587 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | ||
2588 | c->dst.type = OP_REG; | ||
2589 | c->dst.val = c->dst.orig_val = c->modrm_val; | ||
2590 | c->dst.addr.reg = c->modrm_ptr; | ||
2591 | break; | ||
2592 | } | ||
2593 | c->dst.type = OP_MEM; | ||
2594 | c->dst.addr.mem = c->modrm_ea; | ||
2595 | if ((c->d & DstMask) == DstMem64) | 2580 | if ((c->d & DstMask) == DstMem64) |
2596 | c->dst.bytes = 8; | 2581 | c->dst.bytes = 8; |
2597 | else | 2582 | else |
2598 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | 2583 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; |
2599 | c->dst.val = 0; | 2584 | if (c->dst.type == OP_MEM && (c->d & BitOp)) { |
2600 | if (c->d & BitOp) { | ||
2601 | unsigned long mask = ~(c->dst.bytes * 8 - 1); | 2585 | unsigned long mask = ~(c->dst.bytes * 8 - 1); |
2602 | 2586 | ||
2603 | c->dst.addr.mem = c->dst.addr.mem + | 2587 | c->dst.addr.mem = c->dst.addr.mem + |
2604 | (c->src.val & mask) / 8; | 2588 | (c->src.val & mask) / 8; |
2605 | } | 2589 | } |
2590 | c->dst.orig_val = c->dst.val; | ||
2606 | break; | 2591 | break; |
2607 | case DstAcc: | 2592 | case DstAcc: |
2608 | c->dst.type = OP_REG; | 2593 | c->dst.type = OP_REG; |
@@ -2682,11 +2667,15 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt) | |||
2682 | } | 2667 | } |
2683 | 2668 | ||
2684 | if (c->src.type == OP_MEM) { | 2669 | if (c->src.type == OP_MEM) { |
2670 | if (c->d & NoAccess) | ||
2671 | goto no_fetch; | ||
2685 | rc = read_emulated(ctxt, ops, c->src.addr.mem, | 2672 | rc = read_emulated(ctxt, ops, c->src.addr.mem, |
2686 | c->src.valptr, c->src.bytes); | 2673 | c->src.valptr, c->src.bytes); |
2687 | if (rc != X86EMUL_CONTINUE) | 2674 | if (rc != X86EMUL_CONTINUE) |
2688 | goto done; | 2675 | goto done; |
2689 | c->src.orig_val64 = c->src.val64; | 2676 | c->src.orig_val64 = c->src.val64; |
2677 | no_fetch: | ||
2678 | ; | ||
2690 | } | 2679 | } |
2691 | 2680 | ||
2692 | if (c->src2.type == OP_MEM) { | 2681 | if (c->src2.type == OP_MEM) { |