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, | ... | ... |