I286_F6 _call_far_ea16(UINT op) { UINT32 seg; UINT ad; I286_WORKCLOCK(16); if (op < 0xc0) { ad = GET_EA(op, &seg); REGPUSH0(I286_CS) // ToDo REGPUSH0(I286_IP) I286_IP = i286_memoryread_w(seg + ad); I286_CS = i286_memoryread_w(seg + LOW16(ad + 2)); CS_BASE = SEGSELECT(I286_CS); } else { INT_NUM(6, I286_IP - 2); } }
I286_F6 _push_ea16(UINT op) { UINT16 src; if (op >= 0xc0) { I286_WORKCLOCK(3); src = *(REG16_B20(op)); } else { I286_WORKCLOCK(5); src = i286_memoryread_w(CALC_EA(op)); } REGPUSH0(src); }
I286_F6 _call_ea16(UINT op) { UINT16 src; if (op >= 0xc0) { I286_WORKCLOCK(7); src = *(REG16_B20(op)); } else { I286_WORKCLOCK(11); src = i286_memoryread_w(CALC_EA(op)); } REGPUSH0(I286_IP); I286_IP = src; }
/* * STACK */ void ENTER16_IwIb(void) { UINT32 sp, bp; UINT32 val; UINT16 dimsize; UINT16 new_bp; UINT8 level; GET_PCWORD(dimsize); GET_PCBYTE(level); level &= 0x1f; CPU_SET_PREV_ESP(); PUSH0_16(CPU_BP); if (level == 0) { /* enter level=0 */ CPU_WORKCLOCK(11); CPU_BP = CPU_SP; if (!CPU_STAT_SS32) { CPU_SP -= dimsize; } else { CPU_ESP -= dimsize; } } else { --level; if (level == 0) { /* enter level=1 */ CPU_WORKCLOCK(15); sp = CPU_SP; PUSH0_16(sp); CPU_BP = (UINT16)sp; if (!CPU_STAT_SS32) { CPU_SP -= dimsize; } else { CPU_ESP -= dimsize; } } else { /* enter level=2-31 */ CPU_WORKCLOCK(12 + level * 4); if (!CPU_STAT_SS32) { bp = CPU_BP; new_bp = CPU_SP; while (level--) { bp -= 2; CPU_SP -= 2; val = cpu_vmemoryread_w(CPU_SS_INDEX, bp); cpu_vmemorywrite_w(CPU_SS_INDEX, CPU_SP, (UINT16)val); } REGPUSH0(new_bp); CPU_BP = new_bp; CPU_SP -= dimsize; } else { bp = CPU_EBP; new_bp = CPU_SP; while (level--) { bp -= 2; CPU_ESP -= 2; val = cpu_vmemoryread_w(CPU_SS_INDEX, bp); cpu_vmemorywrite_w(CPU_SS_INDEX, CPU_ESP, (UINT16)val); } REGPUSH0_16_32(new_bp); CPU_BP = new_bp; CPU_ESP -= 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(); }