| version 1.10, 2004/02/09 16:12:07 | version 1.25, 2012/02/05 06:31:44 | 
| Line 1 | Line 1 | 
 | /*      $Id$    */ |  | 
 |  |  | 
 | /* | /* | 
 | * Copyright (c) 2003 NONAKA Kimihiro | * Copyright (c) 2003 NONAKA Kimihiro | 
 | * All rights reserved. | * All rights reserved. | 
| Line 12 | Line 10 | 
 | * 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | 
 | *    notice, this list of conditions and the following disclaimer in the | *    notice, this list of conditions and the following disclaimer in the | 
 | *    documentation and/or other materials provided with the distribution. | *    documentation and/or other materials provided with the distribution. | 
 | * 3. The name of the author may not be used to endorse or promote products |  | 
 | *    derived from this software without specific prior written permission. |  | 
 | * | * | 
 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 
 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 
| Line 37 | Line 33 | 
 | /*------------------------------------------------------------------------------ | /*------------------------------------------------------------------------------ | 
 | * JMPfar_pm | * JMPfar_pm | 
 | */ | */ | 
| static void JMPfar_pm_code_segment(selector_t *jmp_sel, DWORD new_ip); | static void CPUCALL JMPfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip); | 
| static void JMPfar_pm_call_gate(selector_t *jmp_sel); | static void CPUCALL JMPfar_pm_call_gate(const selector_t *callgate_sel); | 
| static void JMPfar_pm_task_gate(selector_t *jmp_sel); | static void CPUCALL JMPfar_pm_task_gate(selector_t *taskgate_sel); | 
| static void JMPfar_pm_tss(selector_t *jmp_sel); | static void CPUCALL JMPfar_pm_tss(selector_t *tss_sel); | 
 |  |  | 
| void | void CPUCALL | 
| JMPfar_pm(WORD selector, DWORD new_ip) | JMPfar_pm(UINT16 selector, UINT32 new_ip) | 
 | { | { | 
 | selector_t jmp_sel; | selector_t jmp_sel; | 
 | int rv; | int rv; | 
| Line 57  JMPfar_pm(WORD selector, DWORD new_ip) | Line 53  JMPfar_pm(WORD selector, DWORD new_ip) | 
 | EXCEPTION(GP_EXCEPTION, jmp_sel.idx); | EXCEPTION(GP_EXCEPTION, jmp_sel.idx); | 
 | } | } | 
 |  |  | 
| if (jmp_sel.desc.s) { | if (!SEG_IS_SYSTEM(&jmp_sel.desc)) { | 
 | VERBOSE(("JMPfar_pm: code or data segment descriptor")); | VERBOSE(("JMPfar_pm: code or data segment descriptor")); | 
 |  |  | 
 | /* check segment type */ | /* check segment type */ | 
| if (!jmp_sel.desc.u.seg.c) { | if (SEG_IS_DATA(&jmp_sel.desc)) { | 
 | /* data segment */ | /* data segment */ | 
 | VERBOSE(("JMPfar_pm: data segment")); | VERBOSE(("JMPfar_pm: data segment")); | 
 | EXCEPTION(GP_EXCEPTION, jmp_sel.idx); | EXCEPTION(GP_EXCEPTION, jmp_sel.idx); | 
| Line 105  JMPfar_pm(WORD selector, DWORD new_ip) | Line 101  JMPfar_pm(WORD selector, DWORD new_ip) | 
 | /*--- | /*--- | 
 | * JMPfar: code segment | * JMPfar: code segment | 
 | */ | */ | 
| static void | static void CPUCALL | 
| JMPfar_pm_code_segment(selector_t *cs_sel, DWORD new_ip) | JMPfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip) | 
 | { | { | 
 |  |  | 
 | VERBOSE(("JMPfar_pm: CODE-SEGMENT")); | VERBOSE(("JMPfar_pm: CODE-SEGMENT")); | 
 |  |  | 
 | /* check privilege level */ | /* check privilege level */ | 
| if (!cs_sel->desc.u.seg.ec) { | if (!SEG_IS_CONFORMING_CODE(&cs_sel->desc)) { | 
 | VERBOSE(("JMPfar_pm: NON-CONFORMING-CODE-SEGMENT")); | VERBOSE(("JMPfar_pm: NON-CONFORMING-CODE-SEGMENT")); | 
| /* イシエャ p.119 4.8.1.1. */ | /* 荳句キサ p.119 4.8.1.1. */ | 
 | if (cs_sel->rpl > CPU_STAT_CPL) { | if (cs_sel->rpl > CPU_STAT_CPL) { | 
 | VERBOSE(("JMPfar_pm: RPL(%d) > CPL(%d)", cs_sel->rpl, CPU_STAT_CPL)); | VERBOSE(("JMPfar_pm: RPL(%d) > CPL(%d)", cs_sel->rpl, CPU_STAT_CPL)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel->idx); | EXCEPTION(GP_EXCEPTION, cs_sel->idx); | 
| Line 125  JMPfar_pm_code_segment(selector_t *cs_se | Line 121  JMPfar_pm_code_segment(selector_t *cs_se | 
 | } | } | 
 | } else { | } else { | 
 | VERBOSE(("JMPfar_pm: CONFORMING-CODE-SEGMENT")); | VERBOSE(("JMPfar_pm: CONFORMING-CODE-SEGMENT")); | 
| /* イシエャ p.120 4.8.1.2. */ | /* 荳句キサ p.120 4.8.1.2. */ | 
 | if (cs_sel->desc.dpl > CPU_STAT_CPL) { | if (cs_sel->desc.dpl > CPU_STAT_CPL) { | 
 | VERBOSE(("JMPfar_pm: DPL(%d) > CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL)); | VERBOSE(("JMPfar_pm: DPL(%d) > CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel->idx); | EXCEPTION(GP_EXCEPTION, cs_sel->idx); | 
| Line 134  JMPfar_pm_code_segment(selector_t *cs_se | Line 130  JMPfar_pm_code_segment(selector_t *cs_se | 
 |  |  | 
 | /* not present */ | /* not present */ | 
 | if (selector_is_not_present(cs_sel)) { | if (selector_is_not_present(cs_sel)) { | 
| VERBOSE(("JMPfar_pm: selector is not present")); | VERBOSE(("JMPfar_pm: code selector is not present")); | 
 | EXCEPTION(NP_EXCEPTION, cs_sel->idx); | EXCEPTION(NP_EXCEPTION, cs_sel->idx); | 
 | } | } | 
 |  |  | 
| Line 145  JMPfar_pm_code_segment(selector_t *cs_se | Line 141  JMPfar_pm_code_segment(selector_t *cs_se | 
 | } | } | 
 |  |  | 
 | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | 
| SET_EIP(new_ip); | CPU_EIP = new_ip; | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
 | * JMPfar: call gate | * JMPfar: call gate | 
 | */ | */ | 
| static void | static void CPUCALL | 
| JMPfar_pm_call_gate(selector_t *callgate_sel) | JMPfar_pm_call_gate(const selector_t *callgate_sel) | 
 | { | { | 
 | selector_t cs_sel; | selector_t cs_sel; | 
 | int rv; | int rv; | 
| Line 171  JMPfar_pm_call_gate(selector_t *callgate | Line 167  JMPfar_pm_call_gate(selector_t *callgate | 
 |  |  | 
 | /* not present */ | /* not present */ | 
 | if (selector_is_not_present(callgate_sel)) { | if (selector_is_not_present(callgate_sel)) { | 
| VERBOSE(("JMPfar_pm: selector is not present")); | VERBOSE(("JMPfar_pm: call gate selector is not present")); | 
 | EXCEPTION(NP_EXCEPTION, callgate_sel->idx); | EXCEPTION(NP_EXCEPTION, callgate_sel->idx); | 
 | } | } | 
 |  |  | 
| Line 183  JMPfar_pm_call_gate(selector_t *callgate | Line 179  JMPfar_pm_call_gate(selector_t *callgate | 
 | } | } | 
 |  |  | 
 | /* check segment type */ | /* check segment type */ | 
| if (!cs_sel.desc.s) { | if (SEG_IS_SYSTEM(&cs_sel.desc)) { | 
 | VERBOSE(("JMPfar_pm: code segment is system segment")); | VERBOSE(("JMPfar_pm: code segment is system segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| if (!cs_sel.desc.u.seg.c) { | if (SEG_IS_DATA(&cs_sel.desc)) { | 
 | VERBOSE(("JMPfar_pm: code segment is data segment")); | VERBOSE(("JMPfar_pm: code segment is data segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 |  |  | 
 | /* check privilege level */ | /* check privilege level */ | 
| if (!cs_sel.desc.u.seg.ec) { | if (!SEG_IS_CONFORMING_CODE(&cs_sel.desc)) { | 
| /* イシエャ p.119 4.8.1.1. */ | /* 荳句キサ p.119 4.8.1.1. */ | 
 | if (cs_sel.rpl > CPU_STAT_CPL) { | if (cs_sel.rpl > CPU_STAT_CPL) { | 
 | VERBOSE(("JMPfar_pm: RPL(%d) > CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); | VERBOSE(("JMPfar_pm: RPL(%d) > CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
| Line 204  JMPfar_pm_call_gate(selector_t *callgate | Line 200  JMPfar_pm_call_gate(selector_t *callgate | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 | } else { | } else { | 
| /* イシエャ p.120 4.8.1.2. */ | /* 荳句キサ p.120 4.8.1.2. */ | 
 | if (cs_sel.desc.dpl > CPU_STAT_CPL) { | if (cs_sel.desc.dpl > CPU_STAT_CPL) { | 
 | VERBOSE(("JMPfar_pm: DPL(%d) > CPL(%d)", cs_sel.desc.dpl, CPU_STAT_CPL)); | VERBOSE(("JMPfar_pm: DPL(%d) > CPL(%d)", cs_sel.desc.dpl, CPU_STAT_CPL)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
| Line 213  JMPfar_pm_call_gate(selector_t *callgate | Line 209  JMPfar_pm_call_gate(selector_t *callgate | 
 |  |  | 
 | /* not present */ | /* not present */ | 
 | if (selector_is_not_present(&cs_sel)) { | if (selector_is_not_present(&cs_sel)) { | 
| VERBOSE(("JMPfar_pm: selector is not present")); | VERBOSE(("JMPfar_pm: code selector is not present")); | 
 | EXCEPTION(NP_EXCEPTION, cs_sel.idx); | EXCEPTION(NP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 |  |  | 
| Line 224  JMPfar_pm_call_gate(selector_t *callgate | Line 220  JMPfar_pm_call_gate(selector_t *callgate | 
 | } | } | 
 |  |  | 
 | 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); | CPU_EIP = callgate_sel->desc.u.gate.offset; | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
 | * JMPfar: task gate | * JMPfar: task gate | 
 | */ | */ | 
| static void | static void CPUCALL | 
 | JMPfar_pm_task_gate(selector_t *taskgate_sel) | JMPfar_pm_task_gate(selector_t *taskgate_sel) | 
 | { | { | 
 | selector_t tss_sel; | selector_t tss_sel; | 
| Line 284  JMPfar_pm_task_gate(selector_t *taskgate | Line 280  JMPfar_pm_task_gate(selector_t *taskgate | 
 | } | } | 
 |  |  | 
 | task_switch(&tss_sel, TASK_SWITCH_JMP); | task_switch(&tss_sel, TASK_SWITCH_JMP); | 
 |  |  | 
 |  | /* out of range */ | 
 |  | if (CPU_EIP > CPU_STAT_CS_LIMIT) { | 
 |  | VERBOSE(("JMPfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", CPU_EIP, CPU_STAT_CS_LIMIT)); | 
 |  | EXCEPTION(GP_EXCEPTION, 0); | 
 |  | } | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
 | * JMPfar: TSS | * JMPfar: TSS | 
 | */ | */ | 
| static void | static void CPUCALL | 
 | JMPfar_pm_tss(selector_t *tss_sel) | JMPfar_pm_tss(selector_t *tss_sel) | 
 | { | { | 
 |  |  | 
| Line 312  JMPfar_pm_tss(selector_t *tss_sel) | Line 314  JMPfar_pm_tss(selector_t *tss_sel) | 
 | } | } | 
 |  |  | 
 | task_switch(tss_sel, TASK_SWITCH_JMP); | task_switch(tss_sel, TASK_SWITCH_JMP); | 
 |  |  | 
 |  | /* out of range */ | 
 |  | if (CPU_EIP > CPU_STAT_CS_LIMIT) { | 
 |  | VERBOSE(("JMPfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", CPU_EIP, CPU_STAT_CS_LIMIT)); | 
 |  | EXCEPTION(GP_EXCEPTION, 0); | 
 |  | } | 
 | } | } | 
 |  |  | 
 |  |  | 
 | /*------------------------------------------------------------------------------ | /*------------------------------------------------------------------------------ | 
 | * CALLfar_pm | * CALLfar_pm | 
 | */ | */ | 
| static void CALLfar_pm_code_segment(selector_t *call_sel, DWORD new_ip); | static void CPUCALL CALLfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip); | 
| static void CALLfar_pm_call_gate(selector_t *call_sel); | static void CPUCALL CALLfar_pm_call_gate(const selector_t *callgate_sel); | 
| static void CALLfar_pm_task_gate(selector_t *call_sel); | static void CPUCALL CALLfar_pm_task_gate(selector_t *taskgate_sel); | 
| static void CALLfar_pm_tss(selector_t *call_sel); | static void CPUCALL CALLfar_pm_tss(selector_t *tss_sel); | 
 |  |  | 
| void | void CPUCALL | 
| CALLfar_pm(WORD selector, DWORD new_ip) | CALLfar_pm(UINT16 selector, UINT32 new_ip) | 
 | { | { | 
 | selector_t call_sel; | selector_t call_sel; | 
 | int rv; | int rv; | 
| Line 338  CALLfar_pm(WORD selector, DWORD new_ip) | Line 346  CALLfar_pm(WORD selector, DWORD new_ip) | 
 | EXCEPTION(GP_EXCEPTION, call_sel.idx); | EXCEPTION(GP_EXCEPTION, call_sel.idx); | 
 | } | } | 
 |  |  | 
| if (call_sel.desc.s) { | if (!SEG_IS_SYSTEM(&call_sel.desc)) { | 
 | /* code or data segment descriptor */ | /* code or data segment descriptor */ | 
 | VERBOSE(("CALLfar_pm: code or data segment descriptor")); | VERBOSE(("CALLfar_pm: code or data segment descriptor")); | 
 |  |  | 
| if (!call_sel.desc.u.seg.c) { | if (SEG_IS_DATA(&call_sel.desc)) { | 
 | /* data segment */ | /* data segment */ | 
 | VERBOSE(("CALLfar_pm: data segment")); | VERBOSE(("CALLfar_pm: data segment")); | 
 | EXCEPTION(GP_EXCEPTION, call_sel.idx); | EXCEPTION(GP_EXCEPTION, call_sel.idx); | 
| Line 386  CALLfar_pm(WORD selector, DWORD new_ip) | Line 394  CALLfar_pm(WORD selector, DWORD new_ip) | 
 | /*--- | /*--- | 
 | * CALLfar_pm: code segment | * CALLfar_pm: code segment | 
 | */ | */ | 
| static void | static void CPUCALL | 
| CALLfar_pm_code_segment(selector_t *cs_sel, DWORD new_ip) | CALLfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip) | 
 | { | { | 
| DWORD sp; | UINT32 sp; | 
 |  |  | 
 | VERBOSE(("CALLfar_pm: CODE-SEGMENT")); | VERBOSE(("CALLfar_pm: CODE-SEGMENT")); | 
 |  |  | 
 | /* check privilege level */ | /* check privilege level */ | 
| if (!cs_sel->desc.u.seg.ec) { | if (!SEG_IS_CONFORMING_CODE(&cs_sel->desc)) { | 
 | VERBOSE(("CALLfar_pm: NON-CONFORMING-CODE-SEGMENT")); | VERBOSE(("CALLfar_pm: NON-CONFORMING-CODE-SEGMENT")); | 
| /* イシエャ p.119 4.8.1.1. */ | /* 荳句キサ p.119 4.8.1.1. */ | 
 | if (cs_sel->rpl > CPU_STAT_CPL) { | if (cs_sel->rpl > CPU_STAT_CPL) { | 
 | VERBOSE(("CALLfar_pm: RPL(%d) > CPL(%d)", cs_sel->rpl, CPU_STAT_CPL)); | VERBOSE(("CALLfar_pm: RPL(%d) > CPL(%d)", cs_sel->rpl, CPU_STAT_CPL)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel->idx); | EXCEPTION(GP_EXCEPTION, cs_sel->idx); | 
| Line 407  CALLfar_pm_code_segment(selector_t *cs_s | Line 415  CALLfar_pm_code_segment(selector_t *cs_s | 
 | } | } | 
 | } else { | } else { | 
 | VERBOSE(("CALLfar_pm: CONFORMING-CODE-SEGMENT")); | VERBOSE(("CALLfar_pm: CONFORMING-CODE-SEGMENT")); | 
| /* イシエャ p.120 4.8.1.2. */ | /* 荳句キサ p.120 4.8.1.2. */ | 
 | if (cs_sel->desc.dpl > CPU_STAT_CPL) { | if (cs_sel->desc.dpl > CPU_STAT_CPL) { | 
 | VERBOSE(("CALLfar_pm: DPL(%d) > CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL)); | VERBOSE(("CALLfar_pm: DPL(%d) > CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel->idx); | EXCEPTION(GP_EXCEPTION, cs_sel->idx); | 
| Line 426  CALLfar_pm_code_segment(selector_t *cs_s | Line 434  CALLfar_pm_code_segment(selector_t *cs_s | 
 | sp = CPU_SP; | sp = CPU_SP; | 
 | } | } | 
 | if (CPU_INST_OP32) { | if (CPU_INST_OP32) { | 
| CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 8); | SS_PUSH_CHECK(sp, 8); | 
 |  |  | 
 | /* out of range */ | /* out of range */ | 
 | if (new_ip > cs_sel->desc.u.seg.limit) { | if (new_ip > cs_sel->desc.u.seg.limit) { | 
| Line 437  CALLfar_pm_code_segment(selector_t *cs_s | Line 445  CALLfar_pm_code_segment(selector_t *cs_s | 
 | PUSH0_32(CPU_CS); | PUSH0_32(CPU_CS); | 
 | PUSH0_32(CPU_EIP); | PUSH0_32(CPU_EIP); | 
 | } else { | } else { | 
| CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4); | SS_PUSH_CHECK(sp, 4); | 
 |  |  | 
 | /* out of range */ | /* out of range */ | 
 | if (new_ip > cs_sel->desc.u.seg.limit) { | if (new_ip > cs_sel->desc.u.seg.limit) { | 
| Line 450  CALLfar_pm_code_segment(selector_t *cs_s | Line 458  CALLfar_pm_code_segment(selector_t *cs_s | 
 | } | } | 
 |  |  | 
 | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | 
| SET_EIP(new_ip); | CPU_EIP = new_ip; | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
 | * CALLfar_pm: call gate | * CALLfar_pm: call gate | 
 | */ | */ | 
| static void CALLfar_pm_call_gate_same_privilege(selector_t *call_sel, selector_t *cs_sel); | static void CPUCALL CALLfar_pm_call_gate_same_privilege(const selector_t *call_sel, selector_t *cs_sel); | 
| static void CALLfar_pm_call_gate_more_privilege(selector_t *call_sel, selector_t *cs_sel); | static void CPUCALL CALLfar_pm_call_gate_more_privilege(const selector_t *call_sel, selector_t *cs_sel); | 
 |  |  | 
| static void | static void CPUCALL | 
| CALLfar_pm_call_gate(selector_t *callgate_sel) | CALLfar_pm_call_gate(const selector_t *callgate_sel) | 
 | { | { | 
 | selector_t cs_sel; | selector_t cs_sel; | 
 | int rv; | int rv; | 
| Line 491  CALLfar_pm_call_gate(selector_t *callgat | Line 499  CALLfar_pm_call_gate(selector_t *callgat | 
 | } | } | 
 |  |  | 
 | /* check segment type */ | /* check segment type */ | 
| if (!cs_sel.desc.s) { | if (SEG_IS_SYSTEM(&cs_sel.desc)) { | 
 | VERBOSE(("CALLfar_pm: code segment is system segment")); | VERBOSE(("CALLfar_pm: code segment is system segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| if (!cs_sel.desc.u.seg.c) { | if (SEG_IS_DATA(&cs_sel.desc)) { | 
 | VERBOSE(("CALLfar_pm: code segment is data segment")); | VERBOSE(("CALLfar_pm: code segment is data segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| Line 518  CALLfar_pm_call_gate(selector_t *callgat | Line 526  CALLfar_pm_call_gate(selector_t *callgat | 
 | EXCEPTION(GP_EXCEPTION, 0); | EXCEPTION(GP_EXCEPTION, 0); | 
 | } | } | 
 |  |  | 
| if (!cs_sel.desc.u.seg.ec && (cs_sel.desc.dpl < CPU_STAT_CPL)) { | if (!SEG_IS_CONFORMING_CODE(&cs_sel.desc) && (cs_sel.desc.dpl < CPU_STAT_CPL)) { | 
 | CALLfar_pm_call_gate_more_privilege(callgate_sel, &cs_sel); | CALLfar_pm_call_gate_more_privilege(callgate_sel, &cs_sel); | 
 | } else { | } else { | 
 | CALLfar_pm_call_gate_same_privilege(callgate_sel, &cs_sel); | CALLfar_pm_call_gate_same_privilege(callgate_sel, &cs_sel); | 
| Line 528  CALLfar_pm_call_gate(selector_t *callgat | Line 536  CALLfar_pm_call_gate(selector_t *callgat | 
 | /*--- | /*--- | 
 | * CALLfar_pm: call gate (SAME-PRIVILEGE) | * CALLfar_pm: call gate (SAME-PRIVILEGE) | 
 | */ | */ | 
| static void | static void CPUCALL | 
| CALLfar_pm_call_gate_same_privilege(selector_t *callgate_sel, selector_t *cs_sel) | CALLfar_pm_call_gate_same_privilege(const selector_t *callgate_sel, selector_t *cs_sel) | 
 | { | { | 
| DWORD sp; | UINT32 sp; | 
 |  |  | 
 | VERBOSE(("CALLfar_pm: SAME-PRIVILEGE")); | VERBOSE(("CALLfar_pm: SAME-PRIVILEGE")); | 
 |  |  | 
| Line 540  CALLfar_pm_call_gate_same_privilege(sele | Line 548  CALLfar_pm_call_gate_same_privilege(sele | 
 | } else { | } else { | 
 | sp = CPU_SP; | sp = CPU_SP; | 
 | } | } | 
 |  |  | 
 | 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); | SS_PUSH_CHECK(sp, 8); | 
 |  |  | 
 | PUSH0_32(CPU_CS); | PUSH0_32(CPU_CS); | 
 | PUSH0_32(CPU_EIP); | PUSH0_32(CPU_EIP); | 
 |  |  | 
 | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); |  | 
 | SET_EIP(callgate_sel->desc.u.gate.offset); |  | 
 | } else { | } else { | 
| CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4); | SS_PUSH_CHECK(sp, 4); | 
 |  |  | 
 | PUSH0_16(CPU_CS); | PUSH0_16(CPU_CS); | 
 | PUSH0_16(CPU_IP); | PUSH0_16(CPU_IP); | 
 |  |  | 
 | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); |  | 
 | SET_EIP(callgate_sel->desc.u.gate.offset); |  | 
 | } | } | 
 |  |  | 
 |  | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | 
 |  | CPU_EIP = callgate_sel->desc.u.gate.offset; | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
 | * CALLfar_pm: call gate (MORE-PRIVILEGE) | * CALLfar_pm: call gate (MORE-PRIVILEGE) | 
 | */ | */ | 
| static void | static void CPUCALL | 
| CALLfar_pm_call_gate_more_privilege(selector_t *callgate_sel, selector_t *cs_sel) | CALLfar_pm_call_gate_more_privilege(const selector_t *callgate_sel, selector_t *cs_sel) | 
 | { | { | 
| DWORD param[32];        /* copy param */ | UINT32 param[32];       /* copy param */ | 
 | selector_t ss_sel; | selector_t ss_sel; | 
| DWORD old_eip, old_esp; | UINT stacksize; | 
| DWORD new_esp; | UINT32 old_eip, old_esp; | 
| WORD old_cs, old_ss; | UINT32 new_esp; | 
| WORD new_ss; | UINT16 old_cs, old_ss; | 
|  | UINT16 new_ss; | 
 | int param_count; | int param_count; | 
 | int i; | int i; | 
 | int rv; | int rv; | 
| Line 599  CALLfar_pm_call_gate_more_privilege(sele | Line 604  CALLfar_pm_call_gate_more_privilege(sele | 
 |  |  | 
 | /* check privilege level */ | /* check privilege level */ | 
 | if (ss_sel.rpl != cs_sel->desc.dpl) { | if (ss_sel.rpl != cs_sel->desc.dpl) { | 
| VERBOSE(("CALLfar_pm: RPL[SS](%d) != DPL[CS](%d)", ss_sel.rpl, cs_sel->desc.dpl)); | VERBOSE(("CALLfar_pm: selector RPL[SS](%d) != DPL[CS](%d)", ss_sel.rpl, cs_sel->desc.dpl)); | 
 | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | 
 | } | } | 
 | if (ss_sel.desc.dpl != cs_sel->desc.dpl) { | 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)); | VERBOSE(("CALLfar_pm: descriptor DPL[SS](%d) != DPL[CS](%d)", ss_sel.desc.dpl, cs_sel->desc.dpl)); | 
 | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | 
 | } | } | 
 |  |  | 
 | /* stack segment must be writable data segment. */ | /* stack segment must be writable data segment. */ | 
| if (!ss_sel.desc.s) { | if (SEG_IS_SYSTEM(&ss_sel.desc)) { | 
 | VERBOSE(("CALLfar_pm: stack segment is system segment")); | VERBOSE(("CALLfar_pm: stack segment is system segment")); | 
 | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | 
 | } | } | 
| if (ss_sel.desc.u.seg.c) { | if (SEG_IS_CODE(&ss_sel.desc)) { | 
 | VERBOSE(("CALLfar_pm: stack segment is code segment")); | VERBOSE(("CALLfar_pm: stack segment is code segment")); | 
 | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | 
 | } | } | 
| if (!ss_sel.desc.u.seg.wr) { | if (!SEG_IS_WRITABLE_DATA(&ss_sel.desc)) { | 
 | VERBOSE(("CALLfar_pm: stack segment is read-only data segment")); | VERBOSE(("CALLfar_pm: stack segment is read-only data segment")); | 
 | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | 
 | } | } | 
| Line 630  CALLfar_pm_call_gate_more_privilege(sele | Line 635  CALLfar_pm_call_gate_more_privilege(sele | 
 | param_count = callgate_sel->desc.u.gate.count; | param_count = callgate_sel->desc.u.gate.count; | 
 | VERBOSE(("CALLfar_pm: param_count = %d", param_count)); | VERBOSE(("CALLfar_pm: param_count = %d", param_count)); | 
 |  |  | 
 |  | /* check stack size */ | 
 |  | if (cs_sel->desc.d) { | 
 |  | stacksize = 16; | 
 |  | } else { | 
 |  | stacksize = 8; | 
 |  | } | 
 | 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, new_esp, 16 + param_count * 4); | stacksize += param_count * 4; | 
|  | } else { | 
|  | stacksize += param_count * 2; | 
|  | } | 
|  | cpu_stack_push_check(ss_sel.idx, &ss_sel.desc, new_esp, stacksize); | 
 |  |  | 
 |  | if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { | 
 | /* dump param */ | /* dump param */ | 
 | for (i = 0; i < param_count; i++) { | for (i = 0; i < param_count; i++) { | 
 | param[i] = cpu_vmemoryread_d(CPU_SS_INDEX, old_esp + i * 4); | param[i] = cpu_vmemoryread_d(CPU_SS_INDEX, old_esp + i * 4); | 
| Line 643  CALLfar_pm_call_gate_more_privilege(sele | Line 659  CALLfar_pm_call_gate_more_privilege(sele | 
 | if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { | 
 | CPU_ESP = new_esp; | CPU_ESP = new_esp; | 
 | } else { | } else { | 
| CPU_SP = new_esp; | CPU_SP = (UINT16)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); | CPU_EIP = callgate_sel->desc.u.gate.offset; | 
 |  |  | 
 | PUSH0_32(old_ss); | PUSH0_32(old_ss); | 
 | PUSH0_32(old_esp); | PUSH0_32(old_esp); | 
| Line 661  CALLfar_pm_call_gate_more_privilege(sele | Line 677  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, new_esp, 8 + param_count * 2); |  | 
 |  |  | 
 | /* dump param */ | /* dump param */ | 
 | for (i = 0; i < param_count; i++) { | for (i = 0; i < param_count; i++) { | 
 | param[i] = cpu_vmemoryread_w(CPU_SS_INDEX, old_esp + i * 2); | param[i] = cpu_vmemoryread_w(CPU_SS_INDEX, old_esp + i * 2); | 
| Line 673  CALLfar_pm_call_gate_more_privilege(sele | Line 687  CALLfar_pm_call_gate_more_privilege(sele | 
 | if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { | 
 | CPU_ESP = new_esp; | CPU_ESP = new_esp; | 
 | } else { | } else { | 
| CPU_SP = new_esp; | CPU_SP = (UINT16)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); | CPU_EIP = callgate_sel->desc.u.gate.offset; | 
 |  |  | 
 | PUSH0_16(old_ss); | PUSH0_16(old_ss); | 
 | PUSH0_16(old_esp); | PUSH0_16(old_esp); | 
| Line 696  CALLfar_pm_call_gate_more_privilege(sele | Line 710  CALLfar_pm_call_gate_more_privilege(sele | 
 | /*--- | /*--- | 
 | * CALLfar_pm: task gate | * CALLfar_pm: task gate | 
 | */ | */ | 
| static void | static void CPUCALL | 
 | CALLfar_pm_task_gate(selector_t *taskgate_sel) | CALLfar_pm_task_gate(selector_t *taskgate_sel) | 
 | { | { | 
 | selector_t tss_sel; | selector_t tss_sel; | 
| Line 750  CALLfar_pm_task_gate(selector_t *taskgat | Line 764  CALLfar_pm_task_gate(selector_t *taskgat | 
 | } | } | 
 |  |  | 
 | task_switch(&tss_sel, TASK_SWITCH_CALL); | task_switch(&tss_sel, TASK_SWITCH_CALL); | 
 |  |  | 
 |  | /* out of range */ | 
 |  | if (CPU_EIP > CPU_STAT_CS_LIMIT) { | 
 |  | VERBOSE(("JMPfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", CPU_EIP, CPU_STAT_CS_LIMIT)); | 
 |  | EXCEPTION(GP_EXCEPTION, 0); | 
 |  | } | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
 | * CALLfar_pm: TSS | * CALLfar_pm: TSS | 
 | */ | */ | 
| static void | static void CPUCALL | 
 | CALLfar_pm_tss(selector_t *tss_sel) | CALLfar_pm_tss(selector_t *tss_sel) | 
 | { | { | 
 |  |  | 
| Line 778  CALLfar_pm_tss(selector_t *tss_sel) | Line 798  CALLfar_pm_tss(selector_t *tss_sel) | 
 | } | } | 
 |  |  | 
 | task_switch(tss_sel, TASK_SWITCH_CALL); | task_switch(tss_sel, TASK_SWITCH_CALL); | 
 |  |  | 
 |  | /* out of range */ | 
 |  | if (CPU_EIP > CPU_STAT_CS_LIMIT) { | 
 |  | VERBOSE(("JMPfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", CPU_EIP, CPU_STAT_CS_LIMIT)); | 
 |  | EXCEPTION(GP_EXCEPTION, 0); | 
 |  | } | 
 | } | } | 
 |  |  | 
 |  |  | 
| Line 785  CALLfar_pm_tss(selector_t *tss_sel) | Line 811  CALLfar_pm_tss(selector_t *tss_sel) | 
 | * RETfar_pm | * RETfar_pm | 
 | */ | */ | 
 |  |  | 
| void | void CPUCALL | 
| RETfar_pm(DWORD nbytes) | RETfar_pm(UINT nbytes) | 
 | { | { | 
 | selector_t cs_sel, ss_sel, temp_sel; | selector_t cs_sel, ss_sel, temp_sel; | 
| DWORD sp; | descriptor_t *sdp; | 
| DWORD new_ip, new_sp; | UINT32 sp; | 
| WORD new_cs, new_ss; | UINT32 new_ip, new_sp; | 
|  | UINT16 new_cs, new_ss; | 
 | int rv; | int rv; | 
 | int i; | int i; | 
 |  |  | 
| Line 803  RETfar_pm(DWORD nbytes) | Line 830  RETfar_pm(DWORD nbytes) | 
 | sp = CPU_SP; | sp = CPU_SP; | 
 | } | } | 
 | if (CPU_INST_OP32) { | if (CPU_INST_OP32) { | 
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 8); | SS_POP_CHECK(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_w(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); | SS_POP_CHECK(sp, nbytes + 4); | 
 | new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); | new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); | 
 | new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); | new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); | 
 | } | } | 
 |  |  | 
 | rv = parse_selector(&cs_sel, new_cs); | rv = parse_selector(&cs_sel, new_cs); | 
 | if (rv < 0) { | if (rv < 0) { | 
| VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", cs_sel.selector, rv)); | VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d)", cs_sel.selector, rv)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 |  |  | 
 | /* check segment type */ | /* check segment type */ | 
| if (!cs_sel.desc.s) { | if (SEG_IS_SYSTEM(&cs_sel.desc)) { | 
 | VERBOSE(("RETfar_pm: return to system segment")); | VERBOSE(("RETfar_pm: return to system segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| if (!cs_sel.desc.u.seg.c) { | if (SEG_IS_DATA(&cs_sel.desc)) { | 
 | VERBOSE(("RETfar_pm: return to data segment")); | VERBOSE(("RETfar_pm: return to data segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| Line 833  RETfar_pm(DWORD nbytes) | Line 860  RETfar_pm(DWORD nbytes) | 
 | VERBOSE(("RETfar_pm: RPL(%d) < CPL(%d)", 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); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| if (!cs_sel.desc.u.seg.ec && (cs_sel.desc.dpl > cs_sel.rpl)) { | if (!SEG_IS_CONFORMING_CODE(&cs_sel.desc) && (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)); | 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); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| Line 863  RETfar_pm(DWORD nbytes) | Line 890  RETfar_pm(DWORD nbytes) | 
 | if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { | 
 | CPU_ESP += nbytes; | CPU_ESP += nbytes; | 
 | } else { | } else { | 
| CPU_SP += nbytes; | CPU_SP += (UINT16)nbytes; | 
 | } | } | 
 |  |  | 
 | load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL); | load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL); | 
| SET_EIP(new_ip); | CPU_EIP = new_ip; | 
 | } else { | } else { | 
 | VERBOSE(("RETfar_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); | VERBOSE(("RETfar_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); | 
 |  |  | 
 | if (CPU_INST_OP32) { | if (CPU_INST_OP32) { | 
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 8 + 8 + nbytes); | SS_POP_CHECK(sp, 8 + 8 + nbytes); | 
 | new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 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); | new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8 + nbytes + 4); | 
 | } else { | } else { | 
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4 + 4 + nbytes); | SS_POP_CHECK(sp, 4 + 4 + nbytes); | 
 | new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 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); | 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); | 
 | 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)", ss_sel.selector, rv)); | 
| EXCEPTION(GP_EXCEPTION, ss_sel.idx); | EXCEPTION(GP_EXCEPTION, (rv == -2) ? 0 : ss_sel.idx); | 
 | } | } | 
 |  |  | 
| /* check stack segment descriptor */ | /* stack segment must be writable data segment. */ | 
| if (!ss_sel.desc.s) { | if (SEG_IS_SYSTEM(&ss_sel.desc)) { | 
 | VERBOSE(("RETfar_pm: stack segment is system segment")); | VERBOSE(("RETfar_pm: stack segment is system segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| if (ss_sel.desc.u.seg.c) { | if (SEG_IS_CODE(&ss_sel.desc)) { | 
 | VERBOSE(("RETfar_pm: stack segment is code segment")); | VERBOSE(("RETfar_pm: stack segment is code segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| if (!ss_sel.desc.u.seg.wr) { | if (!SEG_IS_WRITABLE_DATA(&ss_sel.desc)) { | 
 | VERBOSE(("RETfar_pm: stack segment is read-only data segment")); | VERBOSE(("RETfar_pm: stack segment is read-only data segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 |  |  | 
 | /* check privilege level */ | /* check privilege level */ | 
 | if (ss_sel.rpl != cs_sel.rpl) { | if (ss_sel.rpl != cs_sel.rpl) { | 
| VERBOSE(("RETfar_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel.rpl)); | VERBOSE(("RETfar_pm: selector RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel.rpl)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 | if (ss_sel.desc.dpl != cs_sel.rpl) { | if (ss_sel.desc.dpl != cs_sel.rpl) { | 
| VERBOSE(("RETfar_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel.rpl)); | VERBOSE(("RETfar_pm: descriptor DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel.rpl)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 |  |  | 
| Line 926  RETfar_pm(DWORD nbytes) | Line 953  RETfar_pm(DWORD nbytes) | 
 | VERBOSE(("RETfar_pm: new_ip = %08x, new_cs = %04x", new_ip, cs_sel.selector)); | 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)); | 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); | load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.rpl); | 
 | if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { | 
 | CPU_ESP = new_sp + nbytes; | CPU_ESP = new_sp + nbytes; | 
 | } else { | } else { | 
| CPU_SP = new_sp + nbytes; | CPU_SP = (UINT16)(new_sp + nbytes); | 
 | } | } | 
 |  |  | 
 |  | load_cs(cs_sel.selector, &cs_sel.desc, cs_sel.rpl); | 
 |  | CPU_EIP = new_ip; | 
 |  |  | 
 | /* check segment register */ | /* check segment register */ | 
 | for (i = 0; i < CPU_SEGREG_NUM; i++) { | for (i = 0; i < CPU_SEGREG_NUM; i++) { | 
| descriptor_t *dp; | if (i == CPU_SS_INDEX || i == CPU_CS_INDEX) | 
| BOOL valid; | continue; | 
 |  |  | 
| dp = &CPU_STAT_SREG(i); | sdp = &CPU_STAT_SREG(i); | 
| if ((!dp->u.seg.c || !dp->u.seg.ec) | if ((SEG_IS_DATA(sdp) || !SEG_IS_CONFORMING_CODE(sdp)) | 
| && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) { | && (CPU_STAT_CPL > sdp->dpl)) { | 
| /* segment register is invalid */ | /* current segment descriptor is invalid */ | 
 | CPU_REGS_SREG(i) = 0; | CPU_REGS_SREG(i) = 0; | 
| CPU_STAT_SREG_CLEAR(i); | memset(sdp, 0, sizeof(*sdp)); | 
 | continue; | continue; | 
 | } | } | 
 |  |  | 
 |  | /* Reload segment descriptor */ | 
 | rv = parse_selector(&temp_sel, CPU_REGS_SREG(i)); | rv = parse_selector(&temp_sel, CPU_REGS_SREG(i)); | 
 | if (rv < 0) { | if (rv < 0) { | 
 | /* segment register is invalid */ | /* segment register is invalid */ | 
 | CPU_REGS_SREG(i) = 0; | CPU_REGS_SREG(i) = 0; | 
| CPU_STAT_SREG_CLEAR(i); | memset(sdp, 0, sizeof(*sdp)); | 
 | continue; | continue; | 
 | } | } | 
 |  |  | 
| valid = TRUE; | /* | 
| if (!temp_sel.desc.s) { | * - system segment | 
| /* system segment */ | * - execute-only code segment | 
| valid = FALSE; | * - data or conforming code segment && CPL > DPL | 
| } | */ | 
| if (temp_sel.desc.u.seg.c && !temp_sel.desc.u.seg.wr) { | if (SEG_IS_SYSTEM(&temp_sel.desc) | 
| /* execute-only code segment */ | || (SEG_IS_CODE(&temp_sel.desc) | 
| valid = FALSE; | && !SEG_IS_READABLE_CODE(&temp_sel.desc)) | 
| } | || ((SEG_IS_DATA(&temp_sel.desc) | 
| if (!temp_sel.desc.u.seg.c || !temp_sel.desc.u.seg.ec) { | || !SEG_IS_CONFORMING_CODE(&temp_sel.desc)) | 
| if (CPU_STAT_CPL > temp_sel.desc.dpl) { | && (CPU_STAT_CPL > temp_sel.desc.dpl))) { | 
| valid = FALSE; | /* segment descriptor is invalid */ | 
| } |  | 
| } |  | 
|  |  | 
| if (!valid) { |  | 
| /* segment register is invalid */ |  | 
 | CPU_REGS_SREG(i) = 0; | CPU_REGS_SREG(i) = 0; | 
| CPU_STAT_SREG(i).valid = 0; | memset(sdp, 0, sizeof(*sdp)); | 
 | } | } | 
 | } | } | 
 | } | } | 
| Line 989  RETfar_pm(DWORD nbytes) | Line 1012  RETfar_pm(DWORD nbytes) | 
 | * IRET_pm | * IRET_pm | 
 | */ | */ | 
 | static void IRET_pm_nested_task(void); | static void IRET_pm_nested_task(void); | 
| static void IRET_pm_protected_mode_return(DWORD new_cs, DWORD new_ip, DWORD new_flags); | static void CPUCALL IRET_pm_protected_mode_return(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags); | 
| static void IRET_pm_protected_mode_return_same_privilege(selector_t *cs_sel, DWORD new_ip, DWORD new_flags); | static void CPUCALL IRET_pm_protected_mode_return_same_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags); | 
| static void IRET_pm_protected_mode_return_outer_privilege(selector_t *cs_sel, DWORD new_ip, DWORD new_flags); | static void CPUCALL IRET_pm_protected_mode_return_outer_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags); | 
| static void IRET_pm_return_to_vm86(DWORD new_cs, DWORD new_ip, DWORD new_flags); | static void CPUCALL IRET_pm_return_to_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags); | 
| static void IRET_pm_return_from_vm86(DWORD new_cs, DWORD new_ip, DWORD new_flags); | static void CPUCALL IRET_pm_return_from_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags); | 
 |  |  | 
 | void | void | 
 | IRET_pm(void) | IRET_pm(void) | 
 | { | { | 
| DWORD sp; | UINT32 sp; | 
| DWORD new_ip, new_flags; | UINT32 new_ip, new_flags; | 
| WORD new_cs; | UINT16 new_cs; | 
| int rv; |  | 
 |  |  | 
 | VERBOSE(("IRET_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); | VERBOSE(("IRET_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); | 
 |  |  | 
| Line 1015  IRET_pm(void) | Line 1037  IRET_pm(void) | 
 | sp = CPU_SP; | sp = CPU_SP; | 
 | } | } | 
 | if (CPU_INST_OP32) { | if (CPU_INST_OP32) { | 
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 12); | SS_POP_CHECK(sp, 12); | 
 | new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); | new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); | 
 | new_cs = cpu_vmemoryread_w(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); | new_flags = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8); | 
 | } else { | } else { | 
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 6); | SS_POP_CHECK(sp, 6); | 
 | new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); | new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); | 
 | 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); | 
| Line 1031  IRET_pm(void) | Line 1053  IRET_pm(void) | 
 | 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_cs, new_ip, new_flags); | IRET_pm_return_from_vm86(new_cs, new_ip, new_flags); | 
| } else if (new_flags & VM_FLAG) { | } else if ((new_flags & VM_FLAG) && CPU_STAT_CPL == 0) { | 
 | /* RETURN-TO-VIRTUAL-8086-MODE */ | /* RETURN-TO-VIRTUAL-8086-MODE */ | 
 | IRET_pm_return_to_vm86(new_cs, new_ip, new_flags); | IRET_pm_return_to_vm86(new_cs, new_ip, new_flags); | 
 | } else { | } else { | 
| Line 1050  static void | Line 1072  static void | 
 | IRET_pm_nested_task(void) | IRET_pm_nested_task(void) | 
 | { | { | 
 | selector_t tss_sel; | selector_t tss_sel; | 
 |  | UINT16 new_tss; | 
 | int rv; | int rv; | 
 | 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")); | 
 |  |  | 
| Line 1064  IRET_pm_nested_task(void) | Line 1086  IRET_pm_nested_task(void) | 
 | } | } | 
 |  |  | 
 | /* check system segment */ | /* check system segment */ | 
| if (tss_sel.desc.s) { | if (!SEG_IS_SYSTEM(&tss_sel.desc)) { | 
| VERBOSE(("IRET_pm: task segment is %d segment", tss_sel.desc.u.seg.c ? "code" : "data")); | VERBOSE(("IRET_pm: task segment is %s segment", tss_sel.desc.u.seg.c ? "code" : "data")); | 
 | EXCEPTION(GP_EXCEPTION, tss_sel.idx); | EXCEPTION(GP_EXCEPTION, tss_sel.idx); | 
 | } | } | 
 |  |  | 
| Line 1091  IRET_pm_nested_task(void) | Line 1113  IRET_pm_nested_task(void) | 
 | } | } | 
 |  |  | 
 | task_switch(&tss_sel, TASK_SWITCH_IRET); | task_switch(&tss_sel, TASK_SWITCH_IRET); | 
 |  |  | 
 |  | /* out of range */ | 
 |  | if (CPU_EIP > CPU_STAT_CS_LIMIT) { | 
 |  | VERBOSE(("JMPfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", CPU_EIP, CPU_STAT_CS_LIMIT)); | 
 |  | EXCEPTION(GP_EXCEPTION, 0); | 
 |  | } | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
 | * IRET_pm: PROTECTED-MODE-RETURN | * IRET_pm: PROTECTED-MODE-RETURN | 
 | */ | */ | 
| static void | static void CPUCALL | 
| IRET_pm_protected_mode_return(DWORD new_cs, DWORD new_ip, DWORD new_flags) | IRET_pm_protected_mode_return(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags) | 
 | { | { | 
 | selector_t cs_sel; | selector_t cs_sel; | 
 | int rv; | int rv; | 
| Line 1112  IRET_pm_protected_mode_return(DWORD new_ | Line 1140  IRET_pm_protected_mode_return(DWORD new_ | 
 | } | } | 
 |  |  | 
 | /* check code segment descriptor */ | /* check code segment descriptor */ | 
| if (!cs_sel.desc.s) { | if (SEG_IS_SYSTEM(&cs_sel.desc)) { | 
 | VERBOSE(("IRET_pm: return code segment is system segment")); | VERBOSE(("IRET_pm: return code segment is system segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| if (!cs_sel.desc.u.seg.c) { | if (SEG_IS_DATA(&cs_sel.desc)) { | 
 | VERBOSE(("IRET_pm: return code segment is data segment")); | VERBOSE(("IRET_pm: return code segment is data segment")); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| Line 1126  IRET_pm_protected_mode_return(DWORD new_ | Line 1154  IRET_pm_protected_mode_return(DWORD new_ | 
 | VERBOSE(("IRET_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); | VERBOSE(("IRET_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| if (cs_sel.desc.u.seg.ec && (cs_sel.desc.dpl > cs_sel.rpl)) { | if (SEG_IS_CONFORMING_CODE(&cs_sel.desc) && (cs_sel.desc.dpl > cs_sel.rpl)) { | 
| VERBOSE(("IRET_pm: CONFORMING-CODE-SEGMENT and DPL(%d) != RPL(%d)", cs_sel.desc.dpl, cs_sel.rpl)); | VERBOSE(("IRET_pm: CONFORMING-CODE-SEGMENT and DPL(%d) > RPL(%d)", cs_sel.desc.dpl, cs_sel.rpl)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 |  |  | 
| Line 1147  IRET_pm_protected_mode_return(DWORD new_ | Line 1175  IRET_pm_protected_mode_return(DWORD new_ | 
 | /*--- | /*--- | 
 | * IRET_pm: SAME-PRIVILEGE | * IRET_pm: SAME-PRIVILEGE | 
 | */ | */ | 
| static void | static void CPUCALL | 
| IRET_pm_protected_mode_return_same_privilege(selector_t *cs_sel, DWORD new_ip, DWORD new_flags) | IRET_pm_protected_mode_return_same_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags) | 
 | { | { | 
| DWORD mask; | UINT32 mask; | 
| DWORD stacksize; | UINT stacksize; | 
 |  |  | 
 | VERBOSE(("IRET_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); | VERBOSE(("IRET_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); | 
 |  |  | 
| Line 1173  IRET_pm_protected_mode_return_same_privi | Line 1201  IRET_pm_protected_mode_return_same_privi | 
 | } | } | 
 | } | } | 
 |  |  | 
 | /* set new register */ |  | 
 | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); |  | 
 | SET_EIP(new_ip); |  | 
 |  |  | 
 | set_eflags(new_flags, mask); |  | 
 |  |  | 
 | if (CPU_INST_OP32) { | if (CPU_INST_OP32) { | 
 | stacksize = 12; | stacksize = 12; | 
 | } else { | } else { | 
 | stacksize = 6; | stacksize = 6; | 
 | } | } | 
 |  |  | 
 |  | /* set new register */ | 
 |  | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | 
 |  | CPU_EIP = new_ip; | 
 |  |  | 
 | if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { | 
 | CPU_ESP += stacksize; | CPU_ESP += stacksize; | 
 | } else { | } else { | 
| CPU_SP += stacksize; | CPU_SP += (UINT16)stacksize; | 
 | } | } | 
 |  |  | 
 |  | set_eflags(new_flags, mask); | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
 | * IRET_pm: OUTER-PRIVILEGE | * IRET_pm: OUTER-PRIVILEGE | 
 | */ | */ | 
| static void | static void CPUCALL | 
| IRET_pm_protected_mode_return_outer_privilege(selector_t *cs_sel, DWORD new_ip, DWORD new_flags) | IRET_pm_protected_mode_return_outer_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags) | 
 | { | { | 
| descriptor_t *dp; | descriptor_t *sdp; | 
 | selector_t ss_sel; | selector_t ss_sel; | 
| DWORD mask; | UINT32 mask; | 
| DWORD sp; | UINT32 sp; | 
| DWORD new_sp; | UINT32 new_sp; | 
| WORD new_ss; | UINT16 new_ss; | 
 | int rv; | int rv; | 
 | int i; | int i; | 
 |  |  | 
| Line 1214  IRET_pm_protected_mode_return_outer_priv | Line 1243  IRET_pm_protected_mode_return_outer_priv | 
 | sp = CPU_SP; | sp = CPU_SP; | 
 | } | } | 
 | if (CPU_INST_OP32) { | if (CPU_INST_OP32) { | 
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 20); | SS_POP_CHECK(sp, 20); | 
 | new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); | new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); | 
 | new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); | new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); | 
 | } else { | } else { | 
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 10); | SS_POP_CHECK(sp, 10); | 
 | new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 6); | new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 6); | 
 | new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8); | new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8); | 
 | } | } | 
| Line 1227  IRET_pm_protected_mode_return_outer_priv | Line 1256  IRET_pm_protected_mode_return_outer_priv | 
 | rv = parse_selector(&ss_sel, new_ss); | rv = parse_selector(&ss_sel, new_ss); | 
 | 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, (rv == -2) ? 0 : ss_sel.idx); | 
 | } | } | 
 |  |  | 
 | /* check privilege level */ | /* check privilege level */ | 
 | if (ss_sel.rpl != cs_sel->rpl) { | if (ss_sel.rpl != cs_sel->rpl) { | 
| VERBOSE(("IRET_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel->rpl)); | VERBOSE(("IRET_pm: selector 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 0 | 
 | if (ss_sel.desc.dpl != cs_sel->rpl) { | if (ss_sel.desc.dpl != cs_sel->rpl) { | 
| VERBOSE(("IRET_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel->rpl)); | VERBOSE(("IRET_pm: segment 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); | 
 | } | } | 
 |  | if (ss_sel.desc.rpl != cs_sel->rpl) { | 
 |  | VERBOSE(("IRET_pm: segment RPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.rpl, cs_sel->rpl)); | 
 |  | EXCEPTION(GP_EXCEPTION, ss_sel.idx); | 
 |  | } | 
 |  | #endif | 
 |  |  | 
| /* check stack segment descriptor */ | /* stack segment must be writable data segment. */ | 
| if (!ss_sel.desc.s) { | if (SEG_IS_SYSTEM(&ss_sel.desc)) { | 
 | VERBOSE(("IRET_pm: stack segment is system segment")); | VERBOSE(("IRET_pm: stack segment is system segment")); | 
 | EXCEPTION(GP_EXCEPTION, ss_sel.idx); | EXCEPTION(GP_EXCEPTION, ss_sel.idx); | 
 | } | } | 
| if (ss_sel.desc.u.seg.c) { | if (SEG_IS_CODE(&ss_sel.desc)) { | 
 | VERBOSE(("IRET_pm: stack segment is code segment")); | VERBOSE(("IRET_pm: stack segment is code segment")); | 
 | EXCEPTION(GP_EXCEPTION, ss_sel.idx); | EXCEPTION(GP_EXCEPTION, ss_sel.idx); | 
 | } | } | 
| if (!ss_sel.desc.u.seg.wr) { | if (!SEG_IS_WRITABLE_DATA(&ss_sel.desc)) { | 
 | VERBOSE(("IRET_pm: stack segment is read-only data segment")); | VERBOSE(("IRET_pm: stack segment is read-only data segment")); | 
 | EXCEPTION(GP_EXCEPTION, ss_sel.idx); | EXCEPTION(GP_EXCEPTION, ss_sel.idx); | 
 | } | } | 
| Line 1280  IRET_pm_protected_mode_return_outer_priv | Line 1315  IRET_pm_protected_mode_return_outer_priv | 
 |  |  | 
 | /* set new register */ | /* set new register */ | 
 | load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->rpl); | load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->rpl); | 
| SET_EIP(new_ip); | CPU_EIP = new_ip; | 
|  |  | 
| set_eflags(new_flags, mask); |  | 
 |  |  | 
 | load_ss(ss_sel.selector, &ss_sel.desc, cs_sel->rpl); | load_ss(ss_sel.selector, &ss_sel.desc, cs_sel->rpl); | 
 | if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { | 
 | CPU_ESP = new_sp; | CPU_ESP = new_sp; | 
 | } else { | } else { | 
| CPU_SP = new_sp; | CPU_SP = (UINT16)new_sp; | 
 | } | } | 
 |  |  | 
 |  | set_eflags(new_flags, mask); | 
 |  |  | 
 | /* check segment register */ | /* check segment register */ | 
 | for (i = 0; i < CPU_SEGREG_NUM; i++) { | for (i = 0; i < CPU_SEGREG_NUM; i++) { | 
 | if ((i != CPU_CS_INDEX) && (i != CPU_SS_INDEX)) { | if ((i != CPU_CS_INDEX) && (i != CPU_SS_INDEX)) { | 
| dp = &CPU_STAT_SREG(i); | sdp = &CPU_STAT_SREG(i); | 
| if ((!dp->u.seg.c || !dp->u.seg.ec) | if ((SEG_IS_DATA(sdp) || !SEG_IS_CONFORMING_CODE(sdp)) | 
| && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) { | && (sdp->dpl < CPU_STAT_CPL)) { | 
 | /* segment register is invalid */ | /* segment register is invalid */ | 
 | CPU_REGS_SREG(i) = 0; | CPU_REGS_SREG(i) = 0; | 
| CPU_STAT_SREG_CLEAR(i); | memset(sdp, 0, sizeof(*sdp)); | 
| continue; |  | 
 | } | } | 
 | } | } | 
 | } | } | 
| Line 1309  IRET_pm_protected_mode_return_outer_priv | Line 1343  IRET_pm_protected_mode_return_outer_priv | 
 | /*--- | /*--- | 
 | * IRET_pm: new_flags & VM_FLAG | * IRET_pm: new_flags & VM_FLAG | 
 | */ | */ | 
| static void | static void CPUCALL | 
| IRET_pm_return_to_vm86(DWORD new_cs, DWORD new_ip, DWORD new_flags) | IRET_pm_return_to_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags) | 
 | { | { | 
| WORD segsel[CPU_SEGREG_NUM]; | UINT16 segsel[CPU_SEGREG_NUM]; | 
| DWORD sp; | UINT32 sp; | 
| DWORD new_sp; | UINT32 new_sp; | 
 | int i; | int i; | 
 |  |  | 
 | VERBOSE(("IRET_pm: Interrupt procedure was in virtual-8086 mode: PE=1, VM=1 in flags image")); | 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) { | if (!CPU_INST_OP32) { | 
 | ia32_panic("IRET_pm: 16bit mode"); | ia32_panic("IRET_pm: 16bit mode"); | 
 | } | } | 
| Line 1332  IRET_pm_return_to_vm86(DWORD new_cs, DWO | Line 1362  IRET_pm_return_to_vm86(DWORD new_cs, DWO | 
 | } else { | } else { | 
 | sp = CPU_SP; | sp = CPU_SP; | 
 | } | } | 
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 36); | SS_POP_CHECK(sp, 36); | 
|  |  | 
|  | if (new_ip > 0xffff) { | 
|  | EXCEPTION(GP_EXCEPTION, 0); | 
|  | } | 
|  |  | 
 | 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); | 
 | segsel[CPU_ES_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 20); | segsel[CPU_ES_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 20); | 
| Line 1342  IRET_pm_return_to_vm86(DWORD new_cs, DWO | Line 1377  IRET_pm_return_to_vm86(DWORD new_cs, DWO | 
 | segsel[CPU_CS_INDEX] = new_cs; | segsel[CPU_CS_INDEX] = new_cs; | 
 |  |  | 
 | for (i = 0; i < CPU_SEGREG_NUM; i++) { | for (i = 0; i < CPU_SEGREG_NUM; i++) { | 
| CPU_REGS_SREG(i) = segsel[i]; | segdesc_init(i, segsel[i], &CPU_STAT_SREG(i)); | 
| CPU_STAT_SREG_INIT(i); |  | 
 | } | } | 
 |  |  | 
 |  | CPU_ESP = new_sp; | 
 |  | CPU_EIP = new_ip; | 
 |  |  | 
 | /* to VM86 mode */ | /* 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); | 
 |  |  | 
 | new_sp &= 0xffff; |  | 
 | new_ip &= 0xffff; |  | 
 |  |  | 
 | CPU_ESP = new_sp; |  | 
 | SET_EIP(new_ip); |  | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
 | * IRET_pm: VM_FLAG | * IRET_pm: VM_FLAG | 
 | */ | */ | 
| static void | static void CPUCALL | 
| IRET_pm_return_from_vm86(DWORD new_cs, DWORD new_ip, DWORD new_flags) | IRET_pm_return_from_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags) | 
 | { | { | 
| DWORD stacksize; | UINT stacksize; | 
 |  |  | 
 | VERBOSE(("IRET_pm: virtual-8086 mode: VM=1")); | VERBOSE(("IRET_pm: virtual-8086 mode: VM=1")); | 
 |  |  | 
| Line 1379  IRET_pm_return_from_vm86(DWORD new_cs, D | Line 1410  IRET_pm_return_from_vm86(DWORD new_cs, D | 
 | CPU_SP += stacksize; | CPU_SP += stacksize; | 
 | } | } | 
 |  |  | 
| set_eflags(new_flags, I_FLAG|RF_FLAG); | LOAD_SEGREG(CPU_CS_INDEX, new_cs); | 
|  | if (new_ip > CPU_STAT_CS_LIMIT) { | 
|  | EXCEPTION(GP_EXCEPTION, 0); | 
|  | } | 
|  | CPU_EIP = new_ip; | 
 |  |  | 
| CPU_SET_SEGREG(CPU_CS_INDEX, new_cs); | set_eflags(new_flags, I_FLAG|RF_FLAG); | 
| SET_EIP(new_ip); |  | 
 | return; | return; | 
 | } | } | 
 | VERBOSE(("IRET_pm: trap to virtual-8086 monitor: VM=1, IOPL<3")); | VERBOSE(("IRET_pm: trap to virtual-8086 monitor: VM=1, IOPL<3")); |