Esempio n. 1
0
/*---
 * CALLfar_pm: call gate (SAME-PRIVILEGE)
 */
static void
CALLfar_pm_call_gate_same_privilege(const selector_t *callgate_sel, selector_t *cs_sel)
{
    UINT32 sp;

    VERBOSE(("CALLfar_pm: SAME-PRIVILEGE"));

    if (CPU_STAT_SS32) {
        sp = CPU_ESP;
    } else {
        sp = CPU_SP;
    }

    if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) {
        STACK_PUSH_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 8);

        PUSH0_32(CPU_CS);
        PUSH0_32(CPU_EIP);

        load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL);
        SET_EIP(callgate_sel->desc.u.gate.offset);
    } else {
        STACK_PUSH_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 4);

        PUSH0_16(CPU_CS);
        PUSH0_16(CPU_IP);

        load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL);
        SET_EIP(callgate_sel->desc.u.gate.offset);
    }
}
Esempio n. 2
0
void
CALL16_Ap(void)
{
	descriptor_t sd;
	UINT16 new_ip;
	UINT16 new_cs;
	UINT16 sreg;

	CPU_WORKCLOCK(13);
	GET_PCWORD(new_ip);
	GET_PCWORD(new_cs);
	if (!CPU_STAT_PM || CPU_STAT_VM86) {
		/* Real mode or VM86 mode */
		CPU_SET_PREV_ESP();
		load_segreg(CPU_CS_INDEX, new_cs, &sreg, &sd, GP_EXCEPTION);
		if (new_ip > sd.u.seg.limit) {
			EXCEPTION(GP_EXCEPTION, 0);
		}

		PUSH0_16(CPU_CS);
		PUSH0_16(CPU_IP);

		LOAD_SEGREG(CPU_CS_INDEX, new_cs);
		CPU_EIP = new_ip;
		CPU_CLEAR_PREV_ESP();
	} else {
		/* Protected mode */
		CALLfar_pm(new_cs, new_ip);
	}
}
Esempio n. 3
0
static void CPUCALL
interrupt_task_gate(const descriptor_t *gsdp, int intrtype, int errorp, int error_code)
{
    selector_t task_sel;
    int rv;

    VERBOSE(("interrupt: TASK-GATE"));

    rv = parse_selector(&task_sel, gsdp->u.gate.selector);
    if (rv < 0 || task_sel.ldt || !SEG_IS_SYSTEM(&task_sel.desc)) {
        VERBOSE(("interrupt: parse_selector (selector = %04x, rv = %d, %cDT, type = %s)", gsdp->u.gate.selector, rv, task_sel.ldt ? 'L' : 'G', task_sel.desc.s ? "code/data" : "system"));
        EXCEPTION(TS_EXCEPTION, task_sel.idx);
    }

    /* check gate type */
    switch (task_sel.desc.type) {
    case CPU_SYSDESC_TYPE_TSS_16:
    case CPU_SYSDESC_TYPE_TSS_32:
        break;

    case CPU_SYSDESC_TYPE_TSS_BUSY_16:
    case CPU_SYSDESC_TYPE_TSS_BUSY_32:
        VERBOSE(("interrupt: task is busy."));
    /*FALLTHROUGH*/
    default:
        VERBOSE(("interrupt: invalid gate type (%d)", task_sel.desc.type));
        EXCEPTION(TS_EXCEPTION, task_sel.idx);
        break;
    }

    /* not present */
    if (selector_is_not_present(&task_sel)) {
        VERBOSE(("interrupt: selector is not present"));
        EXCEPTION(NP_EXCEPTION, task_sel.idx);
    }

    task_switch(&task_sel, TASK_SWITCH_INTR);

    CPU_SET_PREV_ESP();

    if (errorp) {
        VERBOSE(("interrupt: push error code (%08x)", error_code));
        if (task_sel.desc.type == CPU_SYSDESC_TYPE_TSS_32) {
            PUSH0_32(error_code);
        } else {
            PUSH0_16(error_code);
        }
    }

    /* out of range */
    if (CPU_EIP > CPU_STAT_CS_LIMIT) {
        VERBOSE(("interrupt: new_ip is out of range. new_ip = %08x, limit = %08x", CPU_EIP, CPU_STAT_CS_LIMIT));
        EXCEPTION(GP_EXCEPTION, 0);
    }
}
Esempio n. 4
0
/*
 * PUSHF/POPF
 */
void
PUSHF_Fw(void)
{

	CPU_WORKCLOCK(3);
	if (!CPU_STAT_PM || !CPU_STAT_VM86 || (CPU_STAT_IOPL == CPU_IOPL3)) {
		UINT16 flags = REAL_FLAGREG;
		flags = (flags & ALL_FLAG) | 2;
		PUSH0_16(flags);
		return;
	}
	/* VM86 && IOPL != 3 */
	EXCEPTION(GP_EXCEPTION, 0);
}
Esempio n. 5
0
void CPUCALL
CALL16_Ep(UINT32 op)
{
	descriptor_t sd;
	UINT32 madr;
	UINT16 new_ip;
	UINT16 new_cs;
	UINT16 sreg;

	CPU_WORKCLOCK(16);
	if (op < 0xc0) {
		madr = calc_ea_dst(op);
		new_ip = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr);
		new_cs = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr + 2);
		if (!CPU_STAT_PM || CPU_STAT_VM86) {
			/* Real mode or VM86 mode */
			CPU_SET_PREV_ESP();
			load_segreg(CPU_CS_INDEX, new_cs, &sreg, &sd, GP_EXCEPTION);
			if (new_ip > sd.u.seg.limit) {
				EXCEPTION(GP_EXCEPTION, 0);
			}

			PUSH0_16(CPU_CS);
			PUSH0_16(CPU_IP);

			LOAD_SEGREG(CPU_CS_INDEX, new_cs);
			CPU_EIP = new_ip;
			CPU_CLEAR_PREV_ESP();
		} else {
			/* Protected mode */
			CALLfar_pm(new_cs, new_ip);
		}
		return;
	} 
	EXCEPTION(UD_EXCEPTION, 0);
}
Esempio n. 6
0
/*
 * CALL
 */
void
CALL_Aw(void)
{
	UINT16 new_ip;
	SINT16 dest;

	CPU_WORKCLOCK(7);
	CPU_SET_PREV_ESP();
	GET_PCWORDS(dest);
	new_ip = CPU_EIP + dest;
	if (new_ip > CPU_STAT_CS_LIMIT) {
		EXCEPTION(GP_EXCEPTION, 0);
	}
	PUSH0_16(CPU_IP);
	CPU_EIP = new_ip;
	CPU_CLEAR_PREV_ESP();
}
Esempio n. 7
0
void CPUCALL
CALL_Ew(UINT32 op)
{
	UINT32 madr;
	UINT16 new_ip;

	CPU_SET_PREV_ESP();
	if (op >= 0xc0) {
		CPU_WORKCLOCK(7);
		new_ip = *(reg16_b20[op]);
	} else {
		CPU_WORKCLOCK(11);
		madr = calc_ea_dst(op);
		new_ip = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr);
	}
	if (new_ip > CPU_STAT_CS_LIMIT) {
		EXCEPTION(GP_EXCEPTION, 0);
	}
	PUSH0_16(CPU_IP);
	CPU_EIP = new_ip;
	CPU_CLEAR_PREV_ESP();
}
Esempio n. 8
0
/*
 * STACK
 */
void
ENTER16_IwIb(void)
{
	UINT32 sp, bp;
	UINT32 val;
	UINT16 dimsize;
	UINT16 new_bp;
	UINT8 level;

	GET_PCWORD(dimsize);
	GET_PCBYTE(level);
	level &= 0x1f;

	CPU_SET_PREV_ESP();
	PUSH0_16(CPU_BP);
	if (level == 0) {			/* enter level=0 */
		CPU_WORKCLOCK(11);
		CPU_BP = CPU_SP;
		if (!CPU_STAT_SS32) {
			CPU_SP -= dimsize;
		} else {
			CPU_ESP -= dimsize;
		}
	} else {
		--level;
		if (level == 0) {		/* enter level=1 */
			CPU_WORKCLOCK(15);
			sp = CPU_SP;
			PUSH0_16(sp);
			CPU_BP = (UINT16)sp;
			if (!CPU_STAT_SS32) {
				CPU_SP -= dimsize;
			} else {
				CPU_ESP -= dimsize;
			}
		} else {			/* enter level=2-31 */
			CPU_WORKCLOCK(12 + level * 4);
			if (!CPU_STAT_SS32) {
				bp = CPU_BP;
				new_bp = CPU_SP;
				while (level--) {
					bp -= 2;
					CPU_SP -= 2;
					val = cpu_vmemoryread_w(CPU_SS_INDEX, bp);
					cpu_vmemorywrite_w(CPU_SS_INDEX, CPU_SP, (UINT16)val);
				}
				REGPUSH0(new_bp);
				CPU_BP = new_bp;
				CPU_SP -= dimsize;
			} else {
				bp = CPU_EBP;
				new_bp = CPU_SP;
				while (level--) {
					bp -= 2;
					CPU_ESP -= 2;
					val = cpu_vmemoryread_w(CPU_SS_INDEX, bp);
					cpu_vmemorywrite_w(CPU_SS_INDEX, CPU_ESP, (UINT16)val);
				}
				REGPUSH0_16_32(new_bp);
				CPU_BP = new_bp;
				CPU_ESP -= dimsize;
			}
		}
	}
	CPU_CLEAR_PREV_ESP();
}
Esempio n. 9
0
/*---
 * CALLfar_pm: call gate (MORE-PRIVILEGE)
 */
static void
CALLfar_pm_call_gate_more_privilege(const selector_t *callgate_sel, selector_t *cs_sel)
{
    UINT32 param[32];	/* copy param */
    selector_t ss_sel;
    UINT32 old_eip, old_esp;
    UINT32 new_esp;
    UINT16 old_cs, old_ss;
    UINT16 new_ss;
    int param_count;
    int i;
    int rv;

    VERBOSE(("CALLfar_pm: MORE-PRIVILEGE"));

    /* save register */
    old_cs = CPU_CS;
    old_ss = CPU_SS;
    old_eip = CPU_EIP;
    old_esp = CPU_ESP;
    if (!CPU_STAT_SS32) {
        old_esp &= 0xffff;
    }

    /* get stack pointer from TSS */
    get_stack_pointer_from_tss(cs_sel->desc.dpl, &new_ss, &new_esp);

    /* parse stack segment descriptor */
    rv = parse_selector(&ss_sel, new_ss);
    if (rv < 0) {
        VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", new_ss, rv));
        EXCEPTION(TS_EXCEPTION, ss_sel.idx);
    }

    /* check privilege level */
    if (ss_sel.rpl != cs_sel->desc.dpl) {
        VERBOSE(("CALLfar_pm: RPL[SS](%d) != DPL[CS](%d)", ss_sel.rpl, cs_sel->desc.dpl));
        EXCEPTION(TS_EXCEPTION, ss_sel.idx);
    }
    if (ss_sel.desc.dpl != cs_sel->desc.dpl) {
        VERBOSE(("CALLfar_pm: DPL[SS](%d) != DPL[CS](%d)", ss_sel.desc.dpl, cs_sel->desc.dpl));
        EXCEPTION(TS_EXCEPTION, ss_sel.idx);
    }

    /* stack segment must be writable data segment. */
    if (!ss_sel.desc.s) {
        VERBOSE(("CALLfar_pm: stack segment is system segment"));
        EXCEPTION(TS_EXCEPTION, ss_sel.idx);
    }
    if (ss_sel.desc.u.seg.c) {
        VERBOSE(("CALLfar_pm: stack segment is code segment"));
        EXCEPTION(TS_EXCEPTION, ss_sel.idx);
    }
    if (!ss_sel.desc.u.seg.wr) {
        VERBOSE(("CALLfar_pm: stack segment is read-only data segment"));
        EXCEPTION(TS_EXCEPTION, ss_sel.idx);
    }

    /* not present */
    if (selector_is_not_present(&ss_sel)) {
        VERBOSE(("CALLfar_pm: stack segment selector is not present"));
        EXCEPTION(SS_EXCEPTION, ss_sel.idx);
    }

    param_count = callgate_sel->desc.u.gate.count;
    VERBOSE(("CALLfar_pm: param_count = %d", param_count));

    if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) {
        STACK_PUSH_CHECK(ss_sel.idx, &ss_sel.desc, new_esp, 16 + param_count * 4);

        /* dump param */
        for (i = 0; i < param_count; i++) {
            param[i] = cpu_vmemoryread_d(CPU_SS_INDEX, old_esp + i * 4);
            VERBOSE(("CALLfar_pm: get param[%d] = %08x", i, param[i]));
        }

        load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl);
        if (CPU_STAT_SS32) {
            CPU_ESP = new_esp;
        } else {
            CPU_SP = (UINT16)new_esp;
        }

        load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl);
        SET_EIP(callgate_sel->desc.u.gate.offset);

        PUSH0_32(old_ss);
        PUSH0_32(old_esp);

        /* restore param */
        for (i = param_count; i > 0; i--) {
            PUSH0_32(param[i - 1]);
            VERBOSE(("CALLfar_pm: set param[%d] = %08x", i - 1, param[i - 1]));
        }

        PUSH0_32(old_cs);
        PUSH0_32(old_eip);
    } else {
        STACK_PUSH_CHECK(ss_sel.idx, &ss_sel.desc, new_esp, 8 + param_count * 2);

        /* dump param */
        for (i = 0; i < param_count; i++) {
            param[i] = cpu_vmemoryread_w(CPU_SS_INDEX, old_esp + i * 2);
            VERBOSE(("CALLfar_pm: get param[%d] = %04x", i, param[i]));
        }

        load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl);
        if (CPU_STAT_SS32) {
            CPU_ESP = new_esp;
        } else {
            CPU_SP = (UINT16)new_esp;
        }

        load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl);
        SET_EIP(callgate_sel->desc.u.gate.offset);

        PUSH0_16(old_ss);
        PUSH0_16(old_esp);

        /* restore param */
        for (i = param_count; i > 0; i--) {
            PUSH0_16(param[i - 1]);
            VERBOSE(("CALLfar_pm: set param[%d] = %04x", i - 1, param[i - 1]));
        }

        PUSH0_16(old_cs);
        PUSH0_16(old_eip);
    }
}
Esempio n. 10
0
/*---
 * CALLfar_pm: code segment
 */
static void
CALLfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip)
{
    UINT32 sp;

    VERBOSE(("CALLfar_pm: CODE-SEGMENT"));

    /* check privilege level */
    if (!cs_sel->desc.u.seg.ec) {
        VERBOSE(("CALLfar_pm: NON-CONFORMING-CODE-SEGMENT"));
        /* 下巻 p.119 4.8.1.1. */
        if (cs_sel->rpl > CPU_STAT_CPL) {
            VERBOSE(("CALLfar_pm: RPL(%d) > CPL(%d)", cs_sel->rpl, CPU_STAT_CPL));
            EXCEPTION(GP_EXCEPTION, cs_sel->idx);
        }
        if (cs_sel->desc.dpl != CPU_STAT_CPL) {
            VERBOSE(("CALLfar_pm: DPL(%d) != CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL));
            EXCEPTION(GP_EXCEPTION, cs_sel->idx);
        }
    } else {
        VERBOSE(("CALLfar_pm: CONFORMING-CODE-SEGMENT"));
        /* 下巻 p.120 4.8.1.2. */
        if (cs_sel->desc.dpl > CPU_STAT_CPL) {
            VERBOSE(("CALLfar_pm: DPL(%d) > CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL));
            EXCEPTION(GP_EXCEPTION, cs_sel->idx);
        }
    }

    /* not present */
    if (selector_is_not_present(cs_sel)) {
        VERBOSE(("CALLfar_pm: selector is not present"));
        EXCEPTION(NP_EXCEPTION, cs_sel->idx);
    }

    if (CPU_STAT_SS32) {
        sp = CPU_ESP;
    } else {
        sp = CPU_SP;
    }
    if (CPU_INST_OP32) {
        STACK_PUSH_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 8);

        /* out of range */
        if (new_ip > cs_sel->desc.u.seg.limit) {
            VERBOSE(("CALLfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit));
            EXCEPTION(GP_EXCEPTION, 0);
        }

        PUSH0_32(CPU_CS);
        PUSH0_32(CPU_EIP);
    } else {
        STACK_PUSH_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 4);

        /* out of range */
        if (new_ip > cs_sel->desc.u.seg.limit) {
            VERBOSE(("CALLfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit));
            EXCEPTION(GP_EXCEPTION, 0);
        }

        PUSH0_16(CPU_CS);
        PUSH0_16(CPU_IP);
    }

    load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL);
    SET_EIP(new_ip);
}
Esempio n. 11
0
static void CPUCALL
interrupt_intr_or_trap(const descriptor_t *gsdp, int intrtype, int errorp, int error_code)
{
    selector_t cs_sel, ss_sel;
    UINT stacksize;
    UINT32 old_flags;
    UINT32 new_flags;
    UINT32 mask;
    UINT32 sp;
    UINT32 new_ip, new_sp;
    UINT32 old_ip, old_sp;
    UINT16 old_cs, old_ss, new_ss;
    BOOL is32bit;
    int exc_errcode;
    int rv;

    new_ip = gsdp->u.gate.offset;
    old_ss = CPU_SS;
    old_cs = CPU_CS;
    old_ip = CPU_EIP;
    old_sp = CPU_ESP;
    old_flags = REAL_EFLAGREG;
    new_flags = REAL_EFLAGREG & ~(T_FLAG|RF_FLAG|NT_FLAG|VM_FLAG);
    mask = T_FLAG|RF_FLAG|NT_FLAG|VM_FLAG;

    switch (gsdp->type) {
    case CPU_SYSDESC_TYPE_INTR_16:
    case CPU_SYSDESC_TYPE_INTR_32:
        VERBOSE(("interrupt: INTERRUPT-GATE"));
        new_flags &= ~I_FLAG;
        mask |= I_FLAG;
        break;

    case CPU_SYSDESC_TYPE_TRAP_16:
    case CPU_SYSDESC_TYPE_TRAP_32:
        VERBOSE(("interrupt: TRAP-GATE"));
        break;

    default:
        ia32_panic("interrupt: gate descriptor type is invalid (type = %d)", gsdp->type);
        break;
    }

    exc_errcode = gsdp->u.gate.selector & ~3;
    if (intrtype == INTR_TYPE_EXTINTR)
        exc_errcode++;

    rv = parse_selector(&cs_sel, gsdp->u.gate.selector);
    if (rv < 0) {
        VERBOSE(("interrupt: parse_selector (selector = %04x, rv = %d)", gsdp->u.gate.selector, rv));
        EXCEPTION(GP_EXCEPTION, exc_errcode);
    }

    /* check segment type */
    if (SEG_IS_SYSTEM(&cs_sel.desc)) {
        VERBOSE(("interrupt: code segment is system segment"));
        EXCEPTION(GP_EXCEPTION, exc_errcode);
    }
    if (SEG_IS_DATA(&cs_sel.desc)) {
        VERBOSE(("interrupt: code segment is data segment"));
        EXCEPTION(GP_EXCEPTION, exc_errcode);
    }

    /* check privilege level */
    if (cs_sel.desc.dpl > CPU_STAT_CPL) {
        VERBOSE(("interrupt: DPL(%d) > CPL(%d)", cs_sel.desc.dpl, CPU_STAT_CPL));
        EXCEPTION(GP_EXCEPTION, exc_errcode);
    }

    /* not present */
    if (selector_is_not_present(&cs_sel)) {
        VERBOSE(("interrupt: selector is not present"));
        EXCEPTION(NP_EXCEPTION, exc_errcode);
    }

    is32bit = gsdp->type & CPU_SYSDESC_TYPE_32BIT;
    if (!SEG_IS_CONFORMING_CODE(&cs_sel.desc) && (cs_sel.desc.dpl < CPU_STAT_CPL)) {
        stacksize = errorp ? 12 : 10;
        if (!CPU_STAT_VM86) {
            VERBOSE(("interrupt: INTER-PRIVILEGE-LEVEL-INTERRUPT"));
        } else {
            /* VM86 */
            VERBOSE(("interrupt: INTERRUPT-FROM-VIRTUAL-8086-MODE"));
            if (cs_sel.desc.dpl != 0) {
                /* 16.3.1.1 */
                VERBOSE(("interrupt: DPL[CS](%d) != 0", cs_sel.desc.dpl));
                EXCEPTION(GP_EXCEPTION, exc_errcode);
            }
            stacksize += 8;
        }
        if (is32bit) {
            stacksize *= 2;
        }

        /* get stack pointer from TSS */
        get_stack_pointer_from_tss(cs_sel.desc.dpl, &new_ss, &new_sp);

        /* parse stack segment descriptor */
        rv = parse_selector(&ss_sel, new_ss);

        /* update exception error code */
        exc_errcode = ss_sel.idx;
        if (intrtype == INTR_TYPE_EXTINTR)
            exc_errcode++;

        if (rv < 0) {
            VERBOSE(("interrupt: parse_selector (selector = %04x, rv = %d)", new_ss, rv));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }

        /* check privilege level */
        if (ss_sel.rpl != cs_sel.desc.dpl) {
            VERBOSE(("interrupt: selector RPL[SS](%d) != DPL[CS](%d)", ss_sel.rpl, cs_sel.desc.dpl));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }
        if (ss_sel.desc.dpl != cs_sel.desc.dpl) {
            VERBOSE(("interrupt: descriptor DPL[SS](%d) != DPL[CS](%d)", ss_sel.desc.dpl, cs_sel.desc.dpl));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }

        /* stack segment must be writable data segment. */
        if (SEG_IS_SYSTEM(&ss_sel.desc)) {
            VERBOSE(("interrupt: stack segment is system segment"));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }
        if (SEG_IS_CODE(&ss_sel.desc)) {
            VERBOSE(("interrupt: stack segment is code segment"));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }
        if (!SEG_IS_WRITABLE_DATA(&ss_sel.desc)) {
            VERBOSE(("interrupt: stack segment is read-only data segment"));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }

        /* not present */
        if (selector_is_not_present(&ss_sel)) {
            VERBOSE(("interrupt: selector is not present"));
            EXCEPTION(SS_EXCEPTION, exc_errcode);
        }

        /* check stack room size */
        cpu_stack_push_check(ss_sel.idx, &ss_sel.desc, new_sp, stacksize, ss_sel.desc.d);

        /* out of range */
        if (new_ip > cs_sel.desc.u.seg.limit) {
            VERBOSE(("interrupt: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit));
            EXCEPTION(GP_EXCEPTION, 0);
        }

        load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.desc.dpl);
        CPU_ESP = new_sp;

        load_cs(cs_sel.selector, &cs_sel.desc, cs_sel.desc.dpl);
        CPU_EIP = new_ip;

        if (is32bit) {
            if (CPU_STAT_VM86) {
                PUSH0_32(CPU_GS);
                PUSH0_32(CPU_FS);
                PUSH0_32(CPU_DS);
                PUSH0_32(CPU_ES);

                LOAD_SEGREG(CPU_GS_INDEX, 0);
                CPU_STAT_SREG(CPU_GS_INDEX).valid = 0;
                LOAD_SEGREG(CPU_FS_INDEX, 0);
                CPU_STAT_SREG(CPU_FS_INDEX).valid = 0;
                LOAD_SEGREG(CPU_DS_INDEX, 0);
                CPU_STAT_SREG(CPU_DS_INDEX).valid = 0;
                LOAD_SEGREG(CPU_ES_INDEX, 0);
                CPU_STAT_SREG(CPU_ES_INDEX).valid = 0;
            }
            PUSH0_32(old_ss);
            PUSH0_32(old_sp);
            PUSH0_32(old_flags);
            PUSH0_32(old_cs);
            PUSH0_32(old_ip);
            if (errorp) {
                PUSH0_32(error_code);
            }
        } else {
            if (CPU_STAT_VM86) {
                ia32_panic("interrupt: 16bit gate && VM86");
            }
            PUSH0_16(old_ss);
            PUSH0_16(old_sp);
            PUSH0_16(old_flags);
            PUSH0_16(old_cs);
            PUSH0_16(old_ip);
            if (errorp) {
                PUSH0_16(error_code);
            }
        }
    } else {
        if (CPU_STAT_VM86) {
            VERBOSE(("interrupt: VM86"));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }
        if (!SEG_IS_CONFORMING_CODE(&cs_sel.desc) && (cs_sel.desc.dpl != CPU_STAT_CPL)) {
            VERBOSE(("interrupt: %sCONFORMING-CODE-SEGMENT(%d) && DPL[CS](%d) != CPL", SEG_IS_CONFORMING_CODE(&cs_sel.desc) ? "" : "NON-", cs_sel.desc.dpl, CPU_STAT_CPL));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }

        VERBOSE(("interrupt: INTRA-PRIVILEGE-LEVEL-INTERRUPT"));

        stacksize = errorp ? 8 : 6;
        if (is32bit) {
            stacksize *= 2;
        }

        /* check stack room size */
        if (CPU_STAT_SS32) {
            sp = CPU_ESP;
        } else {
            sp = CPU_SP;
        }
        /*
         * 17.1
         * コールゲート、割り込みゲート、またはトラップゲートを通じて
         * プログラムの制御を他のコード・セグメントに移行するときは、
         * 移行中に使用されるオペランド・サイズは使用されるゲートの
         * タイプ(16 ビットまたは32 ビット)によって決まる(移行命
         * 令のD フラグ、プリフィックスのいずれにもよらない)。
         */
        SS_PUSH_CHECK1(sp, stacksize, is32bit);

        /* out of range */
        if (new_ip > cs_sel.desc.u.seg.limit) {
            VERBOSE(("interrupt: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit));
            EXCEPTION(GP_EXCEPTION, 0);
        }

        load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL);
        CPU_EIP = new_ip;

        if (is32bit) {
            PUSH0_32(old_flags);
            PUSH0_32(old_cs);
            PUSH0_32(old_ip);
            if (errorp) {
                PUSH0_32(error_code);
            }
        } else {
            PUSH0_16(old_flags);
            PUSH0_16(old_cs);
            PUSH0_16(old_ip);
            if (errorp) {
                PUSH0_16(error_code);
            }
        }
    }
    set_eflags(new_flags, mask);

    VERBOSE(("interrupt: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP));
}