void CPUCALL JMP16_Ep(UINT32 op) { descriptor_t sd; UINT32 madr; UINT16 new_ip; UINT16 new_cs; UINT16 sreg; CPU_WORKCLOCK(11); if (op < 0xc0) { madr = calc_ea_dst(op); new_ip = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); new_cs = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr + 2); 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 BTC_EwIb(UINT32 op) { UINT16 *out; UINT32 src, dst, res, madr; UINT16 bit; if (op >= 0xc0) { CPU_WORKCLOCK(2); GET_PCBYTE(src); out = reg16_b20[op]; dst = *out; bit = BIT_MAKEBIT16(src); if (dst & bit) { CPU_FLAGL |= C_FLAG; } else { CPU_FLAGL &= ~C_FLAG; } res = dst ^ bit; *out = (UINT16)res; } else { CPU_WORKCLOCK(6); madr = calc_ea_dst(op); GET_PCBYTE(src); dst = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); bit = BIT_MAKEBIT16(src); if (dst & bit) { CPU_FLAGL |= C_FLAG; } else { CPU_FLAGL &= ~C_FLAG; } res = dst ^ bit; cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, (UINT16)res); } }
/* * BTC */ void BTC_EwGw(void) { UINT16 *out; UINT32 op, src, dst, res, madr; UINT16 bit; PREPART_EA_REG16(op, src); bit = BIT_MAKEBIT16(src); if (op >= 0xc0) { CPU_WORKCLOCK(2); out = reg16_b20[op]; dst = *out; if (dst & bit) { CPU_FLAGL |= C_FLAG; } else { CPU_FLAGL &= ~C_FLAG; } res = dst ^ bit; *out = (UINT16)res; } else { CPU_WORKCLOCK(7); madr = calc_ea_dst(op); madr += BIT_OFFSET16(src); dst = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); if (dst & bit) { CPU_FLAGL |= C_FLAG; } else { CPU_FLAGL &= ~C_FLAG; } res = dst ^ bit; cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, (UINT16)res); } }
void IRET_pm(void) { UINT32 sp; UINT32 new_ip, new_flags; UINT16 new_cs; VERBOSE(("IRET_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); if (!(CPU_EFLAG & VM_FLAG) && (CPU_EFLAG & NT_FLAG)) { /* TASK-RETURN: PE=1, VM=0, NT=1 */ IRET_pm_nested_task(); } else { if (CPU_STAT_SS32) { sp = CPU_ESP; } else { sp = CPU_SP; } if (CPU_INST_OP32) { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 12); new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); new_flags = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8); } else { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 6); new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); new_flags = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); } VERBOSE(("IRET_pm: new_ip = %08x, new_cs = %04x, new_eflags = %08x", new_ip, new_cs, new_flags)); if (CPU_EFLAG & VM_FLAG) { /* RETURN-FROM-VIRTUAL-8086-MODE */ IRET_pm_return_from_vm86(new_cs, new_ip, new_flags); } else if (new_flags & VM_FLAG) { /* RETURN-TO-VIRTUAL-8086-MODE */ IRET_pm_return_to_vm86(new_cs, new_ip, new_flags); } else { /* PROTECTED-MODE-RETURN */ IRET_pm_protected_mode_return(new_cs, new_ip, new_flags); } } VERBOSE(("IRET_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); }
/*--- * IRET_pm: new_flags & VM_FLAG */ static void IRET_pm_return_to_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags) { UINT16 segsel[CPU_SEGREG_NUM]; UINT32 sp; UINT32 new_sp; int i; VERBOSE(("IRET_pm: Interrupt procedure was in virtual-8086 mode: PE=1, VM=1 in flags image")); if (CPU_STAT_CPL != 0) { ia32_panic("IRET_pm: CPL != 0"); } if (!CPU_INST_OP32) { ia32_panic("IRET_pm: 16bit mode"); } if (CPU_STAT_SS32) { sp = CPU_ESP; } else { sp = CPU_SP; } STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 36); new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); segsel[CPU_ES_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 20); segsel[CPU_DS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 24); segsel[CPU_FS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 28); segsel[CPU_GS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 32); segsel[CPU_CS_INDEX] = (UINT16)new_cs; for (i = 0; i < CPU_SEGREG_NUM; i++) { CPU_REGS_SREG(i) = segsel[i]; CPU_STAT_SREG_INIT(i); } /* to VM86 mode */ set_eflags(new_flags, IOPL_FLAG|I_FLAG|VM_FLAG|RF_FLAG); new_sp &= 0xffff; new_ip &= 0xffff; CPU_ESP = new_sp; SET_EIP(new_ip); }
void BOUND_GwMa(void) { UINT32 op, madr; UINT16 reg; CPU_WORKCLOCK(13); GET_PCBYTE(op); if (op < 0xc0) { reg = *(reg16_b53[op]); madr = calc_ea_dst(op); if (reg >= cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr) && reg <= cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr + 2)) { return; } EXCEPTION(BR_EXCEPTION, 0); return; } EXCEPTION(UD_EXCEPTION, 0); }
void CPUCALL CALL16_Ep(UINT32 op) { descriptor_t sd; UINT32 madr; UINT16 new_ip; UINT16 new_cs; UINT16 sreg; CPU_WORKCLOCK(16); if (op < 0xc0) { madr = calc_ea_dst(op); new_ip = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); new_cs = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr + 2); 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_16(CPU_CS); PUSH0_16(CPU_IP); 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 TEST_EwGw(void) { UINT32 op, src, tmp, madr; PREPART_EA_REG16(op, src); if (op >= 0xc0) { CPU_WORKCLOCK(2); tmp = *(reg16_b20[op]); } else { CPU_WORKCLOCK(7); madr = calc_ea_dst(op); tmp = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); } WORD_AND(tmp, src); }
void TEST_EwIw(UINT32 op) { UINT32 src, tmp, madr; if (op >= 0xc0) { CPU_WORKCLOCK(2); tmp = *(reg16_b20[op]); } else { CPU_WORKCLOCK(6); madr = calc_ea_dst(op); tmp = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); } GET_PCWORD(src); WORD_AND(tmp, src); }
void BT_EwIb(UINT32 op) { UINT32 src, dst, madr; if (op >= 0xc0) { CPU_WORKCLOCK(2); GET_PCBYTE(src); dst = *(reg16_b20[op]); } else { CPU_WORKCLOCK(6); madr = calc_ea_dst(op); GET_PCBYTE(src); dst = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); } CPU_FLAGL &= ~C_FLAG; CPU_FLAGL |= (dst >> BIT_INDEX16(src)) & 1; }
/* * BT */ void BT_EwGw(void) { UINT32 op, src, dst, madr; PREPART_EA_REG16(op, src); if (op >= 0xc0) { CPU_WORKCLOCK(2); dst = *(reg16_b20[op]); } else { CPU_WORKCLOCK(7); madr = calc_ea_dst(op); madr += BIT_OFFSET16(src); dst = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); } CPU_FLAGL &= ~C_FLAG; CPU_FLAGL |= (dst >> BIT_INDEX16(src)) & 1; }
void CPUCALL JMP_Ew(UINT32 op) { UINT32 madr; UINT16 new_ip; if (op >= 0xc0) { CPU_WORKCLOCK(7); new_ip = *(reg16_b20[op]); } else { CPU_WORKCLOCK(11); madr = calc_ea_dst(op); new_ip = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); } if (new_ip > CPU_STAT_CS_LIMIT) { EXCEPTION(GP_EXCEPTION, 0); } CPU_EIP = new_ip; }
/* * 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 RETfar_pm(UINT nbytes) { selector_t cs_sel, ss_sel, temp_sel; UINT32 sp; UINT32 new_ip, new_sp; UINT16 new_cs, new_ss; int rv; int i; VERBOSE(("RETfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x, nbytes = %d", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP, nbytes)); if (CPU_STAT_SS32) { sp = CPU_ESP; } else { sp = CPU_SP; } if (CPU_INST_OP32) { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 8); new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); } else { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 4); new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); } rv = parse_selector(&cs_sel, new_cs); if (rv < 0) { VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", cs_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* check segment type */ if (!cs_sel.desc.s) { VERBOSE(("RETfar_pm: return to system segment")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } if (!cs_sel.desc.u.seg.c) { VERBOSE(("RETfar_pm: return to data segment")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* check privilege level */ if (cs_sel.rpl < CPU_STAT_CPL) { VERBOSE(("RETfar_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } if (!cs_sel.desc.u.seg.ec && (cs_sel.desc.dpl > cs_sel.rpl)) { VERBOSE(("RETfar_pm: NON-COMFORMING-CODE-SEGMENT and DPL(%d) > RPL(%d)", cs_sel.desc.dpl, cs_sel.rpl)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* not present */ if (selector_is_not_present(&cs_sel)) { VERBOSE(("RETfar_pm: returned code segment is not present")); EXCEPTION(NP_EXCEPTION, cs_sel.idx); } if (cs_sel.rpl == CPU_STAT_CPL) { VERBOSE(("RETfar_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); /* check code segment limit */ if (new_ip > cs_sel.desc.u.seg.limit) { VERBOSE(("RETfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit)); EXCEPTION(GP_EXCEPTION, 0); } VERBOSE(("RETfar_pm: new_ip = %08x, new_cs = %04x", new_ip, cs_sel.selector)); if (CPU_INST_OP32) { nbytes += 8; } else { nbytes += 4; } if (CPU_STAT_SS32) { CPU_ESP += nbytes; } else { CPU_SP += (UINT16)nbytes; } load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL); SET_EIP(new_ip); } else { VERBOSE(("RETfar_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); if (CPU_INST_OP32) { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 8 + 8 + nbytes); new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8 + nbytes); new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8 + nbytes + 4); } else { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 4 + 4 + nbytes); new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes); new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes + 2); } rv = parse_selector(&ss_sel, new_ss); if (rv < 0) { VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ss_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } /* check stack segment descriptor */ if (!ss_sel.desc.s) { VERBOSE(("RETfar_pm: stack segment is system segment")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } if (ss_sel.desc.u.seg.c) { VERBOSE(("RETfar_pm: stack segment is code segment")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } if (!ss_sel.desc.u.seg.wr) { VERBOSE(("RETfar_pm: stack segment is read-only data segment")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* check privilege level */ if (ss_sel.rpl != cs_sel.rpl) { VERBOSE(("RETfar_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel.rpl)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } if (ss_sel.desc.dpl != cs_sel.rpl) { VERBOSE(("RETfar_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel.rpl)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* not present */ if (selector_is_not_present(&ss_sel)) { VERBOSE(("RETfar_pm: stack segment is not present")); EXCEPTION(SS_EXCEPTION, ss_sel.idx); } /* check code segment limit */ if (new_ip > cs_sel.desc.u.seg.limit) { VERBOSE(("RETfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit)); EXCEPTION(GP_EXCEPTION, 0); } VERBOSE(("RETfar_pm: new_ip = %08x, new_cs = %04x", new_ip, cs_sel.selector)); VERBOSE(("RETfar_pm: new_sp = %08x, new_ss = %04x", new_sp, ss_sel.selector)); load_cs(cs_sel.selector, &cs_sel.desc, cs_sel.rpl); SET_EIP(new_ip); load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.rpl); if (CPU_STAT_SS32) { CPU_ESP = new_sp + nbytes; } else { CPU_SP = (UINT16)(new_sp + nbytes); } /* check segment register */ for (i = 0; i < CPU_SEGREG_NUM; i++) { descriptor_t *dp; BOOL valid; dp = &CPU_STAT_SREG(i); if ((!dp->u.seg.c || !dp->u.seg.ec) && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) { /* segment register is invalid */ CPU_REGS_SREG(i) = 0; CPU_STAT_SREG_CLEAR(i); continue; } rv = parse_selector(&temp_sel, CPU_REGS_SREG(i)); if (rv < 0) { /* segment register is invalid */ CPU_REGS_SREG(i) = 0; CPU_STAT_SREG_CLEAR(i); continue; } valid = TRUE; if (!temp_sel.desc.s) { /* system segment */ valid = FALSE; } if (temp_sel.desc.u.seg.c && !temp_sel.desc.u.seg.wr) { /* execute-only code segment */ valid = FALSE; } if (!temp_sel.desc.u.seg.c || !temp_sel.desc.u.seg.ec) { if (CPU_STAT_CPL > temp_sel.desc.dpl) { valid = FALSE; } } if (!valid) { /* segment register is invalid */ CPU_REGS_SREG(i) = 0; CPU_STAT_SREG(i).valid = 0; } } } VERBOSE(("RETfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); }
/*--- * CALLfar_pm: call gate (MORE-PRIVILEGE) */ static void CALLfar_pm_call_gate_more_privilege(const selector_t *callgate_sel, selector_t *cs_sel) { UINT32 param[32]; /* copy param */ selector_t ss_sel; UINT32 old_eip, old_esp; UINT32 new_esp; UINT16 old_cs, old_ss; UINT16 new_ss; int param_count; int i; int rv; VERBOSE(("CALLfar_pm: MORE-PRIVILEGE")); /* save register */ old_cs = CPU_CS; old_ss = CPU_SS; old_eip = CPU_EIP; old_esp = CPU_ESP; if (!CPU_STAT_SS32) { old_esp &= 0xffff; } /* get stack pointer from TSS */ get_stack_pointer_from_tss(cs_sel->desc.dpl, &new_ss, &new_esp); /* parse stack segment descriptor */ rv = parse_selector(&ss_sel, new_ss); if (rv < 0) { VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", new_ss, rv)); EXCEPTION(TS_EXCEPTION, ss_sel.idx); } /* check privilege level */ if (ss_sel.rpl != cs_sel->desc.dpl) { VERBOSE(("CALLfar_pm: RPL[SS](%d) != DPL[CS](%d)", ss_sel.rpl, cs_sel->desc.dpl)); EXCEPTION(TS_EXCEPTION, ss_sel.idx); } if (ss_sel.desc.dpl != cs_sel->desc.dpl) { VERBOSE(("CALLfar_pm: DPL[SS](%d) != DPL[CS](%d)", ss_sel.desc.dpl, cs_sel->desc.dpl)); EXCEPTION(TS_EXCEPTION, ss_sel.idx); } /* stack segment must be writable data segment. */ if (!ss_sel.desc.s) { VERBOSE(("CALLfar_pm: stack segment is system segment")); EXCEPTION(TS_EXCEPTION, ss_sel.idx); } if (ss_sel.desc.u.seg.c) { VERBOSE(("CALLfar_pm: stack segment is code segment")); EXCEPTION(TS_EXCEPTION, ss_sel.idx); } if (!ss_sel.desc.u.seg.wr) { VERBOSE(("CALLfar_pm: stack segment is read-only data segment")); EXCEPTION(TS_EXCEPTION, ss_sel.idx); } /* not present */ if (selector_is_not_present(&ss_sel)) { VERBOSE(("CALLfar_pm: stack segment selector is not present")); EXCEPTION(SS_EXCEPTION, ss_sel.idx); } param_count = callgate_sel->desc.u.gate.count; VERBOSE(("CALLfar_pm: param_count = %d", param_count)); if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { STACK_PUSH_CHECK(ss_sel.idx, &ss_sel.desc, new_esp, 16 + param_count * 4); /* dump param */ for (i = 0; i < param_count; i++) { param[i] = cpu_vmemoryread_d(CPU_SS_INDEX, old_esp + i * 4); VERBOSE(("CALLfar_pm: get param[%d] = %08x", i, param[i])); } load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); if (CPU_STAT_SS32) { CPU_ESP = new_esp; } else { CPU_SP = (UINT16)new_esp; } load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); SET_EIP(callgate_sel->desc.u.gate.offset); PUSH0_32(old_ss); PUSH0_32(old_esp); /* restore param */ for (i = param_count; i > 0; i--) { PUSH0_32(param[i - 1]); VERBOSE(("CALLfar_pm: set param[%d] = %08x", i - 1, param[i - 1])); } PUSH0_32(old_cs); PUSH0_32(old_eip); } else { STACK_PUSH_CHECK(ss_sel.idx, &ss_sel.desc, new_esp, 8 + param_count * 2); /* dump param */ for (i = 0; i < param_count; i++) { param[i] = cpu_vmemoryread_w(CPU_SS_INDEX, old_esp + i * 2); VERBOSE(("CALLfar_pm: get param[%d] = %04x", i, param[i])); } load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); if (CPU_STAT_SS32) { CPU_ESP = new_esp; } else { CPU_SP = (UINT16)new_esp; } load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); SET_EIP(callgate_sel->desc.u.gate.offset); PUSH0_16(old_ss); PUSH0_16(old_esp); /* restore param */ for (i = param_count; i > 0; i--) { PUSH0_16(param[i - 1]); VERBOSE(("CALLfar_pm: set param[%d] = %04x", i - 1, param[i - 1])); } PUSH0_16(old_cs); PUSH0_16(old_eip); } }
/*--- * IRET_pm: OUTER-PRIVILEGE */ static void IRET_pm_protected_mode_return_outer_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags) { descriptor_t *dp; selector_t ss_sel; UINT32 mask; UINT32 sp; UINT32 new_sp; UINT16 new_ss; int rv; int i; VERBOSE(("IRET_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); if (CPU_STAT_SS32) { sp = CPU_ESP; } else { sp = CPU_SP; } if (CPU_INST_OP32) { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 20); new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); } else { STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 10); new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 6); new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8); } VERBOSE(("IRET_pm: new_sp = 0x%08x, new_ss = 0x%04x", new_sp, new_ss)); rv = parse_selector(&ss_sel, new_ss); if (rv < 0) { VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", ss_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } /* check privilege level */ if (ss_sel.rpl != cs_sel->rpl) { VERBOSE(("IRET_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel->rpl)); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } if (ss_sel.desc.dpl != cs_sel->rpl) { VERBOSE(("IRET_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel->rpl)); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } /* check stack segment descriptor */ if (!ss_sel.desc.s) { VERBOSE(("IRET_pm: stack segment is system segment")); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } if (ss_sel.desc.u.seg.c) { VERBOSE(("IRET_pm: stack segment is code segment")); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } if (!ss_sel.desc.u.seg.wr) { VERBOSE(("IRET_pm: stack segment is read-only data segment")); EXCEPTION(GP_EXCEPTION, ss_sel.idx); } /* not present */ if (selector_is_not_present(&ss_sel)) { VERBOSE(("IRET_pm: stack segment is not present")); EXCEPTION(SS_EXCEPTION, ss_sel.idx); } /* check code segment limit */ if (new_ip > cs_sel->desc.u.seg.limit) { VERBOSE(("IRET_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit)); EXCEPTION(GP_EXCEPTION, 0); } mask = 0; if (CPU_INST_OP32) mask |= RF_FLAG; if (CPU_STAT_CPL <= CPU_STAT_IOPL) mask |= I_FLAG; if (CPU_STAT_CPL == 0) { mask |= IOPL_FLAG; if (CPU_INST_OP32) { mask |= VM_FLAG|VIF_FLAG|VIP_FLAG; } } /* set new register */ load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->rpl); SET_EIP(new_ip); set_eflags(new_flags, mask); load_ss(ss_sel.selector, &ss_sel.desc, cs_sel->rpl); if (CPU_STAT_SS32) { CPU_ESP = new_sp; } else { CPU_SP = (UINT16)new_sp; } /* check segment register */ for (i = 0; i < CPU_SEGREG_NUM; i++) { if ((i != CPU_CS_INDEX) && (i != CPU_SS_INDEX)) { dp = &CPU_STAT_SREG(i); if ((!dp->u.seg.c || !dp->u.seg.ec) && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) { /* segment register is invalid */ CPU_REGS_SREG(i) = 0; CPU_STAT_SREG_CLEAR(i); } } } }