Index: helper.c =================================================================== RCS file: /sources/qemu/qemu/target-i386/helper.c,v retrieving revision 1.74 diff -u -r1.74 helper.c --- helper.c 1 Feb 2007 22:12:19 -0000 1.74 +++ helper.c 27 Mar 2007 11:33:34 -0000 @@ -592,6 +592,16 @@ sp += 4;\ } +void +raise_gpf(int intno, int is_int, int is_hw, int error) +{ + if (!is_int && !is_hw && intno == EXCP0D_GPF) + raise_exception_err(EXCP08_DBLE, 0); + else + raise_exception_err(EXCP0D_GPF, error >= 0 ? error : intno * TARGET_LONG_SIZE + 2); +} + + /* protected mode interrupt */ static void do_interrupt_protected(int intno, int is_int, int error_code, unsigned int next_eip, int is_hw) @@ -624,7 +634,7 @@ dt = &env->idt; if (intno * 8 + 7 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + raise_gpf(intno, is_int, is_hw, -1); ptr = dt->base + intno * 8; e1 = ldl_kernel(ptr); e2 = ldl_kernel(ptr + 4); @@ -661,29 +671,30 @@ case 15: /* 386 trap gate */ break; default: - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + raise_gpf(intno, is_int, is_hw, -1); break; } dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; /* check privledge if software int */ if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + raise_gpf(intno, is_int, is_hw, -1); + /* check valid bit */ if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); selector = e1 >> 16; offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); if ((selector & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); + raise_gpf(intno, is_int, is_hw, 0); if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); if (!(e2 & DESC_C_MASK) && dpl < cpl) { @@ -710,14 +721,14 @@ } else if ((e2 & DESC_C_MASK) || dpl == cpl) { /* to same priviledge */ if (env->eflags & VM_MASK) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); new_stack = 0; sp_mask = get_sp_mask(env->segs[R_SS].flags); ssp = env->segs[R_SS].base; esp = ESP; dpl = cpl; } else { - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); new_stack = 0; /* avoid warning */ sp_mask = 0; /* avoid warning */ ssp = 0; /* avoid warning */ @@ -860,7 +871,7 @@ dt = &env->idt; if (intno * 16 + 15 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 16 + 2); + raise_gpf(intno, is_int, is_hw, -1); ptr = dt->base + intno * 16; e1 = ldl_kernel(ptr); e2 = ldl_kernel(ptr + 4); @@ -872,14 +883,13 @@ case 15: /* 386 trap gate */ break; default: - raise_exception_err(EXCP0D_GPF, intno * 16 + 2); - break; + raise_gpf(intno, is_int, is_hw, -1); } dpl = (e2 >> DESC_DPL_SHIFT) & 3; cpl = env->hflags & HF_CPL_MASK; /* check privledge if software int */ if (is_int && dpl < cpl) - raise_exception_err(EXCP0D_GPF, intno * 16 + 2); + raise_gpf(intno, is_int, is_hw, -1); /* check valid bit */ if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2); @@ -887,19 +897,19 @@ offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); ist = e2 & 7; if ((selector & 0xfffc) == 0) - raise_exception_err(EXCP0D_GPF, 0); + raise_gpf(intno, is_int, is_hw, 0); if (load_segment(&e1, &e2, selector) != 0) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); dpl = (e2 >> DESC_DPL_SHIFT) & 3; if (dpl > cpl) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); if (!(e2 & DESC_P_MASK)) raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { /* to inner priviledge */ if (ist != 0) @@ -912,7 +922,7 @@ } else if ((e2 & DESC_C_MASK) || dpl == cpl) { /* to same priviledge */ if (env->eflags & VM_MASK) - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); new_stack = 0; if (ist != 0) esp = get_rsp_from_tss(ist + 3); @@ -921,7 +931,7 @@ esp &= ~0xfLL; /* align stack */ dpl = cpl; } else { - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); + raise_gpf(intno, is_int, is_hw, selector & 0xfffc); new_stack = 0; /* avoid warning */ esp = 0; /* avoid warning */ } @@ -1089,7 +1099,12 @@ /* real mode (simpler !) */ dt = &env->idt; if (intno * 4 + 3 > dt->limit) - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); + { + if (!is_int && intno == EXCP0D_GPF) + raise_exception_err(EXCP08_DBLE, 0); + else + raise_exception_err(EXCP0D_GPF, intno * 4 + 2); + } ptr = dt->base + intno * 4; offset = lduw_kernel(ptr); selector = lduw_kernel(ptr + 2);