--- np2/i386c/ia32/ctrlxfer.c 2004/02/06 16:49:51 1.9 +++ np2/i386c/ia32/ctrlxfer.c 2012/06/18 14:30:27 1.27 @@ -1,5 +1,3 @@ -/* $Id: ctrlxfer.c,v 1.9 2004/02/06 16:49:51 monaka Exp $ */ - /* * Copyright (c) 2003 NONAKA Kimihiro * All rights reserved. @@ -12,8 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * 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 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -37,13 +33,13 @@ /*------------------------------------------------------------------------------ * JMPfar_pm */ -static void JMPfar_pm_code_segment(selector_t *jmp_sel, DWORD new_ip); -static void JMPfar_pm_call_gate(selector_t *jmp_sel); -static void JMPfar_pm_task_gate(selector_t *jmp_sel); -static void JMPfar_pm_tss(selector_t *jmp_sel); +static void CPUCALL JMPfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip); +static void CPUCALL JMPfar_pm_call_gate(const selector_t *callgate_sel); +static void CPUCALL JMPfar_pm_task_gate(selector_t *taskgate_sel); +static void CPUCALL JMPfar_pm_tss(selector_t *tss_sel); -void -JMPfar_pm(WORD selector, DWORD new_ip) +void CPUCALL +JMPfar_pm(UINT16 selector, UINT32 new_ip) { selector_t jmp_sel; int rv; @@ -57,11 +53,11 @@ JMPfar_pm(WORD selector, DWORD new_ip) 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")); /* check segment type */ - if (!jmp_sel.desc.u.seg.c) { + if (SEG_IS_DATA(&jmp_sel.desc)) { /* data segment */ VERBOSE(("JMPfar_pm: data segment")); EXCEPTION(GP_EXCEPTION, jmp_sel.idx); @@ -105,55 +101,56 @@ JMPfar_pm(WORD selector, DWORD new_ip) /*--- * JMPfar: code segment */ -static void -JMPfar_pm_code_segment(selector_t *code_sel, DWORD new_ip) +static void CPUCALL +JMPfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip) { + VERBOSE(("JMPfar_pm: CODE-SEGMENT")); + /* check privilege level */ - if (!code_sel->desc.u.seg.ec) { + if (!SEG_IS_CONFORMING_CODE(&cs_sel->desc)) { VERBOSE(("JMPfar_pm: NON-CONFORMING-CODE-SEGMENT")); - /* ¥¤¥·¥¨¥ã p.119 4.8.1.1. */ - if (code_sel->rpl > CPU_STAT_CPL) { - VERBOSE(("JMPfar_pm: RPL(%d) > CPL(%d)", code_sel->rpl, CPU_STAT_CPL)); - EXCEPTION(GP_EXCEPTION, code_sel->idx); - } - if (code_sel->desc.dpl != CPU_STAT_CPL) { - VERBOSE(("JMPfar_pm: DPL(%d) != CPL(%d)", code_sel->desc.dpl, CPU_STAT_CPL)); - EXCEPTION(GP_EXCEPTION, code_sel->idx); + /* 躶祭¥µ p.119 4.8.1.1. */ + if (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); + } + if (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); } } else { VERBOSE(("JMPfar_pm: CONFORMING-CODE-SEGMENT")); - /* ¥¤¥·¥¨¥ã p.120 4.8.1.2. */ - if (code_sel->desc.dpl > CPU_STAT_CPL) { - VERBOSE(("JMPfar_pm: DPL(%d) > CPL(%d)", code_sel->desc.dpl, CPU_STAT_CPL)); - EXCEPTION(GP_EXCEPTION, code_sel->idx); + /* 躶祭¥µ p.120 4.8.1.2. */ + if (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); } } /* not present */ - if (selector_is_not_present(code_sel)) { - VERBOSE(("JMPfar_pm: selector is not present")); - EXCEPTION(NP_EXCEPTION, code_sel->idx); + if (selector_is_not_present(cs_sel)) { + VERBOSE(("JMPfar_pm: code selector is not present")); + EXCEPTION(NP_EXCEPTION, cs_sel->idx); } /* out of range */ - if (new_ip > code_sel->desc.u.seg.limit) { - VERBOSE(("JMPfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, code_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); } - load_cs(code_sel->selector, &code_sel->desc, CPU_STAT_CPL); - SET_EIP(new_ip); + load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); + CPU_EIP = new_ip; } /*--- * JMPfar: call gate */ -static void -JMPfar_pm_call_gate(selector_t *callgate_sel) +static void CPUCALL +JMPfar_pm_call_gate(const selector_t *callgate_sel) { selector_t cs_sel; - DWORD new_ip; int rv; VERBOSE(("JMPfar_pm: CALL-GATE")); @@ -170,7 +167,7 @@ JMPfar_pm_call_gate(selector_t *callgate /* not present */ 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); } @@ -182,18 +179,18 @@ JMPfar_pm_call_gate(selector_t *callgate } /* check segment type */ - if (!cs_sel.desc.s) { + if (SEG_IS_SYSTEM(&cs_sel.desc)) { VERBOSE(("JMPfar_pm: code segment is system segment")); 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")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* check privilege level */ - if (!cs_sel.desc.u.seg.ec) { - /* ¥¤¥·¥¨¥ã p.119 4.8.1.1. */ + if (!SEG_IS_CONFORMING_CODE(&cs_sel.desc)) { + /* 躶祭¥µ p.119 4.8.1.1. */ if (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); @@ -203,7 +200,7 @@ JMPfar_pm_call_gate(selector_t *callgate EXCEPTION(GP_EXCEPTION, cs_sel.idx); } } else { - /* ¥¤¥·¥¨¥ã p.120 4.8.1.2. */ + /* 躶祭¥µ p.120 4.8.1.2. */ if (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); @@ -212,25 +209,24 @@ JMPfar_pm_call_gate(selector_t *callgate /* not present */ 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); } /* out of range */ - new_ip = callgate_sel->desc.u.gate.offset; - 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)); + if (callgate_sel->desc.u.gate.offset > cs_sel.desc.u.seg.limit) { + 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)); EXCEPTION(GP_EXCEPTION, 0); } load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL); - SET_EIP(new_ip); + CPU_EIP = callgate_sel->desc.u.gate.offset; } /*--- * JMPfar: task gate */ -static void +static void CPUCALL JMPfar_pm_task_gate(selector_t *taskgate_sel) { selector_t tss_sel; @@ -238,20 +234,6 @@ JMPfar_pm_task_gate(selector_t *taskgate VERBOSE(("JMPfar_pm: TASK-GATE")); - /* - * ¥Æì¶¥ã p.373 JMP ¥Õ¥½¥Û- * - * JMP Ì¿Îá¤Ç¥¿¥¹¥¯¡¦¥¹¥¤¥Ã¥Á¤ò¼Â¹Ô¤¹¤ë¤È¤­¤Ï EFLAGS ¥ì¥¸¥¹¥¿¤Ë - * ¥Í¥¹¥È¤µ¤ì¤¿¥¿¥¹¥¯¡¦¥Õ¥é¥° (NT) ¤¬¥»¥Ã¥È¤µ¤ì¤º¡¢¿·¤·¤¤ TSS ¤Î - * °ÊÁ°¤Î¥¿¥¹¥¯¡¦¥ê¥ó¥¯¡¦¥Õ¥£¡¼¥ë¥É¤ËÁ°¤Î¥¿¥¹¥¯¤Î TSS ¥»¥ì¥¯¥¿¤¬ - * ¥í¡¼¥É¤µ¤ì¤Ê¤¤¤Î¤ÇÃí°Õ¤µ¤ì¤¿¤¤¡£¤·¤¿¤¬¤Ã¤Æ¡¢Á°¤Î¥¿¥¹¥¯¤Ø¤Î - * ¥ê¥¿¡¼¥ó¤Ï IRET Ì¿Îá¤Î¼Â¹Ô¤Ç¤Ï¼Â¸½¤Ç¤­¤Ê¤¤¡£JMP Ì¿Îá¤Ç - * ¥¿¥¹¥¯¡¦¥¹¥¤¥Ã¥Á¤ò¼Â¹Ô¤¹¤ë¤Î¤Ï¡¢¤½¤ÎÅÀ¤Ç CALL Ì¿Îá¤È°Û¤Ê¤ë¡£ - * ¤¹¤Ê¤ï¤Á¡¢CALL Ì¿Îá¤Ï NT ¥Õ¥é¥°¤ò¥»¥Ã¥È¤·¡¢°ÊÁ°¤Î - * ¥¿¥¹¥¯¡¦¥ê¥ó¥¯¾ðÊó¤ò¥»¡¼¥Ö¤¹¤ë¤Î¤Ç¡¢IRET Ì¿Îá¤Ç¤Î¥³¡¼¥ë¸µ - * ¥¿¥¹¥¯¤Ø¤Î¥ê¥¿¡¼¥ó¤¬²Äǽ¤Ë¤Ê¤ë¡£ - */ - /* check privilege level */ if (taskgate_sel->desc.dpl < CPU_STAT_CPL) { VERBOSE(("JMPfar_pm: DPL(%d) < CPL(%d)", taskgate_sel->desc.dpl, CPU_STAT_CPL)); @@ -298,12 +280,18 @@ JMPfar_pm_task_gate(selector_t *taskgate } 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 */ -static void +static void CPUCALL JMPfar_pm_tss(selector_t *tss_sel) { @@ -326,38 +314,25 @@ JMPfar_pm_tss(selector_t *tss_sel) } 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 */ -static void CALLfar_pm_code_segment(selector_t *call_sel, DWORD new_ip); -static void CALLfar_pm_call_gate(selector_t *call_sel); -static void CALLfar_pm_task_gate(selector_t *call_sel); -static void CALLfar_pm_tss(selector_t *call_sel); +static void CPUCALL CALLfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip); +static void CPUCALL CALLfar_pm_call_gate(const selector_t *callgate_sel); +static void CPUCALL CALLfar_pm_task_gate(selector_t *taskgate_sel); +static void CPUCALL CALLfar_pm_tss(selector_t *tss_sel); -/* - * 4.3.6. ÆÃ¸¢¥ì¥Ù¥ë´Ö¤Î¥³¡¼¥ëÁàºî - * - * 1. ¥¢¥¯¥»¥¹¸¢¤Î¥Á¥§¥Ã¥¯(ÆÃ¸¢¥Á¥§¥Ã¥¯)¤ò¼Â¹Ô¤¹¤ë¡£ - * 2. SS, ESP, CS, EIP ¤Î³Æ¥ì¥¸¥¹¥¿¤Î¸½ºßÃͤò°ì»þŪ¤ËÆâÉô¤Ë¥»¡¼¥Ö¤¹¤ë¡£ - * 3. TSS ¥ì¥¸¥¹¥¿¤Ë³ÊǼ¤µ¤ì¤Æ¤¤¤ë¿·¤·¤¤¥¹¥¿¥Ã¥¯(¤¹¤Ê¤ï¤Á¡¢¸½ºß¥³¡¼¥ë¤µ¤ì¤Æ¤¤¤ë - * ÆÃ¸¢¥ì¥Ù¥ëÍѤΥ¹¥¿¥Ã¥¯)¤Î¥»¥°¥á¥ó¥È¥ì¥¸¥¹¥¿¤È¥¹¥¿¥Ã¥¯¥Ý¥¤¥ó¥¿¤ò - * SS ¥ì¥¸¥¹¥¿¤È ESP ¥ì¥¸¥¹¥¿¤Ë¥í¡¼¥É¤·¡¢¿·¤·¤¤¥¹¥¿¥Ã¥¯¤ËÀÚ¤êÂØ¤¨¤ë¡£ - * 4. ¥³¡¼¥ë¸µ¥×¥í¥·¡¼¥¸¥ã¤Î¥¹¥¿¥Ã¥¯¤ËÂФ·¤Æ°ì»þŪ¤Ë¥»¡¼¥Ö¤·¤Æ¤ª¤¤¤¿ SS ¤È - * ESP ¤ò¡¢¤³¤Î¿·¤·¤¤¥¹¥¿¥Ã¥¯¤Ë¥×¥Ã¥·¥å¤¹¤ë¡£ - * 5. ¥³¡¼¥ë¸µ¥×¥í¥·¡¼¥¸¥ã¤Î¥¹¥¿¥Ã¥¯¤«¤é¥Ñ¥é¥á¡¼¥¿¤ò¥³¥Ô¡¼¤¹¤ë¡£¿·¤·¤¤¥¹¥¿¥Ã¥¯ - * ¤Ë¥³¥Ô¡¼¤µ¤ì¤ë¥Ñ¥é¥á¡¼¥¿¤Î¿ô¤Ï¡¢¥³¡¼¥ë¡¦¥²¡¼¥È¡¦¥Ç¥£¥¹¥¯¥ê¥×¥¿Æâ¤ÎÃÍ¤Ç - * ·è¤Þ¤ë¡£ - * 6. ¥³¡¼¥ë¸µ¥×¥í¥·¡¼¥¸¥ã¤ËÂФ·¤Æ°ì»þŪ¤Ë¥»¡¼¥Ö¤·¤Æ¤ª¤¤¤¿ CS ¤È EIP ¤ò¡¢ - * ¿·¤·¤¤¥¹¥¿¥Ã¥¯¤Ë¥×¥Ã¥·¥å¤¹¤ë¡£ - * 7. ¿·¤·¤¤¥³¡¼¥É¡¦¥»¥°¥á¥ó¥È¤Î¥»¥°¥á¥ó¥È¡¦¥»¥ì¥¯¥¿¤È¿·¤·¤¤Ì¿Îá¥Ý¥¤¥ó¥¿¤ò¡¢ - * ¥³¡¼¥ë¡¦¥²¡¼¥È¤«¤é CS ¥ì¥¸¥¹¥¿¤È EIP ¥ì¥¸¥¹¥¿¤Ë¤½¤ì¤¾¤ì¥í¡¼¥É¤¹¤ë¡£ - * 8. ¥³¡¼¥ë¤µ¤ì¤¿¥×¥í¥·¡¼¥¸¥ã¤Î¼Â¹Ô¤ò¿·¤·¤¤ÆÃ¸¢¥ì¥Ù¥ë¤Ç³«»Ï¤¹¤ë¡£ - */ -void -CALLfar_pm(WORD selector, DWORD new_ip) +void CPUCALL +CALLfar_pm(UINT16 selector, UINT32 new_ip) { selector_t call_sel; int rv; @@ -371,11 +346,11 @@ CALLfar_pm(WORD selector, DWORD new_ip) EXCEPTION(GP_EXCEPTION, call_sel.idx); } - if (call_sel.desc.s) { + if (!SEG_IS_SYSTEM(&call_sel.desc)) { /* 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 */ VERBOSE(("CALLfar_pm: data segment")); EXCEPTION(GP_EXCEPTION, call_sel.idx); @@ -419,36 +394,38 @@ CALLfar_pm(WORD selector, DWORD new_ip) /*--- * CALLfar_pm: code segment */ -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) { - DWORD sp; + UINT32 sp; + + VERBOSE(("CALLfar_pm: CODE-SEGMENT")); /* check privilege level */ - if (!call_sel->desc.u.seg.ec) { + if (!SEG_IS_CONFORMING_CODE(&cs_sel->desc)) { VERBOSE(("CALLfar_pm: NON-CONFORMING-CODE-SEGMENT")); - /* ²¼´¬ p.119 4.8.1.1. */ - if (call_sel->rpl > CPU_STAT_CPL) { - VERBOSE(("CALLfar_pm: RPL(%d) > CPL(%d)", call_sel->rpl, CPU_STAT_CPL)); - EXCEPTION(GP_EXCEPTION, call_sel->idx); - } - if (call_sel->desc.dpl != CPU_STAT_CPL) { - VERBOSE(("CALLfar_pm: DPL(%d) != CPL(%d)", call_sel->desc.dpl, CPU_STAT_CPL)); - EXCEPTION(GP_EXCEPTION, call_sel->idx); + /* 丶祭¥µ p.119 4.8.1.1. */ + if (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); + } + if (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); } } else { VERBOSE(("CALLfar_pm: CONFORMING-CODE-SEGMENT")); - /* ¥¤¥·¥¨¥ã p.120 4.8.1.2. */ - if (call_sel->desc.dpl > CPU_STAT_CPL) { - VERBOSE(("CALLfar_pm: DPL(%d) > CPL(%d)", call_sel->desc.dpl, CPU_STAT_CPL)); - EXCEPTION(GP_EXCEPTION, call_sel->idx); + /* 躶祭¥µ p.120 4.8.1.2. */ + if (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); } } /* not present */ - if (selector_is_not_present(call_sel)) { + if (selector_is_not_present(cs_sel)) { VERBOSE(("CALLfar_pm: selector is not present")); - EXCEPTION(NP_EXCEPTION, call_sel->idx); + EXCEPTION(NP_EXCEPTION, cs_sel->idx); } if (CPU_STAT_SS32) { @@ -457,22 +434,22 @@ CALLfar_pm_code_segment(selector_t *call sp = CPU_SP; } if (CPU_INST_OP32) { - CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 8); + SS_PUSH_CHECK(sp, 8); /* out of range */ - if (new_ip > call_sel->desc.u.seg.limit) { - VERBOSE(("CALLfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, call_sel->desc.u.seg.limit)); + if (new_ip > cs_sel->desc.u.seg.limit) { + VERBOSE(("CALLfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit)); EXCEPTION(GP_EXCEPTION, 0); } PUSH0_32(CPU_CS); PUSH0_32(CPU_EIP); } else { - CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4); + SS_PUSH_CHECK(sp, 4); /* out of range */ - if (new_ip > call_sel->desc.u.seg.limit) { - VERBOSE(("CALLfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, call_sel->desc.u.seg.limit)); + if (new_ip > cs_sel->desc.u.seg.limit) { + VERBOSE(("CALLfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit)); EXCEPTION(GP_EXCEPTION, 0); } @@ -480,18 +457,18 @@ CALLfar_pm_code_segment(selector_t *call PUSH0_16(CPU_IP); } - load_cs(call_sel->selector, &call_sel->desc, CPU_STAT_CPL); - SET_EIP(new_ip); + load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); + CPU_EIP = new_ip; } /*--- * CALLfar_pm: call gate */ -static void CALLfar_pm_call_gate_same_privilege(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_same_privilege(const 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 -CALLfar_pm_call_gate(selector_t *callgate_sel) +static void CPUCALL +CALLfar_pm_call_gate(const selector_t *callgate_sel) { selector_t cs_sel; int rv; @@ -522,11 +499,11 @@ CALLfar_pm_call_gate(selector_t *callgat } /* check segment type */ - if (!cs_sel.desc.s) { + if (SEG_IS_SYSTEM(&cs_sel.desc)) { VERBOSE(("CALLfar_pm: code segment is system segment")); 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")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } @@ -549,7 +526,7 @@ CALLfar_pm_call_gate(selector_t *callgat 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); } else { CALLfar_pm_call_gate_same_privilege(callgate_sel, &cs_sel); @@ -559,11 +536,10 @@ CALLfar_pm_call_gate(selector_t *callgat /*--- * CALLfar_pm: call gate (SAME-PRIVILEGE) */ -static void -CALLfar_pm_call_gate_same_privilege(selector_t *callgate_sel, selector_t *cs_sel) +static void CPUCALL +CALLfar_pm_call_gate_same_privilege(const selector_t *callgate_sel, selector_t *cs_sel) { - DWORD sp; - DWORD new_ip; + UINT32 sp; VERBOSE(("CALLfar_pm: SAME-PRIVILEGE")); @@ -572,40 +548,35 @@ CALLfar_pm_call_gate_same_privilege(sele } else { sp = CPU_SP; } - new_ip = callgate_sel->desc.u.gate.offset; - 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_EIP); - - load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); - SET_EIP(new_ip); } else { - CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4); + SS_PUSH_CHECK(sp, 4); PUSH0_16(CPU_CS); PUSH0_16(CPU_IP); - - load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); - SET_EIP(new_ip); } + + 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) */ -static void -CALLfar_pm_call_gate_more_privilege(selector_t *callgate_sel, selector_t *cs_sel) +static void CPUCALL +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; - DWORD sp; - DWORD old_eip, old_esp; - DWORD new_esp; - WORD old_cs, old_ss; - WORD new_ss; + UINT stacksize; + UINT32 old_eip, old_esp; + UINT32 new_esp; + UINT16 old_cs, old_ss; + UINT16 new_ss; int param_count; int i; int rv; @@ -617,15 +588,12 @@ CALLfar_pm_call_gate_more_privilege(sele old_ss = CPU_SS; old_eip = CPU_EIP; old_esp = CPU_ESP; - - if (CPU_STAT_SS32) { - sp = CPU_ESP; - } else { - sp = CPU_SP; + if (!CPU_STAT_SS32) { + old_esp &= 0xffff; } /* get stack pointer from TSS */ - get_stack_from_tss(cs_sel->desc.dpl, &new_ss, &new_esp); + get_stack_pointer_from_tss(cs_sel->desc.dpl, &new_ss, &new_esp); /* parse stack segment descriptor */ rv = parse_selector(&ss_sel, new_ss); @@ -636,24 +604,24 @@ CALLfar_pm_call_gate_more_privilege(sele /* check privilege level */ if (ss_sel.rpl != cs_sel->desc.dpl) { - VERBOSE(("CALLfar_pm: RPL[SS](%d) != DPL[CS](%d)", ss_sel.rpl, cs_sel->desc.dpl)); + VERBOSE(("CALLfar_pm: selector RPL[SS](%d) != DPL[CS](%d)", ss_sel.rpl, cs_sel->desc.dpl)); EXCEPTION(TS_EXCEPTION, ss_sel.idx); } if (ss_sel.desc.dpl != cs_sel->desc.dpl) { - VERBOSE(("CALLfar_pm: DPL[SS](%d) != DPL[CS](%d)", ss_sel.desc.dpl, cs_sel->desc.dpl)); + VERBOSE(("CALLfar_pm: descriptor DPL[SS](%d) != DPL[CS](%d)", ss_sel.desc.dpl, cs_sel->desc.dpl)); EXCEPTION(TS_EXCEPTION, ss_sel.idx); } /* stack segment must be writable data segment. */ - if (!ss_sel.desc.s) { + if (SEG_IS_SYSTEM(&ss_sel.desc)) { VERBOSE(("CALLfar_pm: stack segment is system segment")); 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")); 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")); EXCEPTION(TS_EXCEPTION, ss_sel.idx); } @@ -667,12 +635,23 @@ CALLfar_pm_call_gate_more_privilege(sele param_count = callgate_sel->desc.u.gate.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) { - 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, ss_sel.desc.d); + if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { /* dump param */ for (i = 0; i < param_count; i++) { - param[i] = cpu_vmemoryread_d(CPU_SS_INDEX, sp + i * 4); + param[i] = cpu_vmemoryread_d(CPU_SS_INDEX, old_esp + i * 4); VERBOSE(("CALLfar_pm: get param[%d] = %08x", i, param[i])); } @@ -680,17 +659,17 @@ CALLfar_pm_call_gate_more_privilege(sele if (CPU_STAT_SS32) { CPU_ESP = new_esp; } else { - CPU_SP = new_esp; + CPU_SP = (UINT16)new_esp; } load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); - SET_EIP(callgate_sel->desc.u.gate.offset); + CPU_EIP = callgate_sel->desc.u.gate.offset; PUSH0_32(old_ss); PUSH0_32(old_esp); /* restore param */ - for (i = param_count; i != 0; i--) { + for (i = param_count; i > 0; i--) { PUSH0_32(param[i - 1]); VERBOSE(("CALLfar_pm: set param[%d] = %08x", i - 1, param[i - 1])); } @@ -698,11 +677,9 @@ CALLfar_pm_call_gate_more_privilege(sele PUSH0_32(old_cs); PUSH0_32(old_eip); } else { - CHECK_STACK_PUSH(&ss_sel.desc, new_esp, 8 + param_count * 2); - /* dump param */ for (i = 0; i < param_count; i++) { - param[i] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + i * 2); + param[i] = cpu_vmemoryread_w(CPU_SS_INDEX, old_esp + i * 2); VERBOSE(("CALLfar_pm: get param[%d] = %04x", i, param[i])); } @@ -710,17 +687,17 @@ CALLfar_pm_call_gate_more_privilege(sele if (CPU_STAT_SS32) { CPU_ESP = new_esp; } else { - CPU_SP = new_esp; + CPU_SP = (UINT16)new_esp; } load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); - SET_EIP(callgate_sel->desc.u.gate.offset); + CPU_EIP = callgate_sel->desc.u.gate.offset; PUSH0_16(old_ss); PUSH0_16(old_esp); /* restore param */ - for (i = param_count; i != 0; i--) { + for (i = param_count; i > 0; i--) { PUSH0_16(param[i - 1]); VERBOSE(("CALLfar_pm: set param[%d] = %04x", i - 1, param[i - 1])); } @@ -733,7 +710,7 @@ CALLfar_pm_call_gate_more_privilege(sele /*--- * CALLfar_pm: task gate */ -static void +static void CPUCALL CALLfar_pm_task_gate(selector_t *taskgate_sel) { selector_t tss_sel; @@ -787,12 +764,18 @@ CALLfar_pm_task_gate(selector_t *taskgat } 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 */ -static void +static void CPUCALL CALLfar_pm_tss(selector_t *tss_sel) { @@ -815,6 +798,12 @@ CALLfar_pm_tss(selector_t *tss_sel) } 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); + } } @@ -822,33 +811,14 @@ CALLfar_pm_tss(selector_t *tss_sel) * RETfar_pm */ -/* - * 4.3.6. ¥Ë¥Æ¥¯¡Ö¡¦ø§¥ë¡¦ö¶¥è¡¢¥Û¡¦ô§¥½¡£¥·¡¦óÁàº- * - * 1. ÆÃ¸¢¥Á¥§¥Ã¥¯¤ò¼Â¹Ô¤¹¤ë¡£ - * 2. CS ¥ì¥¸¥¹¥¿¤È EIP ¥ì¥¸¥¹¥¿¤Ë¥³¡¼¥ëÁ°¤ÎÃͤò¥ê¥¹¥È¥¢¤¹¤ë¡£ - * 3. RET Ì¿Îá¤Ë¥ª¥×¥·¥ç¥ó°ú¤­¿ô¤Î n ¤¬¤¢¤ë¾ì¹ç¤Ï¡¢¥Ñ¥é¥á¡¼¥¿¤ò¥¹¥¿¥Ã¥¯¤«¤é - * ³«Êü¤¹¤ë¤¿¤á¡¢n ¥ª¥Ú¥é¥ó¥É¤Ç»ØÄꤵ¤ì¤¿¥Ð¥¤¥È¿ô¤À¤±¥¹¥¿¥Ã¥¯¡¦¥Ý¥¤¥ó¥¿¤ò - * ¥¤¥ó¥¯¥ê¥á¥ó¥È¤¹¤ë¡£¥³¡¼¥ë¡¦¥²¡¼¥È¡¦¥Ç¥£¥¹¥¯¥ê¥×¥¿¤¬¡¢¥¹¥¿¥Ã¥¯´Ö¤Ç - * 1 ¤Ä°Ê¾å¤Î¥Ñ¥é¥á¡¼¥¿¤ò¥³¥Ô¡¼¤¹¤ë¤è¤¦»ØÄꤷ¤Æ¤¤¤ë¾ì¹ç¤Ï¡¢RET n Ì¿Îá¤ò - * »ÈÍѤ·¤ÆÎ¾¥¹¥¿¥Ã¥¯¤«¤é¥Ñ¥é¥á¡¼¥¿¤ò³«Êü¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£n ¥ª¥Ú¥é¥ó¥É - * ¤Ë¤Ï¡¢³Æ¥¹¥¿¥Ã¥¯¾í¤Ç¥Ñ¥é¥á¡¼¥¿¤¬ÀêÍ­¤¹¤ë¥Ð¥¤¥È¿ô¤ò»ØÄꤹ¤ë¡£ - * ¥ê¥¿¡¼¥ó»þ¤Ë¡¢¥×¥í¥»¥Ã¥µ¤Ï³Æ¥¹¥¿¥Ã¥¯¤ËÂФ·¤Æ n ¤À¤± ESP ¤ò¥¤¥ó¥¯¥ê¥á¥ó¥È - * ¤·¡¢¤³¤ì¤é¤Î¥Ñ¥é¥á¡¼¥¿¤ò¥¹¥¿¥Ã¥¯¤«¤é¸úΨ¤è¤¯ºï½ü¤¹¤ë¡£ - * 4. SS ¥ì¥¸¥¹¥¿¤È ESP ¥ì¥¸¥¹¥¿¤Ë¡¢¥³¡¼¥ëÁ°¤ÎÃͤò¥ê¥¹¥È¥¢¤¹¤ë¡£¤³¤ì¤Ç¡¢ - * ¥³¡¼¥ë¸µ¥×¥í¥·¡¼¥¸¥ã¤Î¥¹¥¿¥Ã¥¯¤ØÀÚ¤êÂØ¤¨¤é¤ì¤ë¡£ - * 5. RET Ì¿Îá¤Ë¥ª¥×¥·¥ç¥ó°ú¤­¿ô¤Î n ¤¬¤¢¤ë¾ì¹ç¤Ï¡¢¥Ñ¥é¥á¡¼¥¿¤ò¥¹¥¿¥Ã¥¯¤«¤é - * ³«Êü¤¹¤ë¤¿¤á¡¢n ¥ª¥Ú¥é¥ó¥É¤Ç»ØÄꤵ¤ì¤¿¥Ð¥¤¥È¿ô¤À¤±¥¹¥¿¥Ã¥¯¡¦¥Ý¥¤¥ó¥¿¤ò - * ¥¤¥ó¥¯¥ê¥á¥ó¥È¤¹¤ë(¥¹¥Æ¥Ã¥× 3 ¤ÎÀâÌÀ¤ò»²¾È)¡£ - * 6. ¥³¡¼¥ë¸µ¥×¥í¥·¡¼¥¸¥ã¤Î¼Â¹Ô¤òºÆ³«¤¹¤ë¡£ - */ -void -RETfar_pm(DWORD nbytes) +void CPUCALL +RETfar_pm(UINT nbytes) { - selector_t ret_sel, ss_sel, temp_sel; - DWORD sp; - DWORD new_ip, new_sp; - WORD new_cs, new_ss; + selector_t cs_sel, ss_sel, temp_sel; + descriptor_t *sdp; + UINT32 sp; + UINT32 new_ip, new_sp; + UINT16 new_cs, new_ss; int rv; int i; @@ -860,57 +830,57 @@ RETfar_pm(DWORD nbytes) sp = CPU_SP; } 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_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); } 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_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); } - rv = parse_selector(&ret_sel, new_cs); + rv = parse_selector(&cs_sel, new_cs); if (rv < 0) { - VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ret_sel.selector, rv)); - EXCEPTION(GP_EXCEPTION, ret_sel.idx); + VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d)", cs_sel.selector, rv)); + EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* check segment type */ - if (!ret_sel.desc.s) { + if (SEG_IS_SYSTEM(&cs_sel.desc)) { VERBOSE(("RETfar_pm: return to system segment")); - EXCEPTION(GP_EXCEPTION, ret_sel.idx); + EXCEPTION(GP_EXCEPTION, cs_sel.idx); } - if (!ret_sel.desc.u.seg.c) { + if (SEG_IS_DATA(&cs_sel.desc)) { VERBOSE(("RETfar_pm: return to data segment")); - EXCEPTION(GP_EXCEPTION, ret_sel.idx); + EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* check privilege level */ - if (ret_sel.rpl < CPU_STAT_CPL) { - VERBOSE(("RETfar_pm: RPL(%d) < CPL(%d)", ret_sel.rpl, CPU_STAT_CPL)); - EXCEPTION(GP_EXCEPTION, ret_sel.idx); - } - if (!ret_sel.desc.u.seg.ec && (ret_sel.desc.dpl > ret_sel.rpl)) { - VERBOSE(("RETfar_pm: NON-COMFORMING-CODE-SEGMENT and DPL(%d) > RPL(%d)", ret_sel.desc.dpl, ret_sel.rpl)); - EXCEPTION(GP_EXCEPTION, ret_sel.idx); + if (cs_sel.rpl < CPU_STAT_CPL) { + VERBOSE(("RETfar_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); + EXCEPTION(GP_EXCEPTION, cs_sel.idx); + } + if (!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)); + EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* not present */ - if (selector_is_not_present(&ret_sel)) { + if (selector_is_not_present(&cs_sel)) { VERBOSE(("RETfar_pm: returned code segment is not present")); - EXCEPTION(NP_EXCEPTION, ret_sel.idx); + EXCEPTION(NP_EXCEPTION, cs_sel.idx); } - if (ret_sel.rpl == CPU_STAT_CPL) { + if (cs_sel.rpl == CPU_STAT_CPL) { VERBOSE(("RETfar_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); /* check code segment limit */ - if (new_ip > ret_sel.desc.u.seg.limit) { - VERBOSE(("RETfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, ret_sel.desc.u.seg.limit)); + if (new_ip > cs_sel.desc.u.seg.limit) { + VERBOSE(("RETfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit)); EXCEPTION(GP_EXCEPTION, 0); } - VERBOSE(("RETfar_pm: new_ip = %08x, new_cs = %04x", new_ip, ret_sel.selector)); + VERBOSE(("RETfar_pm: new_ip = %08x, new_cs = %04x", new_ip, cs_sel.selector)); if (CPU_INST_OP32) { nbytes += 8; @@ -920,52 +890,52 @@ RETfar_pm(DWORD nbytes) if (CPU_STAT_SS32) { CPU_ESP += nbytes; } else { - CPU_SP += nbytes; + CPU_SP += (UINT16)nbytes; } - load_cs(ret_sel.selector, &ret_sel.desc, CPU_STAT_CPL); - SET_EIP(new_ip); + load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL); + CPU_EIP = new_ip; } else { VERBOSE(("RETfar_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); 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_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8 + nbytes + 4); } 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_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes + 2); } rv = parse_selector(&ss_sel, new_ss); if (rv < 0) { - VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ss_sel.selector, rv)); - EXCEPTION(GP_EXCEPTION, ss_sel.idx); + VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d)", ss_sel.selector, rv)); + EXCEPTION(GP_EXCEPTION, (rv == -2) ? 0 : ss_sel.idx); } - /* check stack segment descriptor */ - if (!ss_sel.desc.s) { + /* stack segment must be writable data segment. */ + if (SEG_IS_SYSTEM(&ss_sel.desc)) { VERBOSE(("RETfar_pm: stack segment is system segment")); - EXCEPTION(GP_EXCEPTION, ret_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")); - EXCEPTION(GP_EXCEPTION, ret_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")); - EXCEPTION(GP_EXCEPTION, ret_sel.idx); + EXCEPTION(GP_EXCEPTION, cs_sel.idx); } /* check privilege level */ - if (ss_sel.rpl != ret_sel.rpl) { - VERBOSE(("RETfar_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, ret_sel.rpl)); - EXCEPTION(GP_EXCEPTION, ret_sel.idx); - } - if (ss_sel.desc.dpl != ret_sel.rpl) { - VERBOSE(("RETfar_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, ret_sel.rpl)); - EXCEPTION(GP_EXCEPTION, ret_sel.idx); + if (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); + } + if (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); } /* not present */ @@ -975,65 +945,61 @@ RETfar_pm(DWORD nbytes) } /* check code segment limit */ - if (new_ip > ret_sel.desc.u.seg.limit) { - VERBOSE(("RETfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, ret_sel.desc.u.seg.limit)); + if (new_ip > cs_sel.desc.u.seg.limit) { + VERBOSE(("RETfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit)); EXCEPTION(GP_EXCEPTION, 0); } - VERBOSE(("RETfar_pm: new_ip = %08x, new_cs = %04x", new_ip, ret_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)); - load_cs(ret_sel.selector, &ret_sel.desc, ret_sel.rpl); - SET_EIP(new_ip); - - load_ss(ss_sel.selector, &ss_sel.desc, ret_sel.rpl); + load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.rpl); if (CPU_STAT_SS32) { CPU_ESP = new_sp + nbytes; } 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 */ for (i = 0; i < CPU_SEGREG_NUM; i++) { - descriptor_t *dp; - BOOL valid; + if (i == CPU_SS_INDEX || i == CPU_CS_INDEX) + continue; - 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 */ + sdp = &CPU_STAT_SREG(i); + if ((SEG_IS_DATA(sdp) || !SEG_IS_CONFORMING_CODE(sdp)) + && (CPU_STAT_CPL > sdp->dpl)) { + /* current segment descriptor is invalid */ CPU_REGS_SREG(i) = 0; - CPU_STAT_SREG_CLEAR(i); + memset(sdp, 0, sizeof(*sdp)); continue; } + /* Reload segment descriptor */ rv = parse_selector(&temp_sel, CPU_REGS_SREG(i)); if (rv < 0) { /* segment register is invalid */ CPU_REGS_SREG(i) = 0; - CPU_STAT_SREG_CLEAR(i); + memset(sdp, 0, sizeof(*sdp)); 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 */ + /* + * - system segment + * - execute-only code segment + * - data or conforming code segment && CPL > DPL + */ + if (SEG_IS_SYSTEM(&temp_sel.desc) + || (SEG_IS_CODE(&temp_sel.desc) + && !SEG_IS_READABLE_CODE(&temp_sel.desc)) + || ((SEG_IS_DATA(&temp_sel.desc) + || !SEG_IS_CONFORMING_CODE(&temp_sel.desc)) + && (CPU_STAT_CPL > temp_sel.desc.dpl))) { + /* segment descriptor is invalid */ CPU_REGS_SREG(i) = 0; - CPU_STAT_SREG(i).valid = 0; + memset(sdp, 0, sizeof(*sdp)); } } } @@ -1046,68 +1012,123 @@ RETfar_pm(DWORD nbytes) * IRET_pm */ 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_from_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags); +static void CPUCALL IRET_pm_protected_mode_return(UINT16 new_cs, UINT32 new_ip, UINT32 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 CPUCALL IRET_pm_protected_mode_return_outer_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags); +static void CPUCALL IRET_pm_return_to_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags); +static void CPUCALL IRET_pm_return_from_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags); void IRET_pm(void) { - selector_t cs_sel, ss_sel; - descriptor_t *dp; - DWORD sp; - DWORD stacksize; /* for RETURN-TO-SAME-PRIVILEGE-LEVEL */ - DWORD mask = 0; - DWORD new_ip, new_sp, new_flags; - WORD new_cs, new_ss; - int op32; - int rv; - int i; + UINT32 sp; + UINT32 new_ip, new_flags; + UINT16 new_cs; - 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, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); if (!(CPU_EFLAG & VM_FLAG) && (CPU_EFLAG & NT_FLAG)) { /* TASK-RETURN: PE=1, VM=0, NT=1 */ IRET_pm_nested_task(); - VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); - CPU_STAT_NERROR = 0; - return; + } else { + if (CPU_STAT_SS32) { + sp = CPU_ESP; + } else { + sp = CPU_SP; + } + if (CPU_INST_OP32) { + SS_POP_CHECK(sp, 12); + new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); + new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); + new_flags = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8); + } else { + SS_POP_CHECK(sp, 6); + new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); + new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); + new_flags = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); + } + + VERBOSE(("IRET_pm: new_ip = %08x, new_cs = %04x, new_eflags = %08x", new_ip, new_cs, new_flags)); + + if (CPU_EFLAG & VM_FLAG) { + /* RETURN-FROM-VIRTUAL-8086-MODE */ + IRET_pm_return_from_vm86(new_cs, new_ip, new_flags); + } else if ((new_flags & VM_FLAG) && CPU_STAT_CPL == 0) { + /* RETURN-TO-VIRTUAL-8086-MODE */ + IRET_pm_return_to_vm86(new_cs, new_ip, new_flags); + } else { + /* PROTECTED-MODE-RETURN */ + IRET_pm_protected_mode_return(new_cs, new_ip, new_flags); + } } - if (CPU_STAT_SS32) { - sp = CPU_ESP; - } else { - sp = CPU_SP; + VERBOSE(("IRET_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); +} + +/*--- + * IRET_pm: NT_FLAG + */ +static void +IRET_pm_nested_task(void) +{ + selector_t tss_sel; + UINT16 new_tss; + int rv; + + VERBOSE(("IRET_pm: TASK-RETURN: PE=1, VM=0, NT=1")); + + new_tss = get_backlink_selector_from_tss(); + + rv = parse_selector(&tss_sel, new_tss); + if (rv < 0 || tss_sel.ldt) { + 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); } - if (CPU_INST_OP32) { - CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 12); - new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); - new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); - new_flags = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8); - } else { - CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 6); - new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); - new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2); - new_flags = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); + + /* check system segment */ + if (!SEG_IS_SYSTEM(&tss_sel.desc)) { + VERBOSE(("IRET_pm: task segment is %s segment", tss_sel.desc.u.seg.c ? "code" : "data")); + EXCEPTION(GP_EXCEPTION, tss_sel.idx); } - op32 = CPU_INST_OP32; - VERBOSE(("IRET_pm: new_ip = %08x, new_cs = %04x, new_eflags = %08x", new_ip, new_cs, new_flags)); + switch (tss_sel.desc.type) { + case CPU_SYSDESC_TYPE_TSS_BUSY_16: + case CPU_SYSDESC_TYPE_TSS_BUSY_32: + break; - if (CPU_EFLAG & VM_FLAG) { - /* RETURN-FROM-VIRTUAL-8086-MODE */ - IRET_pm_return_from_vm86(new_ip, new_cs, new_flags); - VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); - CPU_STAT_NERROR = 0; - return; + case CPU_SYSDESC_TYPE_TSS_16: + case CPU_SYSDESC_TYPE_TSS_32: + VERBOSE(("IRET_pm: task is not busy")); + /*FALLTHROUGH*/ + default: + VERBOSE(("IRET_pm: invalid descriptor type (type = %d)", tss_sel.desc.type)); + EXCEPTION(GP_EXCEPTION, tss_sel.idx); + break; } - if (new_flags & VM_FLAG) { - /* RETURN-TO-VIRTUAL-8086-MODE */ - IRET_pm_return_to_vm86(new_ip, new_cs, new_flags); - VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); - CPU_STAT_NERROR = 0; - return; + /* not present */ + if (selector_is_not_present(&tss_sel)) { + VERBOSE(("IRET_pm: tss segment is not present")); + EXCEPTION(NP_EXCEPTION, tss_sel.idx); + } + + 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 + */ +static void CPUCALL +IRET_pm_protected_mode_return(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags) +{ + selector_t cs_sel; + int rv; /* PROTECTED-MODE-RETURN */ VERBOSE(("IRET_pm: PE=1, VM=0 in flags image")); @@ -1119,11 +1140,11 @@ IRET_pm(void) } /* 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")); 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")); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } @@ -1133,8 +1154,8 @@ IRET_pm(void) VERBOSE(("IRET_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } - if (cs_sel.desc.u.seg.ec && (cs_sel.desc.dpl > cs_sel.rpl)) { - VERBOSE(("IRET_pm: CONFORMING-CODE-SEGMENT and DPL(%d) != RPL(%d)", 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)); EXCEPTION(GP_EXCEPTION, cs_sel.idx); } @@ -1145,217 +1166,193 @@ IRET_pm(void) } if (cs_sel.rpl > CPU_STAT_CPL) { - VERBOSE(("IRET_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); - - if (CPU_INST_OP32) { - CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 20); - new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); - new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); - } else { - CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 10); - new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 6); - new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8); - } - VERBOSE(("IRET_pm: new_sp = 0x%08x, new_ss = 0x%04x", new_sp, new_ss)); - - rv = parse_selector(&ss_sel, new_ss); - if (rv < 0) { - VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", ss_sel.selector, rv)); - EXCEPTION(GP_EXCEPTION, ss_sel.idx); - } - - /* check privilege level */ - if (ss_sel.rpl != cs_sel.rpl) { - VERBOSE(("IRET_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel.rpl)); - EXCEPTION(GP_EXCEPTION, ss_sel.idx); - } - if (ss_sel.desc.dpl != cs_sel.rpl) { - VERBOSE(("IRET_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel.rpl)); - EXCEPTION(GP_EXCEPTION, ss_sel.idx); - } - - /* check stack segment descriptor */ - if (!ss_sel.desc.s) { - VERBOSE(("IRET_pm: stack segment is system segment")); - EXCEPTION(GP_EXCEPTION, ss_sel.idx); - } - if (ss_sel.desc.u.seg.c) { - VERBOSE(("IRET_pm: stack segment is code segment")); - EXCEPTION(GP_EXCEPTION, ss_sel.idx); - } - if (!ss_sel.desc.u.seg.wr) { - VERBOSE(("IRET_pm: stack segment is read-only data segment")); - EXCEPTION(GP_EXCEPTION, ss_sel.idx); - } - - /* not present */ - if (selector_is_not_present(&ss_sel)) { - VERBOSE(("IRET_pm: stack segment is not present")); - EXCEPTION(SS_EXCEPTION, ss_sel.idx); - } - - /* check code segment limit */ - if (new_ip > cs_sel.desc.u.seg.limit) { - VERBOSE(("IRET_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit)); - EXCEPTION(GP_EXCEPTION, 0); - } + IRET_pm_protected_mode_return_outer_privilege(&cs_sel, new_ip, new_flags); + } else { + IRET_pm_protected_mode_return_same_privilege(&cs_sel, new_ip, new_flags); + } +} - 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; - } - } +/*--- + * IRET_pm: SAME-PRIVILEGE + */ +static void CPUCALL +IRET_pm_protected_mode_return_same_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags) +{ + UINT32 mask; + UINT stacksize; - /* set new register */ - load_cs(cs_sel.selector, &cs_sel.desc, cs_sel.rpl); - SET_EIP(new_ip); + VERBOSE(("IRET_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); - if (op32) { - set_eflags(new_flags, mask); - } else { - set_flags(new_flags, mask); - } + /* 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); + } - load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.rpl); - if (CPU_STAT_SS32) { - CPU_ESP = new_sp; - } else { - CPU_SP = new_sp; + 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; } + } - /* check segment register */ - for (i = 0; i < CPU_SEGREG_NUM; i++) { - if ((i != CPU_CS_INDEX) && (i != CPU_SS_INDEX)) { - dp = &CPU_STAT_SREG(i); - if ((!dp->u.seg.c || !dp->u.seg.ec) - && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) { - /* segment register is invalid */ - CPU_REGS_SREG(i) = 0; - CPU_STAT_SREG_CLEAR(i); - continue; - } - } - } + if (CPU_INST_OP32) { + stacksize = 12; } else { - 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); + stacksize = 6; + } - if (op32) { - set_eflags(new_flags, mask); - } else { - set_flags(new_flags, mask); - } + /* set new register */ + load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); + CPU_EIP = new_ip; - if (CPU_INST_OP32) { - stacksize = 12; - } else { - stacksize = 6; - } - if (CPU_STAT_SS32) { - CPU_ESP += stacksize; - } else { - CPU_SP += stacksize; - } + if (CPU_STAT_SS32) { + CPU_ESP += stacksize; + } else { + CPU_SP += (UINT16)stacksize; } - CPU_STAT_NERROR = 0; - VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); + set_eflags(new_flags, mask); } /*--- - * IRET_pm: NT_FLAG + * IRET_pm: OUTER-PRIVILEGE */ -static void -IRET_pm_nested_task(void) +static void CPUCALL +IRET_pm_protected_mode_return_outer_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags) { - selector_t tss_sel; + descriptor_t *sdp; + selector_t ss_sel; + UINT32 mask; + UINT32 sp; + UINT32 new_sp; + UINT16 new_ss; int rv; - WORD new_tss; - - VERBOSE(("IRET_pm: TASK-RETURN: PE=1, VM=0, NT=1")); + int i; - new_tss = get_link_selector_from_tss(); + VERBOSE(("IRET_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); - rv = parse_selector(&tss_sel, new_tss); - if (rv < 0 || tss_sel.ldt) { - 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); + if (CPU_STAT_SS32) { + sp = CPU_ESP; + } else { + sp = CPU_SP; } + if (CPU_INST_OP32) { + SS_POP_CHECK(sp, 20); + new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); + new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); + } else { + SS_POP_CHECK(sp, 10); + new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 6); + new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8); + } + VERBOSE(("IRET_pm: new_sp = 0x%08x, new_ss = 0x%04x", new_sp, new_ss)); - /* check system segment */ - if (tss_sel.desc.s) { - VERBOSE(("IRET_pm: task segment is %d segment", tss_sel.desc.u.seg.c ? "code" : "data")); - EXCEPTION(GP_EXCEPTION, tss_sel.idx); + rv = parse_selector(&ss_sel, new_ss); + if (rv < 0) { + VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", ss_sel.selector, rv)); + EXCEPTION(GP_EXCEPTION, (rv == -2) ? 0 : ss_sel.idx); } - switch (tss_sel.desc.type) { - case CPU_SYSDESC_TYPE_TSS_BUSY_16: - case CPU_SYSDESC_TYPE_TSS_BUSY_32: - break; + /* check privilege level */ + if (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); + } +#if 0 + if (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); + } + 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 - case CPU_SYSDESC_TYPE_TSS_16: - case CPU_SYSDESC_TYPE_TSS_32: - VERBOSE(("IRET_pm: task is not busy")); - /*FALLTHROUGH*/ - default: - VERBOSE(("IRET_pm: invalid descriptor type (type = %d)", tss_sel.desc.type)); - EXCEPTION(GP_EXCEPTION, tss_sel.idx); - break; + /* stack segment must be writable data segment. */ + if (SEG_IS_SYSTEM(&ss_sel.desc)) { + VERBOSE(("IRET_pm: stack segment is system segment")); + EXCEPTION(GP_EXCEPTION, ss_sel.idx); + } + if (SEG_IS_CODE(&ss_sel.desc)) { + VERBOSE(("IRET_pm: stack segment is code segment")); + EXCEPTION(GP_EXCEPTION, ss_sel.idx); + } + if (!SEG_IS_WRITABLE_DATA(&ss_sel.desc)) { + VERBOSE(("IRET_pm: stack segment is read-only data segment")); + EXCEPTION(GP_EXCEPTION, ss_sel.idx); } /* not present */ - if (selector_is_not_present(&tss_sel)) { - VERBOSE(("IRET_pm: tss segment is not present")); - EXCEPTION(NP_EXCEPTION, tss_sel.idx); + if (selector_is_not_present(&ss_sel)) { + VERBOSE(("IRET_pm: stack segment is not present")); + EXCEPTION(SS_EXCEPTION, ss_sel.idx); } - task_switch(&tss_sel, TASK_SWITCH_IRET); + /* check code segment limit */ + if (new_ip > cs_sel->desc.u.seg.limit) { + VERBOSE(("IRET_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit)); + EXCEPTION(GP_EXCEPTION, 0); + } + + mask = 0; + if (CPU_INST_OP32) + mask |= RF_FLAG; + if (CPU_STAT_CPL <= CPU_STAT_IOPL) + mask |= I_FLAG; + if (CPU_STAT_CPL == 0) { + mask |= IOPL_FLAG; + if (CPU_INST_OP32) { + mask |= VM_FLAG|VIF_FLAG|VIP_FLAG; + } + } + + /* set new register */ + load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->rpl); + CPU_EIP = new_ip; + + load_ss(ss_sel.selector, &ss_sel.desc, cs_sel->rpl); + if (CPU_STAT_SS32) { + CPU_ESP = new_sp; + } else { + CPU_SP = (UINT16)new_sp; + } + + set_eflags(new_flags, mask); + + /* check segment register */ + for (i = 0; i < CPU_SEGREG_NUM; i++) { + if ((i != CPU_CS_INDEX) && (i != CPU_SS_INDEX)) { + sdp = &CPU_STAT_SREG(i); + if ((SEG_IS_DATA(sdp) || !SEG_IS_CONFORMING_CODE(sdp)) + && (sdp->dpl < CPU_STAT_CPL)) { + /* segment register is invalid */ + CPU_REGS_SREG(i) = 0; + memset(sdp, 0, sizeof(*sdp)); + } + } + } } /*--- * IRET_pm: new_flags & VM_FLAG */ -static void -IRET_pm_return_to_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags) +static void CPUCALL +IRET_pm_return_to_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags) { - WORD segsel[CPU_SEGREG_NUM]; - DWORD sp; - DWORD new_sp; + UINT16 segsel[CPU_SEGREG_NUM]; + UINT32 sp; + UINT32 new_sp; int i; VERBOSE(("IRET_pm: Interrupt procedure was in virtual-8086 mode: PE=1, VM=1 in flags image")); - if (CPU_STAT_CPL != 0) { - ia32_panic("IRET_pm: CPL != 0"); - } - if (!CPU_INST_OP32) { ia32_panic("IRET_pm: 16bit mode"); } @@ -1365,7 +1362,8 @@ IRET_pm_return_to_vm86(DWORD new_ip, DWO } else { sp = CPU_SP; } - CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 36); + SS_POP_CHECK(sp, 36); + new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); segsel[CPU_ES_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 20); @@ -1375,25 +1373,23 @@ IRET_pm_return_to_vm86(DWORD new_ip, DWO segsel[CPU_CS_INDEX] = new_cs; for (i = 0; i < CPU_SEGREG_NUM; i++) { - CPU_REGS_SREG(i) = segsel[i]; - CPU_STAT_SREG_INIT(i); + segdesc_init(i, segsel[i], &CPU_STAT_SREG(i)); } + CPU_ESP = new_sp; + CPU_EIP = new_ip & 0xffff; + /* to VM86 mode */ set_eflags(new_flags, IOPL_FLAG|I_FLAG|VM_FLAG|RF_FLAG); - - CPU_ESP = new_sp; - new_ip &= 0xffff; - SET_EIP(new_ip); } /*--- * IRET_pm: VM_FLAG */ -static void -IRET_pm_return_from_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags) +static void CPUCALL +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")); @@ -1410,14 +1406,13 @@ IRET_pm_return_from_vm86(DWORD new_ip, D CPU_SP += stacksize; } - if (CPU_INST_OP32) { - set_eflags(new_flags, I_FLAG|RF_FLAG); - } else { - set_flags(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_EIP(new_ip); + set_eflags(new_flags, I_FLAG|RF_FLAG); return; } VERBOSE(("IRET_pm: trap to virtual-8086 monitor: VM=1, IOPL<3"));