|
|
| version 1.4, 2004/01/26 15:23:21 | version 1.7, 2004/02/04 13:24:35 |
|---|---|
| Line 34 | Line 34 |
| #include "ctrlxfer.h" | #include "ctrlxfer.h" |
| static void check_segreg(void); | |
| /*------------------------------------------------------------------------------ | /*------------------------------------------------------------------------------ |
| * JMPfar_pm | * JMPfar_pm |
| */ | */ |
| Line 53 JMPfar_pm(WORD selector, DWORD new_ip) | Line 51 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: 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)); | 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) { | if (rv < 0) { |
| VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d)", selector, rv)); | VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d)", selector, rv)); |
| EXCEPTION(GP_EXCEPTION, jmp_sel.idx); | EXCEPTION(GP_EXCEPTION, jmp_sel.idx); |
| Line 175 JMPfar_pm_call_gate(selector_t *callgate | Line 173 JMPfar_pm_call_gate(selector_t *callgate |
| } | } |
| /* parse code segment selector */ | /* 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) { | if (rv < 0) { |
| VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d)", callgate_sel->desc.u.gate.selector, rv)); | VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d)", callgate_sel->desc.u.gate.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| Line 268 JMPfar_pm_task_gate(selector_t *taskgate | Line 266 JMPfar_pm_task_gate(selector_t *taskgate |
| } | } |
| /* parse tss selector */ | /* 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) { | 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')); | 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); | EXCEPTION(GP_EXCEPTION, tss_sel.idx); |
| Line 364 CALLfar_pm(WORD selector, DWORD new_ip) | Line 362 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: 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)); | 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) { | if (rv < 0) { |
| VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", selector, rv)); | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", selector, rv)); |
| EXCEPTION(GP_EXCEPTION, call_sel.idx); | EXCEPTION(GP_EXCEPTION, call_sel.idx); |
| Line 514 CALLfar_pm_call_gate(selector_t *callgat | Line 512 CALLfar_pm_call_gate(selector_t *callgat |
| } | } |
| /* parse code segment descriptor */ | /* 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) { | if (rv < 0) { |
| VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", callgate_sel->desc.u.gate.selector, rv)); | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", callgate_sel->desc.u.gate.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| Line 631 CALLfar_pm_call_gate_more_privilege(sele | Line 629 CALLfar_pm_call_gate_more_privilege(sele |
| get_stack_from_tss(cs_sel->desc.dpl, &tss_ss, &tss_esp); | get_stack_from_tss(cs_sel->desc.dpl, &tss_ss, &tss_esp); |
| /* parse stack segment descriptor */ | /* 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) { | if (rv < 0) { |
| VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", tss_ss, rv)); | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", tss_ss, rv)); |
| EXCEPTION(TS_EXCEPTION, ss_sel.idx); | EXCEPTION(TS_EXCEPTION, ss_sel.idx); |
| Line 753 CALLfar_pm_task_gate(selector_t *taskgat | Line 751 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, CPU_IS_USER_MODE()); |
| 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, %s)", tss_sel.selector, rv, tss_sel.ldt ? "LDT" : "GDT")); |
| EXCEPTION(GP_EXCEPTION, tss_sel.idx); | EXCEPTION(GP_EXCEPTION, tss_sel.idx); |
| Line 840 CALLfar_pm_tss(selector_t *tss_sel) | Line 838 CALLfar_pm_tss(selector_t *tss_sel) |
| void | void |
| RETfar_pm(DWORD nbytes) | RETfar_pm(DWORD nbytes) |
| { | { |
| selector_t ret_sel, ss_sel; | selector_t ret_sel, ss_sel, temp_sel; |
| DWORD sp; | DWORD sp; |
| DWORD new_ip, new_sp; | DWORD new_ip, new_sp; |
| WORD new_cs, new_ss; | WORD new_cs, new_ss; |
| int rv; | 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)); | VERBOSE(("RETfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x, nbytes = %d", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP, nbytes)); |
| Line 863 RETfar_pm(DWORD nbytes) | Line 862 RETfar_pm(DWORD nbytes) |
| new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); | 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) { | if (rv < 0) { |
| VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ret_sel.selector, rv)); | VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ret_sel.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, ret_sel.idx); | EXCEPTION(GP_EXCEPTION, ret_sel.idx); |
| Line 932 RETfar_pm(DWORD nbytes) | Line 931 RETfar_pm(DWORD nbytes) |
| new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes + 2); | 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) { | if (rv < 0) { |
| VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ss_sel.selector, rv)); | VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ss_sel.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, ss_sel.idx); | EXCEPTION(GP_EXCEPTION, ss_sel.idx); |
| Line 984 RETfar_pm(DWORD nbytes) | Line 983 RETfar_pm(DWORD nbytes) |
| CPU_ESP = new_sp + nbytes; | CPU_ESP = new_sp + nbytes; |
| /* check segment register */ | /* 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)); | VERBOSE(("RETfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); |
| Line 994 RETfar_pm(DWORD nbytes) | Line 1034 RETfar_pm(DWORD nbytes) |
| /*------------------------------------------------------------------------------ | /*------------------------------------------------------------------------------ |
| * IRET_pm | * IRET_pm |
| */ | */ |
| #undef 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 iret_sel, ss_sel; |
| 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; |
| Line 1014 IRET_pm(void) | Line 1050 IRET_pm(void) |
| WORD new_cs, new_ss; | WORD new_cs, new_ss; |
| int old_cpl; | int old_cpl; |
| int rv; | int rv; |
| int i; | |
| VERBOSE(("IRET_pm: old EIP = %04x:%08x, old ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); | 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 */ | /* TASK-RETURN: PE=1, VM=0, NT=1 */ |
| IRET_pm_nested_task(); | IRET_pm_nested_task(); |
| VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); | VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); |
| Line 1043 IRET_pm(void) | Line 1080 IRET_pm(void) |
| } | } |
| 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 1051 IRET_pm(void) | Line 1087 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 1064 IRET_pm(void) | Line 1099 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(&iret_sel, new_cs, CPU_IS_USER_MODE()); |
| 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)", iret_sel.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, iret_sel.idx); |
| Line 1110 IRET_pm(void) | Line 1145 IRET_pm(void) |
| } | } |
| VERBOSE(("IRET_pm: new_sp = 0x%08x, new_ss = 0x%04x", new_sp, new_ss)); | 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) { | if (rv < 0) { |
| VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", ss_sel.selector, rv)); | VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", ss_sel.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, ss_sel.idx); | EXCEPTION(GP_EXCEPTION, ss_sel.idx); |
| Line 1189 IRET_pm(void) | Line 1224 IRET_pm(void) |
| if (iret_sel.rpl > old_cpl) { | if (iret_sel.rpl > old_cpl) { |
| /* RETURN-OUTER-PRIVILEGE-LEVEL */ | /* RETURN-OUTER-PRIVILEGE-LEVEL */ |
| load_ss(ss_sel.selector, &ss_sel.desc, iret_sel.rpl); | load_ss(ss_sel.selector, &ss_sel.desc, iret_sel.rpl); |
| CPU_ESP = new_sp; | CPU_ESP = new_sp; |
| /* check segment register */ | /* 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 { | } else { |
| /* RETURN-TO-SAME-PRIVILEGE-LEVEL */ | /* RETURN-TO-SAME-PRIVILEGE-LEVEL */ |
| if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { |
| Line 1219 IRET_pm_nested_task(void) | Line 1266 IRET_pm_nested_task(void) |
| VERBOSE(("IRET_pm: TASK-RETURN: PE=1, VM=0, NT=1")); | 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(); | 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) { | if (rv < 0 || iret_sel.ldt) { |
| VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", iret_sel.selector, rv)); | VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", iret_sel.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, iret_sel.idx); |
| Line 1305 IRET_pm_return_to_vm86(DWORD new_ip, DWO | Line 1348 IRET_pm_return_to_vm86(DWORD new_ip, DWO |
| SET_EIP(new_ip); | SET_EIP(new_ip); |
| } | } |
| #ifdef IA32_RETURN_FROM_VM86 | |
| /*--- | /*--- |
| * IRET_pm: VM_FLAG | * IRET_pm: VM_FLAG |
| */ | */ |
| Line 1338 IRET_pm_return_from_vm86(DWORD new_ip, D | Line 1380 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 */ | |
| /*----- | |
| * 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; | |
| } | |
| } | |
| } |