Commit 2c1794c42ef9d23dc6aeb5e07673f2fcd885b9eb
1 parent
8a4c1cc4
more generic ljmp and lcall - fixed REPNZ usage for non compare string ops (FreeDos boot loader fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@340 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
348 additions
and
100 deletions
exec-i386.h
@@ -123,8 +123,12 @@ typedef struct CCTable { | @@ -123,8 +123,12 @@ typedef struct CCTable { | ||
123 | extern CCTable cc_table[]; | 123 | extern CCTable cc_table[]; |
124 | 124 | ||
125 | void load_seg(int seg_reg, int selector, unsigned cur_eip); | 125 | void load_seg(int seg_reg, int selector, unsigned cur_eip); |
126 | -void jmp_seg(int selector, unsigned int new_eip); | 126 | +void helper_ljmp_protected_T0_T1(void); |
127 | +void helper_lcall_real_T0_T1(int shift, int next_eip); | ||
128 | +void helper_lcall_protected_T0_T1(int shift, int next_eip); | ||
129 | +void helper_iret_real(int shift); | ||
127 | void helper_iret_protected(int shift); | 130 | void helper_iret_protected(int shift); |
131 | +void helper_lret_protected(int shift, int addend); | ||
128 | void helper_lldt_T0(void); | 132 | void helper_lldt_T0(void); |
129 | void helper_ltr_T0(void); | 133 | void helper_ltr_T0(void); |
130 | void helper_movl_crN_T0(int reg); | 134 | void helper_movl_crN_T0(int reg); |
helper-i386.c
@@ -185,7 +185,7 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, | @@ -185,7 +185,7 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, | ||
185 | 185 | ||
186 | /* protected mode interrupt */ | 186 | /* protected mode interrupt */ |
187 | static void do_interrupt_protected(int intno, int is_int, int error_code, | 187 | static void do_interrupt_protected(int intno, int is_int, int error_code, |
188 | - unsigned int next_eip) | 188 | + unsigned int next_eip) |
189 | { | 189 | { |
190 | SegmentCache *dt; | 190 | SegmentCache *dt; |
191 | uint8_t *ptr, *ssp; | 191 | uint8_t *ptr, *ssp; |
@@ -378,20 +378,19 @@ static void do_interrupt_real(int intno, int is_int, int error_code, | @@ -378,20 +378,19 @@ static void do_interrupt_real(int intno, int is_int, int error_code, | ||
378 | ptr = dt->base + intno * 4; | 378 | ptr = dt->base + intno * 4; |
379 | offset = lduw(ptr); | 379 | offset = lduw(ptr); |
380 | selector = lduw(ptr + 2); | 380 | selector = lduw(ptr + 2); |
381 | - esp = env->regs[R_ESP] & 0xffff; | ||
382 | - ssp = env->segs[R_SS].base + esp; | 381 | + esp = env->regs[R_ESP]; |
382 | + ssp = env->segs[R_SS].base; | ||
383 | if (is_int) | 383 | if (is_int) |
384 | old_eip = next_eip; | 384 | old_eip = next_eip; |
385 | else | 385 | else |
386 | old_eip = env->eip; | 386 | old_eip = env->eip; |
387 | old_cs = env->segs[R_CS].selector; | 387 | old_cs = env->segs[R_CS].selector; |
388 | - ssp -= 2; | ||
389 | - stw(ssp, compute_eflags()); | ||
390 | - ssp -= 2; | ||
391 | - stw(ssp, old_cs); | ||
392 | - ssp -= 2; | ||
393 | - stw(ssp, old_eip); | ||
394 | - esp -= 6; | 388 | + esp -= 2; |
389 | + stw(ssp + (esp & 0xffff), compute_eflags()); | ||
390 | + esp -= 2; | ||
391 | + stw(ssp + (esp & 0xffff), old_cs); | ||
392 | + esp -= 2; | ||
393 | + stw(ssp + (esp & 0xffff), old_eip); | ||
395 | 394 | ||
396 | /* update processor state */ | 395 | /* update processor state */ |
397 | env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff); | 396 | env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff); |
@@ -733,47 +732,275 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | @@ -733,47 +732,275 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | ||
733 | } | 732 | } |
734 | 733 | ||
735 | /* protected mode jump */ | 734 | /* protected mode jump */ |
736 | -void jmp_seg(int selector, unsigned int new_eip) | 735 | +void helper_ljmp_protected_T0_T1(void) |
737 | { | 736 | { |
737 | + int new_cs, new_eip; | ||
738 | SegmentCache sc1; | 738 | SegmentCache sc1; |
739 | uint32_t e1, e2, cpl, dpl, rpl; | 739 | uint32_t e1, e2, cpl, dpl, rpl; |
740 | 740 | ||
741 | - if ((selector & 0xfffc) == 0) { | 741 | + new_cs = T0; |
742 | + new_eip = T1; | ||
743 | + if ((new_cs & 0xfffc) == 0) | ||
742 | raise_exception_err(EXCP0D_GPF, 0); | 744 | raise_exception_err(EXCP0D_GPF, 0); |
745 | + if (load_segment(&e1, &e2, new_cs) != 0) | ||
746 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
747 | + cpl = env->segs[R_CS].selector & 3; | ||
748 | + if (e2 & DESC_S_MASK) { | ||
749 | + if (!(e2 & DESC_CS_MASK)) | ||
750 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
751 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
752 | + if (e2 & DESC_CS_MASK) { | ||
753 | + /* conforming code segment */ | ||
754 | + if (dpl > cpl) | ||
755 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
756 | + } else { | ||
757 | + /* non conforming code segment */ | ||
758 | + rpl = new_cs & 3; | ||
759 | + if (rpl > cpl) | ||
760 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
761 | + if (dpl != cpl) | ||
762 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
763 | + } | ||
764 | + if (!(e2 & DESC_P_MASK)) | ||
765 | + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | ||
766 | + load_seg_cache(&sc1, e1, e2); | ||
767 | + if (new_eip > sc1.limit) | ||
768 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
769 | + env->segs[R_CS].base = sc1.base; | ||
770 | + env->segs[R_CS].limit = sc1.limit; | ||
771 | + env->segs[R_CS].flags = sc1.flags; | ||
772 | + env->segs[R_CS].selector = (new_cs & 0xfffc) | cpl; | ||
773 | + EIP = new_eip; | ||
774 | + } else { | ||
775 | + cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", | ||
776 | + new_cs, new_eip); | ||
743 | } | 777 | } |
778 | +} | ||
744 | 779 | ||
745 | - if (load_segment(&e1, &e2, selector) != 0) | ||
746 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 780 | +/* real mode call */ |
781 | +void helper_lcall_real_T0_T1(int shift, int next_eip) | ||
782 | +{ | ||
783 | + int new_cs, new_eip; | ||
784 | + uint32_t esp, esp_mask; | ||
785 | + uint8_t *ssp; | ||
786 | + | ||
787 | + new_cs = T0; | ||
788 | + new_eip = T1; | ||
789 | + esp = env->regs[R_ESP]; | ||
790 | + esp_mask = 0xffffffff; | ||
791 | + if (!(env->segs[R_SS].flags & DESC_B_MASK)) | ||
792 | + esp_mask = 0xffff; | ||
793 | + ssp = env->segs[R_SS].base; | ||
794 | + if (shift) { | ||
795 | + esp -= 4; | ||
796 | + stl(ssp + (esp & esp_mask), env->segs[R_CS].selector); | ||
797 | + esp -= 4; | ||
798 | + stl(ssp + (esp & esp_mask), next_eip); | ||
799 | + } else { | ||
800 | + esp -= 2; | ||
801 | + stw(ssp + (esp & esp_mask), env->segs[R_CS].selector); | ||
802 | + esp -= 2; | ||
803 | + stw(ssp + (esp & esp_mask), next_eip); | ||
804 | + } | ||
805 | + | ||
806 | + if (!(env->segs[R_SS].flags & DESC_B_MASK)) | ||
807 | + env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff); | ||
808 | + else | ||
809 | + env->regs[R_ESP] = esp; | ||
810 | + env->eip = new_eip; | ||
811 | + env->segs[R_CS].selector = new_cs; | ||
812 | + env->segs[R_CS].base = (uint8_t *)(new_cs << 4); | ||
813 | +} | ||
814 | + | ||
815 | +/* protected mode call */ | ||
816 | +void helper_lcall_protected_T0_T1(int shift, int next_eip) | ||
817 | +{ | ||
818 | + int new_cs, new_eip; | ||
819 | + SegmentCache sc1; | ||
820 | + uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; | ||
821 | + uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; | ||
822 | + uint32_t old_ss, old_esp, val, i; | ||
823 | + uint8_t *ssp, *old_ssp; | ||
824 | + | ||
825 | + new_cs = T0; | ||
826 | + new_eip = T1; | ||
827 | + if ((new_cs & 0xfffc) == 0) | ||
828 | + raise_exception_err(EXCP0D_GPF, 0); | ||
829 | + if (load_segment(&e1, &e2, new_cs) != 0) | ||
830 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
747 | cpl = env->segs[R_CS].selector & 3; | 831 | cpl = env->segs[R_CS].selector & 3; |
748 | if (e2 & DESC_S_MASK) { | 832 | if (e2 & DESC_S_MASK) { |
749 | if (!(e2 & DESC_CS_MASK)) | 833 | if (!(e2 & DESC_CS_MASK)) |
750 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 834 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
751 | dpl = (e2 >> DESC_DPL_SHIFT) & 3; | 835 | dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
752 | if (e2 & DESC_CS_MASK) { | 836 | if (e2 & DESC_CS_MASK) { |
753 | /* conforming code segment */ | 837 | /* conforming code segment */ |
754 | if (dpl > cpl) | 838 | if (dpl > cpl) |
755 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 839 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
756 | } else { | 840 | } else { |
757 | /* non conforming code segment */ | 841 | /* non conforming code segment */ |
758 | - rpl = selector & 3; | 842 | + rpl = new_cs & 3; |
759 | if (rpl > cpl) | 843 | if (rpl > cpl) |
760 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 844 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
761 | if (dpl != cpl) | 845 | if (dpl != cpl) |
762 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 846 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
763 | } | 847 | } |
764 | if (!(e2 & DESC_P_MASK)) | 848 | if (!(e2 & DESC_P_MASK)) |
765 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | 849 | + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); |
850 | + | ||
851 | + sp = env->regs[R_ESP]; | ||
852 | + if (!(env->segs[R_SS].flags & DESC_B_MASK)) | ||
853 | + sp &= 0xffff; | ||
854 | + ssp = env->segs[R_SS].base + sp; | ||
855 | + if (shift) { | ||
856 | + ssp -= 4; | ||
857 | + stl(ssp, env->segs[R_CS].selector); | ||
858 | + ssp -= 4; | ||
859 | + stl(ssp, next_eip); | ||
860 | + } else { | ||
861 | + ssp -= 2; | ||
862 | + stw(ssp, env->segs[R_CS].selector); | ||
863 | + ssp -= 2; | ||
864 | + stw(ssp, next_eip); | ||
865 | + } | ||
866 | + sp -= (4 << shift); | ||
867 | + | ||
766 | load_seg_cache(&sc1, e1, e2); | 868 | load_seg_cache(&sc1, e1, e2); |
767 | if (new_eip > sc1.limit) | 869 | if (new_eip > sc1.limit) |
768 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 870 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
871 | + /* from this point, not restartable */ | ||
872 | + if (!(env->segs[R_SS].flags & DESC_B_MASK)) | ||
873 | + env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | (sp & 0xffff); | ||
874 | + else | ||
875 | + env->regs[R_ESP] = sp; | ||
769 | env->segs[R_CS].base = sc1.base; | 876 | env->segs[R_CS].base = sc1.base; |
770 | env->segs[R_CS].limit = sc1.limit; | 877 | env->segs[R_CS].limit = sc1.limit; |
771 | env->segs[R_CS].flags = sc1.flags; | 878 | env->segs[R_CS].flags = sc1.flags; |
772 | - env->segs[R_CS].selector = (selector & 0xfffc) | cpl; | 879 | + env->segs[R_CS].selector = (new_cs & 0xfffc) | cpl; |
773 | EIP = new_eip; | 880 | EIP = new_eip; |
774 | } else { | 881 | } else { |
775 | - cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", | ||
776 | - selector, new_eip); | 882 | + /* check gate type */ |
883 | + type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; | ||
884 | + switch(type) { | ||
885 | + case 1: /* available 286 TSS */ | ||
886 | + case 9: /* available 386 TSS */ | ||
887 | + case 5: /* task gate */ | ||
888 | + cpu_abort(env, "task gate not supported"); | ||
889 | + break; | ||
890 | + case 4: /* 286 call gate */ | ||
891 | + case 12: /* 386 call gate */ | ||
892 | + break; | ||
893 | + default: | ||
894 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
895 | + break; | ||
896 | + } | ||
897 | + shift = type >> 3; | ||
898 | + | ||
899 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
900 | + rpl = new_cs & 3; | ||
901 | + if (dpl < cpl || dpl < rpl) | ||
902 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
903 | + /* check valid bit */ | ||
904 | + if (!(e2 & DESC_P_MASK)) | ||
905 | + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | ||
906 | + selector = e1 >> 16; | ||
907 | + offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); | ||
908 | + if ((selector & 0xfffc) == 0) | ||
909 | + raise_exception_err(EXCP0D_GPF, 0); | ||
910 | + | ||
911 | + if (load_segment(&e1, &e2, selector) != 0) | ||
912 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
913 | + if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) | ||
914 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
915 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
916 | + if (dpl > cpl) | ||
917 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
918 | + if (!(e2 & DESC_P_MASK)) | ||
919 | + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | ||
920 | + | ||
921 | + if (!(e2 & DESC_C_MASK) && dpl < cpl) { | ||
922 | + /* to inner priviledge */ | ||
923 | + get_ss_esp_from_tss(&ss, &sp, dpl); | ||
924 | + if ((ss & 0xfffc) == 0) | ||
925 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
926 | + if ((ss & 3) != dpl) | ||
927 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
928 | + if (load_segment(&ss_e1, &ss_e2, ss) != 0) | ||
929 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
930 | + ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; | ||
931 | + if (ss_dpl != dpl) | ||
932 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
933 | + if (!(ss_e2 & DESC_S_MASK) || | ||
934 | + (ss_e2 & DESC_CS_MASK) || | ||
935 | + !(ss_e2 & DESC_W_MASK)) | ||
936 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
937 | + if (!(ss_e2 & DESC_P_MASK)) | ||
938 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
939 | + | ||
940 | + param_count = e2 & 0x1f; | ||
941 | + push_size = ((param_count * 2) + 8) << shift; | ||
942 | + | ||
943 | + old_esp = env->regs[R_ESP]; | ||
944 | + old_ss = env->segs[R_SS].selector; | ||
945 | + if (!(env->segs[R_SS].flags & DESC_B_MASK)) | ||
946 | + old_esp &= 0xffff; | ||
947 | + old_ssp = env->segs[R_SS].base + old_esp; | ||
948 | + | ||
949 | + /* XXX: from this point not restartable */ | ||
950 | + load_seg(R_SS, ss, env->eip); | ||
951 | + | ||
952 | + if (!(env->segs[R_SS].flags & DESC_B_MASK)) | ||
953 | + sp &= 0xffff; | ||
954 | + ssp = env->segs[R_SS].base + sp; | ||
955 | + if (shift) { | ||
956 | + ssp -= 4; | ||
957 | + stl(ssp, old_ss); | ||
958 | + ssp -= 4; | ||
959 | + stl(ssp, old_esp); | ||
960 | + ssp -= 4 * param_count; | ||
961 | + for(i = 0; i < param_count; i++) { | ||
962 | + val = ldl(old_ssp + i * 4); | ||
963 | + stl(ssp + i * 4, val); | ||
964 | + } | ||
965 | + } else { | ||
966 | + ssp -= 2; | ||
967 | + stw(ssp, old_ss); | ||
968 | + ssp -= 2; | ||
969 | + stw(ssp, old_esp); | ||
970 | + ssp -= 2 * param_count; | ||
971 | + for(i = 0; i < param_count; i++) { | ||
972 | + val = lduw(old_ssp + i * 2); | ||
973 | + stw(ssp + i * 2, val); | ||
974 | + } | ||
975 | + } | ||
976 | + } else { | ||
977 | + /* to same priviledge */ | ||
978 | + if (!(env->segs[R_SS].flags & DESC_B_MASK)) | ||
979 | + sp &= 0xffff; | ||
980 | + ssp = env->segs[R_SS].base + sp; | ||
981 | + push_size = (4 << shift); | ||
982 | + } | ||
983 | + | ||
984 | + if (shift) { | ||
985 | + ssp -= 4; | ||
986 | + stl(ssp, env->segs[R_CS].selector); | ||
987 | + ssp -= 4; | ||
988 | + stl(ssp, next_eip); | ||
989 | + } else { | ||
990 | + ssp -= 2; | ||
991 | + stw(ssp, env->segs[R_CS].selector); | ||
992 | + ssp -= 2; | ||
993 | + stw(ssp, next_eip); | ||
994 | + } | ||
995 | + | ||
996 | + sp -= push_size; | ||
997 | + load_seg(R_CS, selector, env->eip); | ||
998 | + /* from this point, not restartable if same priviledge */ | ||
999 | + if (!(env->segs[R_SS].flags & DESC_B_MASK)) | ||
1000 | + env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | (sp & 0xffff); | ||
1001 | + else | ||
1002 | + env->regs[R_ESP] = sp; | ||
1003 | + EIP = offset; | ||
777 | } | 1004 | } |
778 | } | 1005 | } |
779 | 1006 | ||
@@ -820,7 +1047,7 @@ void helper_iret_real(int shift) | @@ -820,7 +1047,7 @@ void helper_iret_real(int shift) | ||
820 | } | 1047 | } |
821 | 1048 | ||
822 | /* protected mode iret */ | 1049 | /* protected mode iret */ |
823 | -void helper_iret_protected(int shift) | 1050 | +static inline void helper_ret_protected(int shift, int is_iret, int addend) |
824 | { | 1051 | { |
825 | uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; | 1052 | uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; |
826 | uint32_t new_es, new_ds, new_fs, new_gs; | 1053 | uint32_t new_es, new_ds, new_fs, new_gs; |
@@ -834,14 +1061,16 @@ void helper_iret_protected(int shift) | @@ -834,14 +1061,16 @@ void helper_iret_protected(int shift) | ||
834 | ssp = env->segs[R_SS].base + sp; | 1061 | ssp = env->segs[R_SS].base + sp; |
835 | if (shift == 1) { | 1062 | if (shift == 1) { |
836 | /* 32 bits */ | 1063 | /* 32 bits */ |
837 | - new_eflags = ldl(ssp + 8); | 1064 | + if (is_iret) |
1065 | + new_eflags = ldl(ssp + 8); | ||
838 | new_cs = ldl(ssp + 4) & 0xffff; | 1066 | new_cs = ldl(ssp + 4) & 0xffff; |
839 | new_eip = ldl(ssp); | 1067 | new_eip = ldl(ssp); |
840 | - if (new_eflags & VM_MASK) | 1068 | + if (is_iret && (new_eflags & VM_MASK)) |
841 | goto return_to_vm86; | 1069 | goto return_to_vm86; |
842 | } else { | 1070 | } else { |
843 | /* 16 bits */ | 1071 | /* 16 bits */ |
844 | - new_eflags = lduw(ssp + 4); | 1072 | + if (is_iret) |
1073 | + new_eflags = lduw(ssp + 4); | ||
845 | new_cs = lduw(ssp + 2); | 1074 | new_cs = lduw(ssp + 2); |
846 | new_eip = lduw(ssp); | 1075 | new_eip = lduw(ssp); |
847 | } | 1076 | } |
@@ -870,17 +1099,18 @@ void helper_iret_protected(int shift) | @@ -870,17 +1099,18 @@ void helper_iret_protected(int shift) | ||
870 | if (rpl == cpl) { | 1099 | if (rpl == cpl) { |
871 | /* return to same priledge level */ | 1100 | /* return to same priledge level */ |
872 | load_seg(R_CS, new_cs, env->eip); | 1101 | load_seg(R_CS, new_cs, env->eip); |
873 | - new_esp = sp + (6 << shift); | 1102 | + new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend; |
874 | } else { | 1103 | } else { |
875 | - /* return to differentr priviledge level */ | 1104 | + /* return to different priviledge level */ |
1105 | + ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; | ||
876 | if (shift == 1) { | 1106 | if (shift == 1) { |
877 | /* 32 bits */ | 1107 | /* 32 bits */ |
878 | - new_esp = ldl(ssp + 12); | ||
879 | - new_ss = ldl(ssp + 16) & 0xffff; | 1108 | + new_esp = ldl(ssp); |
1109 | + new_ss = ldl(ssp + 4) & 0xffff; | ||
880 | } else { | 1110 | } else { |
881 | /* 16 bits */ | 1111 | /* 16 bits */ |
882 | - new_esp = lduw(ssp + 6); | ||
883 | - new_ss = lduw(ssp + 8); | 1112 | + new_esp = lduw(ssp); |
1113 | + new_ss = lduw(ssp + 2); | ||
884 | } | 1114 | } |
885 | 1115 | ||
886 | if ((new_ss & 3) != rpl) | 1116 | if ((new_ss & 3) != rpl) |
@@ -906,13 +1136,15 @@ void helper_iret_protected(int shift) | @@ -906,13 +1136,15 @@ void helper_iret_protected(int shift) | ||
906 | env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | | 1136 | env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | |
907 | (new_esp & 0xffff); | 1137 | (new_esp & 0xffff); |
908 | env->eip = new_eip; | 1138 | env->eip = new_eip; |
909 | - if (cpl == 0) | ||
910 | - eflags_mask = FL_UPDATE_CPL0_MASK; | ||
911 | - else | ||
912 | - eflags_mask = FL_UPDATE_MASK32; | ||
913 | - if (shift == 0) | ||
914 | - eflags_mask &= 0xffff; | ||
915 | - load_eflags(new_eflags, eflags_mask); | 1139 | + if (is_iret) { |
1140 | + if (cpl == 0) | ||
1141 | + eflags_mask = FL_UPDATE_CPL0_MASK; | ||
1142 | + else | ||
1143 | + eflags_mask = FL_UPDATE_MASK32; | ||
1144 | + if (shift == 0) | ||
1145 | + eflags_mask &= 0xffff; | ||
1146 | + load_eflags(new_eflags, eflags_mask); | ||
1147 | + } | ||
916 | return; | 1148 | return; |
917 | 1149 | ||
918 | return_to_vm86: | 1150 | return_to_vm86: |
@@ -936,6 +1168,16 @@ void helper_iret_protected(int shift) | @@ -936,6 +1168,16 @@ void helper_iret_protected(int shift) | ||
936 | env->regs[R_ESP] = new_esp; | 1168 | env->regs[R_ESP] = new_esp; |
937 | } | 1169 | } |
938 | 1170 | ||
1171 | +void helper_iret_protected(int shift) | ||
1172 | +{ | ||
1173 | + helper_ret_protected(shift, 1, 0); | ||
1174 | +} | ||
1175 | + | ||
1176 | +void helper_lret_protected(int shift, int addend) | ||
1177 | +{ | ||
1178 | + helper_ret_protected(shift, 0, addend); | ||
1179 | +} | ||
1180 | + | ||
939 | void helper_movl_crN_T0(int reg) | 1181 | void helper_movl_crN_T0(int reg) |
940 | { | 1182 | { |
941 | env->cr[reg] = T0; | 1183 | env->cr[reg] = T0; |
op-i386.c
@@ -948,9 +948,19 @@ void OPPROTO op_lar(void) | @@ -948,9 +948,19 @@ void OPPROTO op_lar(void) | ||
948 | } | 948 | } |
949 | 949 | ||
950 | /* T0: segment, T1:eip */ | 950 | /* T0: segment, T1:eip */ |
951 | -void OPPROTO op_ljmp_T0_T1(void) | 951 | +void OPPROTO op_ljmp_protected_T0_T1(void) |
952 | { | 952 | { |
953 | - jmp_seg(T0 & 0xffff, T1); | 953 | + helper_ljmp_protected_T0_T1(); |
954 | +} | ||
955 | + | ||
956 | +void OPPROTO op_lcall_real_T0_T1(void) | ||
957 | +{ | ||
958 | + helper_lcall_real_T0_T1(PARAM1, PARAM2); | ||
959 | +} | ||
960 | + | ||
961 | +void OPPROTO op_lcall_protected_T0_T1(void) | ||
962 | +{ | ||
963 | + helper_lcall_protected_T0_T1(PARAM1, PARAM2); | ||
954 | } | 964 | } |
955 | 965 | ||
956 | void OPPROTO op_iret_real(void) | 966 | void OPPROTO op_iret_real(void) |
@@ -963,6 +973,11 @@ void OPPROTO op_iret_protected(void) | @@ -963,6 +973,11 @@ void OPPROTO op_iret_protected(void) | ||
963 | helper_iret_protected(PARAM1); | 973 | helper_iret_protected(PARAM1); |
964 | } | 974 | } |
965 | 975 | ||
976 | +void OPPROTO op_lret_protected(void) | ||
977 | +{ | ||
978 | + helper_lret_protected(PARAM1, PARAM2); | ||
979 | +} | ||
980 | + | ||
966 | void OPPROTO op_lldt_T0(void) | 981 | void OPPROTO op_lldt_T0(void) |
967 | { | 982 | { |
968 | helper_lldt_T0(); | 983 | helper_lldt_T0(); |
translate-i386.c
@@ -1832,19 +1832,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -1832,19 +1832,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
1832 | s->is_jmp = 1; | 1832 | s->is_jmp = 1; |
1833 | break; | 1833 | break; |
1834 | case 3: /* lcall Ev */ | 1834 | case 3: /* lcall Ev */ |
1835 | - /* push return segment + offset */ | ||
1836 | - gen_op_movl_T0_seg(R_CS); | ||
1837 | - gen_push_T0(s); | ||
1838 | - next_eip = s->pc - s->cs_base; | ||
1839 | - gen_op_movl_T0_im(next_eip); | ||
1840 | - gen_push_T0(s); | ||
1841 | - | ||
1842 | gen_op_ld_T1_A0[ot](); | 1835 | gen_op_ld_T1_A0[ot](); |
1843 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); | 1836 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
1844 | gen_op_lduw_T0_A0(); | 1837 | gen_op_lduw_T0_A0(); |
1845 | - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); | ||
1846 | - gen_op_movl_T0_T1(); | ||
1847 | - gen_op_jmp_T0(); | 1838 | + do_lcall: |
1839 | + if (s->pe && !s->vm86) { | ||
1840 | + if (s->cc_op != CC_OP_DYNAMIC) | ||
1841 | + gen_op_set_cc_op(s->cc_op); | ||
1842 | + gen_op_jmp_im(pc_start - s->cs_base); | ||
1843 | + gen_op_lcall_protected_T0_T1(dflag, s->pc - s->cs_base); | ||
1844 | + } else { | ||
1845 | + gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); | ||
1846 | + } | ||
1848 | s->is_jmp = 1; | 1847 | s->is_jmp = 1; |
1849 | break; | 1848 | break; |
1850 | case 4: /* jmp Ev */ | 1849 | case 4: /* jmp Ev */ |
@@ -1857,10 +1856,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -1857,10 +1856,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
1857 | gen_op_ld_T1_A0[ot](); | 1856 | gen_op_ld_T1_A0[ot](); |
1858 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); | 1857 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
1859 | gen_op_lduw_T0_A0(); | 1858 | gen_op_lduw_T0_A0(); |
1859 | + do_ljmp: | ||
1860 | if (s->pe && !s->vm86) { | 1860 | if (s->pe && !s->vm86) { |
1861 | - /* we compute EIP to handle the exception case */ | 1861 | + if (s->cc_op != CC_OP_DYNAMIC) |
1862 | + gen_op_set_cc_op(s->cc_op); | ||
1862 | gen_op_jmp_im(pc_start - s->cs_base); | 1863 | gen_op_jmp_im(pc_start - s->cs_base); |
1863 | - gen_op_ljmp_T0_T1(); | 1864 | + gen_op_ljmp_protected_T0_T1(); |
1864 | } else { | 1865 | } else { |
1865 | gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); | 1866 | gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); |
1866 | gen_op_movl_T0_T1(); | 1867 | gen_op_movl_T0_T1(); |
@@ -2867,7 +2868,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2867,7 +2868,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2867 | else | 2868 | else |
2868 | ot = dflag ? OT_LONG : OT_WORD; | 2869 | ot = dflag ? OT_LONG : OT_WORD; |
2869 | 2870 | ||
2870 | - if (prefixes & PREFIX_REPZ) { | 2871 | + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
2871 | gen_string_ds(s, ot, gen_op_movs + 9); | 2872 | gen_string_ds(s, ot, gen_op_movs + 9); |
2872 | } else { | 2873 | } else { |
2873 | gen_string_ds(s, ot, gen_op_movs); | 2874 | gen_string_ds(s, ot, gen_op_movs); |
@@ -2881,7 +2882,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2881,7 +2882,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2881 | else | 2882 | else |
2882 | ot = dflag ? OT_LONG : OT_WORD; | 2883 | ot = dflag ? OT_LONG : OT_WORD; |
2883 | 2884 | ||
2884 | - if (prefixes & PREFIX_REPZ) { | 2885 | + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
2885 | gen_string_es(s, ot, gen_op_stos + 9); | 2886 | gen_string_es(s, ot, gen_op_stos + 9); |
2886 | } else { | 2887 | } else { |
2887 | gen_string_es(s, ot, gen_op_stos); | 2888 | gen_string_es(s, ot, gen_op_stos); |
@@ -2893,7 +2894,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2893,7 +2894,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2893 | ot = OT_BYTE; | 2894 | ot = OT_BYTE; |
2894 | else | 2895 | else |
2895 | ot = dflag ? OT_LONG : OT_WORD; | 2896 | ot = dflag ? OT_LONG : OT_WORD; |
2896 | - if (prefixes & PREFIX_REPZ) { | 2897 | + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
2897 | gen_string_ds(s, ot, gen_op_lods + 9); | 2898 | gen_string_ds(s, ot, gen_op_lods + 9); |
2898 | } else { | 2899 | } else { |
2899 | gen_string_ds(s, ot, gen_op_lods); | 2900 | gen_string_ds(s, ot, gen_op_lods); |
@@ -2952,7 +2953,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2952,7 +2953,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2952 | ot = OT_BYTE; | 2953 | ot = OT_BYTE; |
2953 | else | 2954 | else |
2954 | ot = dflag ? OT_LONG : OT_WORD; | 2955 | ot = dflag ? OT_LONG : OT_WORD; |
2955 | - if (prefixes & PREFIX_REPZ) { | 2956 | + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
2956 | gen_string_es(s, ot, gen_op_ins + 9); | 2957 | gen_string_es(s, ot, gen_op_ins + 9); |
2957 | } else { | 2958 | } else { |
2958 | gen_string_es(s, ot, gen_op_ins); | 2959 | gen_string_es(s, ot, gen_op_ins); |
@@ -2969,7 +2970,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2969,7 +2970,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2969 | ot = OT_BYTE; | 2970 | ot = OT_BYTE; |
2970 | else | 2971 | else |
2971 | ot = dflag ? OT_LONG : OT_WORD; | 2972 | ot = dflag ? OT_LONG : OT_WORD; |
2972 | - if (prefixes & PREFIX_REPZ) { | 2973 | + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { |
2973 | gen_string_ds(s, ot, gen_op_outs + 9); | 2974 | gen_string_ds(s, ot, gen_op_outs + 9); |
2974 | } else { | 2975 | } else { |
2975 | gen_string_ds(s, ot, gen_op_outs); | 2976 | gen_string_ds(s, ot, gen_op_outs); |
@@ -3062,20 +3063,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3062,20 +3063,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3062 | val = ldsw(s->pc); | 3063 | val = ldsw(s->pc); |
3063 | s->pc += 2; | 3064 | s->pc += 2; |
3064 | do_lret: | 3065 | do_lret: |
3065 | - gen_stack_A0(s); | ||
3066 | - /* pop offset */ | ||
3067 | - gen_op_ld_T0_A0[1 + s->dflag](); | ||
3068 | - if (s->dflag == 0) | ||
3069 | - gen_op_andl_T0_ffff(); | ||
3070 | - /* NOTE: keeping EIP updated is not a problem in case of | ||
3071 | - exception */ | ||
3072 | - gen_op_jmp_T0(); | ||
3073 | - /* pop selector */ | ||
3074 | - gen_op_addl_A0_im(2 << s->dflag); | ||
3075 | - gen_op_ld_T0_A0[1 + s->dflag](); | ||
3076 | - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); | ||
3077 | - /* add stack offset */ | ||
3078 | - gen_stack_update(s, val + (4 << s->dflag)); | 3066 | + if (s->pe && !s->vm86) { |
3067 | + if (s->cc_op != CC_OP_DYNAMIC) | ||
3068 | + gen_op_set_cc_op(s->cc_op); | ||
3069 | + gen_op_jmp_im(pc_start - s->cs_base); | ||
3070 | + gen_op_lret_protected(s->dflag, val); | ||
3071 | + } else { | ||
3072 | + gen_stack_A0(s); | ||
3073 | + /* pop offset */ | ||
3074 | + gen_op_ld_T0_A0[1 + s->dflag](); | ||
3075 | + if (s->dflag == 0) | ||
3076 | + gen_op_andl_T0_ffff(); | ||
3077 | + /* NOTE: keeping EIP updated is not a problem in case of | ||
3078 | + exception */ | ||
3079 | + gen_op_jmp_T0(); | ||
3080 | + /* pop selector */ | ||
3081 | + gen_op_addl_A0_im(2 << s->dflag); | ||
3082 | + gen_op_ld_T0_A0[1 + s->dflag](); | ||
3083 | + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); | ||
3084 | + /* add stack offset */ | ||
3085 | + gen_stack_update(s, val + (4 << s->dflag)); | ||
3086 | + } | ||
3079 | s->is_jmp = 1; | 3087 | s->is_jmp = 1; |
3080 | break; | 3088 | break; |
3081 | case 0xcb: /* lret */ | 3089 | case 0xcb: /* lret */ |
@@ -3114,26 +3122,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3114,26 +3122,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3114 | case 0x9a: /* lcall im */ | 3122 | case 0x9a: /* lcall im */ |
3115 | { | 3123 | { |
3116 | unsigned int selector, offset; | 3124 | unsigned int selector, offset; |
3117 | - /* XXX: not restartable */ | ||
3118 | 3125 | ||
3119 | ot = dflag ? OT_LONG : OT_WORD; | 3126 | ot = dflag ? OT_LONG : OT_WORD; |
3120 | offset = insn_get(s, ot); | 3127 | offset = insn_get(s, ot); |
3121 | selector = insn_get(s, OT_WORD); | 3128 | selector = insn_get(s, OT_WORD); |
3122 | 3129 | ||
3123 | - /* push return segment + offset */ | ||
3124 | - gen_op_movl_T0_seg(R_CS); | ||
3125 | - gen_push_T0(s); | ||
3126 | - next_eip = s->pc - s->cs_base; | ||
3127 | - gen_op_movl_T0_im(next_eip); | ||
3128 | - gen_push_T0(s); | ||
3129 | - | ||
3130 | - /* change cs and pc */ | ||
3131 | gen_op_movl_T0_im(selector); | 3130 | gen_op_movl_T0_im(selector); |
3132 | - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); | ||
3133 | - gen_op_jmp_im((unsigned long)offset); | ||
3134 | - s->is_jmp = 1; | 3131 | + gen_op_movl_T1_im(offset); |
3135 | } | 3132 | } |
3136 | - break; | 3133 | + goto do_lcall; |
3137 | case 0xe9: /* jmp */ | 3134 | case 0xe9: /* jmp */ |
3138 | ot = dflag ? OT_LONG : OT_WORD; | 3135 | ot = dflag ? OT_LONG : OT_WORD; |
3139 | val = insn_get(s, ot); | 3136 | val = insn_get(s, ot); |
@@ -3150,20 +3147,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3150,20 +3147,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
3150 | offset = insn_get(s, ot); | 3147 | offset = insn_get(s, ot); |
3151 | selector = insn_get(s, OT_WORD); | 3148 | selector = insn_get(s, OT_WORD); |
3152 | 3149 | ||
3153 | - /* change cs and pc */ | ||
3154 | gen_op_movl_T0_im(selector); | 3150 | gen_op_movl_T0_im(selector); |
3155 | - if (s->pe && !s->vm86) { | ||
3156 | - /* we compute EIP to handle the exception case */ | ||
3157 | - gen_op_jmp_im(pc_start - s->cs_base); | ||
3158 | - gen_op_movl_T1_im(offset); | ||
3159 | - gen_op_ljmp_T0_T1(); | ||
3160 | - } else { | ||
3161 | - gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); | ||
3162 | - gen_op_jmp_im((unsigned long)offset); | ||
3163 | - } | ||
3164 | - s->is_jmp = 1; | 3151 | + gen_op_movl_T1_im(offset); |
3165 | } | 3152 | } |
3166 | - break; | 3153 | + goto do_ljmp; |
3167 | case 0xeb: /* jmp Jb */ | 3154 | case 0xeb: /* jmp Jb */ |
3168 | val = (int8_t)insn_get(s, OT_BYTE); | 3155 | val = (int8_t)insn_get(s, OT_BYTE); |
3169 | val += s->pc - s->cs_base; | 3156 | val += s->pc - s->cs_base; |