|
|
| version 1.5, 2004/01/27 15:55:49 | version 1.23, 2011/12/21 18:07:57 |
|---|---|
| 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 JMPfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip); |
| static void JMPfar_pm_call_gate(selector_t *jmp_sel); | static void JMPfar_pm_call_gate(const selector_t *callgate_sel); |
| static void JMPfar_pm_task_gate(selector_t *jmp_sel); | static void JMPfar_pm_task_gate(selector_t *taskgate_sel); |
| static void JMPfar_pm_tss(selector_t *jmp_sel); | static void JMPfar_pm_tss(selector_t *tss_sel); |
| void | void |
| 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 98 JMPfar_pm(WORD selector, DWORD new_ip) | Line 94 JMPfar_pm(WORD selector, DWORD new_ip) |
| break; | break; |
| } | } |
| } | } |
| VERBOSE(("JMPfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); | VERBOSE(("JMPfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); |
| } | } |
| Line 105 JMPfar_pm(WORD selector, DWORD new_ip) | Line 102 JMPfar_pm(WORD selector, DWORD new_ip) |
| * JMPfar: code segment | * JMPfar: code segment |
| */ | */ |
| static void | static void |
| JMPfar_pm_code_segment(selector_t *code_sel, DWORD new_ip) | JMPfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip) |
| { | { |
| VERBOSE(("JMPfar_pm: CODE-SEGMENT")); | |
| /* check privilege level */ | /* 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")); | VERBOSE(("JMPfar_pm: NON-CONFORMING-CODE-SEGMENT")); |
| /* ¥¤¥·¥¨¥ã p.119 4.8.1.1. */ | /* 躶祥µ p.119 4.8.1.1. */ |
| if (code_sel->rpl > CPU_STAT_CPL) { | if (cs_sel->rpl > CPU_STAT_CPL) { |
| VERBOSE(("JMPfar_pm: RPL(%d) > CPL(%d)", code_sel->rpl, CPU_STAT_CPL)); | VERBOSE(("JMPfar_pm: RPL(%d) > CPL(%d)", cs_sel->rpl, CPU_STAT_CPL)); |
| EXCEPTION(GP_EXCEPTION, code_sel->idx); | EXCEPTION(GP_EXCEPTION, cs_sel->idx); |
| } | } |
| if (code_sel->desc.dpl != CPU_STAT_CPL) { | if (cs_sel->desc.dpl != CPU_STAT_CPL) { |
| VERBOSE(("JMPfar_pm: DPL(%d) != CPL(%d)", code_sel->desc.dpl, CPU_STAT_CPL)); | VERBOSE(("JMPfar_pm: DPL(%d) != CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL)); |
| EXCEPTION(GP_EXCEPTION, code_sel->idx); | EXCEPTION(GP_EXCEPTION, cs_sel->idx); |
| } | } |
| } 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 (code_sel->desc.dpl > CPU_STAT_CPL) { | if (cs_sel->desc.dpl > CPU_STAT_CPL) { |
| VERBOSE(("JMPfar_pm: DPL(%d) > CPL(%d)", code_sel->desc.dpl, CPU_STAT_CPL)); | VERBOSE(("JMPfar_pm: DPL(%d) > CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL)); |
| EXCEPTION(GP_EXCEPTION, code_sel->idx); | EXCEPTION(GP_EXCEPTION, cs_sel->idx); |
| } | } |
| } | } |
| /* not present */ | /* not present */ |
| if (selector_is_not_present(code_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, code_sel->idx); | EXCEPTION(NP_EXCEPTION, cs_sel->idx); |
| } | } |
| /* out of range */ | /* out of range */ |
| if (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, code_sel->desc.u.seg.limit)); | VERBOSE(("JMPfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit)); |
| EXCEPTION(GP_EXCEPTION, 0); | EXCEPTION(GP_EXCEPTION, 0); |
| } | } |
| load_cs(code_sel->selector, &code_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 |
| 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 168 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 180 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 201 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 210 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 221 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; |
| } | } |
| /*--- | /*--- |
| Line 235 JMPfar_pm_task_gate(selector_t *taskgate | Line 234 JMPfar_pm_task_gate(selector_t *taskgate |
| VERBOSE(("JMPfar_pm: TASK-GATE")); | VERBOSE(("JMPfar_pm: TASK-GATE")); |
| /* | |
| * ¥Æì¶¥ã p.373 JMP ¥Õ¥½¥Û- * | |
| * JMP Ì¿Îá¤Ç¥¿¥¹¥¯¡¦¥¹¥¤¥Ã¥Á¤ò¼Â¹Ô¤¹¤ë¤È¤¤Ï EFLAGS ¥ì¥¸¥¹¥¿¤Ë | |
| * ¥Í¥¹¥È¤µ¤ì¤¿¥¿¥¹¥¯¡¦¥Õ¥é¥° (NT) ¤¬¥»¥Ã¥È¤µ¤ì¤º¡¢¿·¤·¤¤ TSS ¤Î | |
| * °ÊÁ°¤Î¥¿¥¹¥¯¡¦¥ê¥ó¥¯¡¦¥Õ¥£¡¼¥ë¥É¤ËÁ°¤Î¥¿¥¹¥¯¤Î TSS ¥»¥ì¥¯¥¿¤¬ | |
| * ¥í¡¼¥É¤µ¤ì¤Ê¤¤¤Î¤ÇÃí°Õ¤µ¤ì¤¿¤¤¡£¤·¤¿¤¬¤Ã¤Æ¡¢Á°¤Î¥¿¥¹¥¯¤Ø¤Î | |
| * ¥ê¥¿¡¼¥ó¤Ï IRET Ì¿Îá¤Î¼Â¹Ô¤Ç¤Ï¼Â¸½¤Ç¤¤Ê¤¤¡£JMP Ì¿Îá¤Ç | |
| * ¥¿¥¹¥¯¡¦¥¹¥¤¥Ã¥Á¤ò¼Â¹Ô¤¹¤ë¤Î¤Ï¡¢¤½¤ÎÅÀ¤Ç CALL Ì¿Îá¤È°Û¤Ê¤ë¡£ | |
| * ¤¹¤Ê¤ï¤Á¡¢CALL Ì¿Îá¤Ï NT ¥Õ¥é¥°¤ò¥»¥Ã¥È¤·¡¢°ÊÁ°¤Î | |
| * ¥¿¥¹¥¯¡¦¥ê¥ó¥¯¾ðÊó¤ò¥»¡¼¥Ö¤¹¤ë¤Î¤Ç¡¢IRET Ì¿Îá¤Ç¤Î¥³¡¼¥ë¸µ | |
| * ¥¿¥¹¥¯¤Ø¤Î¥ê¥¿¡¼¥ó¤¬²Äǽ¤Ë¤Ê¤ë¡£ | |
| */ | |
| /* check privilege level */ | /* check privilege level */ |
| if (taskgate_sel->desc.dpl < CPU_STAT_CPL) { | if (taskgate_sel->desc.dpl < CPU_STAT_CPL) { |
| VERBOSE(("JMPfar_pm: DPL(%d) < CPL(%d)", taskgate_sel->desc.dpl, CPU_STAT_CPL)); | VERBOSE(("JMPfar_pm: DPL(%d) < CPL(%d)", taskgate_sel->desc.dpl, CPU_STAT_CPL)); |
| Line 295 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); | |
| } | |
| } | } |
| /*--- | /*--- |
| Line 323 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 CALLfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip); |
| static void CALLfar_pm_call_gate(selector_t *call_sel); | static void CALLfar_pm_call_gate(const selector_t *callgate_sel); |
| static void CALLfar_pm_task_gate(selector_t *call_sel); | static void CALLfar_pm_task_gate(selector_t *taskgate_sel); |
| static void CALLfar_pm_tss(selector_t *call_sel); | static void 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 | void |
| 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 368 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 417 CALLfar_pm(WORD selector, DWORD new_ip) | Line 395 CALLfar_pm(WORD selector, DWORD new_ip) |
| * CALLfar_pm: code segment | * CALLfar_pm: code segment |
| */ | */ |
| static void | static void |
| CALLfar_pm_code_segment(selector_t *call_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")); | |
| /* check privilege level */ | /* 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")); | VERBOSE(("CALLfar_pm: NON-CONFORMING-CODE-SEGMENT")); |
| /* ²¼´¬ p.119 4.8.1.1. */ | /* 丶祥µ p.119 4.8.1.1. */ |
| if (call_sel->rpl > CPU_STAT_CPL) { | if (cs_sel->rpl > CPU_STAT_CPL) { |
| VERBOSE(("CALLfar_pm: RPL(%d) > CPL(%d)", call_sel->rpl, CPU_STAT_CPL)); | VERBOSE(("CALLfar_pm: RPL(%d) > CPL(%d)", cs_sel->rpl, CPU_STAT_CPL)); |
| EXCEPTION(GP_EXCEPTION, call_sel->idx); | EXCEPTION(GP_EXCEPTION, cs_sel->idx); |
| } | } |
| if (call_sel->desc.dpl != CPU_STAT_CPL) { | if (cs_sel->desc.dpl != CPU_STAT_CPL) { |
| VERBOSE(("CALLfar_pm: DPL(%d) != CPL(%d)", call_sel->desc.dpl, CPU_STAT_CPL)); | VERBOSE(("CALLfar_pm: DPL(%d) != CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL)); |
| EXCEPTION(GP_EXCEPTION, call_sel->idx); | EXCEPTION(GP_EXCEPTION, cs_sel->idx); |
| } | } |
| } 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 (call_sel->desc.dpl > CPU_STAT_CPL) { | if (cs_sel->desc.dpl > CPU_STAT_CPL) { |
| VERBOSE(("CALLfar_pm: DPL(%d) > CPL(%d)", call_sel->desc.dpl, CPU_STAT_CPL)); | VERBOSE(("CALLfar_pm: DPL(%d) > CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL)); |
| EXCEPTION(GP_EXCEPTION, call_sel->idx); | EXCEPTION(GP_EXCEPTION, cs_sel->idx); |
| } | } |
| } | } |
| /* not present */ | /* not present */ |
| if (selector_is_not_present(call_sel)) { | if (selector_is_not_present(cs_sel)) { |
| VERBOSE(("CALLfar_pm: selector is not present")); | VERBOSE(("CALLfar_pm: selector is not present")); |
| EXCEPTION(NP_EXCEPTION, call_sel->idx); | EXCEPTION(NP_EXCEPTION, cs_sel->idx); |
| } | } |
| if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { |
| Line 454 CALLfar_pm_code_segment(selector_t *call | Line 434 CALLfar_pm_code_segment(selector_t *call |
| 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 > 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, call_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); | EXCEPTION(GP_EXCEPTION, 0); |
| } | } |
| 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 > 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, call_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); | EXCEPTION(GP_EXCEPTION, 0); |
| } | } |
| Line 477 CALLfar_pm_code_segment(selector_t *call | Line 457 CALLfar_pm_code_segment(selector_t *call |
| PUSH0_16(CPU_IP); | PUSH0_16(CPU_IP); |
| } | } |
| load_cs(call_sel->selector, &call_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 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 CALLfar_pm_call_gate_more_privilege(const selector_t *call_sel, selector_t *cs_sel); |
| static void | static void |
| 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 519 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 546 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 557 CALLfar_pm_call_gate(selector_t *callgat | Line 537 CALLfar_pm_call_gate(selector_t *callgat |
| * CALLfar_pm: call gate (SAME-PRIVILEGE) | * CALLfar_pm: call gate (SAME-PRIVILEGE) |
| */ | */ |
| static void | static void |
| 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; |
| DWORD old_eip; | |
| WORD old_cs; | |
| VERBOSE(("CALLfar_pm: SAME-PRIVILEGE")); | VERBOSE(("CALLfar_pm: SAME-PRIVILEGE")); |
| /* save register */ | |
| old_cs = CPU_CS; | |
| old_eip = CPU_EIP; | |
| if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { |
| sp = CPU_ESP; | sp = CPU_ESP; |
| } else { | } else { |
| sp = CPU_SP; | sp = CPU_SP; |
| } | } |
| 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); |
| load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | PUSH0_32(CPU_CS); |
| SET_EIP(callgate_sel->desc.u.gate.offset); | PUSH0_32(CPU_EIP); |
| PUSH0_32(old_cs); | |
| PUSH0_32(old_eip); | |
| } else { | } else { |
| CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4); | SS_PUSH_CHECK(sp, 4); |
| load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | |
| SET_EIP(callgate_sel->desc.u.gate.offset); | |
| PUSH0_16(old_cs); | PUSH0_16(CPU_CS); |
| PUSH0_16(old_eip); | PUSH0_16(CPU_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) | * CALLfar_pm: call gate (MORE-PRIVILEGE) |
| */ | */ |
| static void | static void |
| 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 sp; | UINT stacksize; |
| DWORD old_eip, old_esp; | UINT32 old_eip, old_esp; |
| DWORD tss_esp; | UINT32 new_esp; |
| WORD old_cs, old_ss; | UINT16 old_cs, old_ss; |
| WORD tss_ss; | UINT16 new_ss; |
| int param_count; | int param_count; |
| int i; | int i; |
| int rv; | int rv; |
| Line 618 CALLfar_pm_call_gate_more_privilege(sele | Line 588 CALLfar_pm_call_gate_more_privilege(sele |
| old_ss = CPU_SS; | old_ss = CPU_SS; |
| old_eip = CPU_EIP; | old_eip = CPU_EIP; |
| old_esp = CPU_ESP; | old_esp = CPU_ESP; |
| if (!CPU_STAT_SS32) { | |
| if (CPU_STAT_SS32) { | old_esp &= 0xffff; |
| sp = CPU_ESP; | |
| } else { | |
| sp = CPU_SP; | |
| } | } |
| /* get stack pointer from TSS */ | /* get stack pointer from TSS */ |
| get_stack_from_tss(cs_sel->desc.dpl, &tss_ss, &tss_esp); | get_stack_pointer_from_tss(cs_sel->desc.dpl, &new_ss, &new_esp); |
| /* parse stack segment descriptor */ | /* parse stack segment descriptor */ |
| rv = parse_selector(&ss_sel, tss_ss); | rv = parse_selector(&ss_sel, new_ss); |
| if (rv < 0) { | if (rv < 0) { |
| VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", tss_ss, rv)); | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", new_ss, rv)); |
| EXCEPTION(TS_EXCEPTION, ss_sel.idx); | EXCEPTION(TS_EXCEPTION, ss_sel.idx); |
| } | } |
| /* 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 668 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, tss_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, 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])); | VERBOSE(("CALLfar_pm: get param[%d] = %08x", i, param[i])); |
| } | } |
| load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); | load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); |
| CPU_ESP = tss_esp; | if (CPU_STAT_SS32) { |
| CPU_ESP = new_esp; | |
| } else { | |
| CPU_SP = (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); |
| /* restore param */ | /* restore param */ |
| for (i = param_count; i != 0; i--) { | for (i = param_count; i > 0; i--) { |
| PUSH0_32(param[i - 1]); | PUSH0_32(param[i - 1]); |
| VERBOSE(("CALLfar_pm: set param[%d] = %08x", i - 1, param[i - 1])); | VERBOSE(("CALLfar_pm: set param[%d] = %08x", i - 1, param[i - 1])); |
| } | } |
| Line 695 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, tss_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, 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])); | VERBOSE(("CALLfar_pm: get param[%d] = %04x", i, param[i])); |
| } | } |
| load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); | load_ss(ss_sel.selector, &ss_sel.desc, ss_sel.desc.dpl); |
| CPU_ESP = tss_esp; | if (CPU_STAT_SS32) { |
| CPU_ESP = new_esp; | |
| } else { | |
| CPU_SP = (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); |
| /* restore param */ | /* restore param */ |
| for (i = param_count; i != 0; i--) { | for (i = param_count; i > 0; i--) { |
| PUSH0_16(param[i - 1]); | PUSH0_16(param[i - 1]); |
| VERBOSE(("CALLfar_pm: set param[%d] = %04x", i - 1, param[i - 1])); | VERBOSE(("CALLfar_pm: set param[%d] = %04x", i - 1, param[i - 1])); |
| } | } |
| Line 753 CALLfar_pm_task_gate(selector_t *taskgat | Line 737 CALLfar_pm_task_gate(selector_t *taskgat |
| /* tss descriptor */ | /* tss descriptor */ |
| rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector); | rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector); |
| if (rv < 0 || tss_sel.ldt) { | if (rv < 0 || tss_sel.ldt) { |
| VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d, %s)", tss_sel.selector, rv, tss_sel.ldt ? "LDT" : "GDT")); | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d, %cDT)", tss_sel.selector, rv, tss_sel.ldt ? 'L' : 'G')); |
| EXCEPTION(GP_EXCEPTION, tss_sel.idx); | EXCEPTION(GP_EXCEPTION, tss_sel.idx); |
| } | } |
| Line 780 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); | |
| } | |
| } | } |
| /*--- | /*--- |
| Line 808 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 815 CALLfar_pm_tss(selector_t *tss_sel) | Line 811 CALLfar_pm_tss(selector_t *tss_sel) |
| * RETfar_pm | * 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 | void |
| RETfar_pm(DWORD nbytes) | RETfar_pm(UINT nbytes) |
| { | { |
| selector_t ret_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 853 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_d(CPU_SS_INDEX, sp + 4); | new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); |
| } else { | } else { |
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 4); | 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(&ret_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)", ret_sel.selector, rv)); | VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d)", cs_sel.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, ret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| /* check segment type */ | /* check segment type */ |
| if (!ret_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, 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")); | VERBOSE(("RETfar_pm: return to data segment")); |
| EXCEPTION(GP_EXCEPTION, ret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| /* check privilege level */ | /* check privilege level */ |
| if (ret_sel.rpl < CPU_STAT_CPL) { | if (cs_sel.rpl < CPU_STAT_CPL) { |
| VERBOSE(("RETfar_pm: RPL(%d) < CPL(%d)", ret_sel.rpl, CPU_STAT_CPL)); | VERBOSE(("RETfar_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); |
| EXCEPTION(GP_EXCEPTION, ret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| if (!ret_sel.desc.u.seg.ec && (ret_sel.desc.dpl > ret_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)", ret_sel.desc.dpl, ret_sel.rpl)); | VERBOSE(("RETfar_pm: NON-COMFORMING-CODE-SEGMENT and DPL(%d) > RPL(%d)", cs_sel.desc.dpl, cs_sel.rpl)); |
| EXCEPTION(GP_EXCEPTION, ret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| /* not present */ | /* 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")); | 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")); | VERBOSE(("RETfar_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); |
| /* check code segment limit */ | /* check code segment limit */ |
| if (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, ret_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); | 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) { | if (CPU_INST_OP32) { |
| nbytes += 8; | nbytes += 8; |
| Line 913 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(ret_sel.selector, &ret_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, 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")); | 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")); | 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 */ | /* check privilege level */ |
| if (ss_sel.rpl != ret_sel.rpl) { | if (ss_sel.rpl != cs_sel.rpl) { |
| VERBOSE(("RETfar_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, ret_sel.rpl)); | VERBOSE(("RETfar_pm: selector RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel.rpl)); |
| EXCEPTION(GP_EXCEPTION, ret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| if (ss_sel.desc.dpl != ret_sel.rpl) { | if (ss_sel.desc.dpl != cs_sel.rpl) { |
| VERBOSE(("RETfar_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, ret_sel.rpl)); | VERBOSE(("RETfar_pm: descriptor DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel.rpl)); |
| EXCEPTION(GP_EXCEPTION, ret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| /* not present */ | /* not present */ |
| Line 968 RETfar_pm(DWORD nbytes) | Line 945 RETfar_pm(DWORD nbytes) |
| } | } |
| /* check code segment limit */ | /* check code segment limit */ |
| if (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, ret_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); | 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)); | 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); | load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.rpl); |
| SET_EIP(new_ip); | if (CPU_STAT_SS32) { |
| CPU_ESP = new_sp + nbytes; | |
| } else { | |
| CPU_SP = (UINT16)(new_sp + nbytes); | |
| } | |
| load_ss(ss_sel.selector, &ss_sel.desc, ret_sel.rpl); | load_cs(cs_sel.selector, &cs_sel.desc, cs_sel.rpl); |
| CPU_ESP = new_sp + nbytes; | 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); | segdesc_clear(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); | segdesc_clear(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; | segdesc_clear(sdp); |
| } | } |
| } | } |
| } | } |
| Line 1034 RETfar_pm(DWORD nbytes) | Line 1011 RETfar_pm(DWORD nbytes) |
| /*------------------------------------------------------------------------------ | /*------------------------------------------------------------------------------ |
| * IRET_pm | * IRET_pm |
| */ | */ |
| #define IA32_RETURN_FROM_VM86 | |
| static void IRET_pm_nested_task(void); | static void IRET_pm_nested_task(void); |
| static void IRET_pm_return_to_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags); | static void IRET_pm_protected_mode_return(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags); |
| #if defined(IA32_RETURN_FROM_VM86) | static void IRET_pm_protected_mode_return_same_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags); |
| static void IRET_pm_return_from_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags); | static void IRET_pm_protected_mode_return_outer_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags); |
| #endif /* IA32_RETURN_FROM_VM86 */ | static void IRET_pm_return_to_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags); |
| static void IRET_pm_return_from_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags); | |
| void | void |
| IRET_pm(void) | IRET_pm(void) |
| { | { |
| selector_t iret_sel, ss_sel; | UINT32 sp; |
| descriptor_t *dp; | UINT32 new_ip, new_flags; |
| DWORD sp; | UINT16 new_cs; |
| DWORD stacksize; /* for RETURN-TO-SAME-PRIVILEGE-LEVEL */ | |
| DWORD mask = 0; | |
| DWORD new_ip, new_sp, new_flags; | |
| WORD new_cs, new_ss; | |
| int old_cpl; | |
| int rv; | |
| int i; | |
| VERBOSE(("IRET_pm: old EIP = %04x:%08x, old ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); | 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)) { | if (!(CPU_EFLAG & VM_FLAG) && (CPU_EFLAG & NT_FLAG)) { |
| /* TASK-RETURN: PE=1, VM=0, NT=1 */ | /* TASK-RETURN: PE=1, VM=0, NT=1 */ |
| IRET_pm_nested_task(); | IRET_pm_nested_task(); |
| VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); | } else { |
| CPU_STAT_NERROR = 0; | if (CPU_STAT_SS32) { |
| return; | 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) { | VERBOSE(("IRET_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); |
| sp = CPU_ESP; | } |
| } else { | |
| sp = CPU_SP; | /*--- |
| * 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); | /* check system segment */ |
| new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); | if (!SEG_IS_SYSTEM(&tss_sel.desc)) { |
| new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); | VERBOSE(("IRET_pm: task segment is %s segment", tss_sel.desc.u.seg.c ? "code" : "data")); |
| new_flags = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8); | EXCEPTION(GP_EXCEPTION, tss_sel.idx); |
| } 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); | |
| } | } |
| VERBOSE(("IRET_pm: new_ip = %08x, new_cs = %04x, new_eflags = %08x", new_ip, new_cs, new_flags)); | |
| #ifdef IA32_RETURN_FROM_VM86 | switch (tss_sel.desc.type) { |
| if (CPU_EFLAG & VM_FLAG) { | case CPU_SYSDESC_TYPE_TSS_BUSY_16: |
| /* RETURN-FROM-VIRTUAL-8086-MODE */ | case CPU_SYSDESC_TYPE_TSS_BUSY_32: |
| IRET_pm_return_from_vm86(new_ip, new_cs, new_flags); | break; |
| VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); | |
| CPU_STAT_NERROR = 0; | case CPU_SYSDESC_TYPE_TSS_16: |
| return; | 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; | |
| } | } |
| #endif /* IA32_RETURN_FROM_VM86 */ | |
| if (new_flags & VM_FLAG) { | /* not present */ |
| /* RETURN-TO-VIRTUAL-8086-MODE */ | if (selector_is_not_present(&tss_sel)) { |
| IRET_pm_return_to_vm86(new_ip, new_cs, new_flags); | VERBOSE(("IRET_pm: tss segment is not present")); |
| VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); | EXCEPTION(NP_EXCEPTION, tss_sel.idx); |
| CPU_STAT_NERROR = 0; | } |
| return; | |
| 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 | |
| IRET_pm_protected_mode_return(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags) | |
| { | |
| selector_t cs_sel; | |
| int rv; | |
| /* PROTECTED-MODE-RETURN */ | /* PROTECTED-MODE-RETURN */ |
| VERBOSE(("IRET_pm: PE=1, VM=0 in flags image")); | VERBOSE(("IRET_pm: PE=1, VM=0 in flags image")); |
| rv = parse_selector(&iret_sel, new_cs); | rv = parse_selector(&cs_sel, new_cs); |
| if (rv < 0) { | if (rv < 0) { |
| VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", iret_sel.selector, rv)); | VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", cs_sel.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| /* check code segment descriptor */ | /* check code segment descriptor */ |
| if (!iret_sel.desc.s) { | if (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, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| if (!iret_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, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| /* check privilege level */ | /* check privilege level */ |
| if (iret_sel.rpl < CPU_STAT_CPL) { | if (cs_sel.rpl < CPU_STAT_CPL) { |
| VERBOSE(("IRET_pm: RPL(%d) < CPL(%d)", iret_sel.rpl, CPU_STAT_CPL)); | VERBOSE(("IRET_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| if (iret_sel.desc.u.seg.ec && (iret_sel.desc.dpl > iret_sel.rpl)) { | if (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)", iret_sel.desc.dpl, iret_sel.rpl)); | VERBOSE(("IRET_pm: CONFORMING-CODE-SEGMENT and DPL(%d) > RPL(%d)", cs_sel.desc.dpl, cs_sel.rpl)); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); |
| } | } |
| /* not present */ | /* not present */ |
| if (selector_is_not_present(&iret_sel)) { | if (selector_is_not_present(&cs_sel)) { |
| VERBOSE(("IRET_pm: code segment is not present")); | VERBOSE(("IRET_pm: code segment is not present")); |
| EXCEPTION(NP_EXCEPTION, iret_sel.idx); | EXCEPTION(NP_EXCEPTION, cs_sel.idx); |
| } | } |
| if (iret_sel.rpl > CPU_STAT_CPL) { | if (cs_sel.rpl > CPU_STAT_CPL) { |
| VERBOSE(("IRET_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); | IRET_pm_protected_mode_return_outer_privilege(&cs_sel, new_ip, new_flags); |
| 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 != iret_sel.rpl) { | |
| VERBOSE(("IRET_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, iret_sel.rpl)); | |
| EXCEPTION(GP_EXCEPTION, ss_sel.idx); | |
| } | |
| if (ss_sel.desc.dpl != iret_sel.rpl) { | |
| VERBOSE(("IRET_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, iret_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); | |
| } | |
| /* compiler happy :-) */ | |
| stacksize = 0; | |
| } else { | } else { |
| VERBOSE(("IRET_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); | IRET_pm_protected_mode_return_same_privilege(&cs_sel, new_ip, new_flags); |
| } | |
| } | |
| if (CPU_INST_OP32) { | /*--- |
| stacksize = 12; | * IRET_pm: SAME-PRIVILEGE |
| } else { | */ |
| stacksize = 6; | static void |
| } | IRET_pm_protected_mode_return_same_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags) |
| { | |
| UINT32 mask; | |
| UINT stacksize; | |
| /* compiler happy :-) */ | VERBOSE(("IRET_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL")); |
| new_sp = 0; | |
| new_ss = 0; | |
| } | |
| /* check code segment limit */ | /* check code segment limit */ |
| if (new_ip > iret_sel.desc.u.seg.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, iret_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); | EXCEPTION(GP_EXCEPTION, 0); |
| } | } |
| /* set new register */ | |
| old_cpl = CPU_STAT_CPL; | |
| load_cs(iret_sel.selector, &iret_sel.desc, iret_sel.rpl); | |
| SET_EIP(new_ip); | |
| /* set new eflags */ | |
| mask = 0; | mask = 0; |
| if (CPU_INST_OP32) | if (CPU_INST_OP32) |
| mask |= RF_FLAG; | mask |= RF_FLAG; |
| Line 1227 IRET_pm(void) | Line 1200 IRET_pm(void) |
| mask |= VM_FLAG|VIF_FLAG|VIP_FLAG; | mask |= VM_FLAG|VIF_FLAG|VIP_FLAG; |
| } | } |
| } | } |
| set_eflags(new_flags, mask); | |
| if (iret_sel.rpl > old_cpl) { | if (CPU_INST_OP32) { |
| /* RETURN-OUTER-PRIVILEGE-LEVEL */ | stacksize = 12; |
| } else { | |
| stacksize = 6; | |
| } | |
| load_ss(ss_sel.selector, &ss_sel.desc, iret_sel.rpl); | /* set new register */ |
| CPU_ESP = new_sp; | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); |
| CPU_EIP = new_ip; | |
| /* check segment register */ | if (CPU_STAT_SS32) { |
| for (i = 0; i < CPU_SEGREG_NUM; i++) { | CPU_ESP += stacksize; |
| if ((i != CPU_CS_INDEX) && (i != CPU_SS_INDEX)) { | |
| dp = &CPU_STAT_SREG(i); | |
| if ((!dp->u.seg.c || !dp->u.seg.ec) | |
| && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) { | |
| /* segment register is invalid */ | |
| CPU_REGS_SREG(i) = 0; | |
| CPU_STAT_SREG_CLEAR(i); | |
| continue; | |
| } | |
| } | |
| } | |
| } else { | } else { |
| /* RETURN-TO-SAME-PRIVILEGE-LEVEL */ | CPU_SP += (UINT16)stacksize; |
| if (CPU_STAT_SS32) { | |
| CPU_ESP += stacksize; | |
| } else { | |
| CPU_SP += stacksize; | |
| } | |
| } | } |
| CPU_STAT_NERROR = 0; | |
| VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); | set_eflags(new_flags, mask); |
| } | } |
| /*--- | /*--- |
| * IRET_pm: NT_FLAG | * IRET_pm: OUTER-PRIVILEGE |
| */ | */ |
| static void | static void |
| IRET_pm_nested_task(void) | IRET_pm_protected_mode_return_outer_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags) |
| { | { |
| selector_t iret_sel; | descriptor_t *sdp; |
| selector_t ss_sel; | |
| UINT32 mask; | |
| UINT32 sp; | |
| UINT32 new_sp; | |
| UINT16 new_ss; | |
| int rv; | int rv; |
| WORD new_cs; | int i; |
| VERBOSE(("IRET_pm: TASK-RETURN: PE=1, VM=0, NT=1")); | VERBOSE(("IRET_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); |
| new_cs = get_link_selector_from_tss(); | if (CPU_STAT_SS32) { |
| rv = parse_selector(&iret_sel, new_cs); | sp = CPU_ESP; |
| if (rv < 0 || iret_sel.ldt) { | } else { |
| VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", iret_sel.selector, rv)); | sp = CPU_SP; |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | |
| } | } |
| 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 */ | rv = parse_selector(&ss_sel, new_ss); |
| if (iret_sel.desc.s) { | if (rv < 0) { |
| VERBOSE(("IRET_pm: task segment is %d segment", iret_sel.desc.u.seg.c ? "code" : "data")); | VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", ss_sel.selector, rv)); |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, (rv == -2) ? 0 : ss_sel.idx); |
| } | } |
| switch (iret_sel.desc.type) { | /* check privilege level */ |
| case CPU_SYSDESC_TYPE_TSS_BUSY_16: | if (ss_sel.rpl != cs_sel->rpl) { |
| case CPU_SYSDESC_TYPE_TSS_BUSY_32: | VERBOSE(("IRET_pm: selector RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel->rpl)); |
| break; | 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: | /* stack segment must be writable data segment. */ |
| case CPU_SYSDESC_TYPE_TSS_32: | if (SEG_IS_SYSTEM(&ss_sel.desc)) { |
| VERBOSE(("IRET_pm: task is not busy")); | VERBOSE(("IRET_pm: stack segment is system segment")); |
| /*FALLTHROUGH*/ | EXCEPTION(GP_EXCEPTION, ss_sel.idx); |
| default: | } |
| VERBOSE(("IRET_pm: invalid descriptor type (type = %d)", iret_sel.desc.type)); | if (SEG_IS_CODE(&ss_sel.desc)) { |
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | VERBOSE(("IRET_pm: stack segment is code segment")); |
| break; | 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 */ | /* not present */ |
| if (selector_is_not_present(&iret_sel)) { | if (selector_is_not_present(&ss_sel)) { |
| VERBOSE(("IRET_pm: tss segment is not present")); | VERBOSE(("IRET_pm: stack segment is not present")); |
| EXCEPTION(NP_EXCEPTION, iret_sel.idx); | EXCEPTION(SS_EXCEPTION, ss_sel.idx); |
| } | } |
| task_switch(&iret_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; | |
| segdesc_clear(sdp); | |
| } | |
| } | |
| } | |
| } | } |
| /*--- | /*--- |
| * IRET_pm: new_flags & VM_FLAG | * IRET_pm: new_flags & VM_FLAG |
| */ | */ |
| static void | static void |
| IRET_pm_return_to_vm86(DWORD new_ip, DWORD new_cs, 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) { | if (!CPU_INST_OP32) { |
| ia32_panic("IRET_pm: CPL != 0"); | ia32_panic("IRET_pm: 16bit mode"); |
| } | } |
| if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { |
| Line 1332 IRET_pm_return_to_vm86(DWORD new_ip, DWO | Line 1362 IRET_pm_return_to_vm86(DWORD new_ip, DWO |
| } else { | } else { |
| sp = CPU_SP; | sp = CPU_SP; |
| } | } |
| if (!CPU_INST_OP32) { | SS_POP_CHECK(sp, 36); |
| ia32_panic("IRET_pm: 16bit mode"); | |
| if (new_ip > 0xffff) { | |
| EXCEPTION(GP_EXCEPTION, 0); | |
| } | } |
| CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 36); | |
| new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); | new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); |
| segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); | segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); |
| 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 1346 IRET_pm_return_to_vm86(DWORD new_ip, DWO | Line 1377 IRET_pm_return_to_vm86(DWORD new_ip, 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)); |
| } | } |
| set_eflags(new_flags, IOPL_FLAG|I_FLAG|VM_FLAG|RF_FLAG); | |
| CPU_ESP = new_sp; | CPU_ESP = new_sp; |
| SET_EIP(new_ip); | CPU_EIP = new_ip; |
| /* to VM86 mode */ | |
| set_eflags(new_flags, IOPL_FLAG|I_FLAG|VM_FLAG|RF_FLAG); | |
| } | } |
| #ifdef IA32_RETURN_FROM_VM86 | |
| /*--- | /*--- |
| * IRET_pm: VM_FLAG | * IRET_pm: VM_FLAG |
| */ | */ |
| static void | static void |
| IRET_pm_return_from_vm86(DWORD new_ip, DWORD new_cs, 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_ip, D | Line 1410 IRET_pm_return_from_vm86(DWORD new_ip, D |
| CPU_SP += stacksize; | CPU_SP += stacksize; |
| } | } |
| set_eflags(new_flags, I_FLAG|RF_FLAG); | 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")); |
| EXCEPTION(GP_EXCEPTION, 0); | EXCEPTION(GP_EXCEPTION, 0); |
| } | } |
| #endif /* IA32_RETURN_FROM_VM86 */ |