Commit d0a1ffc9573b15997ecdfbc9ec5ec2fc1403d0f1
1 parent
df0f11a0
added fsave/frstor/fstenv/fldenv/fcomi - fixed cpuid - make lret/iret restartable
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@198 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
315 additions
and
50 deletions
cpu-i386.h
| ... | ... | @@ -436,6 +436,10 @@ void cpu_x86_close(CPUX86State *s); |
| 436 | 436 | /* needed to load some predefinied segment registers */ |
| 437 | 437 | void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); |
| 438 | 438 | |
| 439 | +/* simulate fsave/frstor */ | |
| 440 | +void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32); | |
| 441 | +void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); | |
| 442 | + | |
| 439 | 443 | /* you can call this signal handler from your SIGBUS and SIGSEGV |
| 440 | 444 | signal handlers to inform the virtual CPU of exceptions. non zero |
| 441 | 445 | is returned if the signal was handled by the virtual CPU. */ | ... | ... |
exec-i386.c
| ... | ... | @@ -327,6 +327,30 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) |
| 327 | 327 | env = saved_env; |
| 328 | 328 | } |
| 329 | 329 | |
| 330 | +void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32) | |
| 331 | +{ | |
| 332 | + CPUX86State *saved_env; | |
| 333 | + | |
| 334 | + saved_env = env; | |
| 335 | + env = s; | |
| 336 | + | |
| 337 | + helper_fsave(ptr, data32); | |
| 338 | + | |
| 339 | + env = saved_env; | |
| 340 | +} | |
| 341 | + | |
| 342 | +void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32) | |
| 343 | +{ | |
| 344 | + CPUX86State *saved_env; | |
| 345 | + | |
| 346 | + saved_env = env; | |
| 347 | + env = s; | |
| 348 | + | |
| 349 | + helper_frstor(ptr, data32); | |
| 350 | + | |
| 351 | + env = saved_env; | |
| 352 | +} | |
| 353 | + | |
| 330 | 354 | #undef EAX |
| 331 | 355 | #undef ECX |
| 332 | 356 | #undef EDX | ... | ... |
exec-i386.h
| ... | ... | @@ -225,6 +225,8 @@ void raise_interrupt(int intno, int is_int, int error_code, |
| 225 | 225 | void raise_exception_err(int exception_index, int error_code); |
| 226 | 226 | void raise_exception(int exception_index); |
| 227 | 227 | void cpu_loop_exit(void); |
| 228 | +void helper_fsave(uint8_t *ptr, int data32); | |
| 229 | +void helper_frstor(uint8_t *ptr, int data32); | |
| 228 | 230 | |
| 229 | 231 | void OPPROTO op_movl_eflags_T0(void); |
| 230 | 232 | void OPPROTO op_movl_T0_eflags(void); | ... | ... |
op-i386.c
| ... | ... | @@ -1073,7 +1073,7 @@ void helper_cpuid(void) |
| 1073 | 1073 | EBX = 0x756e6547; |
| 1074 | 1074 | ECX = 0x6c65746e; |
| 1075 | 1075 | EDX = 0x49656e69; |
| 1076 | - } else { | |
| 1076 | + } else if (EAX == 1) { | |
| 1077 | 1077 | /* EAX = 1 info */ |
| 1078 | 1078 | EAX = 0x52b; |
| 1079 | 1079 | EBX = 0; |
| ... | ... | @@ -1899,17 +1899,22 @@ void OPPROTO op_fldt_ST0_A0(void) |
| 1899 | 1899 | ST0 = *(long double *)A0; |
| 1900 | 1900 | } |
| 1901 | 1901 | #else |
| 1902 | -void helper_fldt_ST0_A0(void) | |
| 1902 | +static inline CPU86_LDouble helper_fldt(uint8_t *ptr) | |
| 1903 | 1903 | { |
| 1904 | 1904 | CPU86_LDoubleU temp; |
| 1905 | 1905 | int upper, e; |
| 1906 | 1906 | /* mantissa */ |
| 1907 | - upper = lduw((uint8_t *)A0 + 8); | |
| 1907 | + upper = lduw(ptr + 8); | |
| 1908 | 1908 | /* XXX: handle overflow ? */ |
| 1909 | 1909 | e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ |
| 1910 | 1910 | e |= (upper >> 4) & 0x800; /* sign */ |
| 1911 | - temp.ll = ((ldq((void *)A0) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52); | |
| 1912 | - ST0 = temp.d; | |
| 1911 | + temp.ll = ((ldq(ptr) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52); | |
| 1912 | + return temp.d; | |
| 1913 | +} | |
| 1914 | + | |
| 1915 | +void helper_fldt_ST0_A0(void) | |
| 1916 | +{ | |
| 1917 | + ST0 = helper_fldt((uint8_t *)A0); | |
| 1913 | 1918 | } |
| 1914 | 1919 | |
| 1915 | 1920 | void OPPROTO op_fldt_ST0_A0(void) |
| ... | ... | @@ -2008,17 +2013,23 @@ void OPPROTO op_fstt_ST0_A0(void) |
| 2008 | 2013 | *(long double *)A0 = ST0; |
| 2009 | 2014 | } |
| 2010 | 2015 | #else |
| 2011 | -void helper_fstt_ST0_A0(void) | |
| 2016 | + | |
| 2017 | +static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) | |
| 2012 | 2018 | { |
| 2013 | 2019 | CPU86_LDoubleU temp; |
| 2014 | 2020 | int e; |
| 2015 | - temp.d = ST0; | |
| 2021 | + temp.d = f; | |
| 2016 | 2022 | /* mantissa */ |
| 2017 | - stq((void *)A0, (MANTD(temp) << 11) | (1LL << 63)); | |
| 2023 | + stq(ptr, (MANTD(temp) << 11) | (1LL << 63)); | |
| 2018 | 2024 | /* exponent + sign */ |
| 2019 | 2025 | e = EXPD(temp) - EXPBIAS + 16383; |
| 2020 | 2026 | e |= SIGND(temp) >> 16; |
| 2021 | - stw((uint8_t *)A0 + 8, e); | |
| 2027 | + stw(ptr + 8, e); | |
| 2028 | +} | |
| 2029 | + | |
| 2030 | +void helper_fstt_ST0_A0(void) | |
| 2031 | +{ | |
| 2032 | + helper_fstt(ST0, (uint8_t *)A0); | |
| 2022 | 2033 | } |
| 2023 | 2034 | |
| 2024 | 2035 | void OPPROTO op_fstt_ST0_A0(void) |
| ... | ... | @@ -2254,6 +2265,34 @@ void OPPROTO op_fucom_ST0_FT0(void) |
| 2254 | 2265 | FORCE_RET(); |
| 2255 | 2266 | } |
| 2256 | 2267 | |
| 2268 | +/* XXX: handle nans */ | |
| 2269 | +void OPPROTO op_fcomi_ST0_FT0(void) | |
| 2270 | +{ | |
| 2271 | + int eflags; | |
| 2272 | + eflags = cc_table[CC_OP].compute_all(); | |
| 2273 | + eflags &= ~(CC_Z | CC_P | CC_C); | |
| 2274 | + if (ST0 < FT0) | |
| 2275 | + eflags |= CC_C; | |
| 2276 | + else if (ST0 == FT0) | |
| 2277 | + eflags |= CC_Z; | |
| 2278 | + CC_SRC = eflags; | |
| 2279 | + FORCE_RET(); | |
| 2280 | +} | |
| 2281 | + | |
| 2282 | +/* XXX: handle nans */ | |
| 2283 | +void OPPROTO op_fucomi_ST0_FT0(void) | |
| 2284 | +{ | |
| 2285 | + int eflags; | |
| 2286 | + eflags = cc_table[CC_OP].compute_all(); | |
| 2287 | + eflags &= ~(CC_Z | CC_P | CC_C); | |
| 2288 | + if (ST0 < FT0) | |
| 2289 | + eflags |= CC_C; | |
| 2290 | + else if (ST0 == FT0) | |
| 2291 | + eflags |= CC_Z; | |
| 2292 | + CC_SRC = eflags; | |
| 2293 | + FORCE_RET(); | |
| 2294 | +} | |
| 2295 | + | |
| 2257 | 2296 | void OPPROTO op_fadd_ST0_FT0(void) |
| 2258 | 2297 | { |
| 2259 | 2298 | ST0 += FT0; |
| ... | ... | @@ -2750,6 +2789,149 @@ void OPPROTO op_fninit(void) |
| 2750 | 2789 | env->fptags[7] = 1; |
| 2751 | 2790 | } |
| 2752 | 2791 | |
| 2792 | +void helper_fstenv(uint8_t *ptr, int data32) | |
| 2793 | +{ | |
| 2794 | + int fpus, fptag, exp, i; | |
| 2795 | + uint64_t mant; | |
| 2796 | + CPU86_LDoubleU tmp; | |
| 2797 | + | |
| 2798 | + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; | |
| 2799 | + fptag = 0; | |
| 2800 | + for (i=7; i>=0; i--) { | |
| 2801 | + fptag <<= 2; | |
| 2802 | + if (env->fptags[i]) { | |
| 2803 | + fptag |= 3; | |
| 2804 | + } else { | |
| 2805 | + tmp.d = env->fpregs[i]; | |
| 2806 | + exp = EXPD(tmp); | |
| 2807 | + mant = MANTD(tmp); | |
| 2808 | + if (exp == 0 && mant == 0) { | |
| 2809 | + /* zero */ | |
| 2810 | + fptag |= 1; | |
| 2811 | + } else if (exp == 0 || exp == MAXEXPD | |
| 2812 | +#ifdef USE_X86LDOUBLE | |
| 2813 | + || (mant & (1LL << 63)) == 0 | |
| 2814 | +#endif | |
| 2815 | + ) { | |
| 2816 | + /* NaNs, infinity, denormal */ | |
| 2817 | + fptag |= 2; | |
| 2818 | + } | |
| 2819 | + } | |
| 2820 | + } | |
| 2821 | + if (data32) { | |
| 2822 | + /* 32 bit */ | |
| 2823 | + stl(ptr, env->fpuc); | |
| 2824 | + stl(ptr + 4, fpus); | |
| 2825 | + stl(ptr + 8, fptag); | |
| 2826 | + stl(ptr + 12, 0); | |
| 2827 | + stl(ptr + 16, 0); | |
| 2828 | + stl(ptr + 20, 0); | |
| 2829 | + stl(ptr + 24, 0); | |
| 2830 | + } else { | |
| 2831 | + /* 16 bit */ | |
| 2832 | + stw(ptr, env->fpuc); | |
| 2833 | + stw(ptr + 2, fpus); | |
| 2834 | + stw(ptr + 4, fptag); | |
| 2835 | + stw(ptr + 6, 0); | |
| 2836 | + stw(ptr + 8, 0); | |
| 2837 | + stw(ptr + 10, 0); | |
| 2838 | + stw(ptr + 12, 0); | |
| 2839 | + } | |
| 2840 | +} | |
| 2841 | + | |
| 2842 | +void helper_fldenv(uint8_t *ptr, int data32) | |
| 2843 | +{ | |
| 2844 | + int i, fpus, fptag; | |
| 2845 | + | |
| 2846 | + if (data32) { | |
| 2847 | + env->fpuc = lduw(ptr); | |
| 2848 | + fpus = lduw(ptr + 4); | |
| 2849 | + fptag = lduw(ptr + 8); | |
| 2850 | + } | |
| 2851 | + else { | |
| 2852 | + env->fpuc = lduw(ptr); | |
| 2853 | + fpus = lduw(ptr + 2); | |
| 2854 | + fptag = lduw(ptr + 4); | |
| 2855 | + } | |
| 2856 | + env->fpstt = (fpus >> 11) & 7; | |
| 2857 | + env->fpus = fpus & ~0x3800; | |
| 2858 | + for(i = 0;i < 7; i++) { | |
| 2859 | + env->fptags[i] = ((fptag & 3) == 3); | |
| 2860 | + fptag >>= 2; | |
| 2861 | + } | |
| 2862 | +} | |
| 2863 | + | |
| 2864 | +void helper_fsave(uint8_t *ptr, int data32) | |
| 2865 | +{ | |
| 2866 | + CPU86_LDouble tmp; | |
| 2867 | + int i; | |
| 2868 | + | |
| 2869 | + helper_fstenv(ptr, data32); | |
| 2870 | + | |
| 2871 | + ptr += (14 << data32); | |
| 2872 | + for(i = 0;i < 8; i++) { | |
| 2873 | + tmp = ST(i); | |
| 2874 | +#ifdef USE_X86LDOUBLE | |
| 2875 | + *(long double *)ptr = tmp; | |
| 2876 | +#else | |
| 2877 | + helper_fstt(tmp, ptr); | |
| 2878 | +#endif | |
| 2879 | + ptr += 10; | |
| 2880 | + } | |
| 2881 | + | |
| 2882 | + /* fninit */ | |
| 2883 | + env->fpus = 0; | |
| 2884 | + env->fpstt = 0; | |
| 2885 | + env->fpuc = 0x37f; | |
| 2886 | + env->fptags[0] = 1; | |
| 2887 | + env->fptags[1] = 1; | |
| 2888 | + env->fptags[2] = 1; | |
| 2889 | + env->fptags[3] = 1; | |
| 2890 | + env->fptags[4] = 1; | |
| 2891 | + env->fptags[5] = 1; | |
| 2892 | + env->fptags[6] = 1; | |
| 2893 | + env->fptags[7] = 1; | |
| 2894 | +} | |
| 2895 | + | |
| 2896 | +void helper_frstor(uint8_t *ptr, int data32) | |
| 2897 | +{ | |
| 2898 | + CPU86_LDouble tmp; | |
| 2899 | + int i; | |
| 2900 | + | |
| 2901 | + helper_fldenv(ptr, data32); | |
| 2902 | + ptr += (14 << data32); | |
| 2903 | + | |
| 2904 | + for(i = 0;i < 8; i++) { | |
| 2905 | +#ifdef USE_X86LDOUBLE | |
| 2906 | + tmp = *(long double *)ptr; | |
| 2907 | +#else | |
| 2908 | + tmp = helper_fldt(ptr); | |
| 2909 | +#endif | |
| 2910 | + ST(i) = tmp; | |
| 2911 | + ptr += 10; | |
| 2912 | + } | |
| 2913 | +} | |
| 2914 | + | |
| 2915 | +void OPPROTO op_fnstenv_A0(void) | |
| 2916 | +{ | |
| 2917 | + helper_fstenv((uint8_t *)A0, PARAM1); | |
| 2918 | +} | |
| 2919 | + | |
| 2920 | +void OPPROTO op_fldenv_A0(void) | |
| 2921 | +{ | |
| 2922 | + helper_fldenv((uint8_t *)A0, PARAM1); | |
| 2923 | +} | |
| 2924 | + | |
| 2925 | +void OPPROTO op_fnsave_A0(void) | |
| 2926 | +{ | |
| 2927 | + helper_fsave((uint8_t *)A0, PARAM1); | |
| 2928 | +} | |
| 2929 | + | |
| 2930 | +void OPPROTO op_frstor_A0(void) | |
| 2931 | +{ | |
| 2932 | + helper_frstor((uint8_t *)A0, PARAM1); | |
| 2933 | +} | |
| 2934 | + | |
| 2753 | 2935 | /* threading support */ |
| 2754 | 2936 | void OPPROTO op_lock(void) |
| 2755 | 2937 | { | ... | ... |
translate-i386.c
| ... | ... | @@ -1273,21 +1273,40 @@ static void gen_pop_T0(DisasContext *s) |
| 1273 | 1273 | } |
| 1274 | 1274 | } |
| 1275 | 1275 | |
| 1276 | -static void gen_pop_update(DisasContext *s) | |
| 1276 | +static inline void gen_stack_update(DisasContext *s, int addend) | |
| 1277 | 1277 | { |
| 1278 | 1278 | if (s->ss32) { |
| 1279 | - if (s->dflag) | |
| 1280 | - gen_op_addl_ESP_4(); | |
| 1281 | - else | |
| 1279 | + if (addend == 2) | |
| 1282 | 1280 | gen_op_addl_ESP_2(); |
| 1281 | + else if (addend == 4) | |
| 1282 | + gen_op_addl_ESP_4(); | |
| 1283 | + else | |
| 1284 | + gen_op_addl_ESP_im(addend); | |
| 1283 | 1285 | } else { |
| 1284 | - if (s->dflag) | |
| 1286 | + if (addend == 2) | |
| 1287 | + gen_op_addw_ESP_2(); | |
| 1288 | + else if (addend == 4) | |
| 1285 | 1289 | gen_op_addw_ESP_4(); |
| 1286 | 1290 | else |
| 1287 | - gen_op_addw_ESP_2(); | |
| 1291 | + gen_op_addw_ESP_im(addend); | |
| 1288 | 1292 | } |
| 1289 | 1293 | } |
| 1290 | 1294 | |
| 1295 | +static void gen_pop_update(DisasContext *s) | |
| 1296 | +{ | |
| 1297 | + gen_stack_update(s, 2 << s->dflag); | |
| 1298 | +} | |
| 1299 | + | |
| 1300 | +static void gen_stack_A0(DisasContext *s) | |
| 1301 | +{ | |
| 1302 | + gen_op_movl_A0_ESP(); | |
| 1303 | + if (!s->ss32) | |
| 1304 | + gen_op_andl_A0_ffff(); | |
| 1305 | + gen_op_movl_T1_A0(); | |
| 1306 | + if (s->addseg) | |
| 1307 | + gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); | |
| 1308 | +} | |
| 1309 | + | |
| 1291 | 1310 | /* NOTE: wrap around in 16 bit not fully handled */ |
| 1292 | 1311 | static void gen_pusha(DisasContext *s) |
| 1293 | 1312 | { |
| ... | ... | @@ -1957,7 +1976,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 1957 | 1976 | } |
| 1958 | 1977 | break; |
| 1959 | 1978 | case 0xc9: /* leave */ |
| 1960 | - /* XXX: exception not precise (ESP is update before potential exception) */ | |
| 1979 | + /* XXX: exception not precise (ESP is updated before potential exception) */ | |
| 1961 | 1980 | if (s->ss32) { |
| 1962 | 1981 | gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); |
| 1963 | 1982 | gen_op_mov_reg_T0[OT_LONG][R_ESP](); |
| ... | ... | @@ -2453,9 +2472,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2453 | 2472 | break; |
| 2454 | 2473 | } |
| 2455 | 2474 | break; |
| 2475 | + case 0x0c: /* fldenv mem */ | |
| 2476 | + gen_op_fldenv_A0(s->dflag); | |
| 2477 | + break; | |
| 2456 | 2478 | case 0x0d: /* fldcw mem */ |
| 2457 | 2479 | gen_op_fldcw_A0(); |
| 2458 | 2480 | break; |
| 2481 | + case 0x0e: /* fnstenv mem */ | |
| 2482 | + gen_op_fnstenv_A0(s->dflag); | |
| 2483 | + break; | |
| 2459 | 2484 | case 0x0f: /* fnstcw mem */ |
| 2460 | 2485 | gen_op_fnstcw_A0(); |
| 2461 | 2486 | break; |
| ... | ... | @@ -2467,6 +2492,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2467 | 2492 | gen_op_fstt_ST0_A0(); |
| 2468 | 2493 | gen_op_fpop(); |
| 2469 | 2494 | break; |
| 2495 | + case 0x2c: /* frstor mem */ | |
| 2496 | + gen_op_frstor_A0(s->dflag); | |
| 2497 | + break; | |
| 2498 | + case 0x2e: /* fnsave mem */ | |
| 2499 | + gen_op_fnsave_A0(s->dflag); | |
| 2500 | + break; | |
| 2470 | 2501 | case 0x2f: /* fnstsw mem */ |
| 2471 | 2502 | gen_op_fnstsw_A0(); |
| 2472 | 2503 | break; |
| ... | ... | @@ -2672,6 +2703,20 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2672 | 2703 | goto illegal_op; |
| 2673 | 2704 | } |
| 2674 | 2705 | break; |
| 2706 | + case 0x1d: /* fucomi */ | |
| 2707 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2708 | + gen_op_set_cc_op(s->cc_op); | |
| 2709 | + gen_op_fmov_FT0_STN(opreg); | |
| 2710 | + gen_op_fucomi_ST0_FT0(); | |
| 2711 | + s->cc_op = CC_OP_EFLAGS; | |
| 2712 | + break; | |
| 2713 | + case 0x1e: /* fcomi */ | |
| 2714 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2715 | + gen_op_set_cc_op(s->cc_op); | |
| 2716 | + gen_op_fmov_FT0_STN(opreg); | |
| 2717 | + gen_op_fcomi_ST0_FT0(); | |
| 2718 | + s->cc_op = CC_OP_EFLAGS; | |
| 2719 | + break; | |
| 2675 | 2720 | case 0x2a: /* fst sti */ |
| 2676 | 2721 | gen_op_fmov_STN_ST0(opreg); |
| 2677 | 2722 | break; |
| ... | ... | @@ -2709,6 +2754,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2709 | 2754 | goto illegal_op; |
| 2710 | 2755 | } |
| 2711 | 2756 | break; |
| 2757 | + case 0x3d: /* fucomip */ | |
| 2758 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2759 | + gen_op_set_cc_op(s->cc_op); | |
| 2760 | + gen_op_fmov_FT0_STN(opreg); | |
| 2761 | + gen_op_fucomi_ST0_FT0(); | |
| 2762 | + gen_op_fpop(); | |
| 2763 | + s->cc_op = CC_OP_EFLAGS; | |
| 2764 | + break; | |
| 2765 | + case 0x3e: /* fcomip */ | |
| 2766 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2767 | + gen_op_set_cc_op(s->cc_op); | |
| 2768 | + gen_op_fmov_FT0_STN(opreg); | |
| 2769 | + gen_op_fcomi_ST0_FT0(); | |
| 2770 | + gen_op_fpop(); | |
| 2771 | + s->cc_op = CC_OP_EFLAGS; | |
| 2772 | + break; | |
| 2712 | 2773 | default: |
| 2713 | 2774 | goto illegal_op; |
| 2714 | 2775 | } |
| ... | ... | @@ -2901,10 +2962,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2901 | 2962 | val = ldsw(s->pc); |
| 2902 | 2963 | s->pc += 2; |
| 2903 | 2964 | gen_pop_T0(s); |
| 2904 | - if (s->ss32) | |
| 2905 | - gen_op_addl_ESP_im(val + (2 << s->dflag)); | |
| 2906 | - else | |
| 2907 | - gen_op_addw_ESP_im(val + (2 << s->dflag)); | |
| 2965 | + gen_stack_update(s, val + (2 << s->dflag)); | |
| 2908 | 2966 | if (s->dflag == 0) |
| 2909 | 2967 | gen_op_andl_T0_ffff(); |
| 2910 | 2968 | gen_op_jmp_T0(); |
| ... | ... | @@ -2919,63 +2977,55 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2919 | 2977 | s->is_jmp = 1; |
| 2920 | 2978 | break; |
| 2921 | 2979 | case 0xca: /* lret im */ |
| 2922 | - /* XXX: not restartable */ | |
| 2923 | 2980 | val = ldsw(s->pc); |
| 2924 | 2981 | s->pc += 2; |
| 2982 | + do_lret: | |
| 2983 | + gen_stack_A0(s); | |
| 2925 | 2984 | /* pop offset */ |
| 2926 | - gen_pop_T0(s); | |
| 2985 | + gen_op_ld_T0_A0[1 + s->dflag](); | |
| 2927 | 2986 | if (s->dflag == 0) |
| 2928 | 2987 | gen_op_andl_T0_ffff(); |
| 2988 | + /* NOTE: keeping EIP updated is not a problem in case of | |
| 2989 | + exception */ | |
| 2929 | 2990 | gen_op_jmp_T0(); |
| 2930 | - gen_pop_update(s); | |
| 2931 | 2991 | /* pop selector */ |
| 2932 | - gen_pop_T0(s); | |
| 2992 | + gen_op_addl_A0_im(2 << s->dflag); | |
| 2993 | + gen_op_ld_T0_A0[1 + s->dflag](); | |
| 2933 | 2994 | gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
| 2934 | - gen_pop_update(s); | |
| 2935 | 2995 | /* add stack offset */ |
| 2936 | - if (s->ss32) | |
| 2937 | - gen_op_addl_ESP_im(val); | |
| 2938 | - else | |
| 2939 | - gen_op_addw_ESP_im(val); | |
| 2996 | + gen_stack_update(s, val + (4 << s->dflag)); | |
| 2940 | 2997 | s->is_jmp = 1; |
| 2941 | 2998 | break; |
| 2942 | 2999 | case 0xcb: /* lret */ |
| 2943 | - /* XXX: not restartable */ | |
| 2944 | - /* pop offset */ | |
| 2945 | - gen_pop_T0(s); | |
| 2946 | - if (s->dflag == 0) | |
| 2947 | - gen_op_andl_T0_ffff(); | |
| 2948 | - gen_op_jmp_T0(); | |
| 2949 | - gen_pop_update(s); | |
| 2950 | - /* pop selector */ | |
| 2951 | - gen_pop_T0(s); | |
| 2952 | - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); | |
| 2953 | - gen_pop_update(s); | |
| 2954 | - s->is_jmp = 1; | |
| 2955 | - break; | |
| 3000 | + val = 0; | |
| 3001 | + goto do_lret; | |
| 2956 | 3002 | case 0xcf: /* iret */ |
| 2957 | 3003 | if (s->vm86 && s->iopl != 3) { |
| 2958 | 3004 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| 2959 | 3005 | } else { |
| 2960 | 3006 | /* XXX: not restartable */ |
| 3007 | + gen_stack_A0(s); | |
| 2961 | 3008 | /* pop offset */ |
| 2962 | - gen_pop_T0(s); | |
| 3009 | + gen_op_ld_T0_A0[1 + s->dflag](); | |
| 2963 | 3010 | if (s->dflag == 0) |
| 2964 | 3011 | gen_op_andl_T0_ffff(); |
| 2965 | - gen_op_jmp_T0(); | |
| 2966 | - gen_pop_update(s); | |
| 3012 | + /* NOTE: keeping EIP updated is not a problem in case of | |
| 3013 | + exception */ | |
| 3014 | + gen_op_jmp_T0(); | |
| 2967 | 3015 | /* pop selector */ |
| 2968 | - gen_pop_T0(s); | |
| 2969 | - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); | |
| 2970 | - gen_pop_update(s); | |
| 3016 | + gen_op_addl_A0_im(2 << s->dflag); | |
| 3017 | + gen_op_ld_T0_A0[1 + s->dflag](); | |
| 2971 | 3018 | /* pop eflags */ |
| 2972 | - gen_pop_T0(s); | |
| 3019 | + gen_op_addl_A0_im(2 << s->dflag); | |
| 3020 | + gen_op_ld_T1_A0[1 + s->dflag](); | |
| 3021 | + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); | |
| 3022 | + gen_op_movl_T0_T1(); | |
| 2973 | 3023 | if (s->dflag) { |
| 2974 | 3024 | gen_op_movl_eflags_T0(); |
| 2975 | 3025 | } else { |
| 2976 | 3026 | gen_op_movw_eflags_T0(); |
| 2977 | 3027 | } |
| 2978 | - gen_pop_update(s); | |
| 3028 | + gen_stack_update(s, (6 << s->dflag)); | |
| 2979 | 3029 | s->cc_op = CC_OP_EFLAGS; |
| 2980 | 3030 | } |
| 2981 | 3031 | s->is_jmp = 1; |
| ... | ... | @@ -2997,6 +3047,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2997 | 3047 | case 0x9a: /* lcall im */ |
| 2998 | 3048 | { |
| 2999 | 3049 | unsigned int selector, offset; |
| 3050 | + /* XXX: not restartable */ | |
| 3000 | 3051 | |
| 3001 | 3052 | ot = dflag ? OT_LONG : OT_WORD; |
| 3002 | 3053 | offset = insn_get(s, ot); |
| ... | ... | @@ -3613,6 +3664,8 @@ static uint16_t opc_write_flags[NB_OPS] = { |
| 3613 | 3664 | [INDEX_op_cmpxchg8b] = CC_Z, |
| 3614 | 3665 | [INDEX_op_lar] = CC_Z, |
| 3615 | 3666 | [INDEX_op_lsl] = CC_Z, |
| 3667 | + [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C, | |
| 3668 | + [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C, | |
| 3616 | 3669 | }; |
| 3617 | 3670 | |
| 3618 | 3671 | /* simpler form of an operation if no flags need to be generated */ | ... | ... |