void CALL32_Ap(void) { descriptor_t sd; UINT32 new_ip; UINT16 new_cs; UINT16 sreg; CPU_WORKCLOCK(13); GET_PCDWORD(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_32(CPU_CS); PUSH0_32(CPU_EIP); LOAD_SEGREG(CPU_CS_INDEX, new_cs); CPU_EIP = new_ip; CPU_CLEAR_PREV_ESP(); } else { /* Protected mode */ CALLfar_pm(new_cs, new_ip); } }
void RETfar32(void) { descriptor_t sd; UINT32 new_ip; UINT32 new_cs; UINT16 sreg; CPU_WORKCLOCK(15); if (!CPU_STAT_PM || CPU_STAT_VM86) { /* Real mode or VM86 mode */ CPU_SET_PREV_ESP(); POP0_32(new_ip); POP0_32(new_cs); /* check new instrunction pointer with new code segment */ load_segreg(CPU_CS_INDEX, new_cs, &sreg, &sd, GP_EXCEPTION); if (new_ip > sd.u.seg.limit) { EXCEPTION(GP_EXCEPTION, 0); } LOAD_SEGREG(CPU_CS_INDEX, (UINT16)new_cs); CPU_EIP = new_ip; CPU_CLEAR_PREV_ESP(); } else { /* Protected mode */ RETfar_pm(0); } }
void CPUCALL JMP32_Ep(UINT32 op) { descriptor_t sd; UINT32 madr; UINT32 new_ip; UINT16 new_cs; UINT16 sreg; CPU_WORKCLOCK(11); if (op < 0xc0) { madr = calc_ea_dst(op); new_ip = cpu_vmemoryread_d(CPU_INST_SEGREG_INDEX, madr); new_cs = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr + 4); if (!CPU_STAT_PM || CPU_STAT_VM86) { /* Real mode or VM86 mode */ /* check new instrunction pointer with new code segment */ load_segreg(CPU_CS_INDEX, new_cs, &sreg, &sd, GP_EXCEPTION); if (new_ip > sd.u.seg.limit) { EXCEPTION(GP_EXCEPTION, 0); } LOAD_SEGREG(CPU_CS_INDEX, new_cs); CPU_EIP = new_ip; } else { /* Protected mode */ JMPfar_pm(new_cs, new_ip); } return; } EXCEPTION(UD_EXCEPTION, 0); }
void JMP32_Ap(void) { descriptor_t sd; UINT32 new_ip; UINT16 new_cs; UINT16 sreg; CPU_WORKCLOCK(11); GET_PCDWORD(new_ip); GET_PCWORD(new_cs); if (!CPU_STAT_PM || CPU_STAT_VM86) { /* Real mode or VM86 mode */ /* check new instrunction pointer with new code segment */ load_segreg(CPU_CS_INDEX, new_cs, &sreg, &sd, GP_EXCEPTION); if (new_ip > sd.u.seg.limit) { EXCEPTION(GP_EXCEPTION, 0); } LOAD_SEGREG(CPU_CS_INDEX, new_cs); CPU_EIP = new_ip; } else { /* Protected mode */ JMPfar_pm(new_cs, new_ip); } }
/* * bios call interface */ void ia32_bioscall(void) { UINT32 adrs; if (!CPU_STAT_PM || CPU_STAT_VM86) { #if 1 adrs = CPU_PREV_EIP + (CPU_CS << 4); #else adrs = CPU_PREV_EIP + CPU_STAT_CS_BASE; #endif if ((adrs >= 0xf8000) && (adrs < 0x100000)) { if (biosfunc(adrs)) { /* Nothing to do */ } LOAD_SEGREG(CPU_ES_INDEX, CPU_ES); LOAD_SEGREG(CPU_CS_INDEX, CPU_CS); LOAD_SEGREG(CPU_SS_INDEX, CPU_SS); LOAD_SEGREG(CPU_DS_INDEX, CPU_DS); } } }
void IRET(void) { descriptor_t sd; UINT32 new_ip; UINT32 new_flags; UINT32 new_cs; UINT32 mask; UINT16 sreg; CPU_WORKCLOCK(22); if (!CPU_STAT_PM) { /* Real mode */ CPU_SET_PREV_ESP(); mask = I_FLAG|IOPL_FLAG; if (!CPU_INST_OP32) { POP0_16(new_ip); POP0_16(new_cs); POP0_16(new_flags); } else { POP0_32(new_ip); POP0_32(new_cs); POP0_32(new_flags); mask |= RF_FLAG; } /* check new instrunction pointer with new code segment */ load_segreg(CPU_CS_INDEX, new_cs, &sreg, &sd, GP_EXCEPTION); if (new_ip > sd.u.seg.limit) { EXCEPTION(GP_EXCEPTION, 0); } LOAD_SEGREG(CPU_CS_INDEX, (UINT16)new_cs); CPU_EIP = new_ip; set_eflags(new_flags, mask); CPU_CLEAR_PREV_ESP(); } else { /* Protected mode */ IRET_pm(); } IRQCHECKTERM(); }
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 }
void CPUCALL CALL32_Ep(UINT32 op) { descriptor_t sd; UINT32 madr; UINT32 new_ip; UINT16 new_cs; UINT16 sreg; CPU_WORKCLOCK(16); if (op < 0xc0) { madr = calc_ea_dst(op); new_ip = cpu_vmemoryread_d(CPU_INST_SEGREG_INDEX, madr); new_cs = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr + 4); 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_32(CPU_CS); PUSH0_32(CPU_EIP); 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); }
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)); }
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(); }