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 RETnear32(void) { UINT32 new_ip; CPU_WORKCLOCK(11); CPU_SET_PREV_ESP(); POP0_32(new_ip); if (new_ip > CPU_STAT_CS_LIMIT) { EXCEPTION(GP_EXCEPTION, 0); } CPU_EIP = new_ip; CPU_CLEAR_PREV_ESP(); }
void CALL_Ad(void) { UINT32 new_ip; UINT32 dest; CPU_WORKCLOCK(7); CPU_SET_PREV_ESP(); GET_PCDWORD(dest); new_ip = CPU_EIP + dest; if (new_ip > CPU_STAT_CS_LIMIT) { EXCEPTION(GP_EXCEPTION, 0); } PUSH0_32(CPU_EIP); CPU_EIP = new_ip; CPU_CLEAR_PREV_ESP(); }
/* * 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 LEAVE(void) { CPU_WORKCLOCK(4); CPU_SET_PREV_ESP(); if (!CPU_STAT_SS32) { CPU_SP = CPU_BP; } else { CPU_ESP = CPU_EBP; } if (!CPU_INST_OP32) { POP0_16(CPU_BP); } else { POP0_32(CPU_EBP); } CPU_CLEAR_PREV_ESP(); }
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 RETnear32_Iw(void) { UINT32 new_ip; UINT16 size; CPU_WORKCLOCK(11); CPU_SET_PREV_ESP(); GET_PCWORD(size); POP0_32(new_ip); if (new_ip > CPU_STAT_CS_LIMIT) { EXCEPTION(GP_EXCEPTION, 0); } CPU_EIP = new_ip; if (!CPU_STAT_SS32) { CPU_SP += size; } else { CPU_ESP += size; } CPU_CLEAR_PREV_ESP(); }
void CPUCALL CALL_Ed(UINT32 op) { UINT32 madr; UINT32 new_ip; CPU_SET_PREV_ESP(); if (op >= 0xc0) { CPU_WORKCLOCK(7); new_ip = *(reg32_b20[op]); } else { CPU_WORKCLOCK(11); madr = calc_ea_dst(op); new_ip = cpu_vmemoryread_d(CPU_INST_SEGREG_INDEX, madr); } if (new_ip > CPU_STAT_CS_LIMIT) { EXCEPTION(GP_EXCEPTION, 0); } PUSH0_32(CPU_EIP); CPU_EIP = new_ip; CPU_CLEAR_PREV_ESP(); }
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); }
void ENTER32_IwIb(void) { UINT32 sp, bp; UINT32 new_bp; UINT32 val; UINT16 dimsize; UINT8 level; GET_PCWORD(dimsize); GET_PCBYTE(level); level &= 0x1f; CPU_SET_PREV_ESP(); PUSH0_32(CPU_EBP); if (level == 0) { /* enter level=0 */ CPU_WORKCLOCK(11); CPU_EBP = CPU_ESP; if (!CPU_STAT_SS32) { CPU_SP -= dimsize; } else { CPU_ESP -= dimsize; } } else { --level; if (level == 0) { /* enter level=1 */ CPU_WORKCLOCK(15); sp = CPU_ESP; PUSH0_32(sp); CPU_EBP = sp; if (CPU_STAT_SS32) { CPU_ESP -= dimsize; } else { CPU_SP -= dimsize; } } else { /* enter level=2-31 */ CPU_WORKCLOCK(12 + level * 4); if (CPU_STAT_SS32) { bp = CPU_EBP; new_bp = CPU_ESP; while (level--) { bp -= 4; CPU_ESP -= 4; val = cpu_vmemoryread_d(CPU_SS_INDEX, bp); cpu_vmemorywrite_d(CPU_SS_INDEX, CPU_ESP, val); } REGPUSH0_32(new_bp); CPU_EBP = new_bp; CPU_ESP -= dimsize; } else { bp = CPU_BP; new_bp = CPU_ESP; while (level--) { bp -= 4; CPU_SP -= 4; val = cpu_vmemoryread_d(CPU_SS_INDEX, bp); cpu_vmemorywrite_d(CPU_SS_INDEX, CPU_SP, val); } REGPUSH0_32_16(new_bp); CPU_EBP = new_bp; CPU_SP -= dimsize; } } } CPU_CLEAR_PREV_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(); }