diff options
author | Avi Kivity <avi@qumranet.com> | 2007-11-01 00:31:28 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:52:59 -0500 |
commit | 1c73ef66502311d9aff7fed7d7f970288329c6cb (patch) | |
tree | 1bafc99b5c6e0786670d9198fef2caf113fa820a /drivers/kvm/x86_emulate.c | |
parent | 3b6fff198c2ae3ca87ee8c9103d52ac9e8f40dd5 (diff) |
KVM: x86 emulator: Hoist modrm and abs decoding into separate functions
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/x86_emulate.c')
-rw-r--r-- | drivers/kvm/x86_emulate.c | 337 |
1 files changed, 177 insertions, 160 deletions
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index b352a6c4d4a2..64888a6edc27 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c | |||
@@ -548,14 +548,182 @@ static void decode_register_operand(struct operand *op, | |||
548 | op->orig_val = op->val; | 548 | op->orig_val = op->val; |
549 | } | 549 | } |
550 | 550 | ||
551 | static int decode_modrm(struct x86_emulate_ctxt *ctxt, | ||
552 | struct x86_emulate_ops *ops) | ||
553 | { | ||
554 | struct decode_cache *c = &ctxt->decode; | ||
555 | u8 sib; | ||
556 | int index_reg = 0, base_reg = 0, scale, rip_relative = 0; | ||
557 | int rc = 0; | ||
558 | |||
559 | if (c->rex_prefix) { | ||
560 | c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */ | ||
561 | index_reg = (c->rex_prefix & 2) << 2; /* REX.X */ | ||
562 | c->modrm_rm = base_reg = (c->rex_prefix & 1) << 3; /* REG.B */ | ||
563 | } | ||
564 | |||
565 | c->modrm = insn_fetch(u8, 1, c->eip); | ||
566 | c->modrm_mod |= (c->modrm & 0xc0) >> 6; | ||
567 | c->modrm_reg |= (c->modrm & 0x38) >> 3; | ||
568 | c->modrm_rm |= (c->modrm & 0x07); | ||
569 | c->modrm_ea = 0; | ||
570 | c->use_modrm_ea = 1; | ||
571 | |||
572 | if (c->modrm_mod == 3) { | ||
573 | c->modrm_val = *(unsigned long *) | ||
574 | decode_register(c->modrm_rm, c->regs, c->d & ByteOp); | ||
575 | return rc; | ||
576 | } | ||
577 | |||
578 | if (c->ad_bytes == 2) { | ||
579 | unsigned bx = c->regs[VCPU_REGS_RBX]; | ||
580 | unsigned bp = c->regs[VCPU_REGS_RBP]; | ||
581 | unsigned si = c->regs[VCPU_REGS_RSI]; | ||
582 | unsigned di = c->regs[VCPU_REGS_RDI]; | ||
583 | |||
584 | /* 16-bit ModR/M decode. */ | ||
585 | switch (c->modrm_mod) { | ||
586 | case 0: | ||
587 | if (c->modrm_rm == 6) | ||
588 | c->modrm_ea += insn_fetch(u16, 2, c->eip); | ||
589 | break; | ||
590 | case 1: | ||
591 | c->modrm_ea += insn_fetch(s8, 1, c->eip); | ||
592 | break; | ||
593 | case 2: | ||
594 | c->modrm_ea += insn_fetch(u16, 2, c->eip); | ||
595 | break; | ||
596 | } | ||
597 | switch (c->modrm_rm) { | ||
598 | case 0: | ||
599 | c->modrm_ea += bx + si; | ||
600 | break; | ||
601 | case 1: | ||
602 | c->modrm_ea += bx + di; | ||
603 | break; | ||
604 | case 2: | ||
605 | c->modrm_ea += bp + si; | ||
606 | break; | ||
607 | case 3: | ||
608 | c->modrm_ea += bp + di; | ||
609 | break; | ||
610 | case 4: | ||
611 | c->modrm_ea += si; | ||
612 | break; | ||
613 | case 5: | ||
614 | c->modrm_ea += di; | ||
615 | break; | ||
616 | case 6: | ||
617 | if (c->modrm_mod != 0) | ||
618 | c->modrm_ea += bp; | ||
619 | break; | ||
620 | case 7: | ||
621 | c->modrm_ea += bx; | ||
622 | break; | ||
623 | } | ||
624 | if (c->modrm_rm == 2 || c->modrm_rm == 3 || | ||
625 | (c->modrm_rm == 6 && c->modrm_mod != 0)) | ||
626 | if (!c->override_base) | ||
627 | c->override_base = &ctxt->ss_base; | ||
628 | c->modrm_ea = (u16)c->modrm_ea; | ||
629 | } else { | ||
630 | /* 32/64-bit ModR/M decode. */ | ||
631 | switch (c->modrm_rm) { | ||
632 | case 4: | ||
633 | case 12: | ||
634 | sib = insn_fetch(u8, 1, c->eip); | ||
635 | index_reg |= (sib >> 3) & 7; | ||
636 | base_reg |= sib & 7; | ||
637 | scale = sib >> 6; | ||
638 | |||
639 | switch (base_reg) { | ||
640 | case 5: | ||
641 | if (c->modrm_mod != 0) | ||
642 | c->modrm_ea += c->regs[base_reg]; | ||
643 | else | ||
644 | c->modrm_ea += | ||
645 | insn_fetch(s32, 4, c->eip); | ||
646 | break; | ||
647 | default: | ||
648 | c->modrm_ea += c->regs[base_reg]; | ||
649 | } | ||
650 | switch (index_reg) { | ||
651 | case 4: | ||
652 | break; | ||
653 | default: | ||
654 | c->modrm_ea += c->regs[index_reg] << scale; | ||
655 | } | ||
656 | break; | ||
657 | case 5: | ||
658 | if (c->modrm_mod != 0) | ||
659 | c->modrm_ea += c->regs[c->modrm_rm]; | ||
660 | else if (ctxt->mode == X86EMUL_MODE_PROT64) | ||
661 | rip_relative = 1; | ||
662 | break; | ||
663 | default: | ||
664 | c->modrm_ea += c->regs[c->modrm_rm]; | ||
665 | break; | ||
666 | } | ||
667 | switch (c->modrm_mod) { | ||
668 | case 0: | ||
669 | if (c->modrm_rm == 5) | ||
670 | c->modrm_ea += insn_fetch(s32, 4, c->eip); | ||
671 | break; | ||
672 | case 1: | ||
673 | c->modrm_ea += insn_fetch(s8, 1, c->eip); | ||
674 | break; | ||
675 | case 2: | ||
676 | c->modrm_ea += insn_fetch(s32, 4, c->eip); | ||
677 | break; | ||
678 | } | ||
679 | } | ||
680 | if (rip_relative) { | ||
681 | c->modrm_ea += c->eip; | ||
682 | switch (c->d & SrcMask) { | ||
683 | case SrcImmByte: | ||
684 | c->modrm_ea += 1; | ||
685 | break; | ||
686 | case SrcImm: | ||
687 | if (c->d & ByteOp) | ||
688 | c->modrm_ea += 1; | ||
689 | else | ||
690 | if (c->op_bytes == 8) | ||
691 | c->modrm_ea += 4; | ||
692 | else | ||
693 | c->modrm_ea += c->op_bytes; | ||
694 | } | ||
695 | } | ||
696 | done: | ||
697 | return rc; | ||
698 | } | ||
699 | |||
700 | static int decode_abs(struct x86_emulate_ctxt *ctxt, | ||
701 | struct x86_emulate_ops *ops) | ||
702 | { | ||
703 | struct decode_cache *c = &ctxt->decode; | ||
704 | int rc = 0; | ||
705 | |||
706 | switch (c->ad_bytes) { | ||
707 | case 2: | ||
708 | c->modrm_ea = insn_fetch(u16, 2, c->eip); | ||
709 | break; | ||
710 | case 4: | ||
711 | c->modrm_ea = insn_fetch(u32, 4, c->eip); | ||
712 | break; | ||
713 | case 8: | ||
714 | c->modrm_ea = insn_fetch(u64, 8, c->eip); | ||
715 | break; | ||
716 | } | ||
717 | done: | ||
718 | return rc; | ||
719 | } | ||
720 | |||
551 | int | 721 | int |
552 | x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | 722 | x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) |
553 | { | 723 | { |
554 | struct decode_cache *c = &ctxt->decode; | 724 | struct decode_cache *c = &ctxt->decode; |
555 | u8 sib; | ||
556 | int rc = 0; | 725 | int rc = 0; |
557 | int mode = ctxt->mode; | 726 | int mode = ctxt->mode; |
558 | int index_reg = 0, base_reg = 0, scale, rip_relative = 0; | ||
559 | 727 | ||
560 | /* Shadow copy of register state. Committed on successful emulation. */ | 728 | /* Shadow copy of register state. Committed on successful emulation. */ |
561 | 729 | ||
@@ -637,13 +805,9 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) | |||
637 | done_prefixes: | 805 | done_prefixes: |
638 | 806 | ||
639 | /* REX prefix. */ | 807 | /* REX prefix. */ |
640 | if (c->rex_prefix) { | 808 | if (c->rex_prefix) |
641 | if (c->rex_prefix & 8) | 809 | if (c->rex_prefix & 8) |
642 | c->op_bytes = 8; /* REX.W */ | 810 | c->op_bytes = 8; /* REX.W */ |
643 | c->modrm_reg = (c->rex_prefix & 4) << 1; /* REX.R */ | ||
644 | index_reg = (c->rex_prefix & 2) << 2; /* REX.X */ | ||
645 | c->modrm_rm = base_reg = (c->rex_prefix & 1) << 3; /* REG.B */ | ||
646 | } | ||
647 | 811 | ||
648 | /* Opcode byte(s). */ | 812 | /* Opcode byte(s). */ |
649 | c->d = opcode_table[c->b]; | 813 | c->d = opcode_table[c->b]; |
@@ -663,159 +827,12 @@ done_prefixes: | |||
663 | } | 827 | } |
664 | 828 | ||
665 | /* ModRM and SIB bytes. */ | 829 | /* ModRM and SIB bytes. */ |
666 | if (c->d & ModRM) { | 830 | if (c->d & ModRM) |
667 | c->modrm = insn_fetch(u8, 1, c->eip); | 831 | rc = decode_modrm(ctxt, ops); |
668 | c->modrm_mod |= (c->modrm & 0xc0) >> 6; | 832 | else if (c->d & MemAbs) |
669 | c->modrm_reg |= (c->modrm & 0x38) >> 3; | 833 | rc = decode_abs(ctxt, ops); |
670 | c->modrm_rm |= (c->modrm & 0x07); | 834 | if (rc) |
671 | c->modrm_ea = 0; | 835 | goto done; |
672 | c->use_modrm_ea = 1; | ||
673 | |||
674 | if (c->modrm_mod == 3) { | ||
675 | c->modrm_val = *(unsigned long *) | ||
676 | decode_register(c->modrm_rm, c->regs, c->d & ByteOp); | ||
677 | goto modrm_done; | ||
678 | } | ||
679 | |||
680 | if (c->ad_bytes == 2) { | ||
681 | unsigned bx = c->regs[VCPU_REGS_RBX]; | ||
682 | unsigned bp = c->regs[VCPU_REGS_RBP]; | ||
683 | unsigned si = c->regs[VCPU_REGS_RSI]; | ||
684 | unsigned di = c->regs[VCPU_REGS_RDI]; | ||
685 | |||
686 | /* 16-bit ModR/M decode. */ | ||
687 | switch (c->modrm_mod) { | ||
688 | case 0: | ||
689 | if (c->modrm_rm == 6) | ||
690 | c->modrm_ea += | ||
691 | insn_fetch(u16, 2, c->eip); | ||
692 | break; | ||
693 | case 1: | ||
694 | c->modrm_ea += insn_fetch(s8, 1, c->eip); | ||
695 | break; | ||
696 | case 2: | ||
697 | c->modrm_ea += insn_fetch(u16, 2, c->eip); | ||
698 | break; | ||
699 | } | ||
700 | switch (c->modrm_rm) { | ||
701 | case 0: | ||
702 | c->modrm_ea += bx + si; | ||
703 | break; | ||
704 | case 1: | ||
705 | c->modrm_ea += bx + di; | ||
706 | break; | ||
707 | case 2: | ||
708 | c->modrm_ea += bp + si; | ||
709 | break; | ||
710 | case 3: | ||
711 | c->modrm_ea += bp + di; | ||
712 | break; | ||
713 | case 4: | ||
714 | c->modrm_ea += si; | ||
715 | break; | ||
716 | case 5: | ||
717 | c->modrm_ea += di; | ||
718 | break; | ||
719 | case 6: | ||
720 | if (c->modrm_mod != 0) | ||
721 | c->modrm_ea += bp; | ||
722 | break; | ||
723 | case 7: | ||
724 | c->modrm_ea += bx; | ||
725 | break; | ||
726 | } | ||
727 | if (c->modrm_rm == 2 || c->modrm_rm == 3 || | ||
728 | (c->modrm_rm == 6 && c->modrm_mod != 0)) | ||
729 | if (!c->override_base) | ||
730 | c->override_base = &ctxt->ss_base; | ||
731 | c->modrm_ea = (u16)c->modrm_ea; | ||
732 | } else { | ||
733 | /* 32/64-bit ModR/M decode. */ | ||
734 | switch (c->modrm_rm) { | ||
735 | case 4: | ||
736 | case 12: | ||
737 | sib = insn_fetch(u8, 1, c->eip); | ||
738 | index_reg |= (sib >> 3) & 7; | ||
739 | base_reg |= sib & 7; | ||
740 | scale = sib >> 6; | ||
741 | |||
742 | switch (base_reg) { | ||
743 | case 5: | ||
744 | if (c->modrm_mod != 0) | ||
745 | c->modrm_ea += | ||
746 | c->regs[base_reg]; | ||
747 | else | ||
748 | c->modrm_ea += | ||
749 | insn_fetch(s32, 4, c->eip); | ||
750 | break; | ||
751 | default: | ||
752 | c->modrm_ea += c->regs[base_reg]; | ||
753 | } | ||
754 | switch (index_reg) { | ||
755 | case 4: | ||
756 | break; | ||
757 | default: | ||
758 | c->modrm_ea += | ||
759 | c->regs[index_reg] << scale; | ||
760 | |||
761 | } | ||
762 | break; | ||
763 | case 5: | ||
764 | if (c->modrm_mod != 0) | ||
765 | c->modrm_ea += c->regs[c->modrm_rm]; | ||
766 | else if (mode == X86EMUL_MODE_PROT64) | ||
767 | rip_relative = 1; | ||
768 | break; | ||
769 | default: | ||
770 | c->modrm_ea += c->regs[c->modrm_rm]; | ||
771 | break; | ||
772 | } | ||
773 | switch (c->modrm_mod) { | ||
774 | case 0: | ||
775 | if (c->modrm_rm == 5) | ||
776 | c->modrm_ea += | ||
777 | insn_fetch(s32, 4, c->eip); | ||
778 | break; | ||
779 | case 1: | ||
780 | c->modrm_ea += insn_fetch(s8, 1, c->eip); | ||
781 | break; | ||
782 | case 2: | ||
783 | c->modrm_ea += insn_fetch(s32, 4, c->eip); | ||
784 | break; | ||
785 | } | ||
786 | } | ||
787 | if (rip_relative) { | ||
788 | c->modrm_ea += c->eip; | ||
789 | switch (c->d & SrcMask) { | ||
790 | case SrcImmByte: | ||
791 | c->modrm_ea += 1; | ||
792 | break; | ||
793 | case SrcImm: | ||
794 | if (c->d & ByteOp) | ||
795 | c->modrm_ea += 1; | ||
796 | else | ||
797 | if (c->op_bytes == 8) | ||
798 | c->modrm_ea += 4; | ||
799 | else | ||
800 | c->modrm_ea += c->op_bytes; | ||
801 | } | ||
802 | } | ||
803 | modrm_done: | ||
804 | ; | ||
805 | } else if (c->d & MemAbs) { | ||
806 | switch (c->ad_bytes) { | ||
807 | case 2: | ||
808 | c->modrm_ea = insn_fetch(u16, 2, c->eip); | ||
809 | break; | ||
810 | case 4: | ||
811 | c->modrm_ea = insn_fetch(u32, 4, c->eip); | ||
812 | break; | ||
813 | case 8: | ||
814 | c->modrm_ea = insn_fetch(u64, 8, c->eip); | ||
815 | break; | ||
816 | } | ||
817 | |||
818 | } | ||
819 | 836 | ||
820 | if (!c->override_base) | 837 | if (!c->override_base) |
821 | c->override_base = &ctxt->ds_base; | 838 | c->override_base = &ctxt->ds_base; |