30 |
#include "exec.h" |
#include "exec.h" |
31 |
#include "disas.h" |
#include "disas.h" |
32 |
|
|
|
//#define DEBUG_MMU |
|
|
|
|
33 |
/* XXX: move that elsewhere */ |
/* XXX: move that elsewhere */ |
34 |
static uint16_t *gen_opc_ptr; |
static uint16_t *gen_opc_ptr; |
35 |
static uint32_t *gen_opparam_ptr; |
static uint32_t *gen_opparam_ptr; |
60 |
int cpl; |
int cpl; |
61 |
int iopl; |
int iopl; |
62 |
int tf; /* TF cpu flag */ |
int tf; /* TF cpu flag */ |
63 |
|
int mem_index; /* select memory access functions */ |
64 |
struct TranslationBlock *tb; |
struct TranslationBlock *tb; |
65 |
int popl_esp_hack; /* for correct popl with esp base handling */ |
int popl_esp_hack; /* for correct popl with esp base handling */ |
66 |
} DisasContext; |
} DisasContext; |
564 |
}, |
}, |
565 |
}; |
}; |
566 |
|
|
567 |
static GenOpFunc *gen_op_lds_T0_A0[3] = { |
static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = { |
568 |
gen_op_ldsb_T0_A0, |
gen_op_ldsb_T0_A0, |
569 |
gen_op_ldsw_T0_A0, |
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, |
579 |
}; |
}; |
580 |
|
|
581 |
static GenOpFunc *gen_op_ldu_T0_A0[3] = { |
static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = { |
582 |
gen_op_ldub_T0_A0, |
gen_op_ldub_T0_A0, |
583 |
gen_op_lduw_T0_A0, |
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, |
593 |
}; |
}; |
594 |
|
|
595 |
/* sign does not matter */ |
/* sign does not matter, except for lidt/lgdt call (TODO: fix it) */ |
596 |
static GenOpFunc *gen_op_ld_T0_A0[3] = { |
static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = { |
597 |
gen_op_ldub_T0_A0, |
gen_op_ldub_T0_A0, |
598 |
gen_op_lduw_T0_A0, |
gen_op_lduw_T0_A0, |
599 |
gen_op_ldl_T0_A0, |
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, |
608 |
}; |
}; |
609 |
|
|
610 |
static GenOpFunc *gen_op_ld_T1_A0[3] = { |
static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = { |
611 |
gen_op_ldub_T1_A0, |
gen_op_ldub_T1_A0, |
612 |
gen_op_lduw_T1_A0, |
gen_op_lduw_T1_A0, |
613 |
gen_op_ldl_T1_A0, |
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, |
622 |
}; |
}; |
623 |
|
|
624 |
static GenOpFunc *gen_op_st_T0_A0[3] = { |
static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { |
625 |
gen_op_stb_T0_A0, |
gen_op_stb_T0_A0, |
626 |
gen_op_stw_T0_A0, |
gen_op_stw_T0_A0, |
627 |
gen_op_stl_T0_A0, |
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, |
636 |
}; |
}; |
637 |
|
|
638 |
/* the _a32 and _a16 string operations use A0 as the base register. */ |
/* the _a32 and _a16 string operations use A0 as the base register. */ |
639 |
|
|
640 |
|
#define STRINGOP_NB 9 |
641 |
|
|
642 |
#define STRINGOP(x) \ |
#define STRINGOP(x) \ |
643 |
gen_op_ ## x ## b_fast, \ |
gen_op_ ## x ## b_fast, \ |
644 |
gen_op_ ## x ## w_fast, \ |
gen_op_ ## x ## w_fast, \ |
650 |
gen_op_ ## x ## w_a16, \ |
gen_op_ ## x ## w_a16, \ |
651 |
gen_op_ ## x ## l_a16, |
gen_op_ ## x ## l_a16, |
652 |
|
|
653 |
static GenOpFunc *gen_op_movs[9 * 2] = { |
static GenOpFunc *gen_op_scas[STRINGOP_NB * 3] = { |
654 |
STRINGOP(movs) |
STRINGOP(repz_scas) |
655 |
STRINGOP(rep_movs) |
STRINGOP(repnz_scas) |
656 |
}; |
}; |
657 |
|
|
658 |
static GenOpFunc *gen_op_stos[9 * 2] = { |
static GenOpFunc *gen_op_cmps[STRINGOP_NB * 3] = { |
659 |
STRINGOP(stos) |
STRINGOP(repz_cmps) |
660 |
STRINGOP(rep_stos) |
STRINGOP(repnz_cmps) |
661 |
}; |
}; |
662 |
|
|
663 |
static GenOpFunc *gen_op_lods[9 * 2] = { |
static inline void gen_string_movl_A0_ESI(DisasContext *s) |
664 |
STRINGOP(lods) |
{ |
665 |
STRINGOP(rep_lods) |
int override; |
|
}; |
|
666 |
|
|
667 |
static GenOpFunc *gen_op_scas[9 * 3] = { |
override = s->override; |
668 |
STRINGOP(scas) |
if (s->aflag) { |
669 |
STRINGOP(repz_scas) |
/* 32 bit address */ |
670 |
STRINGOP(repnz_scas) |
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, |
708 |
}; |
}; |
709 |
|
|
710 |
static GenOpFunc *gen_op_cmps[9 * 3] = { |
static GenOpFunc2 *gen_op_jz_ecx[2] = { |
711 |
STRINGOP(cmps) |
gen_op_jz_ecxw, |
712 |
STRINGOP(repz_cmps) |
gen_op_jz_ecxl, |
713 |
STRINGOP(repnz_cmps) |
}; |
714 |
|
|
715 |
|
static GenOpFunc *gen_op_dec_ECX[2] = { |
716 |
|
gen_op_decw_ECX, |
717 |
|
gen_op_decl_ECX, |
718 |
}; |
}; |
719 |
|
|
720 |
static GenOpFunc *gen_op_ins[9 * 2] = { |
static GenOpFunc2 *gen_op_string_jnz_sub[2][3] = { |
721 |
STRINGOP(ins) |
{ |
722 |
STRINGOP(rep_ins) |
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 |
|
}, |
731 |
}; |
}; |
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 |
|
}; |
738 |
|
|
739 |
static GenOpFunc *gen_op_outs[9 * 2] = { |
static GenOpFunc *gen_op_out_DX_T0[3] = { |
740 |
STRINGOP(outs) |
gen_op_outb_DX_T0, |
741 |
STRINGOP(rep_outs) |
gen_op_outw_DX_T0, |
742 |
|
gen_op_outl_DX_T0, |
743 |
}; |
}; |
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 |
|
} |
922 |
|
|
923 |
static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) |
static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func) |
924 |
{ |
{ |
1107 |
if (d != OR_TMP0) { |
if (d != OR_TMP0) { |
1108 |
gen_op_mov_TN_reg[ot][0][d](); |
gen_op_mov_TN_reg[ot][0][d](); |
1109 |
} else { |
} else { |
1110 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s1->mem_index](); |
1111 |
} |
} |
1112 |
switch(op) { |
switch(op) { |
1113 |
case OP_ADCL: |
case OP_ADCL: |
1150 |
if (d != OR_TMP0) |
if (d != OR_TMP0) |
1151 |
gen_op_mov_reg_T0[ot][d](); |
gen_op_mov_reg_T0[ot][d](); |
1152 |
else |
else |
1153 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s1->mem_index](); |
1154 |
} |
} |
1155 |
/* the flags update must happen after the memory write (precise |
/* the flags update must happen after the memory write (precise |
1156 |
exception support) */ |
exception support) */ |
1165 |
if (d != OR_TMP0) |
if (d != OR_TMP0) |
1166 |
gen_op_mov_TN_reg[ot][0][d](); |
gen_op_mov_TN_reg[ot][0][d](); |
1167 |
else |
else |
1168 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s1->mem_index](); |
1169 |
if (s1->cc_op != CC_OP_DYNAMIC) |
if (s1->cc_op != CC_OP_DYNAMIC) |
1170 |
gen_op_set_cc_op(s1->cc_op); |
gen_op_set_cc_op(s1->cc_op); |
1171 |
if (c > 0) { |
if (c > 0) { |
1178 |
if (d != OR_TMP0) |
if (d != OR_TMP0) |
1179 |
gen_op_mov_reg_T0[ot][d](); |
gen_op_mov_reg_T0[ot][d](); |
1180 |
else |
else |
1181 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s1->mem_index](); |
1182 |
gen_op_update_inc_cc(); |
gen_op_update_inc_cc(); |
1183 |
} |
} |
1184 |
|
|
1187 |
if (d != OR_TMP0) |
if (d != OR_TMP0) |
1188 |
gen_op_mov_TN_reg[ot][0][d](); |
gen_op_mov_TN_reg[ot][0][d](); |
1189 |
else |
else |
1190 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s1->mem_index](); |
1191 |
if (s != OR_TMP1) |
if (s != OR_TMP1) |
1192 |
gen_op_mov_TN_reg[ot][1][s](); |
gen_op_mov_TN_reg[ot][1][s](); |
1193 |
/* for zero counts, flags are not updated, so must do it dynamically */ |
/* for zero counts, flags are not updated, so must do it dynamically */ |
1381 |
if (is_store) { |
if (is_store) { |
1382 |
if (reg != OR_TMP0) |
if (reg != OR_TMP0) |
1383 |
gen_op_mov_TN_reg[ot][0][reg](); |
gen_op_mov_TN_reg[ot][0][reg](); |
1384 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
1385 |
} else { |
} else { |
1386 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s->mem_index](); |
1387 |
if (reg != OR_TMP0) |
if (reg != OR_TMP0) |
1388 |
gen_op_mov_reg_T0[ot][reg](); |
gen_op_mov_reg_T0[ot][reg](); |
1389 |
} |
} |
1650 |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); |
1651 |
for(i = 0;i < 8; i++) { |
for(i = 0;i < 8; i++) { |
1652 |
gen_op_mov_TN_reg[OT_LONG][0][7 - i](); |
gen_op_mov_TN_reg[OT_LONG][0][7 - i](); |
1653 |
gen_op_st_T0_A0[OT_WORD + s->dflag](); |
gen_op_st_T0_A0[OT_WORD + s->dflag + s->mem_index](); |
1654 |
gen_op_addl_A0_im(2 << s->dflag); |
gen_op_addl_A0_im(2 << s->dflag); |
1655 |
} |
} |
1656 |
gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); |
gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); |
1670 |
for(i = 0;i < 8; i++) { |
for(i = 0;i < 8; i++) { |
1671 |
/* ESP is not reloaded */ |
/* ESP is not reloaded */ |
1672 |
if (i != 3) { |
if (i != 3) { |
1673 |
gen_op_ld_T0_A0[OT_WORD + s->dflag](); |
gen_op_ld_T0_A0[OT_WORD + s->dflag + s->mem_index](); |
1674 |
gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i](); |
gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i](); |
1675 |
} |
} |
1676 |
gen_op_addl_A0_im(2 << s->dflag); |
gen_op_addl_A0_im(2 << s->dflag); |
1698 |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); |
1699 |
/* push bp */ |
/* push bp */ |
1700 |
gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); |
gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); |
1701 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
1702 |
if (level) { |
if (level) { |
1703 |
while (level--) { |
while (level--) { |
1704 |
gen_op_addl_A0_im(-opsize); |
gen_op_addl_A0_im(-opsize); |
1705 |
gen_op_addl_T0_im(-opsize); |
gen_op_addl_T0_im(-opsize); |
1706 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
1707 |
} |
} |
1708 |
gen_op_addl_A0_im(-opsize); |
gen_op_addl_A0_im(-opsize); |
1709 |
/* XXX: add st_T1_A0 ? */ |
/* XXX: add st_T1_A0 ? */ |
1710 |
gen_op_movl_T0_T1(); |
gen_op_movl_T0_T1(); |
1711 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
1712 |
} |
} |
1713 |
gen_op_mov_reg_T1[ot][R_EBP](); |
gen_op_mov_reg_T1[ot][R_EBP](); |
1714 |
addend = -esp_addend; |
addend = -esp_addend; |
1887 |
rm = modrm & 7; |
rm = modrm & 7; |
1888 |
if (mod != 3) { |
if (mod != 3) { |
1889 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
1890 |
gen_op_ld_T1_A0[ot](); |
gen_op_ld_T1_A0[ot + s->mem_index](); |
1891 |
} else if (op == OP_XORL && rm == reg) { |
} else if (op == OP_XORL && rm == reg) { |
1892 |
goto xor_zero; |
goto xor_zero; |
1893 |
} else { |
} else { |
1965 |
op = (modrm >> 3) & 7; |
op = (modrm >> 3) & 7; |
1966 |
if (mod != 3) { |
if (mod != 3) { |
1967 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
1968 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s->mem_index](); |
1969 |
} else { |
} else { |
1970 |
gen_op_mov_TN_reg[ot][0][rm](); |
gen_op_mov_TN_reg[ot][0][rm](); |
1971 |
} |
} |
1980 |
case 2: /* not */ |
case 2: /* not */ |
1981 |
gen_op_notl_T0(); |
gen_op_notl_T0(); |
1982 |
if (mod != 3) { |
if (mod != 3) { |
1983 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
1984 |
} else { |
} else { |
1985 |
gen_op_mov_reg_T0[ot][rm](); |
gen_op_mov_reg_T0[ot][rm](); |
1986 |
} |
} |
1988 |
case 3: /* neg */ |
case 3: /* neg */ |
1989 |
gen_op_negl_T0(); |
gen_op_negl_T0(); |
1990 |
if (mod != 3) { |
if (mod != 3) { |
1991 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
1992 |
} else { |
} else { |
1993 |
gen_op_mov_reg_T0[ot][rm](); |
gen_op_mov_reg_T0[ot][rm](); |
1994 |
} |
} |
2075 |
if (mod != 3) { |
if (mod != 3) { |
2076 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
2077 |
if (op >= 2 && op != 3 && op != 5) |
if (op >= 2 && op != 3 && op != 5) |
2078 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s->mem_index](); |
2079 |
} else { |
} else { |
2080 |
gen_op_mov_TN_reg[ot][0][rm](); |
gen_op_mov_TN_reg[ot][0][rm](); |
2081 |
} |
} |
2106 |
s->is_jmp = 1; |
s->is_jmp = 1; |
2107 |
break; |
break; |
2108 |
case 3: /* lcall Ev */ |
case 3: /* lcall Ev */ |
2109 |
gen_op_ld_T1_A0[ot](); |
gen_op_ld_T1_A0[ot + s->mem_index](); |
2110 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
2111 |
gen_op_lduw_T0_A0(); |
gen_op_ld_T0_A0[OT_WORD + s->mem_index](); |
2112 |
do_lcall: |
do_lcall: |
2113 |
if (s->pe && !s->vm86) { |
if (s->pe && !s->vm86) { |
2114 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->cc_op != CC_OP_DYNAMIC) |
2127 |
s->is_jmp = 1; |
s->is_jmp = 1; |
2128 |
break; |
break; |
2129 |
case 5: /* ljmp Ev */ |
case 5: /* ljmp Ev */ |
2130 |
gen_op_ld_T1_A0[ot](); |
gen_op_ld_T1_A0[ot + s->mem_index](); |
2131 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
2132 |
gen_op_lduw_T0_A0(); |
gen_op_lduw_T0_A0(); |
2133 |
do_ljmp: |
do_ljmp: |
2239 |
} else { |
} else { |
2240 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
2241 |
gen_op_mov_TN_reg[ot][0][reg](); |
gen_op_mov_TN_reg[ot][0][reg](); |
2242 |
gen_op_ld_T1_A0[ot](); |
gen_op_ld_T1_A0[ot + s->mem_index](); |
2243 |
gen_op_addl_T0_T1(); |
gen_op_addl_T0_T1(); |
2244 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
2245 |
gen_op_mov_reg_T1[ot][reg](); |
gen_op_mov_reg_T1[ot][reg](); |
2246 |
} |
} |
2247 |
gen_op_update2_cc(); |
gen_op_update2_cc(); |
2264 |
gen_op_mov_reg_T0[ot][rm](); |
gen_op_mov_reg_T0[ot][rm](); |
2265 |
} else { |
} else { |
2266 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
2267 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s->mem_index](); |
2268 |
gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot](); |
gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot](); |
2269 |
} |
} |
2270 |
s->cc_op = CC_OP_SUBB + ot; |
s->cc_op = CC_OP_SUBB + ot; |
2395 |
val = insn_get(s, ot); |
val = insn_get(s, ot); |
2396 |
gen_op_movl_T0_im(val); |
gen_op_movl_T0_im(val); |
2397 |
if (mod != 3) |
if (mod != 3) |
2398 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
2399 |
else |
else |
2400 |
gen_op_mov_reg_T0[ot][modrm & 7](); |
gen_op_mov_reg_T0[ot][modrm & 7](); |
2401 |
break; |
break; |
2469 |
} else { |
} else { |
2470 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
2471 |
if (b & 8) { |
if (b & 8) { |
2472 |
gen_op_lds_T0_A0[ot](); |
gen_op_lds_T0_A0[ot + s->mem_index](); |
2473 |
} else { |
} else { |
2474 |
gen_op_ldu_T0_A0[ot](); |
gen_op_ldu_T0_A0[ot + s->mem_index](); |
2475 |
} |
} |
2476 |
gen_op_mov_reg_T0[d_ot][reg](); |
gen_op_mov_reg_T0[d_ot][reg](); |
2477 |
} |
} |
2519 |
} |
} |
2520 |
} |
} |
2521 |
if ((b & 2) == 0) { |
if ((b & 2) == 0) { |
2522 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s->mem_index](); |
2523 |
gen_op_mov_reg_T0[ot][R_EAX](); |
gen_op_mov_reg_T0[ot][R_EAX](); |
2524 |
} else { |
} else { |
2525 |
gen_op_mov_TN_reg[ot][0][R_EAX](); |
gen_op_mov_TN_reg[ot][0][R_EAX](); |
2526 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
2527 |
} |
} |
2528 |
break; |
break; |
2529 |
case 0xd7: /* xlat */ |
case 0xd7: /* xlat */ |
2546 |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); |
gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); |
2547 |
} |
} |
2548 |
} |
} |
2549 |
gen_op_ldub_T0_A0(); |
gen_op_ldu_T0_A0[OT_BYTE + s->mem_index](); |
2550 |
gen_op_mov_reg_T0[OT_BYTE][R_EAX](); |
gen_op_mov_reg_T0[OT_BYTE][R_EAX](); |
2551 |
break; |
break; |
2552 |
case 0xb0 ... 0xb7: /* mov R, Ib */ |
case 0xb0 ... 0xb7: /* mov R, Ib */ |
2589 |
/* for xchg, lock is implicit */ |
/* for xchg, lock is implicit */ |
2590 |
if (!(prefixes & PREFIX_LOCK)) |
if (!(prefixes & PREFIX_LOCK)) |
2591 |
gen_op_lock(); |
gen_op_lock(); |
2592 |
gen_op_ld_T1_A0[ot](); |
gen_op_ld_T1_A0[ot + s->mem_index](); |
2593 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
2594 |
if (!(prefixes & PREFIX_LOCK)) |
if (!(prefixes & PREFIX_LOCK)) |
2595 |
gen_op_unlock(); |
gen_op_unlock(); |
2596 |
gen_op_mov_reg_T1[ot][reg](); |
gen_op_mov_reg_T1[ot][reg](); |
2618 |
if (mod == 3) |
if (mod == 3) |
2619 |
goto illegal_op; |
goto illegal_op; |
2620 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
2621 |
gen_op_ld_T1_A0[ot](); |
gen_op_ld_T1_A0[ot + s->mem_index](); |
2622 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
2623 |
/* load the segment first to handle exceptions properly */ |
/* load the segment first to handle exceptions properly */ |
2624 |
gen_op_lduw_T0_A0(); |
gen_op_lduw_T0_A0(); |
2698 |
|
|
2699 |
if (mod != 3) { |
if (mod != 3) { |
2700 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
2701 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s->mem_index](); |
2702 |
} else { |
} else { |
2703 |
gen_op_mov_TN_reg[ot][0][rm](); |
gen_op_mov_TN_reg[ot][0][rm](); |
2704 |
} |
} |
3143 |
ot = dflag ? OT_LONG : OT_WORD; |
ot = dflag ? OT_LONG : OT_WORD; |
3144 |
|
|
3145 |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
3146 |
gen_string_ds(s, ot, gen_op_movs + 9); |
gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
3147 |
} else { |
} else { |
3148 |
gen_string_ds(s, ot, gen_op_movs); |
gen_movs(s, ot); |
3149 |
} |
} |
3150 |
break; |
break; |
3151 |
|
|
3157 |
ot = dflag ? OT_LONG : OT_WORD; |
ot = dflag ? OT_LONG : OT_WORD; |
3158 |
|
|
3159 |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
3160 |
gen_string_es(s, ot, gen_op_stos + 9); |
gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
3161 |
} else { |
} else { |
3162 |
gen_string_es(s, ot, gen_op_stos); |
gen_stos(s, ot); |
3163 |
} |
} |
3164 |
break; |
break; |
3165 |
case 0xac: /* lodsS */ |
case 0xac: /* lodsS */ |
3169 |
else |
else |
3170 |
ot = dflag ? OT_LONG : OT_WORD; |
ot = dflag ? OT_LONG : OT_WORD; |
3171 |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
3172 |
gen_string_ds(s, ot, gen_op_lods + 9); |
gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
3173 |
} else { |
} else { |
3174 |
gen_string_ds(s, ot, gen_op_lods); |
gen_lods(s, ot); |
3175 |
} |
} |
3176 |
break; |
break; |
3177 |
case 0xae: /* scasS */ |
case 0xae: /* scasS */ |
3183 |
if (prefixes & PREFIX_REPNZ) { |
if (prefixes & PREFIX_REPNZ) { |
3184 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->cc_op != CC_OP_DYNAMIC) |
3185 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
3186 |
gen_string_es(s, ot, gen_op_scas + 9 * 2); |
gen_string_es(s, ot, gen_op_scas + STRINGOP_NB); |
3187 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
3188 |
} else if (prefixes & PREFIX_REPZ) { |
} else if (prefixes & PREFIX_REPZ) { |
3189 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->cc_op != CC_OP_DYNAMIC) |
3190 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
3191 |
gen_string_es(s, ot, gen_op_scas + 9); |
gen_string_es(s, ot, gen_op_scas); |
3192 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
3193 |
} else { |
} else { |
3194 |
gen_string_es(s, ot, gen_op_scas); |
gen_scas(s, ot); |
3195 |
s->cc_op = CC_OP_SUBB + ot; |
s->cc_op = CC_OP_SUBB + ot; |
3196 |
} |
} |
3197 |
break; |
break; |
3205 |
if (prefixes & PREFIX_REPNZ) { |
if (prefixes & PREFIX_REPNZ) { |
3206 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->cc_op != CC_OP_DYNAMIC) |
3207 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
3208 |
gen_string_ds(s, ot, gen_op_cmps + 9 * 2); |
gen_string_ds(s, ot, gen_op_cmps + STRINGOP_NB); |
3209 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
3210 |
} else if (prefixes & PREFIX_REPZ) { |
} else if (prefixes & PREFIX_REPZ) { |
3211 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->cc_op != CC_OP_DYNAMIC) |
3212 |
gen_op_set_cc_op(s->cc_op); |
gen_op_set_cc_op(s->cc_op); |
3213 |
gen_string_ds(s, ot, gen_op_cmps + 9); |
gen_string_ds(s, ot, gen_op_cmps); |
3214 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
3215 |
} else { |
} else { |
3216 |
gen_string_ds(s, ot, gen_op_cmps); |
gen_cmps(s, ot); |
3217 |
s->cc_op = CC_OP_SUBB + ot; |
s->cc_op = CC_OP_SUBB + ot; |
3218 |
} |
} |
3219 |
break; |
break; |
3228 |
else |
else |
3229 |
ot = dflag ? OT_LONG : OT_WORD; |
ot = dflag ? OT_LONG : OT_WORD; |
3230 |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
3231 |
gen_string_es(s, ot, gen_op_ins + 9); |
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
3232 |
} else { |
} else { |
3233 |
gen_string_es(s, ot, gen_op_ins); |
gen_ins(s, ot); |
3234 |
} |
} |
3235 |
} |
} |
3236 |
break; |
break; |
3245 |
else |
else |
3246 |
ot = dflag ? OT_LONG : OT_WORD; |
ot = dflag ? OT_LONG : OT_WORD; |
3247 |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
3248 |
gen_string_ds(s, ot, gen_op_outs + 9); |
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); |
3249 |
} else { |
} else { |
3250 |
gen_string_ds(s, ot, gen_op_outs); |
gen_outs(s, ot); |
3251 |
} |
} |
3252 |
} |
} |
3253 |
break; |
break; |
3345 |
} else { |
} else { |
3346 |
gen_stack_A0(s); |
gen_stack_A0(s); |
3347 |
/* pop offset */ |
/* pop offset */ |
3348 |
gen_op_ld_T0_A0[1 + s->dflag](); |
gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); |
3349 |
if (s->dflag == 0) |
if (s->dflag == 0) |
3350 |
gen_op_andl_T0_ffff(); |
gen_op_andl_T0_ffff(); |
3351 |
/* NOTE: keeping EIP updated is not a problem in case of |
/* NOTE: keeping EIP updated is not a problem in case of |
3353 |
gen_op_jmp_T0(); |
gen_op_jmp_T0(); |
3354 |
/* pop selector */ |
/* pop selector */ |
3355 |
gen_op_addl_A0_im(2 << s->dflag); |
gen_op_addl_A0_im(2 << s->dflag); |
3356 |
gen_op_ld_T0_A0[1 + s->dflag](); |
gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); |
3357 |
gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); |
gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); |
3358 |
/* add stack offset */ |
/* add stack offset */ |
3359 |
gen_stack_update(s, val + (4 << s->dflag)); |
gen_stack_update(s, val + (4 << s->dflag)); |
3462 |
gen_setcc(s, b); |
gen_setcc(s, b); |
3463 |
if (mod != 3) { |
if (mod != 3) { |
3464 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
3465 |
gen_op_ld_T1_A0[ot](); |
gen_op_ld_T1_A0[ot + s->mem_index](); |
3466 |
} else { |
} else { |
3467 |
rm = modrm & 7; |
rm = modrm & 7; |
3468 |
gen_op_mov_TN_reg[ot][1][rm](); |
gen_op_mov_TN_reg[ot][1][rm](); |
3553 |
rm = modrm & 7; |
rm = modrm & 7; |
3554 |
if (mod != 3) { |
if (mod != 3) { |
3555 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
3556 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s->mem_index](); |
3557 |
} else { |
} else { |
3558 |
gen_op_mov_TN_reg[ot][0][rm](); |
gen_op_mov_TN_reg[ot][0][rm](); |
3559 |
} |
} |
3567 |
s->cc_op = CC_OP_SARB + ot; |
s->cc_op = CC_OP_SARB + ot; |
3568 |
if (op != 0) { |
if (op != 0) { |
3569 |
if (mod != 3) |
if (mod != 3) |
3570 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
3571 |
else |
else |
3572 |
gen_op_mov_reg_T0[ot][rm](); |
gen_op_mov_reg_T0[ot][rm](); |
3573 |
gen_op_update_bt_cc(); |
gen_op_update_bt_cc(); |
3598 |
gen_op_add_bitw_A0_T1(); |
gen_op_add_bitw_A0_T1(); |
3599 |
else |
else |
3600 |
gen_op_add_bitl_A0_T1(); |
gen_op_add_bitl_A0_T1(); |
3601 |
gen_op_ld_T0_A0[ot](); |
gen_op_ld_T0_A0[ot + s->mem_index](); |
3602 |
} else { |
} else { |
3603 |
gen_op_mov_TN_reg[ot][0][rm](); |
gen_op_mov_TN_reg[ot][0][rm](); |
3604 |
} |
} |
3606 |
s->cc_op = CC_OP_SARB + ot; |
s->cc_op = CC_OP_SARB + ot; |
3607 |
if (op != 0) { |
if (op != 0) { |
3608 |
if (mod != 3) |
if (mod != 3) |
3609 |
gen_op_st_T0_A0[ot](); |
gen_op_st_T0_A0[ot + s->mem_index](); |
3610 |
else |
else |
3611 |
gen_op_mov_reg_T0[ot][rm](); |
gen_op_mov_reg_T0[ot][rm](); |
3612 |
gen_op_update_bt_cc(); |
gen_op_update_bt_cc(); |
3843 |
gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); |
gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); |
3844 |
else |
else |
3845 |
gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); |
gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); |
3846 |
gen_op_stw_T0_A0(); |
gen_op_st_T0_A0[OT_WORD + s->mem_index](); |
3847 |
gen_op_addl_A0_im(2); |
gen_op_addl_A0_im(2); |
3848 |
if (op == 0) |
if (op == 0) |
3849 |
gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base)); |
gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base)); |
3851 |
gen_op_movl_T0_env(offsetof(CPUX86State,idt.base)); |
gen_op_movl_T0_env(offsetof(CPUX86State,idt.base)); |
3852 |
if (!s->dflag) |
if (!s->dflag) |
3853 |
gen_op_andl_T0_im(0xffffff); |
gen_op_andl_T0_im(0xffffff); |
3854 |
gen_op_stl_T0_A0(); |
gen_op_st_T0_A0[OT_LONG + s->mem_index](); |
3855 |
break; |
break; |
3856 |
case 2: /* lgdt */ |
case 2: /* lgdt */ |
3857 |
case 3: /* lidt */ |
case 3: /* lidt */ |
3861 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3862 |
} else { |
} else { |
3863 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
3864 |
gen_op_lduw_T1_A0(); |
gen_op_ld_T1_A0[OT_WORD + s->mem_index](); |
3865 |
gen_op_addl_A0_im(2); |
gen_op_addl_A0_im(2); |
3866 |
gen_op_ldl_T0_A0(); |
gen_op_ld_T0_A0[OT_LONG + s->mem_index](); |
3867 |
if (!s->dflag) |
if (!s->dflag) |
3868 |
gen_op_andl_T0_im(0xffffff); |
gen_op_andl_T0_im(0xffffff); |
3869 |
if (op == 2) { |
if (op == 2) { |
4264 |
[INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \ |
[INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \ |
4265 |
[INDEX_op_ ## x ## l_a16] = CC_OSZAPC, |
[INDEX_op_ ## x ## l_a16] = CC_OSZAPC, |
4266 |
|
|
|
STRINGOP(scas) |
|
4267 |
STRINGOP(repz_scas) |
STRINGOP(repz_scas) |
4268 |
STRINGOP(repnz_scas) |
STRINGOP(repnz_scas) |
|
STRINGOP(cmps) |
|
4269 |
STRINGOP(repz_cmps) |
STRINGOP(repz_cmps) |
4270 |
STRINGOP(repnz_cmps) |
STRINGOP(repnz_cmps) |
4271 |
|
|
4322 |
[INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, |
[INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, |
4323 |
}; |
}; |
4324 |
|
|
4325 |
static void optimize_flags_init(void) |
void optimize_flags_init(void) |
4326 |
{ |
{ |
4327 |
int i; |
int i; |
4328 |
/* put default values in arrays */ |
/* put default values in arrays */ |
4392 |
dc->cs_base = cs_base; |
dc->cs_base = cs_base; |
4393 |
dc->tb = tb; |
dc->tb = tb; |
4394 |
dc->popl_esp_hack = 0; |
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 |
|
} |
4403 |
|
|
4404 |
gen_opc_ptr = gen_opc_buf; |
gen_opc_ptr = gen_opc_buf; |
4405 |
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
4514 |
return gen_intermediate_code_internal(env, tb, 1); |
return gen_intermediate_code_internal(env, tb, 1); |
4515 |
} |
} |
4516 |
|
|
|
CPUX86State *cpu_x86_init(void) |
|
|
{ |
|
|
CPUX86State *env; |
|
|
int i; |
|
|
static int inited; |
|
|
|
|
|
cpu_exec_init(); |
|
|
|
|
|
env = malloc(sizeof(CPUX86State)); |
|
|
if (!env) |
|
|
return NULL; |
|
|
memset(env, 0, sizeof(CPUX86State)); |
|
|
/* basic FPU init */ |
|
|
for(i = 0;i < 8; i++) |
|
|
env->fptags[i] = 1; |
|
|
env->fpuc = 0x37f; |
|
|
/* flags setup : we activate the IRQs by default as in user mode */ |
|
|
env->eflags = 0x2 | IF_MASK; |
|
|
|
|
|
/* init various static tables */ |
|
|
if (!inited) { |
|
|
inited = 1; |
|
|
optimize_flags_init(); |
|
|
} |
|
|
return env; |
|
|
} |
|
|
|
|
|
void cpu_x86_close(CPUX86State *env) |
|
|
{ |
|
|
free(env); |
|
|
} |
|
|
|
|
|
/***********************************************************/ |
|
|
/* x86 mmu */ |
|
|
/* XXX: add PGE support */ |
|
|
|
|
|
/* called when cr3 or PG bit are modified */ |
|
|
static int last_pg_state = -1; |
|
|
static int last_pe_state = 0; |
|
|
int phys_ram_size; |
|
|
int phys_ram_fd; |
|
|
uint8_t *phys_ram_base; |
|
|
|
|
|
void cpu_x86_update_cr0(CPUX86State *env) |
|
|
{ |
|
|
int pg_state, pe_state; |
|
|
void *map_addr; |
|
|
|
|
|
#ifdef DEBUG_MMU |
|
|
printf("CR0 update: CR0=0x%08x\n", env->cr[0]); |
|
|
#endif |
|
|
pg_state = env->cr[0] & CR0_PG_MASK; |
|
|
if (pg_state != last_pg_state) { |
|
|
if (!pg_state) { |
|
|
/* we map the physical memory at address 0 */ |
|
|
|
|
|
map_addr = mmap((void *)0, phys_ram_size, PROT_WRITE | PROT_READ, |
|
|
MAP_SHARED | MAP_FIXED, phys_ram_fd, 0); |
|
|
if (map_addr == MAP_FAILED) { |
|
|
fprintf(stderr, |
|
|
"Could not map physical memory at host address 0x%08x\n", |
|
|
0); |
|
|
exit(1); |
|
|
} |
|
|
page_set_flags(0, phys_ram_size, |
|
|
PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC); |
|
|
} else { |
|
|
/* we unmap the physical memory */ |
|
|
munmap((void *)0, phys_ram_size); |
|
|
page_set_flags(0, phys_ram_size, 0); |
|
|
} |
|
|
last_pg_state = pg_state; |
|
|
} |
|
|
pe_state = env->cr[0] & CR0_PE_MASK; |
|
|
if (last_pe_state != pe_state) { |
|
|
tb_flush(); |
|
|
last_pe_state = pe_state; |
|
|
} |
|
|
} |
|
|
|
|
|
void cpu_x86_update_cr3(CPUX86State *env) |
|
|
{ |
|
|
if (env->cr[0] & CR0_PG_MASK) { |
|
|
#if defined(DEBUG_MMU) |
|
|
printf("CR3 update: CR3=%08x\n", env->cr[3]); |
|
|
#endif |
|
|
page_unmap(); |
|
|
} |
|
|
} |
|
|
|
|
|
void cpu_x86_init_mmu(CPUX86State *env) |
|
|
{ |
|
|
last_pg_state = -1; |
|
|
cpu_x86_update_cr0(env); |
|
|
} |
|
|
|
|
|
/* XXX: also flush 4MB pages */ |
|
|
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) |
|
|
{ |
|
|
int flags; |
|
|
unsigned long virt_addr; |
|
|
|
|
|
flags = page_get_flags(addr); |
|
|
if (flags & PAGE_VALID) { |
|
|
virt_addr = addr & ~0xfff; |
|
|
munmap((void *)virt_addr, 4096); |
|
|
page_set_flags(virt_addr, virt_addr + 4096, 0); |
|
|
} |
|
|
} |
|
|
|
|
|
/* return value: |
|
|
-1 = cannot handle fault |
|
|
0 = nothing more to do |
|
|
1 = generate PF fault |
|
|
*/ |
|
|
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) |
|
|
{ |
|
|
uint8_t *pde_ptr, *pte_ptr; |
|
|
uint32_t pde, pte, virt_addr; |
|
|
int cpl, error_code, is_dirty, is_user, prot, page_size; |
|
|
void *map_addr; |
|
|
|
|
|
cpl = env->cpl; |
|
|
is_user = (cpl == 3); |
|
|
|
|
|
#ifdef DEBUG_MMU |
|
|
printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", |
|
|
addr, is_write, is_user, env->eip); |
|
|
#endif |
|
|
|
|
|
if (env->user_mode_only) { |
|
|
/* user mode only emulation */ |
|
|
error_code = 0; |
|
|
goto do_fault; |
|
|
} |
|
|
|
|
|
if (!(env->cr[0] & CR0_PG_MASK)) |
|
|
return -1; |
|
|
|
|
|
/* page directory entry */ |
|
|
pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); |
|
|
pde = ldl(pde_ptr); |
|
|
if (!(pde & PG_PRESENT_MASK)) { |
|
|
error_code = 0; |
|
|
goto do_fault; |
|
|
} |
|
|
if (is_user) { |
|
|
if (!(pde & PG_USER_MASK)) |
|
|
goto do_fault_protect; |
|
|
if (is_write && !(pde & PG_RW_MASK)) |
|
|
goto do_fault_protect; |
|
|
} else { |
|
|
if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && |
|
|
is_write && !(pde & PG_RW_MASK)) |
|
|
goto do_fault_protect; |
|
|
} |
|
|
/* if PSE bit is set, then we use a 4MB page */ |
|
|
if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { |
|
|
is_dirty = is_write && !(pde & PG_DIRTY_MASK); |
|
|
if (!(pde & PG_ACCESSED_MASK)) { |
|
|
pde |= PG_ACCESSED_MASK; |
|
|
if (is_dirty) |
|
|
pde |= PG_DIRTY_MASK; |
|
|
stl(pde_ptr, pde); |
|
|
} |
|
|
|
|
|
pte = pde & ~0x003ff000; /* align to 4MB */ |
|
|
page_size = 4096 * 1024; |
|
|
virt_addr = addr & ~0x003fffff; |
|
|
} else { |
|
|
if (!(pde & PG_ACCESSED_MASK)) { |
|
|
pde |= PG_ACCESSED_MASK; |
|
|
stl(pde_ptr, pde); |
|
|
} |
|
|
|
|
|
/* page directory entry */ |
|
|
pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); |
|
|
pte = ldl(pte_ptr); |
|
|
if (!(pte & PG_PRESENT_MASK)) { |
|
|
error_code = 0; |
|
|
goto do_fault; |
|
|
} |
|
|
if (is_user) { |
|
|
if (!(pte & PG_USER_MASK)) |
|
|
goto do_fault_protect; |
|
|
if (is_write && !(pte & PG_RW_MASK)) |
|
|
goto do_fault_protect; |
|
|
} else { |
|
|
if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && |
|
|
is_write && !(pte & PG_RW_MASK)) |
|
|
goto do_fault_protect; |
|
|
} |
|
|
is_dirty = is_write && !(pte & PG_DIRTY_MASK); |
|
|
if (!(pte & PG_ACCESSED_MASK) || is_dirty) { |
|
|
pte |= PG_ACCESSED_MASK; |
|
|
if (is_dirty) |
|
|
pte |= PG_DIRTY_MASK; |
|
|
stl(pte_ptr, pte); |
|
|
} |
|
|
page_size = 4096; |
|
|
virt_addr = addr & ~0xfff; |
|
|
} |
|
|
/* the page can be put in the TLB */ |
|
|
prot = PROT_READ; |
|
|
if (is_user) { |
|
|
if (pte & PG_RW_MASK) |
|
|
prot |= PROT_WRITE; |
|
|
} else { |
|
|
if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || |
|
|
(pte & PG_RW_MASK)) |
|
|
prot |= PROT_WRITE; |
|
|
} |
|
|
map_addr = mmap((void *)virt_addr, page_size, prot, |
|
|
MAP_SHARED | MAP_FIXED, phys_ram_fd, pte & ~0xfff); |
|
|
if (map_addr == MAP_FAILED) { |
|
|
fprintf(stderr, |
|
|
"mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", |
|
|
pte & ~0xfff, virt_addr); |
|
|
exit(1); |
|
|
} |
|
|
page_set_flags(virt_addr, virt_addr + page_size, |
|
|
PAGE_VALID | PAGE_EXEC | prot); |
|
|
#ifdef DEBUG_MMU |
|
|
printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", |
|
|
pte & ~0xfff, virt_addr, (page_size != 4096)); |
|
|
#endif |
|
|
return 0; |
|
|
do_fault_protect: |
|
|
error_code = PG_ERROR_P_MASK; |
|
|
do_fault: |
|
|
env->cr[2] = addr; |
|
|
env->error_code = (is_write << PG_ERROR_W_BIT) | error_code; |
|
|
if (is_user) |
|
|
env->error_code |= PG_ERROR_U_MASK; |
|
|
return 1; |
|
|
} |
|
|
|
|
|
/***********************************************************/ |
|
|
/* x86 debug */ |
|
|
|
|
|
static const char *cc_op_str[] = { |
|
|
"DYNAMIC", |
|
|
"EFLAGS", |
|
|
"MUL", |
|
|
"ADDB", |
|
|
"ADDW", |
|
|
"ADDL", |
|
|
"ADCB", |
|
|
"ADCW", |
|
|
"ADCL", |
|
|
"SUBB", |
|
|
"SUBW", |
|
|
"SUBL", |
|
|
"SBBB", |
|
|
"SBBW", |
|
|
"SBBL", |
|
|
"LOGICB", |
|
|
"LOGICW", |
|
|
"LOGICL", |
|
|
"INCB", |
|
|
"INCW", |
|
|
"INCL", |
|
|
"DECB", |
|
|
"DECW", |
|
|
"DECL", |
|
|
"SHLB", |
|
|
"SHLW", |
|
|
"SHLL", |
|
|
"SARB", |
|
|
"SARW", |
|
|
"SARL", |
|
|
}; |
|
|
|
|
|
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) |
|
|
{ |
|
|
int eflags; |
|
|
char cc_op_name[32]; |
|
|
|
|
|
eflags = env->eflags; |
|
|
fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" |
|
|
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" |
|
|
"EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n", |
|
|
env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], |
|
|
env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], |
|
|
env->eip, eflags, |
|
|
eflags & DF_MASK ? 'D' : '-', |
|
|
eflags & CC_O ? 'O' : '-', |
|
|
eflags & CC_S ? 'S' : '-', |
|
|
eflags & CC_Z ? 'Z' : '-', |
|
|
eflags & CC_A ? 'A' : '-', |
|
|
eflags & CC_P ? 'P' : '-', |
|
|
eflags & CC_C ? 'C' : '-'); |
|
|
fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", |
|
|
env->segs[R_CS].selector, |
|
|
env->segs[R_SS].selector, |
|
|
env->segs[R_DS].selector, |
|
|
env->segs[R_ES].selector, |
|
|
env->segs[R_FS].selector, |
|
|
env->segs[R_GS].selector); |
|
|
if (flags & X86_DUMP_CCOP) { |
|
|
if ((unsigned)env->cc_op < CC_OP_NB) |
|
|
strcpy(cc_op_name, cc_op_str[env->cc_op]); |
|
|
else |
|
|
snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); |
|
|
fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", |
|
|
env->cc_src, env->cc_dst, cc_op_name); |
|
|
} |
|
|
if (flags & X86_DUMP_FPU) { |
|
|
fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", |
|
|
(double)env->fpregs[0], |
|
|
(double)env->fpregs[1], |
|
|
(double)env->fpregs[2], |
|
|
(double)env->fpregs[3]); |
|
|
fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", |
|
|
(double)env->fpregs[4], |
|
|
(double)env->fpregs[5], |
|
|
(double)env->fpregs[7], |
|
|
(double)env->fpregs[8]); |
|
|
} |
|
|
} |
|