static void MEMCALL cpu_memorywrite_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_DATA(sdp) && !SEG_IS_WRITABLE_DATA(sdp))) { goto exc; } switch (sdp->type) { case 2: case 3: /* rw */ case 6: case 7: /* rw (expand down) */ if (!check_limit_upstairs(sdp, offset, len, SEG_IS_32BIT(sdp))) goto exc; break; default: goto exc; } sdp->flag |= CPU_DESC_FLAG_WRITABLE | CPU_DESC_FLAG_READABLE; return; exc: VERBOSE(("cpu_memorywrite_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); }
void CPUCALL interrupt(int num, int intrtype, int errorp, int error_code) { descriptor_t gsd; UINT idt_idx; UINT32 new_ip; UINT16 new_cs; int exc_errcode; VERBOSE(("interrupt: num = 0x%02x, intrtype = %s, errorp = %s, error_code = %08x", num, (intrtype == INTR_TYPE_EXTINTR) ? "external" : (intrtype == INTR_TYPE_EXCEPTION ? "exception" : "softint"), errorp ? "on" : "off", error_code)); if(num == 0x21 && md_int21()) { return; } CPU_SET_PREV_ESP(); if (!CPU_STAT_PM) { /* real mode */ CPU_WORKCLOCK(20); idt_idx = num * 4; if (idt_idx + 3 > CPU_IDTR_LIMIT) { VERBOSE(("interrupt: real-mode IDTR limit check failure (idx = 0x%04x, limit = 0x%08x", idt_idx, CPU_IDTR_LIMIT)); EXCEPTION(GP_EXCEPTION, idt_idx + 2); } if ((intrtype == INTR_TYPE_EXTINTR) && CPU_STAT_HLT) { VERBOSE(("interrupt: reset HTL in real mode")); CPU_EIP++; CPU_STAT_HLT = 0; } REGPUSH0(REAL_FLAGREG); REGPUSH0(CPU_CS); REGPUSH0(CPU_IP); CPU_EFLAG &= ~(T_FLAG | I_FLAG | AC_FLAG | RF_FLAG); CPU_TRAP = 0; new_ip = cpu_memoryread_w(CPU_IDTR_BASE + idt_idx); new_cs = cpu_memoryread_w(CPU_IDTR_BASE + idt_idx + 2); LOAD_SEGREG(CPU_CS_INDEX, new_cs); CPU_EIP = new_ip; } else { /* protected mode */ CPU_WORKCLOCK(200); VERBOSE(("interrupt: -------------------------------------------------------------- start")); VERBOSE(("interrupt: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); #if defined(DEBUG) if (num == 0x80) { /* Linux, FreeBSD, NetBSD, OpenBSD system call */ VERBOSE(("interrupt: syscall# = %d\n%s", CPU_EAX, cpu_reg2str())); } #endif idt_idx = num * 8; exc_errcode = idt_idx + 2; if (intrtype == INTR_TYPE_EXTINTR) exc_errcode++; if (idt_idx + 7 > CPU_IDTR_LIMIT) { VERBOSE(("interrupt: IDTR limit check failure (idx = 0x%04x, limit = 0x%08x", idt_idx, CPU_IDTR_LIMIT)); EXCEPTION(GP_EXCEPTION, exc_errcode); } /* load a gate descriptor from interrupt descriptor table */ memset(&gsd, 0, sizeof(gsd)); load_descriptor(&gsd, CPU_IDTR_BASE + idt_idx); if (!SEG_IS_VALID(&gsd)) { VERBOSE(("interrupt: gate descripter is invalid.")); EXCEPTION(GP_EXCEPTION, exc_errcode); } if (!SEG_IS_SYSTEM(&gsd)) { VERBOSE(("interrupt: gate descriptor is not system segment.")); EXCEPTION(GP_EXCEPTION, exc_errcode); } switch (gsd.type) { case CPU_SYSDESC_TYPE_TASK: case CPU_SYSDESC_TYPE_INTR_16: case CPU_SYSDESC_TYPE_INTR_32: case CPU_SYSDESC_TYPE_TRAP_16: case CPU_SYSDESC_TYPE_TRAP_32: break; default: VERBOSE(("interrupt: invalid gate type (%d)", gsd.type)); EXCEPTION(GP_EXCEPTION, exc_errcode); break; } /* 5.10.1.1. 例外/割り込みハンドラ・プロシージャの保護 */ if ((intrtype == INTR_TYPE_SOFTINTR) && (gsd.dpl < CPU_STAT_CPL)) { VERBOSE(("interrupt: intrtype(softint) && DPL(%d) < CPL(%d)", gsd.dpl, CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, exc_errcode); } if (!SEG_IS_PRESENT(&gsd)) { VERBOSE(("interrupt: gate descriptor is not present.")); EXCEPTION(NP_EXCEPTION, exc_errcode); } if ((intrtype == INTR_TYPE_EXTINTR) && CPU_STAT_HLT) { VERBOSE(("interrupt: reset HTL in protected mode")); CPU_EIP++; CPU_STAT_HLT = 0; } switch (gsd.type) { case CPU_SYSDESC_TYPE_TASK: interrupt_task_gate(&gsd, intrtype, errorp, error_code); break; case CPU_SYSDESC_TYPE_INTR_16: case CPU_SYSDESC_TYPE_INTR_32: case CPU_SYSDESC_TYPE_TRAP_16: case CPU_SYSDESC_TYPE_TRAP_32: interrupt_intr_or_trap(&gsd, intrtype, errorp, error_code); break; default: EXCEPTION(GP_EXCEPTION, exc_errcode); break; } VERBOSE(("interrupt: ---------------------------------------------------------------- end")); } CPU_CLEAR_PREV_ESP(); }