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 */ | ... | ... |