|
|
| version 1.5, 2004/01/27 15:55:49 | version 1.9, 2004/02/06 16:49:51 |
|---|---|
| Line 98 JMPfar_pm(WORD selector, DWORD new_ip) | Line 98 JMPfar_pm(WORD selector, DWORD new_ip) |
| break; | break; |
| } | } |
| } | } |
| VERBOSE(("JMPfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); | VERBOSE(("JMPfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); |
| } | } |
| Line 152 static void | Line 153 static void |
| JMPfar_pm_call_gate(selector_t *callgate_sel) | JMPfar_pm_call_gate(selector_t *callgate_sel) |
| { | { |
| selector_t cs_sel; | selector_t cs_sel; |
| DWORD new_ip; | |
| int rv; | int rv; |
| VERBOSE(("JMPfar_pm: CALL-GATE")); | VERBOSE(("JMPfar_pm: CALL-GATE")); |
| Line 215 JMPfar_pm_call_gate(selector_t *callgate | Line 217 JMPfar_pm_call_gate(selector_t *callgate |
| } | } |
| /* out of range */ | /* out of range */ |
| if (callgate_sel->desc.u.gate.offset > cs_sel.desc.u.seg.limit) { | new_ip = callgate_sel->desc.u.gate.offset; |
| VERBOSE(("JMPfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", callgate_sel->desc.u.gate.offset, cs_sel.desc.u.seg.limit)); | if (new_ip > cs_sel.desc.u.seg.limit) { |
| VERBOSE(("JMPfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit)); | |
| EXCEPTION(GP_EXCEPTION, 0); | EXCEPTION(GP_EXCEPTION, 0); |
| } | } |
| load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL); | load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL); |
| SET_EIP(callgate_sel->desc.u.gate.offset); | SET_EIP(new_ip); |
| } | } |
| /*--- | /*--- |
| Line 560 static void | Line 563 static void |
| CALLfar_pm_call_gate_same_privilege(selector_t *callgate_sel, selector_t *cs_sel) | CALLfar_pm_call_gate_same_privilege(selector_t *callgate_sel, selector_t *cs_sel) |
| { | { |
| DWORD sp; | DWORD sp; |
| DWORD old_eip; | DWORD new_ip; |
| WORD old_cs; | |
| VERBOSE(("CALLfar_pm: SAME-PRIVILEGE")); | VERBOSE(("CALLfar_pm: SAME-PRIVILEGE")); |
| /* save register */ | |
| old_cs = CPU_CS; | |
| old_eip = CPU_EIP; | |
| if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { |
| sp = CPU_ESP; | sp = CPU_ESP; |
| } else { | } else { |
| sp = CPU_SP; | sp = CPU_SP; |
| } | } |
| new_ip = callgate_sel->desc.u.gate.offset; | |
| if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { | if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { |
| CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 8); | CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 8); |
| load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | PUSH0_32(CPU_CS); |
| SET_EIP(callgate_sel->desc.u.gate.offset); | PUSH0_32(CPU_EIP); |
| PUSH0_32(old_cs); | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); |
| PUSH0_32(old_eip); | SET_EIP(new_ip); |
| } else { | } else { |
| CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4); | CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4); |
| load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | PUSH0_16(CPU_CS); |
| SET_EIP(callgate_sel->desc.u.gate.offset); | PUSH0_16(CPU_IP); |
| PUSH0_16(old_cs); | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); |
| PUSH0_16(old_eip); | SET_EIP(new_ip); |
| } | } |
| } | } |
| Line 604 CALLfar_pm_call_gate_more_privilege(sele | Line 603 CALLfar_pm_call_gate_more_privilege(sele |
| selector_t ss_sel; | selector_t ss_sel; |
| DWORD sp; | DWORD sp; |
| DWORD old_eip, old_esp; | DWORD old_eip, old_esp; |
| DWORD tss_esp; | DWORD new_esp; |
| WORD old_cs, old_ss; | WORD old_cs, old_ss; |
| WORD tss_ss; | WORD new_ss; |
| int param_count; | int param_count; |
| int i; | int i; |
| int rv; | int rv; |
| Line 626 CALLfar_pm_call_gate_more_privilege(sele | Line 625 CALLfar_pm_call_gate_more_privilege(sele |
| } | } |
| /* get stack pointer from TSS */ | /* get stack pointer from TSS */ |
| get_stack_from_tss(cs_sel->desc.dpl, &tss_ss, &tss_esp); | get_stack_from_tss(cs_sel->desc.dpl, &new_ss, &new_esp); |
| /* parse stack segment descriptor */ | /* parse stack segment descriptor */ |
| rv = parse_selector(&ss_sel, tss_ss); | rv = parse_selector(&ss_sel, new_ss); |
| if (rv < 0) { | if (rv < 0) { |
| VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", tss_ss, rv)); | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", new_ss, rv)); |
| EXCEPTION(TS_EXCEPTION, ss_sel.idx); | EXCEPTION(TS_EXCEPTION, ss_sel.idx); |
| } | } |
| Line 669 CALLfar_pm_call_gate_more_privilege(sele | Line 668 CALLfar_pm_call_gate_more_privilege(sele |
| VERBOSE(("CALLfar_pm: param_count = %d", param_count)); | VERBOSE(("CALLfar_pm: param_count = %d", param_count)); |
| if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { | if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { |
| CHECK_STACK_PUSH(&ss_sel.desc, tss_esp, 16 + param_count * 4); | CHECK_STACK_PUSH(&ss_sel.desc, new_esp, 16 + param_count * 4); |
| /* dump param */ | /* dump param */ |
| for (i = 0; i < param_count; i++) { | for (i = 0; i < param_count; i++) { |
| Line 678 CALLfar_pm_call_gate_more_privilege(sele | Line 677 CALLfar_pm_call_gate_more_privilege(sele |
| } | } |
| load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); | load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); |
| CPU_ESP = tss_esp; | if (CPU_STAT_SS32) { |
| CPU_ESP = new_esp; | |
| } else { | |
| CPU_SP = new_esp; | |
| } | |
| load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); | load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); |
| SET_EIP(callgate_sel->desc.u.gate.offset); | SET_EIP(callgate_sel->desc.u.gate.offset); |
| Line 695 CALLfar_pm_call_gate_more_privilege(sele | Line 698 CALLfar_pm_call_gate_more_privilege(sele |
| PUSH0_32(old_cs); | PUSH0_32(old_cs); |
| PUSH0_32(old_eip); | PUSH0_32(old_eip); |
| } else { | } else { |
| CHECK_STACK_PUSH(&ss_sel.desc, tss_esp, 8 + param_count * 2); | CHECK_STACK_PUSH(&ss_sel.desc, new_esp, 8 + param_count * 2); |
| /* dump param */ | /* dump param */ |
| for (i = 0; i < param_count; i++) { | for (i = 0; i < param_count; i++) { |
| Line 704 CALLfar_pm_call_gate_more_privilege(sele | Line 707 CALLfar_pm_call_gate_more_privilege(sele |
| } | } |
| load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); | load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); |
| CPU_ESP = tss_esp; | if (CPU_STAT_SS32) { |
| CPU_ESP = new_esp; | |
| } else { | |
| CPU_SP = new_esp; | |
| } | |
| load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); | load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); |
| SET_EIP(callgate_sel->desc.u.gate.offset); | SET_EIP(callgate_sel->desc.u.gate.offset); |
| Line 753 CALLfar_pm_task_gate(selector_t *taskgat | Line 760 CALLfar_pm_task_gate(selector_t *taskgat |
| /* tss descriptor */ | /* tss descriptor */ |
| rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector); | rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector); |
| if (rv < 0 || tss_sel.ldt) { | 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")); | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d, %cDT)", tss_sel.selector, rv, tss_sel.ldt ? 'L' : 'G')); |
| EXCEPTION(GP_EXCEPTION, tss_sel.idx); | EXCEPTION(GP_EXCEPTION, tss_sel.idx); |
| } | } |
| Line 855 RETfar_pm(DWORD nbytes) | Line 862 RETfar_pm(DWORD nbytes) |
| if (CPU_INST_OP32) { | if (CPU_INST_OP32) { |
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 8); | CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 8); |
| new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); | 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); |
| } else { | } else { |
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 4); | CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 4); |
| new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); | new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); |
| Line 980 RETfar_pm(DWORD nbytes) | Line 987 RETfar_pm(DWORD nbytes) |
| SET_EIP(new_ip); | SET_EIP(new_ip); |
| load_ss(ss_sel.selector, &ss_sel.desc, ret_sel.rpl); | load_ss(ss_sel.selector, &ss_sel.desc, ret_sel.rpl); |
| CPU_ESP = new_sp + nbytes; | if (CPU_STAT_SS32) { |
| CPU_ESP = new_sp + nbytes; | |
| } else { | |
| CPU_SP = new_sp + nbytes; | |
| } | |
| /* check segment register */ | /* check segment register */ |
| for (i = 0; i < CPU_SEGREG_NUM; i++) { | for (i = 0; i < CPU_SEGREG_NUM; i++) { |
| Line 1034 RETfar_pm(DWORD nbytes) | Line 1045 RETfar_pm(DWORD nbytes) |
| /*------------------------------------------------------------------------------ | /*------------------------------------------------------------------------------ |
| * IRET_pm | * IRET_pm |
| */ | */ |
| #define IA32_RETURN_FROM_VM86 | |
| static void IRET_pm_nested_task(void); | static void IRET_pm_nested_task(void); |
| static void IRET_pm_return_to_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags); | static void IRET_pm_return_to_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags); |
| #if defined(IA32_RETURN_FROM_VM86) | |
| static void IRET_pm_return_from_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags); | static void IRET_pm_return_from_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags); |
| #endif /* IA32_RETURN_FROM_VM86 */ | |
| void | void |
| IRET_pm(void) | IRET_pm(void) |
| { | { |
| selector_t iret_sel, ss_sel; | selector_t cs_sel, ss_sel; |
| descriptor_t *dp; | descriptor_t *dp; |
| DWORD sp; | DWORD sp; |
| DWORD stacksize; /* for RETURN-TO-SAME-PRIVILEGE-LEVEL */ | DWORD stacksize; /* for RETURN-TO-SAME-PRIVILEGE-LEVEL */ |
| DWORD mask = 0; | DWORD mask = 0; |
| DWORD new_ip, new_sp, new_flags; | DWORD new_ip, new_sp, new_flags; |
| WORD new_cs, new_ss; | WORD new_cs, new_ss; |
| int old_cpl; | int op32; |
| int rv; | int rv; |
| int i; | int i; |
| Line 1083 IRET_pm(void) | Line 1089 IRET_pm(void) |
| new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); | new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); |
| new_flags = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); | new_flags = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); |
| } | } |
| op32 = CPU_INST_OP32; | |
| VERBOSE(("IRET_pm: new_ip = %08x, new_cs = %04x, new_eflags = %08x", new_ip, new_cs, new_flags)); | VERBOSE(("IRET_pm: new_ip = %08x, new_cs = %04x, new_eflags = %08x", new_ip, new_cs, new_flags)); |
| #ifdef IA32_RETURN_FROM_VM86 | |
| if (CPU_EFLAG & VM_FLAG) { | if (CPU_EFLAG & VM_FLAG) { |
| /* RETURN-FROM-VIRTUAL-8086-MODE */ | /* RETURN-FROM-VIRTUAL-8086-MODE */ |
| IRET_pm_return_from_vm86(new_ip, new_cs, new_flags); | IRET_pm_return_from_vm86(new_ip, new_cs, new_flags); |
| Line 1093 IRET_pm(void) | Line 1100 IRET_pm(void) |
| CPU_STAT_NERROR = 0; | CPU_STAT_NERROR = 0; |
| return; | return; |
| } | } |
| #endif /* IA32_RETURN_FROM_VM86 */ | |
| if (new_flags & VM_FLAG) { | if (new_flags & VM_FLAG) { |
| /* RETURN-TO-VIRTUAL-8086-MODE */ | /* RETURN-TO-VIRTUAL-8086-MODE */ |
| Line 1106 IRET_pm(void) | Line 1112 IRET_pm(void) |
| /* PROTECTED-MODE-RETURN */ | /* PROTECTED-MODE-RETURN */ |
| VERBOSE(("IRET_pm: PE=1, VM=0 in flags image")); | VERBOSE(("IRET_pm: PE=1, VM=0 in flags image")); |
| rv = parse_selector(&iret_sel, new_cs); | rv = parse_selector(&cs_sel, new_cs); |
| if (rv < 0) { | if (rv < 0) { |
| VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", iret_sel.selector, rv)); | VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", cs_sel.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| /* check code segment descriptor */ | /* check code segment descriptor */ |
| if (!iret_sel.desc.s) { | if (!cs_sel.desc.s) { |
| VERBOSE(("IRET_pm: return code segment is system segment")); | VERBOSE(("IRET_pm: return code segment is system segment")); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| if (!iret_sel.desc.u.seg.c) { | if (!cs_sel.desc.u.seg.c) { |
| VERBOSE(("IRET_pm: return code segment is data segment")); | VERBOSE(("IRET_pm: return code segment is data segment")); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| /* check privilege level */ | /* check privilege level */ |
| if (iret_sel.rpl < CPU_STAT_CPL) { | if (cs_sel.rpl < CPU_STAT_CPL) { |
| VERBOSE(("IRET_pm: RPL(%d) < CPL(%d)", iret_sel.rpl, CPU_STAT_CPL)); | VERBOSE(("IRET_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| if (iret_sel.desc.u.seg.ec && (iret_sel.desc.dpl > iret_sel.rpl)) { | if (cs_sel.desc.u.seg.ec && (cs_sel.desc.dpl > cs_sel.rpl)) { |
| VERBOSE(("IRET_pm: CONFORMING-CODE-SEGMENT and DPL(%d) != RPL(%d)", iret_sel.desc.dpl, iret_sel.rpl)); | VERBOSE(("IRET_pm: CONFORMING-CODE-SEGMENT and DPL(%d) != RPL(%d)", cs_sel.desc.dpl, cs_sel.rpl)); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| /* not present */ | /* not present */ |
| if (selector_is_not_present(&iret_sel)) { | if (selector_is_not_present(&cs_sel)) { |
| VERBOSE(("IRET_pm: code segment is not present")); | VERBOSE(("IRET_pm: code segment is not present")); |
| EXCEPTION(NP_EXCEPTION, iret_sel.idx); | EXCEPTION(NP_EXCEPTION, cs_sel.idx); |
| } | } |
| if (iret_sel.rpl > CPU_STAT_CPL) { | if (cs_sel.rpl > CPU_STAT_CPL) { |
| VERBOSE(("IRET_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); | VERBOSE(("IRET_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); |
| if (CPU_INST_OP32) { | if (CPU_INST_OP32) { |
| Line 1159 IRET_pm(void) | Line 1165 IRET_pm(void) |
| } | } |
| /* check privilege level */ | /* check privilege level */ |
| if (ss_sel.rpl != iret_sel.rpl) { | if (ss_sel.rpl != cs_sel.rpl) { |
| VERBOSE(("IRET_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, iret_sel.rpl)); | VERBOSE(("IRET_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel.rpl)); |
| EXCEPTION(GP_EXCEPTION, ss_sel.idx); | EXCEPTION(GP_EXCEPTION, ss_sel.idx); |
| } | } |
| if (ss_sel.desc.dpl != iret_sel.rpl) { | if (ss_sel.desc.dpl != cs_sel.rpl) { |
| VERBOSE(("IRET_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, iret_sel.rpl)); | VERBOSE(("IRET_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel.rpl)); |
| EXCEPTION(GP_EXCEPTION, ss_sel.idx); | EXCEPTION(GP_EXCEPTION, ss_sel.idx); |
| } | } |
| Line 1188 IRET_pm(void) | Line 1194 IRET_pm(void) |
| EXCEPTION(SS_EXCEPTION, ss_sel.idx); | EXCEPTION(SS_EXCEPTION, ss_sel.idx); |
| } | } |
| /* compiler happy :-) */ | /* check code segment limit */ |
| stacksize = 0; | if (new_ip > cs_sel.desc.u.seg.limit) { |
| } else { | VERBOSE(("IRET_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit)); |
| VERBOSE(("IRET_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); | EXCEPTION(GP_EXCEPTION, 0); |
| if (CPU_INST_OP32) { | |
| stacksize = 12; | |
| } else { | |
| stacksize = 6; | |
| } | } |
| /* compiler happy :-) */ | mask = 0; |
| new_sp = 0; | if (CPU_INST_OP32) |
| new_ss = 0; | mask |= RF_FLAG; |
| } | if (CPU_STAT_CPL <= CPU_STAT_IOPL) |
| mask |= I_FLAG; | |
| /* check code segment limit */ | if (CPU_STAT_CPL == 0) { |
| if (new_ip > iret_sel.desc.u.seg.limit) { | mask |= IOPL_FLAG; |
| VERBOSE(("IRET_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, iret_sel.desc.u.seg.limit)); | if (CPU_INST_OP32) { |
| EXCEPTION(GP_EXCEPTION, 0); | mask |= VM_FLAG|VIF_FLAG|VIP_FLAG; |
| } | } |
| } | |
| /* set new register */ | /* set new register */ |
| old_cpl = CPU_STAT_CPL; | load_cs(cs_sel.selector, &cs_sel.desc, cs_sel.rpl); |
| load_cs(iret_sel.selector, &iret_sel.desc, iret_sel.rpl); | SET_EIP(new_ip); |
| SET_EIP(new_ip); | |
| /* set new eflags */ | if (op32) { |
| mask = 0; | set_eflags(new_flags, mask); |
| if (CPU_INST_OP32) | } else { |
| mask |= RF_FLAG; | set_flags(new_flags, mask); |
| 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_eflags(new_flags, mask); | |
| if (iret_sel.rpl > old_cpl) { | load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.rpl); |
| /* RETURN-OUTER-PRIVILEGE-LEVEL */ | if (CPU_STAT_SS32) { |
| CPU_ESP = new_sp; | |
| load_ss(ss_sel.selector, &ss_sel.desc, iret_sel.rpl); | } else { |
| CPU_ESP = new_sp; | CPU_SP = new_sp; |
| } | |
| /* check segment register */ | /* check segment register */ |
| for (i = 0; i < CPU_SEGREG_NUM; i++) { | for (i = 0; i < CPU_SEGREG_NUM; i++) { |
| Line 1249 IRET_pm(void) | Line 1243 IRET_pm(void) |
| } | } |
| } | } |
| } else { | } else { |
| /* RETURN-TO-SAME-PRIVILEGE-LEVEL */ | VERBOSE(("IRET_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); |
| /* 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, CPU_STAT_CPL); | |
| SET_EIP(new_ip); | |
| if (op32) { | |
| set_eflags(new_flags, mask); | |
| } else { | |
| set_flags(new_flags, mask); | |
| } | |
| if (CPU_INST_OP32) { | |
| stacksize = 12; | |
| } else { | |
| stacksize = 6; | |
| } | |
| if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { |
| CPU_ESP += stacksize; | CPU_ESP += stacksize; |
| } else { | } else { |
| Line 1267 IRET_pm(void) | Line 1295 IRET_pm(void) |
| static void | static void |
| IRET_pm_nested_task(void) | IRET_pm_nested_task(void) |
| { | { |
| selector_t iret_sel; | selector_t tss_sel; |
| int rv; | int rv; |
| WORD new_cs; | WORD new_tss; |
| VERBOSE(("IRET_pm: TASK-RETURN: PE=1, VM=0, NT=1")); | VERBOSE(("IRET_pm: TASK-RETURN: PE=1, VM=0, NT=1")); |
| new_cs = get_link_selector_from_tss(); | new_tss = get_link_selector_from_tss(); |
| rv = parse_selector(&iret_sel, new_cs); | |
| if (rv < 0 || iret_sel.ldt) { | rv = parse_selector(&tss_sel, new_tss); |
| VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", iret_sel.selector, rv)); | if (rv < 0 || tss_sel.ldt) { |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d, %cDT)", tss_sel.selector, rv, tss_sel.ldt ? 'L' : 'G')); |
| EXCEPTION(GP_EXCEPTION, tss_sel.idx); | |
| } | } |
| /* check system segment */ | /* check system segment */ |
| if (iret_sel.desc.s) { | if (tss_sel.desc.s) { |
| VERBOSE(("IRET_pm: task segment is %d segment", iret_sel.desc.u.seg.c ? "code" : "data")); | VERBOSE(("IRET_pm: task segment is %d segment", tss_sel.desc.u.seg.c ? "code" : "data")); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, tss_sel.idx); |
| } | } |
| switch (iret_sel.desc.type) { | switch (tss_sel.desc.type) { |
| case CPU_SYSDESC_TYPE_TSS_BUSY_16: | case CPU_SYSDESC_TYPE_TSS_BUSY_16: |
| case CPU_SYSDESC_TYPE_TSS_BUSY_32: | case CPU_SYSDESC_TYPE_TSS_BUSY_32: |
| break; | break; |
| Line 1296 IRET_pm_nested_task(void) | Line 1325 IRET_pm_nested_task(void) |
| VERBOSE(("IRET_pm: task is not busy")); | VERBOSE(("IRET_pm: task is not busy")); |
| /*FALLTHROUGH*/ | /*FALLTHROUGH*/ |
| default: | default: |
| VERBOSE(("IRET_pm: invalid descriptor type (type = %d)", iret_sel.desc.type)); | VERBOSE(("IRET_pm: invalid descriptor type (type = %d)", tss_sel.desc.type)); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, tss_sel.idx); |
| break; | break; |
| } | } |
| /* not present */ | /* not present */ |
| if (selector_is_not_present(&iret_sel)) { | if (selector_is_not_present(&tss_sel)) { |
| VERBOSE(("IRET_pm: tss segment is not present")); | VERBOSE(("IRET_pm: tss segment is not present")); |
| EXCEPTION(NP_EXCEPTION, iret_sel.idx); | EXCEPTION(NP_EXCEPTION, tss_sel.idx); |
| } | } |
| task_switch(&iret_sel, TASK_SWITCH_IRET); | task_switch(&tss_sel, TASK_SWITCH_IRET); |
| } | } |
| /*--- | /*--- |
| Line 1327 IRET_pm_return_to_vm86(DWORD new_ip, DWO | Line 1356 IRET_pm_return_to_vm86(DWORD new_ip, DWO |
| ia32_panic("IRET_pm: CPL != 0"); | ia32_panic("IRET_pm: CPL != 0"); |
| } | } |
| if (!CPU_INST_OP32) { | |
| ia32_panic("IRET_pm: 16bit mode"); | |
| } | |
| if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { |
| sp = CPU_ESP; | sp = CPU_ESP; |
| } else { | } else { |
| sp = CPU_SP; | sp = CPU_SP; |
| } | } |
| if (!CPU_INST_OP32) { | |
| ia32_panic("IRET_pm: 16bit mode"); | |
| } | |
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 36); | CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 36); |
| new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); | new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); |
| segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); | segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); |
| Line 1347 IRET_pm_return_to_vm86(DWORD new_ip, DWO | Line 1376 IRET_pm_return_to_vm86(DWORD new_ip, DWO |
| for (i = 0; i < CPU_SEGREG_NUM; i++) { | for (i = 0; i < CPU_SEGREG_NUM; i++) { |
| CPU_REGS_SREG(i) = segsel[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); | set_eflags(new_flags, IOPL_FLAG|I_FLAG|VM_FLAG|RF_FLAG); |
| CPU_ESP = new_sp; | CPU_ESP = new_sp; |
| new_ip &= 0xffff; | |
| SET_EIP(new_ip); | SET_EIP(new_ip); |
| } | } |
| #ifdef IA32_RETURN_FROM_VM86 | |
| /*--- | /*--- |
| * IRET_pm: VM_FLAG | * IRET_pm: VM_FLAG |
| */ | */ |
| Line 1379 IRET_pm_return_from_vm86(DWORD new_ip, D | Line 1410 IRET_pm_return_from_vm86(DWORD new_ip, D |
| CPU_SP += stacksize; | CPU_SP += stacksize; |
| } | } |
| set_eflags(new_flags, I_FLAG|RF_FLAG); | if (CPU_INST_OP32) { |
| set_eflags(new_flags, I_FLAG|RF_FLAG); | |
| } else { | |
| set_flags(new_flags, I_FLAG|RF_FLAG); | |
| } | |
| CPU_SET_SEGREG(CPU_CS_INDEX, new_cs); | CPU_SET_SEGREG(CPU_CS_INDEX, new_cs); |
| SET_EIP(new_ip); | SET_EIP(new_ip); |
| Line 1388 IRET_pm_return_from_vm86(DWORD new_ip, D | Line 1423 IRET_pm_return_from_vm86(DWORD new_ip, D |
| VERBOSE(("IRET_pm: trap to virtual-8086 monitor: VM=1, IOPL<3")); | VERBOSE(("IRET_pm: trap to virtual-8086 monitor: VM=1, IOPL<3")); |
| EXCEPTION(GP_EXCEPTION, 0); | EXCEPTION(GP_EXCEPTION, 0); |
| } | } |
| #endif /* IA32_RETURN_FROM_VM86 */ |