Revision 4021dab0 translate-i386.c
b/translate-i386.c | ||
---|---|---|
30 | 30 |
#include "exec.h" |
31 | 31 |
#include "disas.h" |
32 | 32 |
|
33 |
//#define DEBUG_MMU |
|
34 |
|
|
35 | 33 |
/* XXX: move that elsewhere */ |
36 | 34 |
static uint16_t *gen_opc_ptr; |
37 | 35 |
static uint32_t *gen_opparam_ptr; |
... | ... | |
62 | 60 |
int cpl; |
63 | 61 |
int iopl; |
64 | 62 |
int tf; /* TF cpu flag */ |
63 |
int mem_index; /* select memory access functions */ |
|
65 | 64 |
struct TranslationBlock *tb; |
66 | 65 |
int popl_esp_hack; /* for correct popl with esp base handling */ |
67 | 66 |
} DisasContext; |
... | ... | |
565 | 564 |
}, |
566 | 565 |
}; |
567 | 566 |
|
568 |
static GenOpFunc *gen_op_lds_T0_A0[3] = { |
|
567 |
static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = {
|
|
569 | 568 |
gen_op_ldsb_T0_A0, |
570 | 569 |
gen_op_ldsw_T0_A0, |
570 |
NULL, |
|
571 |
|
|
572 |
gen_op_ldsb_kernel_T0_A0, |
|
573 |
gen_op_ldsw_kernel_T0_A0, |
|
574 |
NULL, |
|
575 |
|
|
576 |
gen_op_ldsb_user_T0_A0, |
|
577 |
gen_op_ldsw_user_T0_A0, |
|
578 |
NULL, |
|
571 | 579 |
}; |
572 | 580 |
|
573 |
static GenOpFunc *gen_op_ldu_T0_A0[3] = { |
|
581 |
static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = {
|
|
574 | 582 |
gen_op_ldub_T0_A0, |
575 | 583 |
gen_op_lduw_T0_A0, |
584 |
NULL, |
|
585 |
|
|
586 |
gen_op_ldub_kernel_T0_A0, |
|
587 |
gen_op_lduw_kernel_T0_A0, |
|
588 |
NULL, |
|
589 |
|
|
590 |
gen_op_ldub_user_T0_A0, |
|
591 |
gen_op_lduw_user_T0_A0, |
|
592 |
NULL, |
|
576 | 593 |
}; |
577 | 594 |
|
578 |
/* sign does not matter */ |
|
579 |
static GenOpFunc *gen_op_ld_T0_A0[3] = { |
|
595 |
/* sign does not matter, except for lidt/lgdt call (TODO: fix it) */
|
|
596 |
static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = {
|
|
580 | 597 |
gen_op_ldub_T0_A0, |
581 | 598 |
gen_op_lduw_T0_A0, |
582 | 599 |
gen_op_ldl_T0_A0, |
600 |
|
|
601 |
gen_op_ldub_kernel_T0_A0, |
|
602 |
gen_op_lduw_kernel_T0_A0, |
|
603 |
gen_op_ldl_kernel_T0_A0, |
|
604 |
|
|
605 |
gen_op_ldub_user_T0_A0, |
|
606 |
gen_op_lduw_user_T0_A0, |
|
607 |
gen_op_ldl_user_T0_A0, |
|
583 | 608 |
}; |
584 | 609 |
|
585 |
static GenOpFunc *gen_op_ld_T1_A0[3] = { |
|
610 |
static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = {
|
|
586 | 611 |
gen_op_ldub_T1_A0, |
587 | 612 |
gen_op_lduw_T1_A0, |
588 | 613 |
gen_op_ldl_T1_A0, |
614 |
|
|
615 |
gen_op_ldub_kernel_T1_A0, |
|
616 |
gen_op_lduw_kernel_T1_A0, |
|
617 |
gen_op_ldl_kernel_T1_A0, |
|
618 |
|
|
619 |
gen_op_ldub_user_T1_A0, |
|
620 |
gen_op_lduw_user_T1_A0, |
|
621 |
gen_op_ldl_user_T1_A0, |
|
589 | 622 |
}; |
590 | 623 |
|
591 |
static GenOpFunc *gen_op_st_T0_A0[3] = { |
|
624 |
static GenOpFunc *gen_op_st_T0_A0[3 * 3] = {
|
|
592 | 625 |
gen_op_stb_T0_A0, |
593 | 626 |
gen_op_stw_T0_A0, |
594 | 627 |
gen_op_stl_T0_A0, |
628 |
|
|
629 |
gen_op_stb_kernel_T0_A0, |
|
630 |
gen_op_stw_kernel_T0_A0, |
|
631 |
gen_op_stl_kernel_T0_A0, |
|
632 |
|
|
633 |
gen_op_stb_user_T0_A0, |
|
634 |
gen_op_stw_user_T0_A0, |
|
635 |
gen_op_stl_user_T0_A0, |
|
595 | 636 |
}; |
596 | 637 |
|
597 | 638 |
/* the _a32 and _a16 string operations use A0 as the base register. */ |
598 | 639 |
|
640 |
#define STRINGOP_NB 9 |
|
641 |
|
|
599 | 642 |
#define STRINGOP(x) \ |
600 | 643 |
gen_op_ ## x ## b_fast, \ |
601 | 644 |
gen_op_ ## x ## w_fast, \ |
... | ... | |
607 | 650 |
gen_op_ ## x ## w_a16, \ |
608 | 651 |
gen_op_ ## x ## l_a16, |
609 | 652 |
|
610 |
static GenOpFunc *gen_op_movs[9 * 2] = {
|
|
611 |
STRINGOP(movs)
|
|
612 |
STRINGOP(rep_movs)
|
|
653 |
static GenOpFunc *gen_op_scas[STRINGOP_NB * 3] = {
|
|
654 |
STRINGOP(repz_scas)
|
|
655 |
STRINGOP(repnz_scas)
|
|
613 | 656 |
}; |
614 | 657 |
|
615 |
static GenOpFunc *gen_op_stos[9 * 2] = {
|
|
616 |
STRINGOP(stos)
|
|
617 |
STRINGOP(rep_stos)
|
|
658 |
static GenOpFunc *gen_op_cmps[STRINGOP_NB * 3] = {
|
|
659 |
STRINGOP(repz_cmps)
|
|
660 |
STRINGOP(repnz_cmps)
|
|
618 | 661 |
}; |
619 | 662 |
|
620 |
static GenOpFunc *gen_op_lods[9 * 2] = { |
|
621 |
STRINGOP(lods) |
|
622 |
STRINGOP(rep_lods) |
|
623 |
}; |
|
663 |
static inline void gen_string_movl_A0_ESI(DisasContext *s) |
|
664 |
{ |
|
665 |
int override; |
|
624 | 666 |
|
625 |
static GenOpFunc *gen_op_scas[9 * 3] = { |
|
626 |
STRINGOP(scas) |
|
627 |
STRINGOP(repz_scas) |
|
628 |
STRINGOP(repnz_scas) |
|
667 |
override = s->override; |
|
668 |
if (s->aflag) { |
|
669 |
/* 32 bit address */ |
|
670 |
if (s->addseg && override < 0) |
|
671 |
override = R_DS; |
|
672 |
if (override >= 0) { |
|
673 |
gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); |
|
674 |
gen_op_addl_A0_reg_sN[0][R_ESI](); |
|
675 |
} else { |
|
676 |
gen_op_movl_A0_reg[R_ESI](); |
|
677 |
} |
|
678 |
} else { |
|
679 |
/* 16 address, always override */ |
|
680 |
if (override < 0) |
|
681 |
override = R_DS; |
|
682 |
gen_op_movl_A0_reg[R_ESI](); |
|
683 |
gen_op_andl_A0_ffff(); |
|
684 |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); |
|
685 |
} |
|
686 |
} |
|
687 |
|
|
688 |
static inline void gen_string_movl_A0_EDI(DisasContext *s) |
|
689 |
{ |
|
690 |
if (s->aflag) { |
|
691 |
if (s->addseg) { |
|
692 |
gen_op_movl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); |
|
693 |
gen_op_addl_A0_reg_sN[0][R_EDI](); |
|
694 |
} else { |
|
695 |
gen_op_movl_A0_reg[R_EDI](); |
|
696 |
} |
|
697 |
} else { |
|
698 |
gen_op_movl_A0_reg[R_EDI](); |
|
699 |
gen_op_andl_A0_ffff(); |
|
700 |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); |
|
701 |
} |
|
702 |
} |
|
703 |
|
|
704 |
static GenOpFunc *gen_op_movl_T0_Dshift[3] = { |
|
705 |
gen_op_movl_T0_Dshiftb, |
|
706 |
gen_op_movl_T0_Dshiftw, |
|
707 |
gen_op_movl_T0_Dshiftl, |
|
629 | 708 |
}; |
630 | 709 |
|
631 |
static GenOpFunc *gen_op_cmps[9 * 3] = { |
|
632 |
STRINGOP(cmps) |
|
633 |
STRINGOP(repz_cmps) |
|
634 |
STRINGOP(repnz_cmps) |
|
710 |
static GenOpFunc2 *gen_op_jz_ecx[2] = { |
|
711 |
gen_op_jz_ecxw, |
|
712 |
gen_op_jz_ecxl, |
|
713 |
}; |
|
714 |
|
|
715 |
static GenOpFunc *gen_op_dec_ECX[2] = { |
|
716 |
gen_op_decw_ECX, |
|
717 |
gen_op_decl_ECX, |
|
635 | 718 |
}; |
636 | 719 |
|
637 |
static GenOpFunc *gen_op_ins[9 * 2] = { |
|
638 |
STRINGOP(ins) |
|
639 |
STRINGOP(rep_ins) |
|
720 |
static GenOpFunc2 *gen_op_string_jnz_sub[2][3] = { |
|
721 |
{ |
|
722 |
gen_op_string_jnz_subb, |
|
723 |
gen_op_string_jnz_subw, |
|
724 |
gen_op_string_jnz_subl, |
|
725 |
}, |
|
726 |
{ |
|
727 |
gen_op_string_jz_subb, |
|
728 |
gen_op_string_jz_subw, |
|
729 |
gen_op_string_jz_subl, |
|
730 |
}, |
|
640 | 731 |
}; |
641 | 732 |
|
733 |
static GenOpFunc *gen_op_in_DX_T0[3] = { |
|
734 |
gen_op_inb_DX_T0, |
|
735 |
gen_op_inw_DX_T0, |
|
736 |
gen_op_inl_DX_T0, |
|
737 |
}; |
|
642 | 738 |
|
643 |
static GenOpFunc *gen_op_outs[9 * 2] = { |
|
644 |
STRINGOP(outs) |
|
645 |
STRINGOP(rep_outs) |
|
739 |
static GenOpFunc *gen_op_out_DX_T0[3] = { |
|
740 |
gen_op_outb_DX_T0, |
|
741 |
gen_op_outw_DX_T0, |
|
742 |
gen_op_outl_DX_T0, |
|
646 | 743 |
}; |
647 | 744 |
|
745 |
static inline void gen_movs(DisasContext *s, int ot) |
|
746 |
{ |
|
747 |
gen_string_movl_A0_ESI(s); |
|
748 |
gen_op_ld_T0_A0[ot + s->mem_index](); |
|
749 |
gen_string_movl_A0_EDI(s); |
|
750 |
gen_op_st_T0_A0[ot + s->mem_index](); |
|
751 |
gen_op_movl_T0_Dshift[ot](); |
|
752 |
if (s->aflag) { |
|
753 |
gen_op_addl_ESI_T0(); |
|
754 |
gen_op_addl_EDI_T0(); |
|
755 |
} else { |
|
756 |
gen_op_addw_ESI_T0(); |
|
757 |
gen_op_addw_EDI_T0(); |
|
758 |
} |
|
759 |
} |
|
760 |
|
|
761 |
/* same method as Valgrind : we generate jumps to current or next |
|
762 |
instruction */ |
|
763 |
static inline void gen_repz_movs(DisasContext *s, int ot, |
|
764 |
unsigned int cur_eip, unsigned int next_eip) |
|
765 |
{ |
|
766 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
767 |
gen_op_set_cc_op(s->cc_op); |
|
768 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
769 |
gen_movs(s, ot); |
|
770 |
gen_op_dec_ECX[s->aflag](); |
|
771 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
772 |
s->is_jmp = 3; |
|
773 |
} |
|
774 |
|
|
775 |
static inline void gen_stos(DisasContext *s, int ot) |
|
776 |
{ |
|
777 |
gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); |
|
778 |
gen_string_movl_A0_EDI(s); |
|
779 |
gen_op_st_T0_A0[ot + s->mem_index](); |
|
780 |
gen_op_movl_T0_Dshift[ot](); |
|
781 |
if (s->aflag) { |
|
782 |
gen_op_addl_EDI_T0(); |
|
783 |
} else { |
|
784 |
gen_op_addw_EDI_T0(); |
|
785 |
} |
|
786 |
} |
|
787 |
|
|
788 |
static inline void gen_repz_stos(DisasContext *s, int ot, |
|
789 |
unsigned int cur_eip, unsigned int next_eip) |
|
790 |
{ |
|
791 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
792 |
gen_op_set_cc_op(s->cc_op); |
|
793 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
794 |
gen_stos(s, ot); |
|
795 |
gen_op_dec_ECX[s->aflag](); |
|
796 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
797 |
s->is_jmp = 3; |
|
798 |
} |
|
799 |
|
|
800 |
static inline void gen_lods(DisasContext *s, int ot) |
|
801 |
{ |
|
802 |
gen_string_movl_A0_ESI(s); |
|
803 |
gen_op_ld_T0_A0[ot + s->mem_index](); |
|
804 |
gen_op_mov_reg_T0[ot][R_EAX](); |
|
805 |
gen_op_movl_T0_Dshift[ot](); |
|
806 |
if (s->aflag) { |
|
807 |
gen_op_addl_ESI_T0(); |
|
808 |
} else { |
|
809 |
gen_op_addw_ESI_T0(); |
|
810 |
} |
|
811 |
} |
|
812 |
|
|
813 |
static inline void gen_repz_lods(DisasContext *s, int ot, |
|
814 |
unsigned int cur_eip, unsigned int next_eip) |
|
815 |
{ |
|
816 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
817 |
gen_op_set_cc_op(s->cc_op); |
|
818 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
819 |
gen_lods(s, ot); |
|
820 |
gen_op_dec_ECX[s->aflag](); |
|
821 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
822 |
s->is_jmp = 3; |
|
823 |
} |
|
824 |
|
|
825 |
static inline void gen_scas(DisasContext *s, int ot) |
|
826 |
{ |
|
827 |
gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); |
|
828 |
gen_string_movl_A0_EDI(s); |
|
829 |
gen_op_ld_T1_A0[ot + s->mem_index](); |
|
830 |
gen_op_cmpl_T0_T1_cc(); |
|
831 |
gen_op_movl_T0_Dshift[ot](); |
|
832 |
if (s->aflag) { |
|
833 |
gen_op_addl_EDI_T0(); |
|
834 |
} else { |
|
835 |
gen_op_addw_EDI_T0(); |
|
836 |
} |
|
837 |
} |
|
838 |
|
|
839 |
#if 0 |
|
840 |
static inline void gen_repz_scas(DisasContext *s, int ot, |
|
841 |
unsigned int cur_eip, unsigned int next_eip, |
|
842 |
int nz) |
|
843 |
{ |
|
844 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
845 |
gen_op_set_cc_op(s->cc_op); |
|
846 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
847 |
gen_scas(s, ot); |
|
848 |
gen_op_set_cc_op(CC_OP_SUBB + ot); |
|
849 |
gen_op_string_jnz_sub[nz][ot]((long)s->tb, next_eip); |
|
850 |
gen_op_dec_ECX[s->aflag](); |
|
851 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
852 |
s->is_jmp = 3; |
|
853 |
} |
|
854 |
#endif |
|
855 |
|
|
856 |
static inline void gen_cmps(DisasContext *s, int ot) |
|
857 |
{ |
|
858 |
gen_string_movl_A0_ESI(s); |
|
859 |
gen_op_ld_T0_A0[ot + s->mem_index](); |
|
860 |
gen_string_movl_A0_EDI(s); |
|
861 |
gen_op_ld_T1_A0[ot + s->mem_index](); |
|
862 |
gen_op_cmpl_T0_T1_cc(); |
|
863 |
gen_op_movl_T0_Dshift[ot](); |
|
864 |
if (s->aflag) { |
|
865 |
gen_op_addl_ESI_T0(); |
|
866 |
gen_op_addl_EDI_T0(); |
|
867 |
} else { |
|
868 |
gen_op_addw_ESI_T0(); |
|
869 |
gen_op_addw_EDI_T0(); |
|
870 |
} |
|
871 |
} |
|
872 |
|
|
873 |
static inline void gen_ins(DisasContext *s, int ot) |
|
874 |
{ |
|
875 |
gen_op_in_DX_T0[ot](); |
|
876 |
gen_string_movl_A0_EDI(s); |
|
877 |
gen_op_st_T0_A0[ot + s->mem_index](); |
|
878 |
gen_op_movl_T0_Dshift[ot](); |
|
879 |
if (s->aflag) { |
|
880 |
gen_op_addl_EDI_T0(); |
|
881 |
} else { |
|
882 |
gen_op_addw_EDI_T0(); |
|
883 |
} |
|
884 |
} |
|
885 |
|
|
886 |
static inline void gen_repz_ins(DisasContext *s, int ot, |
|
887 |
unsigned int cur_eip, unsigned int next_eip) |
|
888 |
{ |
|
889 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
890 |
gen_op_set_cc_op(s->cc_op); |
|
891 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
892 |
gen_ins(s, ot); |
|
893 |
gen_op_dec_ECX[s->aflag](); |
|
894 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
895 |
s->is_jmp = 3; |
|
896 |
} |
|
897 |
|
|
898 |
static inline void gen_outs(DisasContext *s, int ot) |
|
899 |
{ |
|
900 |
gen_string_movl_A0_ESI(s); |
|
901 |
gen_op_ld_T0_A0[ot + s->mem_index](); |
|
902 |
gen_op_out_DX_T0[ot](); |
|
903 |
gen_op_movl_T0_Dshift[ot](); |
|
904 |
if (s->aflag) { |
|
905 |
gen_op_addl_ESI_T0(); |
|
906 |
} else { |
|
907 |
gen_op_addw_ESI_T0(); |
|
908 |
} |
|
909 |
} |
|
910 |
|
|
911 |
static inline void gen_repz_outs(DisasContext *s, int ot, |
|
912 |
unsigned int cur_eip, unsigned int next_eip) |
|
913 |
{ |
|
914 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
915 |
gen_op_set_cc_op(s->cc_op); |
|
916 |
gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); |
|
917 |
gen_outs(s, ot); |
|
918 |
gen_op_dec_ECX[s->aflag](); |
|
919 |
gen_op_jmp_tb_next((long)s->tb, cur_eip); |
|
920 |
s->is_jmp = 3; |
|
921 |
} |
|
648 | 922 |
|
649 | 923 |
static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) |
650 | 924 |
{ |
... | ... | |
833 | 1107 |
if (d != OR_TMP0) { |
834 | 1108 |
gen_op_mov_TN_reg[ot][0][d](); |
835 | 1109 |
} else { |
836 |
gen_op_ld_T0_A0[ot](); |
|
1110 |
gen_op_ld_T0_A0[ot + s1->mem_index]();
|
|
837 | 1111 |
} |
838 | 1112 |
switch(op) { |
839 | 1113 |
case OP_ADCL: |
... | ... | |
876 | 1150 |
if (d != OR_TMP0) |
877 | 1151 |
gen_op_mov_reg_T0[ot][d](); |
878 | 1152 |
else |
879 |
gen_op_st_T0_A0[ot](); |
|
1153 |
gen_op_st_T0_A0[ot + s1->mem_index]();
|
|
880 | 1154 |
} |
881 | 1155 |
/* the flags update must happen after the memory write (precise |
882 | 1156 |
exception support) */ |
... | ... | |
891 | 1165 |
if (d != OR_TMP0) |
892 | 1166 |
gen_op_mov_TN_reg[ot][0][d](); |
893 | 1167 |
else |
894 |
gen_op_ld_T0_A0[ot](); |
|
1168 |
gen_op_ld_T0_A0[ot + s1->mem_index]();
|
|
895 | 1169 |
if (s1->cc_op != CC_OP_DYNAMIC) |
896 | 1170 |
gen_op_set_cc_op(s1->cc_op); |
897 | 1171 |
if (c > 0) { |
... | ... | |
904 | 1178 |
if (d != OR_TMP0) |
905 | 1179 |
gen_op_mov_reg_T0[ot][d](); |
906 | 1180 |
else |
907 |
gen_op_st_T0_A0[ot](); |
|
1181 |
gen_op_st_T0_A0[ot + s1->mem_index]();
|
|
908 | 1182 |
gen_op_update_inc_cc(); |
909 | 1183 |
} |
910 | 1184 |
|
... | ... | |
913 | 1187 |
if (d != OR_TMP0) |
914 | 1188 |
gen_op_mov_TN_reg[ot][0][d](); |
915 | 1189 |
else |
916 |
gen_op_ld_T0_A0[ot](); |
|
1190 |
gen_op_ld_T0_A0[ot + s1->mem_index]();
|
|
917 | 1191 |
if (s != OR_TMP1) |
918 | 1192 |
gen_op_mov_TN_reg[ot][1][s](); |
919 | 1193 |
/* for zero counts, flags are not updated, so must do it dynamically */ |
... | ... | |
1107 | 1381 |
if (is_store) { |
1108 | 1382 |
if (reg != OR_TMP0) |
1109 | 1383 |
gen_op_mov_TN_reg[ot][0][reg](); |
1110 |
gen_op_st_T0_A0[ot](); |
|
1384 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
1111 | 1385 |
} else { |
1112 |
gen_op_ld_T0_A0[ot](); |
|
1386 |
gen_op_ld_T0_A0[ot + s->mem_index]();
|
|
1113 | 1387 |
if (reg != OR_TMP0) |
1114 | 1388 |
gen_op_mov_reg_T0[ot][reg](); |
1115 | 1389 |
} |
... | ... | |
1376 | 1650 |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); |
1377 | 1651 |
for(i = 0;i < 8; i++) { |
1378 | 1652 |
gen_op_mov_TN_reg[OT_LONG][0][7 - i](); |
1379 |
gen_op_st_T0_A0[OT_WORD + s->dflag](); |
|
1653 |
gen_op_st_T0_A0[OT_WORD + s->dflag + s->mem_index]();
|
|
1380 | 1654 |
gen_op_addl_A0_im(2 << s->dflag); |
1381 | 1655 |
} |
1382 | 1656 |
gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); |
... | ... | |
1396 | 1670 |
for(i = 0;i < 8; i++) { |
1397 | 1671 |
/* ESP is not reloaded */ |
1398 | 1672 |
if (i != 3) { |
1399 |
gen_op_ld_T0_A0[OT_WORD + s->dflag](); |
|
1673 |
gen_op_ld_T0_A0[OT_WORD + s->dflag + s->mem_index]();
|
|
1400 | 1674 |
gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i](); |
1401 | 1675 |
} |
1402 | 1676 |
gen_op_addl_A0_im(2 << s->dflag); |
... | ... | |
1424 | 1698 |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); |
1425 | 1699 |
/* push bp */ |
1426 | 1700 |
gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); |
1427 |
gen_op_st_T0_A0[ot](); |
|
1701 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
1428 | 1702 |
if (level) { |
1429 | 1703 |
while (level--) { |
1430 | 1704 |
gen_op_addl_A0_im(-opsize); |
1431 | 1705 |
gen_op_addl_T0_im(-opsize); |
1432 |
gen_op_st_T0_A0[ot](); |
|
1706 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
1433 | 1707 |
} |
1434 | 1708 |
gen_op_addl_A0_im(-opsize); |
1435 | 1709 |
/* XXX: add st_T1_A0 ? */ |
1436 | 1710 |
gen_op_movl_T0_T1(); |
1437 |
gen_op_st_T0_A0[ot](); |
|
1711 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
1438 | 1712 |
} |
1439 | 1713 |
gen_op_mov_reg_T1[ot][R_EBP](); |
1440 | 1714 |
addend = -esp_addend; |
... | ... | |
1613 | 1887 |
rm = modrm & 7; |
1614 | 1888 |
if (mod != 3) { |
1615 | 1889 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
1616 |
gen_op_ld_T1_A0[ot](); |
|
1890 |
gen_op_ld_T1_A0[ot + s->mem_index]();
|
|
1617 | 1891 |
} else if (op == OP_XORL && rm == reg) { |
1618 | 1892 |
goto xor_zero; |
1619 | 1893 |
} else { |
... | ... | |
1691 | 1965 |
op = (modrm >> 3) & 7; |
1692 | 1966 |
if (mod != 3) { |
1693 | 1967 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
1694 |
gen_op_ld_T0_A0[ot](); |
|
1968 |
gen_op_ld_T0_A0[ot + s->mem_index]();
|
|
1695 | 1969 |
} else { |
1696 | 1970 |
gen_op_mov_TN_reg[ot][0][rm](); |
1697 | 1971 |
} |
... | ... | |
1706 | 1980 |
case 2: /* not */ |
1707 | 1981 |
gen_op_notl_T0(); |
1708 | 1982 |
if (mod != 3) { |
1709 |
gen_op_st_T0_A0[ot](); |
|
1983 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
1710 | 1984 |
} else { |
1711 | 1985 |
gen_op_mov_reg_T0[ot][rm](); |
1712 | 1986 |
} |
... | ... | |
1714 | 1988 |
case 3: /* neg */ |
1715 | 1989 |
gen_op_negl_T0(); |
1716 | 1990 |
if (mod != 3) { |
1717 |
gen_op_st_T0_A0[ot](); |
|
1991 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
1718 | 1992 |
} else { |
1719 | 1993 |
gen_op_mov_reg_T0[ot][rm](); |
1720 | 1994 |
} |
... | ... | |
1801 | 2075 |
if (mod != 3) { |
1802 | 2076 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
1803 | 2077 |
if (op >= 2 && op != 3 && op != 5) |
1804 |
gen_op_ld_T0_A0[ot](); |
|
2078 |
gen_op_ld_T0_A0[ot + s->mem_index]();
|
|
1805 | 2079 |
} else { |
1806 | 2080 |
gen_op_mov_TN_reg[ot][0][rm](); |
1807 | 2081 |
} |
... | ... | |
1832 | 2106 |
s->is_jmp = 1; |
1833 | 2107 |
break; |
1834 | 2108 |
case 3: /* lcall Ev */ |
1835 |
gen_op_ld_T1_A0[ot](); |
|
2109 |
gen_op_ld_T1_A0[ot + s->mem_index]();
|
|
1836 | 2110 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
1837 |
gen_op_lduw_T0_A0();
|
|
2111 |
gen_op_ld_T0_A0[OT_WORD + s->mem_index]();
|
|
1838 | 2112 |
do_lcall: |
1839 | 2113 |
if (s->pe && !s->vm86) { |
1840 | 2114 |
if (s->cc_op != CC_OP_DYNAMIC) |
... | ... | |
1853 | 2127 |
s->is_jmp = 1; |
1854 | 2128 |
break; |
1855 | 2129 |
case 5: /* ljmp Ev */ |
1856 |
gen_op_ld_T1_A0[ot](); |
|
2130 |
gen_op_ld_T1_A0[ot + s->mem_index]();
|
|
1857 | 2131 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
1858 | 2132 |
gen_op_lduw_T0_A0(); |
1859 | 2133 |
do_ljmp: |
... | ... | |
1965 | 2239 |
} else { |
1966 | 2240 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
1967 | 2241 |
gen_op_mov_TN_reg[ot][0][reg](); |
1968 |
gen_op_ld_T1_A0[ot](); |
|
2242 |
gen_op_ld_T1_A0[ot + s->mem_index]();
|
|
1969 | 2243 |
gen_op_addl_T0_T1(); |
1970 |
gen_op_st_T0_A0[ot](); |
|
2244 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
1971 | 2245 |
gen_op_mov_reg_T1[ot][reg](); |
1972 | 2246 |
} |
1973 | 2247 |
gen_op_update2_cc(); |
... | ... | |
1990 | 2264 |
gen_op_mov_reg_T0[ot][rm](); |
1991 | 2265 |
} else { |
1992 | 2266 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
1993 |
gen_op_ld_T0_A0[ot](); |
|
2267 |
gen_op_ld_T0_A0[ot + s->mem_index]();
|
|
1994 | 2268 |
gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot](); |
1995 | 2269 |
} |
1996 | 2270 |
s->cc_op = CC_OP_SUBB + ot; |
... | ... | |
2121 | 2395 |
val = insn_get(s, ot); |
2122 | 2396 |
gen_op_movl_T0_im(val); |
2123 | 2397 |
if (mod != 3) |
2124 |
gen_op_st_T0_A0[ot](); |
|
2398 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
2125 | 2399 |
else |
2126 | 2400 |
gen_op_mov_reg_T0[ot][modrm & 7](); |
2127 | 2401 |
break; |
... | ... | |
2195 | 2469 |
} else { |
2196 | 2470 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
2197 | 2471 |
if (b & 8) { |
2198 |
gen_op_lds_T0_A0[ot](); |
|
2472 |
gen_op_lds_T0_A0[ot + s->mem_index]();
|
|
2199 | 2473 |
} else { |
2200 |
gen_op_ldu_T0_A0[ot](); |
|
2474 |
gen_op_ldu_T0_A0[ot + s->mem_index]();
|
|
2201 | 2475 |
} |
2202 | 2476 |
gen_op_mov_reg_T0[d_ot][reg](); |
2203 | 2477 |
} |
... | ... | |
2245 | 2519 |
} |
2246 | 2520 |
} |
2247 | 2521 |
if ((b & 2) == 0) { |
2248 |
gen_op_ld_T0_A0[ot](); |
|
2522 |
gen_op_ld_T0_A0[ot + s->mem_index]();
|
|
2249 | 2523 |
gen_op_mov_reg_T0[ot][R_EAX](); |
2250 | 2524 |
} else { |
2251 | 2525 |
gen_op_mov_TN_reg[ot][0][R_EAX](); |
2252 |
gen_op_st_T0_A0[ot](); |
|
2526 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
2253 | 2527 |
} |
2254 | 2528 |
break; |
2255 | 2529 |
case 0xd7: /* xlat */ |
... | ... | |
2272 | 2546 |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); |
2273 | 2547 |
} |
2274 | 2548 |
} |
2275 |
gen_op_ldub_T0_A0();
|
|
2549 |
gen_op_ldu_T0_A0[OT_BYTE + s->mem_index]();
|
|
2276 | 2550 |
gen_op_mov_reg_T0[OT_BYTE][R_EAX](); |
2277 | 2551 |
break; |
2278 | 2552 |
case 0xb0 ... 0xb7: /* mov R, Ib */ |
... | ... | |
2315 | 2589 |
/* for xchg, lock is implicit */ |
2316 | 2590 |
if (!(prefixes & PREFIX_LOCK)) |
2317 | 2591 |
gen_op_lock(); |
2318 |
gen_op_ld_T1_A0[ot](); |
|
2319 |
gen_op_st_T0_A0[ot](); |
|
2592 |
gen_op_ld_T1_A0[ot + s->mem_index]();
|
|
2593 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
2320 | 2594 |
if (!(prefixes & PREFIX_LOCK)) |
2321 | 2595 |
gen_op_unlock(); |
2322 | 2596 |
gen_op_mov_reg_T1[ot][reg](); |
... | ... | |
2344 | 2618 |
if (mod == 3) |
2345 | 2619 |
goto illegal_op; |
2346 | 2620 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
2347 |
gen_op_ld_T1_A0[ot](); |
|
2621 |
gen_op_ld_T1_A0[ot + s->mem_index]();
|
|
2348 | 2622 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
2349 | 2623 |
/* load the segment first to handle exceptions properly */ |
2350 | 2624 |
gen_op_lduw_T0_A0(); |
... | ... | |
2424 | 2698 |
|
2425 | 2699 |
if (mod != 3) { |
2426 | 2700 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
2427 |
gen_op_ld_T0_A0[ot](); |
|
2701 |
gen_op_ld_T0_A0[ot + s->mem_index]();
|
|
2428 | 2702 |
} else { |
2429 | 2703 |
gen_op_mov_TN_reg[ot][0][rm](); |
2430 | 2704 |
} |
... | ... | |
2869 | 3143 |
ot = dflag ? OT_LONG : OT_WORD; |
2870 | 3144 |
|
2871 | 3145 |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
2872 |
gen_string_ds(s, ot, gen_op_movs + 9);
|
|
3146 |
gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
|
2873 | 3147 |
} else { |
2874 |
gen_string_ds(s, ot, gen_op_movs);
|
|
3148 |
gen_movs(s, ot);
|
|
2875 | 3149 |
} |
2876 | 3150 |
break; |
2877 | 3151 |
|
... | ... | |
2883 | 3157 |
ot = dflag ? OT_LONG : OT_WORD; |
2884 | 3158 |
|
2885 | 3159 |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
2886 |
gen_string_es(s, ot, gen_op_stos + 9);
|
|
3160 |
gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
|
2887 | 3161 |
} else { |
2888 |
gen_string_es(s, ot, gen_op_stos);
|
|
3162 |
gen_stos(s, ot);
|
|
2889 | 3163 |
} |
2890 | 3164 |
break; |
2891 | 3165 |
case 0xac: /* lodsS */ |
... | ... | |
2895 | 3169 |
else |
2896 | 3170 |
ot = dflag ? OT_LONG : OT_WORD; |
2897 | 3171 |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
2898 |
gen_string_ds(s, ot, gen_op_lods + 9);
|
|
3172 |
gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
|
2899 | 3173 |
} else { |
2900 |
gen_string_ds(s, ot, gen_op_lods);
|
|
3174 |
gen_lods(s, ot);
|
|
2901 | 3175 |
} |
2902 | 3176 |
break; |
2903 | 3177 |
case 0xae: /* scasS */ |
... | ... | |
2909 | 3183 |
if (prefixes & PREFIX_REPNZ) { |
2910 | 3184 |
if (s->cc_op != CC_OP_DYNAMIC) |
2911 | 3185 |
gen_op_set_cc_op(s->cc_op); |
2912 |
gen_string_es(s, ot, gen_op_scas + 9 * 2);
|
|
3186 |
gen_string_es(s, ot, gen_op_scas + STRINGOP_NB);
|
|
2913 | 3187 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
2914 | 3188 |
} else if (prefixes & PREFIX_REPZ) { |
2915 | 3189 |
if (s->cc_op != CC_OP_DYNAMIC) |
2916 | 3190 |
gen_op_set_cc_op(s->cc_op); |
2917 |
gen_string_es(s, ot, gen_op_scas + 9);
|
|
3191 |
gen_string_es(s, ot, gen_op_scas); |
|
2918 | 3192 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
2919 | 3193 |
} else { |
2920 |
gen_string_es(s, ot, gen_op_scas);
|
|
3194 |
gen_scas(s, ot);
|
|
2921 | 3195 |
s->cc_op = CC_OP_SUBB + ot; |
2922 | 3196 |
} |
2923 | 3197 |
break; |
... | ... | |
2931 | 3205 |
if (prefixes & PREFIX_REPNZ) { |
2932 | 3206 |
if (s->cc_op != CC_OP_DYNAMIC) |
2933 | 3207 |
gen_op_set_cc_op(s->cc_op); |
2934 |
gen_string_ds(s, ot, gen_op_cmps + 9 * 2);
|
|
3208 |
gen_string_ds(s, ot, gen_op_cmps + STRINGOP_NB);
|
|
2935 | 3209 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
2936 | 3210 |
} else if (prefixes & PREFIX_REPZ) { |
2937 | 3211 |
if (s->cc_op != CC_OP_DYNAMIC) |
2938 | 3212 |
gen_op_set_cc_op(s->cc_op); |
2939 |
gen_string_ds(s, ot, gen_op_cmps + 9);
|
|
3213 |
gen_string_ds(s, ot, gen_op_cmps); |
|
2940 | 3214 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
2941 | 3215 |
} else { |
2942 |
gen_string_ds(s, ot, gen_op_cmps);
|
|
3216 |
gen_cmps(s, ot);
|
|
2943 | 3217 |
s->cc_op = CC_OP_SUBB + ot; |
2944 | 3218 |
} |
2945 | 3219 |
break; |
... | ... | |
2954 | 3228 |
else |
2955 | 3229 |
ot = dflag ? OT_LONG : OT_WORD; |
2956 | 3230 |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
2957 |
gen_string_es(s, ot, gen_op_ins + 9);
|
|
3231 |
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
|
2958 | 3232 |
} else { |
2959 |
gen_string_es(s, ot, gen_op_ins);
|
|
3233 |
gen_ins(s, ot);
|
|
2960 | 3234 |
} |
2961 | 3235 |
} |
2962 | 3236 |
break; |
... | ... | |
2971 | 3245 |
else |
2972 | 3246 |
ot = dflag ? OT_LONG : OT_WORD; |
2973 | 3247 |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
2974 |
gen_string_ds(s, ot, gen_op_outs + 9);
|
|
3248 |
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
|
2975 | 3249 |
} else { |
2976 |
gen_string_ds(s, ot, gen_op_outs);
|
|
3250 |
gen_outs(s, ot);
|
|
2977 | 3251 |
} |
2978 | 3252 |
} |
2979 | 3253 |
break; |
... | ... | |
3071 | 3345 |
} else { |
3072 | 3346 |
gen_stack_A0(s); |
3073 | 3347 |
/* pop offset */ |
3074 |
gen_op_ld_T0_A0[1 + s->dflag](); |
|
3348 |
gen_op_ld_T0_A0[1 + s->dflag + s->mem_index]();
|
|
3075 | 3349 |
if (s->dflag == 0) |
3076 | 3350 |
gen_op_andl_T0_ffff(); |
3077 | 3351 |
/* NOTE: keeping EIP updated is not a problem in case of |
... | ... | |
3079 | 3353 |
gen_op_jmp_T0(); |
3080 | 3354 |
/* pop selector */ |
3081 | 3355 |
gen_op_addl_A0_im(2 << s->dflag); |
3082 |
gen_op_ld_T0_A0[1 + s->dflag](); |
|
3356 |
gen_op_ld_T0_A0[1 + s->dflag + s->mem_index]();
|
|
3083 | 3357 |
gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); |
3084 | 3358 |
/* add stack offset */ |
3085 | 3359 |
gen_stack_update(s, val + (4 << s->dflag)); |
... | ... | |
3188 | 3462 |
gen_setcc(s, b); |
3189 | 3463 |
if (mod != 3) { |
3190 | 3464 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
3191 |
gen_op_ld_T1_A0[ot](); |
|
3465 |
gen_op_ld_T1_A0[ot + s->mem_index]();
|
|
3192 | 3466 |
} else { |
3193 | 3467 |
rm = modrm & 7; |
3194 | 3468 |
gen_op_mov_TN_reg[ot][1][rm](); |
... | ... | |
3279 | 3553 |
rm = modrm & 7; |
3280 | 3554 |
if (mod != 3) { |
3281 | 3555 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
3282 |
gen_op_ld_T0_A0[ot](); |
|
3556 |
gen_op_ld_T0_A0[ot + s->mem_index]();
|
|
3283 | 3557 |
} else { |
3284 | 3558 |
gen_op_mov_TN_reg[ot][0][rm](); |
3285 | 3559 |
} |
... | ... | |
3293 | 3567 |
s->cc_op = CC_OP_SARB + ot; |
3294 | 3568 |
if (op != 0) { |
3295 | 3569 |
if (mod != 3) |
3296 |
gen_op_st_T0_A0[ot](); |
|
3570 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
3297 | 3571 |
else |
3298 | 3572 |
gen_op_mov_reg_T0[ot][rm](); |
3299 | 3573 |
gen_op_update_bt_cc(); |
... | ... | |
3324 | 3598 |
gen_op_add_bitw_A0_T1(); |
3325 | 3599 |
else |
3326 | 3600 |
gen_op_add_bitl_A0_T1(); |
3327 |
gen_op_ld_T0_A0[ot](); |
|
3601 |
gen_op_ld_T0_A0[ot + s->mem_index]();
|
|
3328 | 3602 |
} else { |
3329 | 3603 |
gen_op_mov_TN_reg[ot][0][rm](); |
3330 | 3604 |
} |
... | ... | |
3332 | 3606 |
s->cc_op = CC_OP_SARB + ot; |
3333 | 3607 |
if (op != 0) { |
3334 | 3608 |
if (mod != 3) |
3335 |
gen_op_st_T0_A0[ot](); |
|
3609 |
gen_op_st_T0_A0[ot + s->mem_index]();
|
|
3336 | 3610 |
else |
3337 | 3611 |
gen_op_mov_reg_T0[ot][rm](); |
3338 | 3612 |
gen_op_update_bt_cc(); |
... | ... | |
3569 | 3843 |
gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); |
3570 | 3844 |
else |
3571 | 3845 |
gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); |
3572 |
gen_op_stw_T0_A0();
|
|
3846 |
gen_op_st_T0_A0[OT_WORD + s->mem_index]();
|
|
3573 | 3847 |
gen_op_addl_A0_im(2); |
3574 | 3848 |
if (op == 0) |
3575 | 3849 |
gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base)); |
... | ... | |
3577 | 3851 |
gen_op_movl_T0_env(offsetof(CPUX86State,idt.base)); |
3578 | 3852 |
if (!s->dflag) |
3579 | 3853 |
gen_op_andl_T0_im(0xffffff); |
3580 |
gen_op_stl_T0_A0();
|
|
3854 |
gen_op_st_T0_A0[OT_LONG + s->mem_index]();
|
|
3581 | 3855 |
break; |
3582 | 3856 |
case 2: /* lgdt */ |
3583 | 3857 |
case 3: /* lidt */ |
... | ... | |
3587 | 3861 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3588 | 3862 |
} else { |
3589 | 3863 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
3590 |
gen_op_lduw_T1_A0();
|
|
3864 |
gen_op_ld_T1_A0[OT_WORD + s->mem_index]();
|
|
3591 | 3865 |
gen_op_addl_A0_im(2); |
3592 |
gen_op_ldl_T0_A0();
|
|
3866 |
gen_op_ld_T0_A0[OT_LONG + s->mem_index]();
|
|
3593 | 3867 |
if (!s->dflag) |
3594 | 3868 |
gen_op_andl_T0_im(0xffffff); |
3595 | 3869 |
if (op == 2) { |
... | ... | |
3990 | 4264 |
[INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \ |
3991 | 4265 |
[INDEX_op_ ## x ## l_a16] = CC_OSZAPC, |
3992 | 4266 |
|
3993 |
STRINGOP(scas) |
|
3994 | 4267 |
STRINGOP(repz_scas) |
3995 | 4268 |
STRINGOP(repnz_scas) |
3996 |
STRINGOP(cmps) |
|
3997 | 4269 |
STRINGOP(repz_cmps) |
3998 | 4270 |
STRINGOP(repnz_cmps) |
3999 | 4271 |
|
... | ... | |
4050 | 4322 |
[INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, |
4051 | 4323 |
}; |
4052 | 4324 |
|
4053 |
static void optimize_flags_init(void)
|
|
4325 |
void optimize_flags_init(void) |
|
4054 | 4326 |
{ |
4055 | 4327 |
int i; |
4056 | 4328 |
/* put default values in arrays */ |
... | ... | |
4120 | 4392 |
dc->cs_base = cs_base; |
4121 | 4393 |
dc->tb = tb; |
4122 | 4394 |
dc->popl_esp_hack = 0; |
4395 |
/* select memory access functions */ |
|
4396 |
dc->mem_index = 0; |
|
4397 |
if ((flags >> GEN_FLAG_SOFT_MMU_SHIFT) & 1) { |
|
4398 |
if (dc->cpl == 3) |
|
4399 |
dc->mem_index = 6; |
|
4400 |
else |
|
4401 |
dc->mem_index = 3; |
|
4402 |
} |
|
4123 | 4403 |
|
4124 | 4404 |
gen_opc_ptr = gen_opc_buf; |
4125 | 4405 |
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
... | ... | |
4234 | 4514 |
return gen_intermediate_code_internal(env, tb, 1); |
4235 | 4515 |
} |
4236 | 4516 |
|
4237 |
CPUX86State *cpu_x86_init(void) |
|
4238 |
{ |
|
4239 |
CPUX86State *env; |
|
4240 |
int i; |
|
4241 |
static int inited; |
|
4242 |
|
|
4243 |
cpu_exec_init(); |
|
4244 |
|
|
4245 |
env = malloc(sizeof(CPUX86State)); |
|
4246 |
if (!env) |
|
4247 |
return NULL; |
|
4248 |
memset(env, 0, sizeof(CPUX86State)); |
|
4249 |
/* basic FPU init */ |
|
4250 |
for(i = 0;i < 8; i++) |
|
4251 |
env->fptags[i] = 1; |
|
4252 |
env->fpuc = 0x37f; |
|
4253 |
/* flags setup : we activate the IRQs by default as in user mode */ |
|
4254 |
env->eflags = 0x2 | IF_MASK; |
|
4255 |
|
|
4256 |
/* init various static tables */ |
|
4257 |
if (!inited) { |
|
4258 |
inited = 1; |
|
4259 |
optimize_flags_init(); |
|
4260 |
} |
|
4261 |
return env; |
|
4262 |
} |
|
4263 |
|
|
4264 |
void cpu_x86_close(CPUX86State *env) |
|
4265 |
{ |
|
4266 |
free(env); |
|
4267 |
} |
|
4268 |
|
|
4269 |
/***********************************************************/ |
|
4270 |
/* x86 mmu */ |
|
4271 |
/* XXX: add PGE support */ |
|
4272 |
|
|
4273 |
/* called when cr3 or PG bit are modified */ |
|
4274 |
static int last_pg_state = -1; |
|
4275 |
static int last_pe_state = 0; |
|
4276 |
int phys_ram_size; |
|
4277 |
int phys_ram_fd; |
|
4278 |
uint8_t *phys_ram_base; |
|
4279 |
|
|
4280 |
void cpu_x86_update_cr0(CPUX86State *env) |
|
4281 |
{ |
|
4282 |
int pg_state, pe_state; |
|
4283 |
void *map_addr; |
|
4284 |
|
|
4285 |
#ifdef DEBUG_MMU |
|
4286 |
printf("CR0 update: CR0=0x%08x\n", env->cr[0]); |
|
4287 |
#endif |
|
4288 |
pg_state = env->cr[0] & CR0_PG_MASK; |
|
4289 |
if (pg_state != last_pg_state) { |
|
4290 |
if (!pg_state) { |
|
4291 |
/* we map the physical memory at address 0 */ |
|
4292 |
|
|
4293 |
map_addr = mmap((void *)0, phys_ram_size, PROT_WRITE | PROT_READ, |
|
4294 |
MAP_SHARED | MAP_FIXED, phys_ram_fd, 0); |
|
4295 |
if (map_addr == MAP_FAILED) { |
|
4296 |
fprintf(stderr, |
|
4297 |
"Could not map physical memory at host address 0x%08x\n", |
|
4298 |
0); |
|
4299 |
exit(1); |
|
4300 |
} |
|
4301 |
page_set_flags(0, phys_ram_size, |
|
4302 |
PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC); |
|
4303 |
} else { |
|
4304 |
/* we unmap the physical memory */ |
|
4305 |
munmap((void *)0, phys_ram_size); |
|
4306 |
page_set_flags(0, phys_ram_size, 0); |
|
4307 |
} |
|
4308 |
last_pg_state = pg_state; |
|
4309 |
} |
|
4310 |
pe_state = env->cr[0] & CR0_PE_MASK; |
|
4311 |
if (last_pe_state != pe_state) { |
|
4312 |
tb_flush(); |
|
4313 |
last_pe_state = pe_state; |
|
4314 |
} |
|
4315 |
} |
|
4316 |
|
|
4317 |
void cpu_x86_update_cr3(CPUX86State *env) |
|
4318 |
{ |
|
4319 |
if (env->cr[0] & CR0_PG_MASK) { |
|
4320 |
#if defined(DEBUG_MMU) |
|
4321 |
printf("CR3 update: CR3=%08x\n", env->cr[3]); |
|
4322 |
#endif |
|
4323 |
page_unmap(); |
|
4324 |
} |
|
4325 |
} |
|
4326 |
|
|
4327 |
void cpu_x86_init_mmu(CPUX86State *env) |
|
4328 |
{ |
|
4329 |
last_pg_state = -1; |
|
4330 |
cpu_x86_update_cr0(env); |
|
4331 |
} |
|
4332 |
|
|
4333 |
/* XXX: also flush 4MB pages */ |
|
4334 |
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) |
|
4335 |
{ |
|
4336 |
int flags; |
|
4337 |
unsigned long virt_addr; |
|
4338 |
|
|
4339 |
flags = page_get_flags(addr); |
|
4340 |
if (flags & PAGE_VALID) { |
|
4341 |
virt_addr = addr & ~0xfff; |
|
4342 |
munmap((void *)virt_addr, 4096); |
|
4343 |
page_set_flags(virt_addr, virt_addr + 4096, 0); |
|
4344 |
} |
|
4345 |
} |
|
4346 |
|
|
4347 |
/* return value: |
|
4348 |
-1 = cannot handle fault |
|
4349 |
0 = nothing more to do |
|
4350 |
1 = generate PF fault |
|
4351 |
*/ |
|
4352 |
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) |
|
4353 |
{ |
|
4354 |
uint8_t *pde_ptr, *pte_ptr; |
|
4355 |
uint32_t pde, pte, virt_addr; |
|
4356 |
int cpl, error_code, is_dirty, is_user, prot, page_size; |
|
4357 |
void *map_addr; |
|
4358 |
|
|
4359 |
cpl = env->cpl; |
|
4360 |
is_user = (cpl == 3); |
|
4361 |
|
|
4362 |
#ifdef DEBUG_MMU |
|
4363 |
printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", |
|
4364 |
addr, is_write, is_user, env->eip); |
|
4365 |
#endif |
|
4366 |
|
|
4367 |
if (env->user_mode_only) { |
|
4368 |
/* user mode only emulation */ |
|
4369 |
error_code = 0; |
|
4370 |
goto do_fault; |
|
4371 |
} |
|
4372 |
|
|
4373 |
if (!(env->cr[0] & CR0_PG_MASK)) |
|
4374 |
return -1; |
|
4375 |
|
|
4376 |
/* page directory entry */ |
|
4377 |
pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); |
|
4378 |
pde = ldl(pde_ptr); |
|
4379 |
if (!(pde & PG_PRESENT_MASK)) { |
|
4380 |
error_code = 0; |
|
4381 |
goto do_fault; |
|
4382 |
} |
|
4383 |
if (is_user) { |
|
4384 |
if (!(pde & PG_USER_MASK)) |
|
4385 |
goto do_fault_protect; |
|
4386 |
if (is_write && !(pde & PG_RW_MASK)) |
|
4387 |
goto do_fault_protect; |
|
4388 |
} else { |
|
4389 |
if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && |
|
4390 |
is_write && !(pde & PG_RW_MASK)) |
|
4391 |
goto do_fault_protect; |
|
4392 |
} |
|
4393 |
/* if PSE bit is set, then we use a 4MB page */ |
|
4394 |
if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { |
|
4395 |
is_dirty = is_write && !(pde & PG_DIRTY_MASK); |
|
4396 |
if (!(pde & PG_ACCESSED_MASK)) { |
|
4397 |
pde |= PG_ACCESSED_MASK; |
|
4398 |
if (is_dirty) |
|
4399 |
pde |= PG_DIRTY_MASK; |
|
4400 |
stl(pde_ptr, pde); |
|
4401 |
} |
|
4402 |
|
|
4403 |
pte = pde & ~0x003ff000; /* align to 4MB */ |
|
4404 |
page_size = 4096 * 1024; |
|
4405 |
virt_addr = addr & ~0x003fffff; |
|
4406 |
} else { |
|
4407 |
if (!(pde & PG_ACCESSED_MASK)) { |
|
4408 |
pde |= PG_ACCESSED_MASK; |
|
4409 |
stl(pde_ptr, pde); |
|
4410 |
} |
|
4411 |
|
|
4412 |
/* page directory entry */ |
|
4413 |
pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); |
|
4414 |
pte = ldl(pte_ptr); |
|
4415 |
if (!(pte & PG_PRESENT_MASK)) { |
|
4416 |
error_code = 0; |
|
4417 |
goto do_fault; |
|
4418 |
} |
|
4419 |
if (is_user) { |
|
4420 |
if (!(pte & PG_USER_MASK)) |
|
4421 |
goto do_fault_protect; |
|
4422 |
if (is_write && !(pte & PG_RW_MASK)) |
|
4423 |
goto do_fault_protect; |
|
4424 |
} else { |
|
4425 |
if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && |
|
4426 |
is_write && !(pte & PG_RW_MASK)) |
|
4427 |
goto do_fault_protect; |
|
4428 |
} |
|
4429 |
is_dirty = is_write && !(pte & PG_DIRTY_MASK); |
|
4430 |
if (!(pte & PG_ACCESSED_MASK) || is_dirty) { |
|
4431 |
pte |= PG_ACCESSED_MASK; |
|
4432 |
if (is_dirty) |
|
4433 |
pte |= PG_DIRTY_MASK; |
|
4434 |
stl(pte_ptr, pte); |
|
4435 |
} |
|
4436 |
page_size = 4096; |
|
4437 |
virt_addr = addr & ~0xfff; |
|
4438 |
} |
|
4439 |
/* the page can be put in the TLB */ |
|
4440 |
prot = PROT_READ; |
|
4441 |
if (is_user) { |
|
4442 |
if (pte & PG_RW_MASK) |
|
4443 |
prot |= PROT_WRITE; |
|
4444 |
} else { |
|
4445 |
if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || |
|
4446 |
(pte & PG_RW_MASK)) |
|
4447 |
prot |= PROT_WRITE; |
|
4448 |
} |
|
4449 |
map_addr = mmap((void *)virt_addr, page_size, prot, |
|
4450 |
MAP_SHARED | MAP_FIXED, phys_ram_fd, pte & ~0xfff); |
|
4451 |
if (map_addr == MAP_FAILED) { |
|
4452 |
fprintf(stderr, |
|
4453 |
"mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", |
|
4454 |
pte & ~0xfff, virt_addr); |
|
4455 |
exit(1); |
|
4456 |
} |
|
4457 |
page_set_flags(virt_addr, virt_addr + page_size, |
|
4458 |
PAGE_VALID | PAGE_EXEC | prot); |
|
4459 |
#ifdef DEBUG_MMU |
|
4460 |
printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", |
|
4461 |
pte & ~0xfff, virt_addr, (page_size != 4096)); |
|
4462 |
#endif |
|
4463 |
return 0; |
|
4464 |
do_fault_protect: |
|
4465 |
error_code = PG_ERROR_P_MASK; |
|
4466 |
do_fault: |
|
4467 |
env->cr[2] = addr; |
|
4468 |
env->error_code = (is_write << PG_ERROR_W_BIT) | error_code; |
|
4469 |
if (is_user) |
|
4470 |
env->error_code |= PG_ERROR_U_MASK; |
|
4471 |
return 1; |
|
4472 |
} |
|
4473 |
|
|
4474 |
/***********************************************************/ |
|
4475 |
/* x86 debug */ |
|
4476 |
|
|
4477 |
static const char *cc_op_str[] = { |
|
4478 |
"DYNAMIC", |
|
4479 |
"EFLAGS", |
|
4480 |
"MUL", |
|
4481 |
"ADDB", |
|
4482 |
"ADDW", |
|
4483 |
"ADDL", |
|
4484 |
"ADCB", |
|
4485 |
"ADCW", |
|
4486 |
"ADCL", |
|
4487 |
"SUBB", |
|
4488 |
"SUBW", |
|
4489 |
"SUBL", |
|
4490 |
"SBBB", |
|
4491 |
"SBBW", |
|
4492 |
"SBBL", |
|
4493 |
"LOGICB", |
|
4494 |
"LOGICW", |
|
4495 |
"LOGICL", |
|
4496 |
"INCB", |
|
4497 |
"INCW", |
|
4498 |
"INCL", |
|
4499 |
"DECB", |
|
4500 |
"DECW", |
|
4501 |
"DECL", |
|
4502 |
"SHLB", |
|
4503 |
"SHLW", |
|
4504 |
"SHLL", |
|
4505 |
"SARB", |
|
4506 |
"SARW", |
|
4507 |
"SARL", |
|
4508 |
}; |
|
4509 |
|
|
4510 |
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) |
|
4511 |
{ |
|
4512 |
int eflags; |
|
4513 |
char cc_op_name[32]; |
|
4514 |
|
|
4515 |
eflags = env->eflags; |
|
4516 |
fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" |
|
4517 |
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" |
|
4518 |
"EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n", |
|
4519 |
env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], |
|
4520 |
env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], |
|
4521 |
env->eip, eflags, |
|
4522 |
eflags & DF_MASK ? 'D' : '-', |
|
4523 |
eflags & CC_O ? 'O' : '-', |
|
4524 |
eflags & CC_S ? 'S' : '-', |
|
4525 |
eflags & CC_Z ? 'Z' : '-', |
|
4526 |
eflags & CC_A ? 'A' : '-', |
|
4527 |
eflags & CC_P ? 'P' : '-', |
|
4528 |
eflags & CC_C ? 'C' : '-'); |
|
4529 |
fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", |
|
4530 |
env->segs[R_CS].selector, |
|
4531 |
env->segs[R_SS].selector, |
|
4532 |
env->segs[R_DS].selector, |
|
4533 |
env->segs[R_ES].selector, |
|
4534 |
env->segs[R_FS].selector, |
|
4535 |
env->segs[R_GS].selector); |
|
4536 |
if (flags & X86_DUMP_CCOP) { |
|
4537 |
if ((unsigned)env->cc_op < CC_OP_NB) |
|
4538 |
strcpy(cc_op_name, cc_op_str[env->cc_op]); |
|
4539 |
else |
|
4540 |
snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); |
|
4541 |
fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", |
|
4542 |
env->cc_src, env->cc_dst, cc_op_name); |
|
4543 |
} |
|
4544 |
if (flags & X86_DUMP_FPU) { |
|
4545 |
fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", |
|
4546 |
(double)env->fpregs[0], |
|
4547 |
(double)env->fpregs[1], |
|
4548 |
(double)env->fpregs[2], |
|
4549 |
(double)env->fpregs[3]); |
|
4550 |
fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", |
|
4551 |
(double)env->fpregs[4], |
|
4552 |
(double)env->fpregs[5], |
|
4553 |
(double)env->fpregs[7], |
|
4554 |
(double)env->fpregs[8]); |
|
4555 |
} |
|
4556 |
} |
Also available in: Unified diff