Commit f631ef9bd262796779dd2b18741cf924831dab54
1 parent
f7341ff4
better vm86 support - added iret - fixed push/pop fs/gs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@68 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
168 additions
and
7 deletions
op-i386.c
... | ... | @@ -611,6 +611,35 @@ void OPPROTO op_into(void) |
611 | 611 | } |
612 | 612 | } |
613 | 613 | |
614 | +/* XXX: add IOPL/CPL tests */ | |
615 | +void OPPROTO op_cli(void) | |
616 | +{ | |
617 | + raise_exception(EXCP0D_GPF); | |
618 | +} | |
619 | + | |
620 | +/* XXX: add IOPL/CPL tests */ | |
621 | +void OPPROTO op_sti(void) | |
622 | +{ | |
623 | + raise_exception(EXCP0D_GPF); | |
624 | +} | |
625 | + | |
626 | +/* vm86plus instructions */ | |
627 | + | |
628 | +void OPPROTO op_cli_vm(void) | |
629 | +{ | |
630 | + env->eflags &= ~VIF_MASK; | |
631 | +} | |
632 | + | |
633 | +void OPPROTO op_sti_vm(void) | |
634 | +{ | |
635 | + env->eflags |= VIF_MASK; | |
636 | + if (env->eflags & VIP_MASK) { | |
637 | + EIP = PARAM1; | |
638 | + raise_exception(EXCP0D_GPF); | |
639 | + } | |
640 | + FORCE_RET(); | |
641 | +} | |
642 | + | |
614 | 643 | void OPPROTO op_boundw(void) |
615 | 644 | { |
616 | 645 | int low, high, v; |
... | ... | @@ -1234,7 +1263,8 @@ void OPPROTO op_set_cc_op(void) |
1234 | 1263 | CC_OP = PARAM1; |
1235 | 1264 | } |
1236 | 1265 | |
1237 | -#define FL_UPDATE_MASK (TF_MASK | AC_MASK | ID_MASK) | |
1266 | +#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) | |
1267 | +#define FL_UPDATE_MASK16 (TF_MASK) | |
1238 | 1268 | |
1239 | 1269 | void OPPROTO op_movl_eflags_T0(void) |
1240 | 1270 | { |
... | ... | @@ -1243,7 +1273,56 @@ void OPPROTO op_movl_eflags_T0(void) |
1243 | 1273 | CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); |
1244 | 1274 | DF = 1 - (2 * ((eflags >> 10) & 1)); |
1245 | 1275 | /* we also update some system flags as in user mode */ |
1246 | - env->eflags = (env->eflags & ~FL_UPDATE_MASK) | (eflags & FL_UPDATE_MASK); | |
1276 | + env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | (eflags & FL_UPDATE_MASK32); | |
1277 | +} | |
1278 | + | |
1279 | +void OPPROTO op_movw_eflags_T0(void) | |
1280 | +{ | |
1281 | + int eflags; | |
1282 | + eflags = T0; | |
1283 | + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); | |
1284 | + DF = 1 - (2 * ((eflags >> 10) & 1)); | |
1285 | + /* we also update some system flags as in user mode */ | |
1286 | + env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16); | |
1287 | +} | |
1288 | + | |
1289 | +/* vm86 version */ | |
1290 | +void OPPROTO op_movw_eflags_T0_vm(void) | |
1291 | +{ | |
1292 | + int eflags; | |
1293 | + eflags = T0; | |
1294 | + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); | |
1295 | + DF = 1 - (2 * ((eflags >> 10) & 1)); | |
1296 | + /* we also update some system flags as in user mode */ | |
1297 | + env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) | | |
1298 | + (eflags & FL_UPDATE_MASK16); | |
1299 | + if (eflags & IF_MASK) { | |
1300 | + env->eflags |= VIF_MASK; | |
1301 | + if (env->eflags & VIP_MASK) { | |
1302 | + EIP = PARAM1; | |
1303 | + raise_exception(EXCP0D_GPF); | |
1304 | + } | |
1305 | + } | |
1306 | + FORCE_RET(); | |
1307 | +} | |
1308 | + | |
1309 | +void OPPROTO op_movl_eflags_T0_vm(void) | |
1310 | +{ | |
1311 | + int eflags; | |
1312 | + eflags = T0; | |
1313 | + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); | |
1314 | + DF = 1 - (2 * ((eflags >> 10) & 1)); | |
1315 | + /* we also update some system flags as in user mode */ | |
1316 | + env->eflags = (env->eflags & ~(FL_UPDATE_MASK32 | VIF_MASK)) | | |
1317 | + (eflags & FL_UPDATE_MASK32); | |
1318 | + if (eflags & IF_MASK) { | |
1319 | + env->eflags |= VIF_MASK; | |
1320 | + if (env->eflags & VIP_MASK) { | |
1321 | + EIP = PARAM1; | |
1322 | + raise_exception(EXCP0D_GPF); | |
1323 | + } | |
1324 | + } | |
1325 | + FORCE_RET(); | |
1247 | 1326 | } |
1248 | 1327 | |
1249 | 1328 | /* XXX: compute only O flag */ |
... | ... | @@ -1263,6 +1342,18 @@ void OPPROTO op_movl_T0_eflags(void) |
1263 | 1342 | T0 = eflags; |
1264 | 1343 | } |
1265 | 1344 | |
1345 | +/* vm86 version */ | |
1346 | +void OPPROTO op_movl_T0_eflags_vm(void) | |
1347 | +{ | |
1348 | + int eflags; | |
1349 | + eflags = cc_table[CC_OP].compute_all(); | |
1350 | + eflags |= (DF & DF_MASK); | |
1351 | + eflags |= env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); | |
1352 | + if (env->eflags & VIF_MASK) | |
1353 | + eflags |= IF_MASK; | |
1354 | + T0 = eflags; | |
1355 | +} | |
1356 | + | |
1266 | 1357 | void OPPROTO op_cld(void) |
1267 | 1358 | { |
1268 | 1359 | DF = 1; |
... | ... | @@ -1377,7 +1468,9 @@ CCTable cc_table[CC_OP_NB] = { |
1377 | 1468 | [CC_OP_SARL] = { compute_all_sarl, compute_c_shll }, |
1378 | 1469 | }; |
1379 | 1470 | |
1380 | -/* floating point support */ | |
1471 | +/* floating point support. Some of the code for complicated x87 | |
1472 | + functions comes from the LGPL'ed x86 emulator found in the Willows | |
1473 | + TWIN windows emulator. */ | |
1381 | 1474 | |
1382 | 1475 | #ifdef USE_X86LDOUBLE |
1383 | 1476 | /* use long double functions */ | ... | ... |
opc-i386.h
... | ... | @@ -232,6 +232,10 @@ DEF(jmp_im, 1) |
232 | 232 | DEF(int_im, 1) |
233 | 233 | DEF(int3, 1) |
234 | 234 | DEF(into, 0) |
235 | +DEF(cli, 0) | |
236 | +DEF(sti, 0) | |
237 | +DEF(cli_vm, 0) | |
238 | +DEF(sti_vm, 1) | |
235 | 239 | DEF(boundw, 0) |
236 | 240 | DEF(boundl, 0) |
237 | 241 | DEF(cmpxchg8b, 0) |
... | ... | @@ -551,8 +555,12 @@ DEF(setle_T0_cc, 0) |
551 | 555 | DEF(xor_T0_1, 0) |
552 | 556 | DEF(set_cc_op, 1) |
553 | 557 | DEF(movl_eflags_T0, 0) |
558 | +DEF(movw_eflags_T0, 0) | |
559 | +DEF(movw_eflags_T0_vm, 1) | |
560 | +DEF(movl_eflags_T0_vm, 1) | |
554 | 561 | DEF(movb_eflags_T0, 0) |
555 | 562 | DEF(movl_T0_eflags, 0) |
563 | +DEF(movl_T0_eflags_vm, 0) | |
556 | 564 | DEF(cld, 0) |
557 | 565 | DEF(std, 0) |
558 | 566 | DEF(clc, 0) | ... | ... |
translate-i386.c
... | ... | @@ -1919,7 +1919,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
1919 | 1919 | break; |
1920 | 1920 | case 0x1a0: /* push fs */ |
1921 | 1921 | case 0x1a8: /* push gs */ |
1922 | - gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS); | |
1922 | + gen_op_movl_T0_seg((b >> 3) & 7); | |
1923 | 1923 | gen_push_T0(s); |
1924 | 1924 | break; |
1925 | 1925 | case 0x07: /* pop es */ |
... | ... | @@ -1932,7 +1932,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
1932 | 1932 | case 0x1a1: /* pop fs */ |
1933 | 1933 | case 0x1a9: /* pop gs */ |
1934 | 1934 | gen_pop_T0(s); |
1935 | - gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS); | |
1935 | + gen_movl_seg_T0(s, (b >> 3) & 7); | |
1936 | 1936 | gen_pop_update(s); |
1937 | 1937 | break; |
1938 | 1938 | |
... | ... | @@ -2833,6 +2833,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
2833 | 2833 | s->is_jmp = 1; |
2834 | 2834 | break; |
2835 | 2835 | case 0xca: /* lret im */ |
2836 | + /* XXX: not restartable */ | |
2836 | 2837 | val = ldsw(s->pc); |
2837 | 2838 | s->pc += 2; |
2838 | 2839 | /* pop offset */ |
... | ... | @@ -2853,6 +2854,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
2853 | 2854 | s->is_jmp = 1; |
2854 | 2855 | break; |
2855 | 2856 | case 0xcb: /* lret */ |
2857 | + /* XXX: not restartable */ | |
2856 | 2858 | /* pop offset */ |
2857 | 2859 | gen_pop_T0(s); |
2858 | 2860 | if (s->dflag == 0) |
... | ... | @@ -2865,6 +2867,35 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
2865 | 2867 | gen_pop_update(s); |
2866 | 2868 | s->is_jmp = 1; |
2867 | 2869 | break; |
2870 | + case 0xcf: /* iret */ | |
2871 | + /* XXX: not restartable */ | |
2872 | + /* pop offset */ | |
2873 | + gen_pop_T0(s); | |
2874 | + if (s->dflag == 0) | |
2875 | + gen_op_andl_T0_ffff(); | |
2876 | + gen_op_jmp_T0(); | |
2877 | + gen_pop_update(s); | |
2878 | + /* pop selector */ | |
2879 | + gen_pop_T0(s); | |
2880 | + gen_movl_seg_T0(s, R_CS); | |
2881 | + gen_pop_update(s); | |
2882 | + /* pop eflags */ | |
2883 | + gen_pop_T0(s); | |
2884 | + if (s->dflag) { | |
2885 | + if (s->vm86) | |
2886 | + gen_op_movl_eflags_T0_vm(pc_start - s->cs_base); | |
2887 | + else | |
2888 | + gen_op_movl_eflags_T0(); | |
2889 | + } else { | |
2890 | + if (s->vm86) | |
2891 | + gen_op_movw_eflags_T0_vm(pc_start - s->cs_base); | |
2892 | + else | |
2893 | + gen_op_movw_eflags_T0(); | |
2894 | + } | |
2895 | + gen_pop_update(s); | |
2896 | + s->cc_op = CC_OP_EFLAGS; | |
2897 | + s->is_jmp = 1; | |
2898 | + break; | |
2868 | 2899 | case 0xe8: /* call im */ |
2869 | 2900 | { |
2870 | 2901 | unsigned int next_eip; |
... | ... | @@ -2978,12 +3009,25 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
2978 | 3009 | case 0x9c: /* pushf */ |
2979 | 3010 | if (s->cc_op != CC_OP_DYNAMIC) |
2980 | 3011 | gen_op_set_cc_op(s->cc_op); |
2981 | - gen_op_movl_T0_eflags(); | |
3012 | + if (s->vm86) | |
3013 | + gen_op_movl_T0_eflags_vm(); | |
3014 | + else | |
3015 | + gen_op_movl_T0_eflags(); | |
2982 | 3016 | gen_push_T0(s); |
2983 | 3017 | break; |
2984 | 3018 | case 0x9d: /* popf */ |
2985 | 3019 | gen_pop_T0(s); |
2986 | - gen_op_movl_eflags_T0(); | |
3020 | + if (s->dflag) { | |
3021 | + if (s->vm86) | |
3022 | + gen_op_movl_eflags_T0_vm(pc_start - s->cs_base); | |
3023 | + else | |
3024 | + gen_op_movl_eflags_T0(); | |
3025 | + } else { | |
3026 | + if (s->vm86) | |
3027 | + gen_op_movw_eflags_T0_vm(pc_start - s->cs_base); | |
3028 | + else | |
3029 | + gen_op_movw_eflags_T0(); | |
3030 | + } | |
2987 | 3031 | gen_pop_update(s); |
2988 | 3032 | s->cc_op = CC_OP_EFLAGS; |
2989 | 3033 | break; |
... | ... | @@ -3159,6 +3203,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
3159 | 3203 | gen_op_set_cc_op(s->cc_op); |
3160 | 3204 | gen_op_into(); |
3161 | 3205 | break; |
3206 | + case 0xfa: /* cli */ | |
3207 | + if (s->vm86) | |
3208 | + gen_op_cli_vm(); | |
3209 | + else | |
3210 | + gen_op_cli(); | |
3211 | + break; | |
3212 | + case 0xfb: /* sti */ | |
3213 | + if (s->vm86) | |
3214 | + gen_op_sti_vm(pc_start - s->cs_base); | |
3215 | + else | |
3216 | + gen_op_sti(); | |
3217 | + break; | |
3162 | 3218 | case 0x62: /* bound */ |
3163 | 3219 | ot = dflag ? OT_LONG : OT_WORD; |
3164 | 3220 | modrm = ldub(s->pc++); |
... | ... | @@ -3308,6 +3364,7 @@ static uint16_t opc_read_flags[NB_OPS] = { |
3308 | 3364 | [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z, |
3309 | 3365 | |
3310 | 3366 | [INDEX_op_movl_T0_eflags] = CC_OSZAPC, |
3367 | + [INDEX_op_movl_T0_eflags_vm] = CC_OSZAPC, | |
3311 | 3368 | [INDEX_op_cmc] = CC_C, |
3312 | 3369 | [INDEX_op_salc] = CC_C, |
3313 | 3370 | |
... | ... | @@ -3356,7 +3413,10 @@ static uint16_t opc_write_flags[NB_OPS] = { |
3356 | 3413 | [INDEX_op_daa] = CC_OSZAPC, |
3357 | 3414 | |
3358 | 3415 | [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, |
3416 | + [INDEX_op_movw_eflags_T0] = CC_OSZAPC, | |
3417 | + [INDEX_op_movw_eflags_T0_vm] = CC_OSZAPC, | |
3359 | 3418 | [INDEX_op_movl_eflags_T0] = CC_OSZAPC, |
3419 | + [INDEX_op_movl_eflags_T0_vm] = CC_OSZAPC, | |
3360 | 3420 | [INDEX_op_clc] = CC_C, |
3361 | 3421 | [INDEX_op_stc] = CC_C, |
3362 | 3422 | [INDEX_op_cmc] = CC_C, | ... | ... |