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); | ... | ... |