--- np2/i386c/ia32/ctrlxfer.c 2004/01/23 14:33:26 1.3 +++ np2/i386c/ia32/ctrlxfer.c 2004/02/04 13:24:35 1.7 @@ -1,4 +1,4 @@ -/* $Id: ctrlxfer.c,v 1.3 2004/01/23 14:33:26 monaka Exp $ */ +/* $Id: ctrlxfer.c,v 1.7 2004/02/04 13:24:35 monaka Exp $ */ /* * Copyright (c) 2003 NONAKA Kimihiro @@ -34,8 +34,6 @@ #include "ctrlxfer.h" -static void check_segreg(void); - /*------------------------------------------------------------------------------ * JMPfar_pm */ @@ -53,7 +51,7 @@ JMPfar_pm(WORD selector, DWORD new_ip) VERBOSE(("JMPfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); VERBOSE(("JMPfar_pm: selector = 0x%04x, new_ip = 0x%08x", selector, new_ip)); - rv = parse_selector(&jmp_sel, selector); + rv = parse_selector(&jmp_sel, selector, CPU_IS_USER_MODE()); if (rv < 0) { VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d)", selector, rv)); EXCEPTION(GP_EXCEPTION, jmp_sel.idx); @@ -175,7 +173,7 @@ JMPfar_pm_call_gate(selector_t *callgate } /* parse code segment selector */ - rv = parse_selector(&cs_sel, callgate_sel->desc.u.gate.selector); + rv = parse_selector(&cs_sel, callgate_sel->desc.u.gate.selector, CPU_IS_USER_MODE()); if (rv < 0) { VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d)", callgate_sel->desc.u.gate.selector, rv)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); @@ -268,7 +266,7 @@ JMPfar_pm_task_gate(selector_t *taskgate } /* parse tss selector */ - rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector); + rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector, CPU_IS_USER_MODE()); if (rv < 0 || tss_sel.ldt) { VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d, %cDT)", taskgate_sel->desc.u.gate.selector, rv, tss_sel.ldt ? 'L' : 'G')); EXCEPTION(GP_EXCEPTION, tss_sel.idx); @@ -364,7 +362,7 @@ CALLfar_pm(WORD selector, DWORD new_ip) VERBOSE(("CALLfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); VERBOSE(("CALLfar_pm: selector = 0x%04x, new_ip = 0x%08x", selector, new_ip)); - rv = parse_selector(&call_sel, selector); + rv = parse_selector(&call_sel, selector, CPU_IS_USER_MODE()); if (rv < 0) { VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", selector, rv)); EXCEPTION(GP_EXCEPTION, call_sel.idx); @@ -514,7 +512,7 @@ CALLfar_pm_call_gate(selector_t *callgat } /* parse code segment descriptor */ - rv = parse_selector(&cs_sel, callgate_sel->desc.u.gate.selector); + rv = parse_selector(&cs_sel, callgate_sel->desc.u.gate.selector, CPU_IS_USER_MODE()); if (rv < 0) { VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", callgate_sel->desc.u.gate.selector, rv)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); @@ -631,7 +629,7 @@ CALLfar_pm_call_gate_more_privilege(sele get_stack_from_tss(cs_sel->desc.dpl, &tss_ss, &tss_esp); /* parse stack segment descriptor */ - rv = parse_selector(&ss_sel, tss_ss); + rv = parse_selector(&ss_sel, tss_ss, CPU_IS_USER_MODE()); if (rv < 0) { VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", tss_ss, rv)); EXCEPTION(TS_EXCEPTION, ss_sel.idx); @@ -706,7 +704,7 @@ CALLfar_pm_call_gate_more_privilege(sele } load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); - CPU_SP = tss_esp; + CPU_ESP = tss_esp; load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); SET_EIP(callgate_sel->desc.u.gate.offset); @@ -753,7 +751,7 @@ CALLfar_pm_task_gate(selector_t *taskgat } /* tss descriptor */ - rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector); + rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector, CPU_IS_USER_MODE()); if (rv < 0 || tss_sel.ldt) { VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d, %s)", tss_sel.selector, rv, tss_sel.ldt ? "LDT" : "GDT")); EXCEPTION(GP_EXCEPTION, tss_sel.idx); @@ -840,11 +838,12 @@ CALLfar_pm_tss(selector_t *tss_sel) void RETfar_pm(DWORD nbytes) { - selector_t ret_sel, ss_sel; + selector_t ret_sel, ss_sel, temp_sel; DWORD sp; DWORD new_ip, new_sp; WORD 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)); @@ -863,7 +862,7 @@ RETfar_pm(DWORD nbytes) new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); } - rv = parse_selector(&ret_sel, new_cs); + rv = parse_selector(&ret_sel, new_cs, CPU_IS_USER_MODE()); if (rv < 0) { VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ret_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, ret_sel.idx); @@ -932,7 +931,7 @@ RETfar_pm(DWORD nbytes) new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes + 2); } - rv = parse_selector(&ss_sel, new_ss); + rv = parse_selector(&ss_sel, new_ss, CPU_IS_USER_MODE()); if (rv < 0) { VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ss_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, ss_sel.idx); @@ -981,14 +980,51 @@ RETfar_pm(DWORD nbytes) SET_EIP(new_ip); load_ss(ss_sel.selector, &ss_sel.desc, ret_sel.rpl); - if (CPU_STAT_SS32) { - CPU_ESP = new_sp + nbytes; - } else { - CPU_SP = new_sp + nbytes; - } + CPU_ESP = new_sp + nbytes; /* check segment register */ - check_segreg(); + 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), CPU_IS_USER_MODE()); + 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)); @@ -998,32 +1034,31 @@ RETfar_pm(DWORD nbytes) /*------------------------------------------------------------------------------ * IRET_pm */ - -#undef RETURN_FROM_VM86 - static void IRET_pm_nested_task(void); static void IRET_pm_return_to_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags); -#ifdef RETURN_FROM_VM86 static void IRET_pm_return_from_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags); -#endif /* RETURN_FROM_VM86 */ void IRET_pm(void) { selector_t iret_sel, ss_sel; + descriptor_t *dp; DWORD sp; DWORD stacksize; /* for RETURN-TO-SAME-PRIVILEGE-LEVEL */ DWORD mask = 0; DWORD new_ip, new_sp, new_flags; WORD new_cs, new_ss; + int old_cpl; int rv; + int i; VERBOSE(("IRET_pm: old EIP = %04x:%08x, old ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); - if (CPU_EFLAG & NT_FLAG) { + if (!(CPU_EFLAG & VM_FLAG) && (CPU_EFLAG & NT_FLAG)) { /* TASK-RETURN: PE=1, VM=0, NT=1 */ IRET_pm_nested_task(); VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); + CPU_STAT_NERROR = 0; return; } @@ -1035,7 +1070,7 @@ IRET_pm(void) if (CPU_INST_OP32) { CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 12); new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); - new_cs = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 4); + new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); new_flags = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8); } else { CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 6); @@ -1045,26 +1080,26 @@ IRET_pm(void) } VERBOSE(("IRET_pm: new_ip = %08x, new_cs = %04x, new_eflags = %08x", new_ip, new_cs, new_flags)); -#ifdef RETURN_FROM_VM86 if (CPU_EFLAG & VM_FLAG) { /* RETURN-FROM-VIRTUAL-8086-MODE */ IRET_pm_return_from_vm86(new_ip, new_cs, new_flags); VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); + CPU_STAT_NERROR = 0; return; } -#endif /* RETURN_FROM_VM86 */ if (new_flags & VM_FLAG) { /* RETURN-TO-VIRTUAL-8086-MODE */ IRET_pm_return_to_vm86(new_ip, new_cs, new_flags); VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); + CPU_STAT_NERROR = 0; return; } /* PROTECTED-MODE-RETURN */ VERBOSE(("IRET_pm: PE=1, VM=0 in flags image")); - rv = parse_selector(&iret_sel, new_cs); + rv = parse_selector(&iret_sel, new_cs, CPU_IS_USER_MODE()); if (rv < 0) { VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", iret_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, iret_sel.idx); @@ -1102,7 +1137,7 @@ IRET_pm(void) if (CPU_INST_OP32) { CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 20); new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); - new_ss = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 16); + new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); } else { CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 10); new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 6); @@ -1110,7 +1145,7 @@ IRET_pm(void) } VERBOSE(("IRET_pm: new_sp = 0x%08x, new_ss = 0x%04x", new_sp, new_ss)); - rv = parse_selector(&ss_sel, new_ss); + rv = parse_selector(&ss_sel, new_ss, CPU_IS_USER_MODE()); if (rv < 0) { VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", ss_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, ss_sel.idx); @@ -1146,6 +1181,7 @@ IRET_pm(void) EXCEPTION(SS_EXCEPTION, ss_sel.idx); } + /* compiler happy :-) */ stacksize = 0; } else { VERBOSE(("IRET_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); @@ -1167,6 +1203,12 @@ IRET_pm(void) EXCEPTION(GP_EXCEPTION, 0); } + /* set new register */ + old_cpl = CPU_STAT_CPL; + load_cs(iret_sel.selector, &iret_sel.desc, iret_sel.rpl); + SET_EIP(new_ip); + + /* set new eflags */ mask = 0; if (CPU_INST_OP32) mask |= RF_FLAG; @@ -1178,20 +1220,27 @@ IRET_pm(void) mask |= VM_FLAG|VIF_FLAG|VIP_FLAG; } } - - /* set new register */ - load_cs(iret_sel.selector, &iret_sel.desc, iret_sel.rpl); - SET_EIP(new_ip); - set_eflags(new_flags, mask); - if (iret_sel.rpl != CPU_STAT_CPL) { + if (iret_sel.rpl > old_cpl) { /* RETURN-OUTER-PRIVILEGE-LEVEL */ - load_ss(new_ss, &ss_sel.desc, iret_sel.rpl); + + load_ss(ss_sel.selector, &ss_sel.desc, iret_sel.rpl); CPU_ESP = new_sp; /* check segment register */ - check_segreg(); + 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); + continue; + } + } + } } else { /* RETURN-TO-SAME-PRIVILEGE-LEVEL */ if (CPU_STAT_SS32) { @@ -1200,6 +1249,7 @@ IRET_pm(void) CPU_SP += stacksize; } } + CPU_STAT_NERROR = 0; VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); } @@ -1216,12 +1266,8 @@ IRET_pm_nested_task(void) VERBOSE(("IRET_pm: TASK-RETURN: PE=1, VM=0, NT=1")); - if (CPU_STAT_VM86) { - ia32_panic("IRET_pm: VM86"); - } - new_cs = get_link_selector_from_tss(); - rv = parse_selector(&iret_sel, new_cs); + rv = parse_selector(&iret_sel, new_cs, CPU_IS_USER_MODE()); if (rv < 0 || iret_sel.ldt) { VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", iret_sel.selector, rv)); EXCEPTION(GP_EXCEPTION, iret_sel.idx); @@ -1285,11 +1331,11 @@ IRET_pm_return_to_vm86(DWORD new_ip, DWO CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 36); new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); - segsel[CPU_SS_INDEX] = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 16); - segsel[CPU_ES_INDEX] = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 20); - segsel[CPU_DS_INDEX] = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 24); - segsel[CPU_FS_INDEX] = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 28); - segsel[CPU_GS_INDEX] = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 32); + 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] = new_cs; for (i = 0; i < CPU_SEGREG_NUM; i++) { @@ -1302,7 +1348,6 @@ IRET_pm_return_to_vm86(DWORD new_ip, DWO SET_EIP(new_ip); } -#ifdef RETURN_FROM_VM86 /*--- * IRET_pm: VM_FLAG */ @@ -1335,52 +1380,3 @@ IRET_pm_return_from_vm86(DWORD new_ip, D VERBOSE(("IRET_pm: trap to virtual-8086 monitor: VM=1, IOPL<3")); EXCEPTION(GP_EXCEPTION, 0); } -#endif /* RETURN_FROM_VM86 */ - - -/*----- - * Misc. - */ -static void -check_segreg(void) -{ - selector_t temp_sel; - BOOL valid; - int rv; - int i; - - /* check segment register */ - for (i = 0; i < CPU_SEGREG_NUM; i++) { - if (i == CPU_CS_INDEX || i == CPU_SS_INDEX) - 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(i).valid = 0; - 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; - } - } -}