Commit 8145122b0862ff307ebb4c50ffd0207c675685dc
1 parent
7399c5a9
correct NT flag behavior - zero ldt task switch bug fix - task switch thru call insn bug fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@586 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
47 additions
and
24 deletions
target-i386/helper.c
| ... | ... | @@ -21,6 +21,14 @@ |
| 21 | 21 | |
| 22 | 22 | //#define DEBUG_PCALL |
| 23 | 23 | |
| 24 | +#if 0 | |
| 25 | +#define raise_exception_err(a, b)\ | |
| 26 | +do {\ | |
| 27 | + printf("raise_exception line=%d\n", __LINE__);\ | |
| 28 | + (raise_exception_err)(a, b);\ | |
| 29 | +} while (0) | |
| 30 | +#endif | |
| 31 | + | |
| 24 | 32 | const uint8_t parity_table[256] = { |
| 25 | 33 | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
| 26 | 34 | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
| ... | ... | @@ -424,7 +432,7 @@ static void switch_tss(int tss_selector, |
| 424 | 432 | possible exception */ |
| 425 | 433 | env->eip = new_eip; |
| 426 | 434 | eflags_mask = TF_MASK | AC_MASK | ID_MASK | |
| 427 | - IF_MASK | IOPL_MASK | VM_MASK | RF_MASK; | |
| 435 | + IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK; | |
| 428 | 436 | if (!(type & 8)) |
| 429 | 437 | eflags_mask &= 0xffff; |
| 430 | 438 | load_eflags(new_eflags, eflags_mask); |
| ... | ... | @@ -452,18 +460,20 @@ static void switch_tss(int tss_selector, |
| 452 | 460 | if (new_ldt & 4) |
| 453 | 461 | raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); |
| 454 | 462 | |
| 455 | - dt = &env->gdt; | |
| 456 | - index = new_ldt & ~7; | |
| 457 | - if ((index + 7) > dt->limit) | |
| 458 | - raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); | |
| 459 | - ptr = dt->base + index; | |
| 460 | - e1 = ldl_kernel(ptr); | |
| 461 | - e2 = ldl_kernel(ptr + 4); | |
| 462 | - if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) | |
| 463 | - raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); | |
| 464 | - if (!(e2 & DESC_P_MASK)) | |
| 465 | - raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); | |
| 466 | - load_seg_cache_raw_dt(&env->ldt, e1, e2); | |
| 463 | + if ((new_ldt & 0xfffc) != 0) { | |
| 464 | + dt = &env->gdt; | |
| 465 | + index = new_ldt & ~7; | |
| 466 | + if ((index + 7) > dt->limit) | |
| 467 | + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); | |
| 468 | + ptr = dt->base + index; | |
| 469 | + e1 = ldl_kernel(ptr); | |
| 470 | + e2 = ldl_kernel(ptr + 4); | |
| 471 | + if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) | |
| 472 | + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); | |
| 473 | + if (!(e2 & DESC_P_MASK)) | |
| 474 | + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc); | |
| 475 | + load_seg_cache_raw_dt(&env->ldt, e1, e2); | |
| 476 | + } | |
| 467 | 477 | |
| 468 | 478 | /* load the segments */ |
| 469 | 479 | if (!(new_eflags & VM_MASK)) { |
| ... | ... | @@ -748,6 +758,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, |
| 748 | 758 | if (env->eflags & VM_MASK) { |
| 749 | 759 | /* XXX: explain me why W2K hangs if the whole segment cache is |
| 750 | 760 | reset ? */ |
| 761 | +#if 1 | |
| 751 | 762 | env->segs[R_ES].selector = 0; |
| 752 | 763 | env->segs[R_ES].flags = 0; |
| 753 | 764 | env->segs[R_DS].selector = 0; |
| ... | ... | @@ -756,6 +767,12 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, |
| 756 | 767 | env->segs[R_FS].flags = 0; |
| 757 | 768 | env->segs[R_GS].selector = 0; |
| 758 | 769 | env->segs[R_GS].flags = 0; |
| 770 | +#else | |
| 771 | + cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0, 0); | |
| 772 | + cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0, 0); | |
| 773 | + cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0, 0); | |
| 774 | + cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0, 0); | |
| 775 | +#endif | |
| 759 | 776 | } |
| 760 | 777 | ss = (ss & ~3) | dpl; |
| 761 | 778 | cpu_x86_load_seg_cache(env, R_SS, ss, |
| ... | ... | @@ -853,13 +870,19 @@ void do_interrupt(int intno, int is_int, int error_code, |
| 853 | 870 | { |
| 854 | 871 | extern FILE *stdout; |
| 855 | 872 | static int count; |
| 856 | - if ((env->cr[0] && CR0_PE_MASK)) { | |
| 857 | - fprintf(stdout, "%d: interrupt: vector=%02x error_code=%04x int=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x EAX=%08x\n", | |
| 873 | + if (env->cr[0] & CR0_PE_MASK) { | |
| 874 | + fprintf(stdout, "%d: v=%02x e=%04x i=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x", | |
| 858 | 875 | count, intno, error_code, is_int, |
| 859 | 876 | env->hflags & HF_CPL_MASK, |
| 860 | 877 | env->segs[R_CS].selector, EIP, |
| 861 | - env->segs[R_SS].selector, ESP, | |
| 862 | - EAX); | |
| 878 | + env->segs[R_SS].selector, ESP); | |
| 879 | + if (intno == 0x0e) { | |
| 880 | + fprintf(stdout, " CR2=%08x", env->cr[2]); | |
| 881 | + } else { | |
| 882 | + fprintf(stdout, " EAX=%08x", env->regs[R_EAX]); | |
| 883 | + } | |
| 884 | + fprintf(stdout, "\n"); | |
| 885 | + | |
| 863 | 886 | if (0) { |
| 864 | 887 | cpu_x86_dump_state(env, stdout, X86_DUMP_CCOP); |
| 865 | 888 | #if 0 |
| ... | ... | @@ -879,7 +902,6 @@ void do_interrupt(int intno, int is_int, int error_code, |
| 879 | 902 | } |
| 880 | 903 | } |
| 881 | 904 | #endif |
| 882 | - | |
| 883 | 905 | #ifdef DEBUG_PCALL |
| 884 | 906 | if (loglevel) { |
| 885 | 907 | static int count; |
| ... | ... | @@ -925,7 +947,8 @@ void raise_interrupt(int intno, int is_int, int error_code, |
| 925 | 947 | } |
| 926 | 948 | |
| 927 | 949 | /* shortcuts to generate exceptions */ |
| 928 | -void raise_exception_err(int exception_index, int error_code) | |
| 950 | + | |
| 951 | +void (raise_exception_err)(int exception_index, int error_code) | |
| 929 | 952 | { |
| 930 | 953 | raise_interrupt(exception_index, 0, error_code, 0); |
| 931 | 954 | } |
| ... | ... | @@ -1409,7 +1432,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) |
| 1409 | 1432 | if (dpl < cpl || dpl < rpl) |
| 1410 | 1433 | raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
| 1411 | 1434 | switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL); |
| 1412 | - break; | |
| 1435 | + return; | |
| 1413 | 1436 | case 4: /* 286 call gate */ |
| 1414 | 1437 | case 12: /* 386 call gate */ |
| 1415 | 1438 | break; |
| ... | ... | @@ -1551,9 +1574,9 @@ void helper_iret_real(int shift) |
| 1551 | 1574 | load_seg_vm(R_CS, new_cs); |
| 1552 | 1575 | env->eip = new_eip; |
| 1553 | 1576 | if (env->eflags & VM_MASK) |
| 1554 | - eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK; | |
| 1577 | + eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK; | |
| 1555 | 1578 | else |
| 1556 | - eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK; | |
| 1579 | + eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK; | |
| 1557 | 1580 | if (shift == 0) |
| 1558 | 1581 | eflags_mask &= 0xffff; |
| 1559 | 1582 | load_eflags(new_eflags, eflags_mask); |
| ... | ... | @@ -1688,7 +1711,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) |
| 1688 | 1711 | env->eip = new_eip; |
| 1689 | 1712 | if (is_iret) { |
| 1690 | 1713 | /* NOTE: 'cpl' is the _old_ CPL */ |
| 1691 | - eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK; | |
| 1714 | + eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK; | |
| 1692 | 1715 | if (cpl == 0) |
| 1693 | 1716 | eflags_mask |= IOPL_MASK; |
| 1694 | 1717 | iopl = (env->eflags >> IOPL_SHIFT) & 3; |
| ... | ... | @@ -1710,7 +1733,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) |
| 1710 | 1733 | |
| 1711 | 1734 | /* modify processor state */ |
| 1712 | 1735 | load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | |
| 1713 | - IF_MASK | IOPL_MASK | VM_MASK | VIF_MASK | VIP_MASK); | |
| 1736 | + IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK); | |
| 1714 | 1737 | load_seg_vm(R_CS, new_cs & 0xffff); |
| 1715 | 1738 | cpu_x86_set_cpl(env, 3); |
| 1716 | 1739 | load_seg_vm(R_SS, new_ss & 0xffff); | ... | ... |