Commit 8e682019e37c8f8939244fcf44a592fa6347d127
1 parent
cf495bcf
correct zero segment values when coming from VM86 mode - cache infos in CPUID - …
…simpler exception handling in load_seg() - validate segments after lret/iret git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@485 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
107 additions
and
55 deletions
target-i386/exec.h
| @@ -122,7 +122,7 @@ typedef struct CCTable { | @@ -122,7 +122,7 @@ typedef struct CCTable { | ||
| 122 | 122 | ||
| 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); |
| 126 | void helper_ljmp_protected_T0_T1(void); | 126 | void helper_ljmp_protected_T0_T1(void); |
| 127 | void helper_lcall_real_T0_T1(int shift, int next_eip); | 127 | void helper_lcall_real_T0_T1(int shift, int next_eip); |
| 128 | void helper_lcall_protected_T0_T1(int shift, int next_eip); | 128 | void helper_lcall_protected_T0_T1(int shift, int next_eip); |
target-i386/helper.c
| @@ -676,6 +676,8 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, | @@ -676,6 +676,8 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, | ||
| 676 | ssp = get_seg_base(ss_e1, ss_e2); | 676 | ssp = get_seg_base(ss_e1, ss_e2); |
| 677 | } else if ((e2 & DESC_C_MASK) || dpl == cpl) { | 677 | } else if ((e2 & DESC_C_MASK) || dpl == cpl) { |
| 678 | /* to same priviledge */ | 678 | /* to same priviledge */ |
| 679 | + if (env->eflags & VM_MASK) | ||
| 680 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
| 679 | new_stack = 0; | 681 | new_stack = 0; |
| 680 | sp_mask = get_sp_mask(env->segs[R_SS].flags); | 682 | sp_mask = get_sp_mask(env->segs[R_SS].flags); |
| 681 | ssp = env->segs[R_SS].base; | 683 | ssp = env->segs[R_SS].base; |
| @@ -702,13 +704,13 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, | @@ -702,13 +704,13 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, | ||
| 702 | else | 704 | else |
| 703 | old_eip = env->eip; | 705 | old_eip = env->eip; |
| 704 | if (shift == 1) { | 706 | if (shift == 1) { |
| 705 | - if (env->eflags & VM_MASK) { | ||
| 706 | - PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); | ||
| 707 | - PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); | ||
| 708 | - PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); | ||
| 709 | - PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); | ||
| 710 | - } | ||
| 711 | if (new_stack) { | 707 | if (new_stack) { |
| 708 | + if (env->eflags & VM_MASK) { | ||
| 709 | + PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); | ||
| 710 | + PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); | ||
| 711 | + PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); | ||
| 712 | + PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); | ||
| 713 | + } | ||
| 712 | PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); | 714 | PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); |
| 713 | PUSHL(ssp, esp, sp_mask, ESP); | 715 | PUSHL(ssp, esp, sp_mask, ESP); |
| 714 | } | 716 | } |
| @@ -720,6 +722,12 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, | @@ -720,6 +722,12 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, | ||
| 720 | } | 722 | } |
| 721 | } else { | 723 | } else { |
| 722 | if (new_stack) { | 724 | if (new_stack) { |
| 725 | + if (env->eflags & VM_MASK) { | ||
| 726 | + PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector); | ||
| 727 | + PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector); | ||
| 728 | + PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector); | ||
| 729 | + PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector); | ||
| 730 | + } | ||
| 723 | PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); | 731 | PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); |
| 724 | PUSHW(ssp, esp, sp_mask, ESP); | 732 | PUSHW(ssp, esp, sp_mask, ESP); |
| 725 | } | 733 | } |
| @@ -732,6 +740,18 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, | @@ -732,6 +740,18 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, | ||
| 732 | } | 740 | } |
| 733 | 741 | ||
| 734 | if (new_stack) { | 742 | if (new_stack) { |
| 743 | + if (env->eflags & VM_MASK) { | ||
| 744 | + /* XXX: explain me why W2K hangs if the whole segment cache is | ||
| 745 | + reset ? */ | ||
| 746 | + env->segs[R_ES].selector = 0; | ||
| 747 | + env->segs[R_ES].flags = 0; | ||
| 748 | + env->segs[R_DS].selector = 0; | ||
| 749 | + env->segs[R_DS].flags = 0; | ||
| 750 | + env->segs[R_FS].selector = 0; | ||
| 751 | + env->segs[R_FS].flags = 0; | ||
| 752 | + env->segs[R_GS].selector = 0; | ||
| 753 | + env->segs[R_GS].flags = 0; | ||
| 754 | + } | ||
| 735 | ss = (ss & ~3) | dpl; | 755 | ss = (ss & ~3) | dpl; |
| 736 | cpu_x86_load_seg_cache(env, R_SS, ss, | 756 | cpu_x86_load_seg_cache(env, R_SS, ss, |
| 737 | ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); | 757 | ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); |
| @@ -824,22 +844,37 @@ void do_interrupt_user(int intno, int is_int, int error_code, | @@ -824,22 +844,37 @@ void do_interrupt_user(int intno, int is_int, int error_code, | ||
| 824 | void do_interrupt(int intno, int is_int, int error_code, | 844 | void do_interrupt(int intno, int is_int, int error_code, |
| 825 | unsigned int next_eip, int is_hw) | 845 | unsigned int next_eip, int is_hw) |
| 826 | { | 846 | { |
| 847 | +#if 0 | ||
| 848 | + { | ||
| 849 | + extern FILE *stdout; | ||
| 850 | + static int count; | ||
| 851 | + if (env->cr[0] & CR0_PE_MASK) { | ||
| 852 | + fprintf(stdout, "%d: interrupt: vector=%02x error_code=%04x int=%d\n", | ||
| 853 | + count, intno, error_code, is_int); | ||
| 854 | + count++; | ||
| 855 | + } | ||
| 856 | + } | ||
| 857 | + if ((env->cr[0] & CR0_PE_MASK) && intno == 0x10) { | ||
| 858 | + tb_flush(env); | ||
| 859 | + cpu_set_log(CPU_LOG_ALL); | ||
| 860 | + } | ||
| 861 | +#endif | ||
| 827 | #ifdef DEBUG_PCALL | 862 | #ifdef DEBUG_PCALL |
| 828 | if (loglevel) { | 863 | if (loglevel) { |
| 829 | static int count; | 864 | static int count; |
| 830 | fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n", | 865 | fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d\n", |
| 831 | count, intno, error_code, is_int); | 866 | count, intno, error_code, is_int); |
| 832 | cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); | 867 | cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP); |
| 833 | -#if 0 | 868 | +#if 1 |
| 834 | { | 869 | { |
| 835 | int i; | 870 | int i; |
| 836 | uint8_t *ptr; | 871 | uint8_t *ptr; |
| 837 | - printf(" code="); | 872 | + fprintf(logfile, " code="); |
| 838 | ptr = env->segs[R_CS].base + env->eip; | 873 | ptr = env->segs[R_CS].base + env->eip; |
| 839 | for(i = 0; i < 16; i++) { | 874 | for(i = 0; i < 16; i++) { |
| 840 | - printf(" %02x", ldub(ptr + i)); | 875 | + fprintf(logfile, " %02x", ldub(ptr + i)); |
| 841 | } | 876 | } |
| 842 | - printf("\n"); | 877 | + fprintf(logfile, "\n"); |
| 843 | } | 878 | } |
| 844 | #endif | 879 | #endif |
| 845 | count++; | 880 | count++; |
| @@ -955,7 +990,6 @@ void helper_cmpxchg8b(void) | @@ -955,7 +990,6 @@ void helper_cmpxchg8b(void) | ||
| 955 | CC_SRC = eflags; | 990 | CC_SRC = eflags; |
| 956 | } | 991 | } |
| 957 | 992 | ||
| 958 | -/* We simulate a pre-MMX pentium as in valgrind */ | ||
| 959 | #define CPUID_FP87 (1 << 0) | 993 | #define CPUID_FP87 (1 << 0) |
| 960 | #define CPUID_VME (1 << 1) | 994 | #define CPUID_VME (1 << 1) |
| 961 | #define CPUID_DE (1 << 2) | 995 | #define CPUID_DE (1 << 2) |
| @@ -979,31 +1013,43 @@ void helper_cmpxchg8b(void) | @@ -979,31 +1013,43 @@ void helper_cmpxchg8b(void) | ||
| 979 | 1013 | ||
| 980 | void helper_cpuid(void) | 1014 | void helper_cpuid(void) |
| 981 | { | 1015 | { |
| 982 | - if (EAX == 0) { | ||
| 983 | - EAX = 1; /* max EAX index supported */ | 1016 | + switch(EAX) { |
| 1017 | + case 0: | ||
| 1018 | + EAX = 2; /* max EAX index supported */ | ||
| 984 | EBX = 0x756e6547; | 1019 | EBX = 0x756e6547; |
| 985 | ECX = 0x6c65746e; | 1020 | ECX = 0x6c65746e; |
| 986 | EDX = 0x49656e69; | 1021 | EDX = 0x49656e69; |
| 987 | - } else if (EAX == 1) { | ||
| 988 | - int family, model, stepping; | ||
| 989 | - /* EAX = 1 info */ | 1022 | + break; |
| 1023 | + case 1: | ||
| 1024 | + { | ||
| 1025 | + int family, model, stepping; | ||
| 1026 | + /* EAX = 1 info */ | ||
| 990 | #if 0 | 1027 | #if 0 |
| 991 | - /* pentium 75-200 */ | ||
| 992 | - family = 5; | ||
| 993 | - model = 2; | ||
| 994 | - stepping = 11; | 1028 | + /* pentium 75-200 */ |
| 1029 | + family = 5; | ||
| 1030 | + model = 2; | ||
| 1031 | + stepping = 11; | ||
| 995 | #else | 1032 | #else |
| 996 | - /* pentium pro */ | ||
| 997 | - family = 6; | ||
| 998 | - model = 1; | ||
| 999 | - stepping = 3; | 1033 | + /* pentium pro */ |
| 1034 | + family = 6; | ||
| 1035 | + model = 1; | ||
| 1036 | + stepping = 3; | ||
| 1000 | #endif | 1037 | #endif |
| 1001 | - EAX = (family << 8) | (model << 4) | stepping; | 1038 | + EAX = (family << 8) | (model << 4) | stepping; |
| 1039 | + EBX = 0; | ||
| 1040 | + ECX = 0; | ||
| 1041 | + EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | | ||
| 1042 | + CPUID_TSC | CPUID_MSR | CPUID_MCE | | ||
| 1043 | + CPUID_CX8 | CPUID_PGE | CPUID_CMOV; | ||
| 1044 | + } | ||
| 1045 | + break; | ||
| 1046 | + default: | ||
| 1047 | + /* cache info: needed for Pentium Pro compatibility */ | ||
| 1048 | + EAX = 0x410601; | ||
| 1002 | EBX = 0; | 1049 | EBX = 0; |
| 1003 | ECX = 0; | 1050 | ECX = 0; |
| 1004 | - EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | | ||
| 1005 | - CPUID_TSC | CPUID_MSR | CPUID_MCE | | ||
| 1006 | - CPUID_CX8 | CPUID_PGE | CPUID_CMOV; | 1051 | + EDX = 0; |
| 1052 | + break; | ||
| 1007 | } | 1053 | } |
| 1008 | } | 1054 | } |
| 1009 | 1055 | ||
| @@ -1070,14 +1116,14 @@ void helper_ltr_T0(void) | @@ -1070,14 +1116,14 @@ void helper_ltr_T0(void) | ||
| 1070 | if (!(e2 & DESC_P_MASK)) | 1116 | if (!(e2 & DESC_P_MASK)) |
| 1071 | raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | 1117 | raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
| 1072 | load_seg_cache_raw_dt(&env->tr, e1, e2); | 1118 | load_seg_cache_raw_dt(&env->tr, e1, e2); |
| 1073 | - e2 |= 0x00000200; /* set the busy bit */ | 1119 | + e2 |= DESC_TSS_BUSY_MASK; |
| 1074 | stl_kernel(ptr + 4, e2); | 1120 | stl_kernel(ptr + 4, e2); |
| 1075 | } | 1121 | } |
| 1076 | env->tr.selector = selector; | 1122 | env->tr.selector = selector; |
| 1077 | } | 1123 | } |
| 1078 | 1124 | ||
| 1079 | /* only works if protected mode and not VM86. seg_reg must be != R_CS */ | 1125 | /* only works if protected mode and not VM86. seg_reg must be != R_CS */ |
| 1080 | -void load_seg(int seg_reg, int selector, unsigned int cur_eip) | 1126 | +void load_seg(int seg_reg, int selector) |
| 1081 | { | 1127 | { |
| 1082 | uint32_t e1, e2; | 1128 | uint32_t e1, e2; |
| 1083 | int cpl, dpl, rpl; | 1129 | int cpl, dpl, rpl; |
| @@ -1085,14 +1131,12 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | @@ -1085,14 +1131,12 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | ||
| 1085 | int index; | 1131 | int index; |
| 1086 | uint8_t *ptr; | 1132 | uint8_t *ptr; |
| 1087 | 1133 | ||
| 1134 | + selector &= 0xffff; | ||
| 1088 | if ((selector & 0xfffc) == 0) { | 1135 | if ((selector & 0xfffc) == 0) { |
| 1089 | /* null selector case */ | 1136 | /* null selector case */ |
| 1090 | - if (seg_reg == R_SS) { | ||
| 1091 | - EIP = cur_eip; | 1137 | + if (seg_reg == R_SS) |
| 1092 | raise_exception_err(EXCP0D_GPF, 0); | 1138 | raise_exception_err(EXCP0D_GPF, 0); |
| 1093 | - } else { | ||
| 1094 | - cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); | ||
| 1095 | - } | 1139 | + cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); |
| 1096 | } else { | 1140 | } else { |
| 1097 | 1141 | ||
| 1098 | if (selector & 0x4) | 1142 | if (selector & 0x4) |
| @@ -1100,49 +1144,36 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | @@ -1100,49 +1144,36 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | ||
| 1100 | else | 1144 | else |
| 1101 | dt = &env->gdt; | 1145 | dt = &env->gdt; |
| 1102 | index = selector & ~7; | 1146 | index = selector & ~7; |
| 1103 | - if ((index + 7) > dt->limit) { | ||
| 1104 | - EIP = cur_eip; | 1147 | + if ((index + 7) > dt->limit) |
| 1105 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 1148 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
| 1106 | - } | ||
| 1107 | ptr = dt->base + index; | 1149 | ptr = dt->base + index; |
| 1108 | e1 = ldl_kernel(ptr); | 1150 | e1 = ldl_kernel(ptr); |
| 1109 | e2 = ldl_kernel(ptr + 4); | 1151 | e2 = ldl_kernel(ptr + 4); |
| 1110 | 1152 | ||
| 1111 | - if (!(e2 & DESC_S_MASK)) { | ||
| 1112 | - EIP = cur_eip; | 1153 | + if (!(e2 & DESC_S_MASK)) |
| 1113 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 1154 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
| 1114 | - } | ||
| 1115 | rpl = selector & 3; | 1155 | rpl = selector & 3; |
| 1116 | dpl = (e2 >> DESC_DPL_SHIFT) & 3; | 1156 | dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
| 1117 | cpl = env->hflags & HF_CPL_MASK; | 1157 | cpl = env->hflags & HF_CPL_MASK; |
| 1118 | if (seg_reg == R_SS) { | 1158 | if (seg_reg == R_SS) { |
| 1119 | /* must be writable segment */ | 1159 | /* must be writable segment */ |
| 1120 | - if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) { | ||
| 1121 | - EIP = cur_eip; | 1160 | + if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) |
| 1122 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 1161 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
| 1123 | - } | ||
| 1124 | - if (rpl != cpl || dpl != cpl) { | ||
| 1125 | - EIP = cur_eip; | 1162 | + if (rpl != cpl || dpl != cpl) |
| 1126 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 1163 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
| 1127 | - } | ||
| 1128 | } else { | 1164 | } else { |
| 1129 | /* must be readable segment */ | 1165 | /* must be readable segment */ |
| 1130 | - if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { | ||
| 1131 | - EIP = cur_eip; | 1166 | + if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) |
| 1132 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 1167 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
| 1133 | - } | ||
| 1134 | 1168 | ||
| 1135 | if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { | 1169 | if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { |
| 1136 | /* if not conforming code, test rights */ | 1170 | /* if not conforming code, test rights */ |
| 1137 | - if (dpl < cpl || dpl < rpl) { | ||
| 1138 | - EIP = cur_eip; | 1171 | + if (dpl < cpl || dpl < rpl) |
| 1139 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 1172 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
| 1140 | - } | ||
| 1141 | } | 1173 | } |
| 1142 | } | 1174 | } |
| 1143 | 1175 | ||
| 1144 | if (!(e2 & DESC_P_MASK)) { | 1176 | if (!(e2 & DESC_P_MASK)) { |
| 1145 | - EIP = cur_eip; | ||
| 1146 | if (seg_reg == R_SS) | 1177 | if (seg_reg == R_SS) |
| 1147 | raise_exception_err(EXCP0C_STACK, selector & 0xfffc); | 1178 | raise_exception_err(EXCP0C_STACK, selector & 0xfffc); |
| 1148 | else | 1179 | else |
| @@ -1507,6 +1538,21 @@ void helper_iret_real(int shift) | @@ -1507,6 +1538,21 @@ void helper_iret_real(int shift) | ||
| 1507 | load_eflags(new_eflags, eflags_mask); | 1538 | load_eflags(new_eflags, eflags_mask); |
| 1508 | } | 1539 | } |
| 1509 | 1540 | ||
| 1541 | +static inline void validate_seg(int seg_reg, int cpl) | ||
| 1542 | +{ | ||
| 1543 | + int dpl; | ||
| 1544 | + uint32_t e2; | ||
| 1545 | + | ||
| 1546 | + e2 = env->segs[seg_reg].flags; | ||
| 1547 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
| 1548 | + if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { | ||
| 1549 | + /* data or non conforming code segment */ | ||
| 1550 | + if (dpl < cpl) { | ||
| 1551 | + cpu_x86_load_seg_cache(env, seg_reg, 0, NULL, 0, 0); | ||
| 1552 | + } | ||
| 1553 | + } | ||
| 1554 | +} | ||
| 1555 | + | ||
| 1510 | /* protected mode iret */ | 1556 | /* protected mode iret */ |
| 1511 | static inline void helper_ret_protected(int shift, int is_iret, int addend) | 1557 | static inline void helper_ret_protected(int shift, int is_iret, int addend) |
| 1512 | { | 1558 | { |
| @@ -1610,6 +1656,12 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) | @@ -1610,6 +1656,12 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) | ||
| 1610 | cpu_x86_set_cpl(env, rpl); | 1656 | cpu_x86_set_cpl(env, rpl); |
| 1611 | sp = new_esp; | 1657 | sp = new_esp; |
| 1612 | /* XXX: change sp_mask according to old segment ? */ | 1658 | /* XXX: change sp_mask according to old segment ? */ |
| 1659 | + | ||
| 1660 | + /* validate data segments */ | ||
| 1661 | + validate_seg(R_ES, cpl); | ||
| 1662 | + validate_seg(R_DS, cpl); | ||
| 1663 | + validate_seg(R_FS, cpl); | ||
| 1664 | + validate_seg(R_GS, cpl); | ||
| 1613 | } | 1665 | } |
| 1614 | ESP = (ESP & ~sp_mask) | (sp & sp_mask); | 1666 | ESP = (ESP & ~sp_mask) | (sp & sp_mask); |
| 1615 | env->eip = new_eip; | 1667 | env->eip = new_eip; |