/*--- * 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 IRET_pm(void) { UINT32 sp; UINT32 new_ip, new_flags; UINT16 new_cs; VERBOSE(("IRET_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); if (!(CPU_EFLAG & VM_FLAG) && (CPU_EFLAG & NT_FLAG)) { /* TASK-RETURN: PE=1, VM=0, NT=1 */ IRET_pm_nested_task(); } else { if (CPU_STAT_SS32) { sp = CPU_ESP; } else { sp = CPU_SP; } if (CPU_INST_OP32) { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 12); new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); new_flags = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8); } else { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 6); new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); new_flags = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); } VERBOSE(("IRET_pm: new_ip = %08x, new_cs = %04x, new_eflags = %08x", new_ip, new_cs, new_flags)); if (CPU_EFLAG & VM_FLAG) { /* RETURN-FROM-VIRTUAL-8086-MODE */ IRET_pm_return_from_vm86(new_cs, new_ip, new_flags); } else if (new_flags & VM_FLAG) { /* RETURN-TO-VIRTUAL-8086-MODE */ IRET_pm_return_to_vm86(new_cs, new_ip, new_flags); } else { /* PROTECTED-MODE-RETURN */ IRET_pm_protected_mode_return(new_cs, new_ip, new_flags); } } VERBOSE(("IRET_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); }
void debugsub_status(void) { static int filenum = 0; FILEH fh; OEMCHAR work[512]; const OEMCHAR *p; OEMSPRINTF(work, file_i386reg, filenum); fh = file_create_c(work); if (fh != FILEH_INVALID) { p = debugsub_regs(); file_write(fh, p, OEMSTRLEN(p) * sizeof(OEMCHAR)); OEMSPRINTF(work, str_picstat, pic.pi[0].imr, pic.pi[0].irr, pic.pi[0].isr, pic.pi[1].imr, pic.pi[1].irr, pic.pi[1].isr, mouseif.upd8255.portc, sysport.c); file_write(fh, work, OEMSTRLEN(work) * sizeof(OEMCHAR)); OEMSPRINTF(work, OEMTEXT("CS = %.8x:%.8x") OEMTEXT(CRLITERAL), CPU_STAT_SREGBASE(CPU_CS_INDEX), CPU_STAT_SREGLIMIT(CPU_CS_INDEX)); file_write(fh, work, OEMSTRLEN(work) * sizeof(OEMCHAR)); file_close(fh); } OEMSPRINTF(work, file_i386cs, filenum); debugwriteseg(work, &CPU_STAT_SREG(CPU_CS_INDEX), CPU_EIP & 0xffff0000, 0x10000); OEMSPRINTF(work, file_i386ds, filenum); debugwriteseg(work, &CPU_STAT_SREG(CPU_DS_INDEX), 0, 0x10000); OEMSPRINTF(work, file_i386es, filenum); debugwriteseg(work, &CPU_STAT_SREG(CPU_ES_INDEX), 0, 0x10000); OEMSPRINTF(work, file_i386ss, filenum); debugwriteseg(work, &CPU_STAT_SREG(CPU_SS_INDEX), CPU_ESP & 0xffff0000, 0x10000); filenum++; }
/*--- * IRET_pm: new_flags & VM_FLAG */ static void IRET_pm_return_to_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags) { UINT16 segsel[CPU_SEGREG_NUM]; UINT32 sp; UINT32 new_sp; int i; VERBOSE(("IRET_pm: Interrupt procedure was in virtual-8086 mode: PE=1, VM=1 in flags image")); if (CPU_STAT_CPL != 0) { ia32_panic("IRET_pm: CPL != 0"); } if (!CPU_INST_OP32) { ia32_panic("IRET_pm: 16bit mode"); } if (CPU_STAT_SS32) { sp = CPU_ESP; } else { sp = CPU_SP; } STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 36); new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); segsel[CPU_ES_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 20); segsel[CPU_DS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 24); segsel[CPU_FS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 28); segsel[CPU_GS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 32); segsel[CPU_CS_INDEX] = (UINT16)new_cs; for (i = 0; i < CPU_SEGREG_NUM; i++) { CPU_REGS_SREG(i) = segsel[i]; CPU_STAT_SREG_INIT(i); } /* to VM86 mode */ set_eflags(new_flags, IOPL_FLAG|I_FLAG|VM_FLAG|RF_FLAG); new_sp &= 0xffff; new_ip &= 0xffff; CPU_ESP = new_sp; SET_EIP(new_ip); }
void ia32_initreg(void) { int i; CPU_STATSAVE.cpu_inst_default.seg_base = (UINT32)-1; CPU_EDX = (CPU_FAMILY << 8) | (CPU_MODEL << 4) | CPU_STEPPING; CPU_EFLAG = 2; CPU_CR0 = CPU_CR0_CD | CPU_CR0_NW; #if defined(USE_FPU) CPU_CR0 &= ~CPU_CR0_EM; CPU_CR0 |= CPU_CR0_ET; #else CPU_CR0 |= CPU_CR0_EM | CPU_CR0_NE; CPU_CR0 &= ~(CPU_CR0_MP | CPU_CR0_ET); #endif CPU_MXCSR = 0x1f80; CPU_GDTR_BASE = 0x0; CPU_GDTR_LIMIT = 0xffff; CPU_IDTR_BASE = 0x0; CPU_IDTR_LIMIT = 0xffff; CPU_LDTR_BASE = 0x0; CPU_LDTR_LIMIT = 0xffff; CPU_TR_BASE = 0x0; CPU_TR_LIMIT = 0xffff; CPU_STATSAVE.cpu_regs.dr[6] = 0xffff1ff0; for (i = 0; i < CPU_SEGREG_NUM; ++i) { segdesc_init(i, 0, &CPU_STAT_SREG(i)); } LOAD_SEGREG(CPU_CS_INDEX, 0xf000); CPU_STAT_CS_BASE = 0xffff0000; CPU_EIP = 0xfff0; CPU_ADRSMASK = 0x000fffff; tlb_init(); #if defined(USE_FPU) fpu_init(); #endif }
REG80 MEMCALL cpu_vmemoryread_f(int idx, UINT32 offset) { descriptor_t *sdp; UINT32 addr; int exc; __ASSERT((unsigned int)idx < CPU_SEGREG_NUM); sdp = &CPU_STAT_SREG(idx); addr = sdp->u.seg.segbase + offset; if (!CPU_STAT_PM) return cpu_memoryread_f(addr); if (!SEG_IS_VALID(sdp)) { exc = GP_EXCEPTION; goto err; } if (!(sdp->flag & CPU_DESC_FLAG_READABLE)) { cpu_memoryread_check(sdp, offset, 10, CHOOSE_EXCEPTION(idx)); } else if (!(sdp->flag & CPU_DESC_FLAG_WHOLEADR)) { if (!check_limit_upstairs(sdp, offset, 10, SEG_IS_32BIT(sdp))) goto range_failure; } return cpu_lmemoryread_f(addr, CPU_PAGE_READ_DATA | CPU_STAT_USER_MODE); range_failure: VERBOSE(("cpu_vmemoryread_f: type = %d, offset = %08x, limit = %08x", sdp->type, offset, sdp->u.seg.limit)); exc = CHOOSE_EXCEPTION(idx); err: EXCEPTION(exc, 0); { REG80 dummy; memset(&dummy, 0, sizeof(dummy)); return dummy; /* compiler happy */ } }
void MEMCALL cpu_vmemorywrite_f(int idx, UINT32 offset, const REG80 *value) { descriptor_t *sdp; UINT32 addr; int exc; __ASSERT((unsigned int)idx < CPU_SEGREG_NUM); sdp = &CPU_STAT_SREG(idx); addr = sdp->u.seg.segbase + offset; if (!CPU_STAT_PM) { cpu_memorywrite_f(addr, value); return; } if (!SEG_IS_VALID(sdp)) { exc = GP_EXCEPTION; goto err; } if (!(sdp->flag & CPU_DESC_FLAG_WRITABLE)) { cpu_memorywrite_check(sdp, offset, 10, CHOOSE_EXCEPTION(idx)); } else if (!(sdp->flag & CPU_DESC_FLAG_WHOLEADR)) { if (!check_limit_upstairs(sdp, offset, 10, SEG_IS_32BIT(sdp))) goto range_failure; } cpu_lmemorywrite_f(addr, value, CPU_PAGE_WRITE_DATA | CPU_STAT_USER_MODE); return; range_failure: VERBOSE(("cpu_vmemorywrite_f: type = %d, offset = %08x, limit = %08x", sdp->type, offset, sdp->u.seg.limit)); exc = CHOOSE_EXCEPTION(idx); err: EXCEPTION(exc, 0); }
void RETfar_pm(UINT nbytes) { selector_t cs_sel, ss_sel, temp_sel; UINT32 sp; UINT32 new_ip, new_sp; UINT16 new_cs, new_ss; int rv; int i; VERBOSE(("RETfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x, nbytes = %d", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP, nbytes)); if (CPU_STAT_SS32) { sp = CPU_ESP; } else { sp = CPU_SP; } if (CPU_INST_OP32) { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 8); new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); } else { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 4); new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); } rv = parse_selector(&cs_sel, new_cs); if (rv < 0) { VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", cs_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* check segment type */ if (!cs_sel.desc.s) { VERBOSE(("RETfar_pm: return to system segment")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } if (!cs_sel.desc.u.seg.c) { VERBOSE(("RETfar_pm: return to data segment")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* check privilege level */ if (cs_sel.rpl < CPU_STAT_CPL) { VERBOSE(("RETfar_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } if (!cs_sel.desc.u.seg.ec && (cs_sel.desc.dpl > cs_sel.rpl)) { VERBOSE(("RETfar_pm: NON-COMFORMING-CODE-SEGMENT and DPL(%d) > RPL(%d)", cs_sel.desc.dpl, cs_sel.rpl)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* not present */ if (selector_is_not_present(&cs_sel)) { VERBOSE(("RETfar_pm: returned code segment is not present")); EXCEPTION(NP_EXCEPTION, cs_sel.idx); } if (cs_sel.rpl == CPU_STAT_CPL) { VERBOSE(("RETfar_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); /* check code segment limit */ if (new_ip > cs_sel.desc.u.seg.limit) { VERBOSE(("RETfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit)); EXCEPTION(GP_EXCEPTION, 0); } VERBOSE(("RETfar_pm: new_ip = %08x, new_cs = %04x", new_ip, cs_sel.selector)); if (CPU_INST_OP32) { nbytes += 8; } else { nbytes += 4; } if (CPU_STAT_SS32) { CPU_ESP += nbytes; } else { CPU_SP += (UINT16)nbytes; } load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL); SET_EIP(new_ip); } else { VERBOSE(("RETfar_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); if (CPU_INST_OP32) { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 8 + 8 + nbytes); new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8 + nbytes); new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8 + nbytes + 4); } else { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 4 + 4 + nbytes); new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes); new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes + 2); } rv = parse_selector(&ss_sel, new_ss); if (rv < 0) { VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ss_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } /* check stack segment descriptor */ if (!ss_sel.desc.s) { VERBOSE(("RETfar_pm: stack segment is system segment")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } if (ss_sel.desc.u.seg.c) { VERBOSE(("RETfar_pm: stack segment is code segment")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } if (!ss_sel.desc.u.seg.wr) { VERBOSE(("RETfar_pm: stack segment is read-only data segment")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* check privilege level */ if (ss_sel.rpl != cs_sel.rpl) { VERBOSE(("RETfar_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel.rpl)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } if (ss_sel.desc.dpl != cs_sel.rpl) { VERBOSE(("RETfar_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel.rpl)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* not present */ if (selector_is_not_present(&ss_sel)) { VERBOSE(("RETfar_pm: stack segment is not present")); EXCEPTION(SS_EXCEPTION, ss_sel.idx); } /* check code segment limit */ if (new_ip > cs_sel.desc.u.seg.limit) { VERBOSE(("RETfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit)); EXCEPTION(GP_EXCEPTION, 0); } VERBOSE(("RETfar_pm: new_ip = %08x, new_cs = %04x", new_ip, cs_sel.selector)); VERBOSE(("RETfar_pm: new_sp = %08x, new_ss = %04x", new_sp, ss_sel.selector)); load_cs(cs_sel.selector, &cs_sel.desc, cs_sel.rpl); SET_EIP(new_ip); load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.rpl); if (CPU_STAT_SS32) { CPU_ESP = new_sp + nbytes; } else { CPU_SP = (UINT16)(new_sp + nbytes); } /* check segment register */ for (i = 0; i < CPU_SEGREG_NUM; i++) { descriptor_t *dp; BOOL valid; dp = &CPU_STAT_SREG(i); if ((!dp->u.seg.c || !dp->u.seg.ec) && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) { /* segment register is invalid */ CPU_REGS_SREG(i) = 0; CPU_STAT_SREG_CLEAR(i); continue; } rv = parse_selector(&temp_sel, CPU_REGS_SREG(i)); if (rv < 0) { /* segment register is invalid */ CPU_REGS_SREG(i) = 0; CPU_STAT_SREG_CLEAR(i); continue; } valid = TRUE; if (!temp_sel.desc.s) { /* system segment */ valid = FALSE; } if (temp_sel.desc.u.seg.c && !temp_sel.desc.u.seg.wr) { /* execute-only code segment */ valid = FALSE; } if (!temp_sel.desc.u.seg.c || !temp_sel.desc.u.seg.ec) { if (CPU_STAT_CPL > temp_sel.desc.dpl) { valid = FALSE; } } if (!valid) { /* segment register is invalid */ CPU_REGS_SREG(i) = 0; CPU_STAT_SREG(i).valid = 0; } } } VERBOSE(("RETfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); }
/*--- * 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); }
/*--- * IRET_pm: OUTER-PRIVILEGE */ static void IRET_pm_protected_mode_return_outer_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags) { descriptor_t *dp; selector_t ss_sel; UINT32 mask; UINT32 sp; UINT32 new_sp; UINT16 new_ss; int rv; int i; VERBOSE(("IRET_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); if (CPU_STAT_SS32) { sp = CPU_ESP; } else { sp = CPU_SP; } if (CPU_INST_OP32) { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 20); new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); } else { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 10); new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 6); new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8); } VERBOSE(("IRET_pm: new_sp = 0x%08x, new_ss = 0x%04x", new_sp, new_ss)); rv = parse_selector(&ss_sel, new_ss); if (rv < 0) { VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", ss_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } /* check privilege level */ if (ss_sel.rpl != cs_sel->rpl) { VERBOSE(("IRET_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel->rpl)); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } if (ss_sel.desc.dpl != cs_sel->rpl) { VERBOSE(("IRET_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel->rpl)); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } /* check stack segment descriptor */ if (!ss_sel.desc.s) { VERBOSE(("IRET_pm: stack segment is system segment")); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } if (ss_sel.desc.u.seg.c) { VERBOSE(("IRET_pm: stack segment is code segment")); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } if (!ss_sel.desc.u.seg.wr) { VERBOSE(("IRET_pm: stack segment is read-only data segment")); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } /* not present */ if (selector_is_not_present(&ss_sel)) { VERBOSE(("IRET_pm: stack segment is not present")); EXCEPTION(SS_EXCEPTION, ss_sel.idx); } /* check code segment limit */ if (new_ip > cs_sel->desc.u.seg.limit) { VERBOSE(("IRET_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit)); EXCEPTION(GP_EXCEPTION, 0); } mask = 0; if (CPU_INST_OP32) mask |= RF_FLAG; if (CPU_STAT_CPL <= CPU_STAT_IOPL) mask |= I_FLAG; if (CPU_STAT_CPL == 0) { mask |= IOPL_FLAG; if (CPU_INST_OP32) { mask |= VM_FLAG|VIF_FLAG|VIP_FLAG; } } /* set new register */ load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->rpl); SET_EIP(new_ip); set_eflags(new_flags, mask); load_ss(ss_sel.selector, &ss_sel.desc, cs_sel->rpl); if (CPU_STAT_SS32) { CPU_ESP = new_sp; } else { CPU_SP = (UINT16)new_sp; } /* check segment register */ for (i = 0; i < CPU_SEGREG_NUM; i++) { if ((i != CPU_CS_INDEX) && (i != CPU_SS_INDEX)) { dp = &CPU_STAT_SREG(i); if ((!dp->u.seg.c || !dp->u.seg.ec) && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) { /* segment register is invalid */ CPU_REGS_SREG(i) = 0; CPU_STAT_SREG_CLEAR(i); } } } }
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)); }