Commit 8145122b0862ff307ebb4c50ffd0207c675685dc

Authored by bellard
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);
... ...