/*--- * 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); } }
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); } }
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); } }
/* * 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); }
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); }
/* * 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(); }
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(); }
/* * 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(); }
/*--- * 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); } }
/*--- * 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); }
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)); }