Commit d0a1ffc9573b15997ecdfbc9ec5ec2fc1403d0f1

Authored by bellard
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
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 */
... ...