void MEMCALL cpu_stack_pop_check(UINT16 s, descriptor_t *sdp, UINT32 sp, UINT len, BOOL is32bit) { __ASSERT(sdp != NULL); __ASSERT(len > 0); if (!SEG_IS_VALID(sdp) || !SEG_IS_PRESENT(sdp) || SEG_IS_SYSTEM(sdp) || SEG_IS_CODE(sdp) || !SEG_IS_WRITABLE_DATA(sdp)) { goto exc; } if (!check_limit_upstairs(sdp, sp, len, is32bit)) goto exc; return; exc: VERBOSE(("cpu_stack_pop_check: check failure: selector = 0x%04x, sp = 0x%08x, len = %d", s, sp, len)); #if defined(DEBUG) segdesc_dump(sdp); #endif EXCEPTION(SS_EXCEPTION, s & 0xfffc); }
static void MEMCALL cpu_memoryread_check(descriptor_t *sdp, UINT32 offset, UINT len, int e) { __ASSERT(sdp != NULL); __ASSERT(len > 0); if (!SEG_IS_VALID(sdp)) { e = GP_EXCEPTION; goto exc; } if (!SEG_IS_PRESENT(sdp) || SEG_IS_SYSTEM(sdp) || (SEG_IS_CODE(sdp) && !SEG_IS_READABLE_CODE(sdp))) { goto exc; } switch (sdp->type) { case 0: case 1: /* ro */ case 2: case 3: /* rw */ case 4: case 5: /* ro (expand down) */ case 6: case 7: /* rw (expand down) */ case 10: case 11: /* rx */ case 14: case 15: /* rxc */ if (!check_limit_upstairs(sdp, offset, len, SEG_IS_32BIT(sdp))) goto exc; break; default: goto exc; } sdp->flag |= CPU_DESC_FLAG_READABLE; return; exc: VERBOSE(("cpu_memoryread_check: check failure: offset = 0x%08x, len = %d", offset, len)); #if defined(DEBUG) segdesc_dump(sdp); #endif EXCEPTION(e, 0); }
void MEMCALL cpu_stack_push_check(UINT16 s, descriptor_t *sdp, UINT32 sp, UINT len, BOOL is32bit) { UINT32 limit; UINT32 start; __ASSERT(sdp != NULL); __ASSERT(len > 0); len--; if (!SEG_IS_VALID(sdp) || !SEG_IS_PRESENT(sdp) || SEG_IS_SYSTEM(sdp) || SEG_IS_CODE(sdp) || !SEG_IS_WRITABLE_DATA(sdp)) { goto exc; } start = sp - len; limit = is32bit ? 0xffffffff : 0x0000ffff; if (SEG_IS_EXPANDDOWN_DATA(sdp)) { /* expand-down stack */ if (!SEG_IS_32BIT(sdp)) { if (sp > limit) { /* [*] */ goto exc; } } if (sdp->u.seg.limit == 0) { /* * 32bit 16bit * +-------+ +-------+ FFFFFFFFh * | | | [*] | * | | +-------+ 0000FFFFh * | valid | | | * | | | valid | * | | | | * +-------+ +-------+ 00000000h */ if (!SEG_IS_32BIT(sdp)) { if (sp > limit) { /* [1] */ goto exc; } } else { sdp->flag |= CPU_DESC_FLAG_WHOLEADR; } } else { /* * 32bit 16bit * +-------+ +-------+ FFFFFFFFh * | | | [*] | * | valid | +-------+ 0000FFFFh * | | | valid | * +-------+ +-------+ seg.limit + len - 1 * | | | | * +..[1]..+ +..[1]..+ seg.limit * | | | | * +-------+ +-------+ 00000000h */ if ((len > limit - sdp->u.seg.limit) /* len check */ || (start > sp) /* wrap check */ || (start < sdp->u.seg.limit)) { /* [1] */ goto exc; } } } else { /* expand-up stack */ if (sdp->u.seg.limit == limit) { /* * 32bit 16bit * +-------+ +-------+ FFFFFFFFh * | | | [1] | * | | +-------+ 0000FFFFh * | valid | | | * | | | valid | * | | | | * +-------+ +-------+ 00000000h */ if (!SEG_IS_32BIT(sdp)) { if (sp > limit) { /* [1] */ goto exc; } } else { sdp->flag |= CPU_DESC_FLAG_WHOLEADR; } } else { /* * 32bit 16bit * +-------+ +-------+ FFFFFFFFh * | | | | * | [1] | + [1] + 0000FFFFh * | | | | * +-------+ +-------+ seg.limit * | valid | | valid | * +.......+ +.......+ len - 1 * | [+] | | [+] | * +-------+ +-------+ 00000000h * * [+]: wrap check */ if ((len > sdp->u.seg.limit) /* len check */ || (start > sp) /* wrap check */ || (sp > sdp->u.seg.limit + 1)) { /* [1] */ goto exc; } } } return; exc: VERBOSE(("cpu_stack_push_check: check failure: selector = 0x%04x, sp = 0x%08x, len = %d", s, sp, len)); #if defined(DEBUG) segdesc_dump(sdp); #endif EXCEPTION(SS_EXCEPTION, s & 0xfffc); }
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)); }