| version 1.7, 2004/02/04 13:24:35 | version 1.10, 2004/02/09 16:12:07 | 
| Line 51  JMPfar_pm(WORD selector, DWORD new_ip) | Line 51  JMPfar_pm(WORD selector, DWORD new_ip) | 
 | VERBOSE(("JMPfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); | VERBOSE(("JMPfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); | 
 | VERBOSE(("JMPfar_pm: selector = 0x%04x, new_ip = 0x%08x", selector, new_ip)); | VERBOSE(("JMPfar_pm: selector = 0x%04x, new_ip = 0x%08x", selector, new_ip)); | 
 |  |  | 
| rv = parse_selector(&jmp_sel, selector, CPU_IS_USER_MODE()); | rv = parse_selector(&jmp_sel, selector); | 
 | if (rv < 0) { | if (rv < 0) { | 
 | VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d)", selector, rv)); | VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d)", selector, rv)); | 
 | EXCEPTION(GP_EXCEPTION, jmp_sel.idx); | EXCEPTION(GP_EXCEPTION, jmp_sel.idx); | 
| Line 98  JMPfar_pm(WORD selector, DWORD new_ip) | Line 98  JMPfar_pm(WORD selector, DWORD new_ip) | 
 | break; | break; | 
 | } | } | 
 | } | } | 
 |  |  | 
 | VERBOSE(("JMPfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); | VERBOSE(("JMPfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); | 
 | } | } | 
 |  |  | 
| Line 105  JMPfar_pm(WORD selector, DWORD new_ip) | Line 106  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(selector_t *cs_sel, DWORD new_ip) | 
 | { | { | 
 |  |  | 
 |  | VERBOSE(("JMPfar_pm: CODE-SEGMENT")); | 
 |  |  | 
 | /* check privilege level */ | /* check privilege level */ | 
| if (!code_sel->desc.u.seg.ec) { | if (!cs_sel->desc.u.seg.ec) { | 
 | 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: 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); | SET_EIP(new_ip); | 
 | } | } | 
 |  |  | 
| Line 173  JMPfar_pm_call_gate(selector_t *callgate | Line 176  JMPfar_pm_call_gate(selector_t *callgate | 
 | } | } | 
 |  |  | 
 | /* parse code segment selector */ | /* parse code segment selector */ | 
| rv = parse_selector(&cs_sel, callgate_sel->desc.u.gate.selector, CPU_IS_USER_MODE()); | rv = parse_selector(&cs_sel, callgate_sel->desc.u.gate.selector); | 
 | if (rv < 0) { | if (rv < 0) { | 
 | VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d)", callgate_sel->desc.u.gate.selector, rv)); | VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d)", callgate_sel->desc.u.gate.selector, rv)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
| Line 235  JMPfar_pm_task_gate(selector_t *taskgate | Line 238  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 266  JMPfar_pm_task_gate(selector_t *taskgate | Line 255  JMPfar_pm_task_gate(selector_t *taskgate | 
 | } | } | 
 |  |  | 
 | /* parse tss selector */ | /* parse tss selector */ | 
| rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector, CPU_IS_USER_MODE()); | rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector); | 
 | if (rv < 0 || tss_sel.ldt) { | if (rv < 0 || tss_sel.ldt) { | 
 | VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d, %cDT)", taskgate_sel->desc.u.gate.selector, rv, tss_sel.ldt ? 'L' : 'G')); | VERBOSE(("JMPfar_pm: parse_selector (selector = %04x, rv = %d, %cDT)", taskgate_sel->desc.u.gate.selector, rv, tss_sel.ldt ? 'L' : 'G')); | 
 | EXCEPTION(GP_EXCEPTION, tss_sel.idx); | EXCEPTION(GP_EXCEPTION, tss_sel.idx); | 
| Line 334  static void CALLfar_pm_call_gate(selecto | Line 323  static void CALLfar_pm_call_gate(selecto | 
 | static void CALLfar_pm_task_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 CALLfar_pm_tss(selector_t *call_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(WORD selector, DWORD new_ip) | 
 | { | { | 
| Line 362  CALLfar_pm(WORD selector, DWORD new_ip) | Line 332  CALLfar_pm(WORD selector, DWORD new_ip) | 
 | VERBOSE(("CALLfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); | VERBOSE(("CALLfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); | 
 | VERBOSE(("CALLfar_pm: selector = 0x%04x, new_ip = 0x%08x", selector, new_ip)); | VERBOSE(("CALLfar_pm: selector = 0x%04x, new_ip = 0x%08x", selector, new_ip)); | 
 |  |  | 
| rv = parse_selector(&call_sel, selector, CPU_IS_USER_MODE()); | rv = parse_selector(&call_sel, selector); | 
 | if (rv < 0) { | if (rv < 0) { | 
 | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", selector, rv)); | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", selector, rv)); | 
 | EXCEPTION(GP_EXCEPTION, call_sel.idx); | EXCEPTION(GP_EXCEPTION, call_sel.idx); | 
| Line 417  CALLfar_pm(WORD selector, DWORD new_ip) | Line 387  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(selector_t *cs_sel, DWORD new_ip) | 
 | { | { | 
 | DWORD sp; | DWORD sp; | 
 |  |  | 
 |  | VERBOSE(("CALLfar_pm: CODE-SEGMENT")); | 
 |  |  | 
 | /* check privilege level */ | /* check privilege level */ | 
| if (!call_sel->desc.u.seg.ec) { | if (!cs_sel->desc.u.seg.ec) { | 
 | 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 457  CALLfar_pm_code_segment(selector_t *call | Line 429  CALLfar_pm_code_segment(selector_t *call | 
 | CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 8); | CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), 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); | 
 | } | } | 
 |  |  | 
| Line 468  CALLfar_pm_code_segment(selector_t *call | Line 440  CALLfar_pm_code_segment(selector_t *call | 
 | CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4); | CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), 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 449  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); | SET_EIP(new_ip); | 
 | } | } | 
 |  |  | 
| Line 512  CALLfar_pm_call_gate(selector_t *callgat | Line 484  CALLfar_pm_call_gate(selector_t *callgat | 
 | } | } | 
 |  |  | 
 | /* parse code segment descriptor */ | /* parse code segment descriptor */ | 
| rv = parse_selector(&cs_sel, callgate_sel->desc.u.gate.selector, CPU_IS_USER_MODE()); | rv = parse_selector(&cs_sel, callgate_sel->desc.u.gate.selector); | 
 | if (rv < 0) { | if (rv < 0) { | 
 | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", callgate_sel->desc.u.gate.selector, rv)); | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", callgate_sel->desc.u.gate.selector, rv)); | 
 | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
| Line 560  static void | Line 532  static void | 
 | CALLfar_pm_call_gate_same_privilege(selector_t *callgate_sel, selector_t *cs_sel) | CALLfar_pm_call_gate_same_privilege(selector_t *callgate_sel, selector_t *cs_sel) | 
 | { | { | 
 | DWORD sp; | DWORD sp; | 
 | DWORD old_eip; |  | 
 | 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 { | 
| Line 578  CALLfar_pm_call_gate_same_privilege(sele | Line 544  CALLfar_pm_call_gate_same_privilege(sele | 
 | if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { | if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { | 
 | CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 8); | CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 8); | 
 |  |  | 
 |  | PUSH0_32(CPU_CS); | 
 |  | PUSH0_32(CPU_EIP); | 
 |  |  | 
 | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | 
 | SET_EIP(callgate_sel->desc.u.gate.offset); | SET_EIP(callgate_sel->desc.u.gate.offset); | 
 |  |  | 
 | PUSH0_32(old_cs); |  | 
 | PUSH0_32(old_eip); |  | 
 | } else { | } else { | 
 | CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4); | CHECK_STACK_PUSH(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 4); | 
 |  |  | 
 |  | PUSH0_16(CPU_CS); | 
 |  | PUSH0_16(CPU_IP); | 
 |  |  | 
 | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | 
 | SET_EIP(callgate_sel->desc.u.gate.offset); | SET_EIP(callgate_sel->desc.u.gate.offset); | 
 |  |  | 
 | PUSH0_16(old_cs); |  | 
 | PUSH0_16(old_eip); |  | 
 | } | } | 
 | } | } | 
 |  |  | 
| Line 602  CALLfar_pm_call_gate_more_privilege(sele | Line 568  CALLfar_pm_call_gate_more_privilege(sele | 
 | { | { | 
 | DWORD param[32];        /* copy param */ | DWORD param[32];        /* copy param */ | 
 | selector_t ss_sel; | selector_t ss_sel; | 
 | DWORD sp; |  | 
 | DWORD old_eip, old_esp; | DWORD old_eip, old_esp; | 
| DWORD tss_esp; | DWORD new_esp; | 
 | WORD old_cs, old_ss; | WORD old_cs, old_ss; | 
| WORD tss_ss; | WORD new_ss; | 
 | int param_count; | int param_count; | 
 | int i; | int i; | 
 | int rv; | int rv; | 
| Line 618  CALLfar_pm_call_gate_more_privilege(sele | Line 583  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, CPU_IS_USER_MODE()); | rv = parse_selector(&ss_sel, new_ss); | 
 | if (rv < 0) { | if (rv < 0) { | 
| VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", tss_ss, rv)); | VERBOSE(("CALLfar_pm: parse_selector (selector = %04x, rv = %d)", new_ss, rv)); | 
 | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | EXCEPTION(TS_EXCEPTION, ss_sel.idx); | 
 | } | } | 
 |  |  | 
| Line 669  CALLfar_pm_call_gate_more_privilege(sele | Line 631  CALLfar_pm_call_gate_more_privilege(sele | 
 | VERBOSE(("CALLfar_pm: param_count = %d", param_count)); | VERBOSE(("CALLfar_pm: param_count = %d", param_count)); | 
 |  |  | 
 | if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { | if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) { | 
| CHECK_STACK_PUSH(&ss_sel.desc, tss_esp, 16 + param_count * 4); | CHECK_STACK_PUSH(&ss_sel.desc, new_esp, 16 + param_count * 4); | 
 |  |  | 
 | /* dump param */ | /* dump param */ | 
 | for (i = 0; i < param_count; i++) { | for (i = 0; i < param_count; i++) { | 
| 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 = new_esp; | 
|  | } | 
 |  |  | 
 | load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); | load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); | 
 | SET_EIP(callgate_sel->desc.u.gate.offset); | SET_EIP(callgate_sel->desc.u.gate.offset); | 
| Line 687  CALLfar_pm_call_gate_more_privilege(sele | Line 653  CALLfar_pm_call_gate_more_privilege(sele | 
 | 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 661  CALLfar_pm_call_gate_more_privilege(sele | 
 | PUSH0_32(old_cs); | PUSH0_32(old_cs); | 
 | PUSH0_32(old_eip); | PUSH0_32(old_eip); | 
 | } else { | } else { | 
| CHECK_STACK_PUSH(&ss_sel.desc, tss_esp, 8 + param_count * 2); | CHECK_STACK_PUSH(&ss_sel.desc, new_esp, 8 + param_count * 2); | 
 |  |  | 
 | /* dump param */ | /* dump param */ | 
 | for (i = 0; i < param_count; i++) { | for (i = 0; i < param_count; i++) { | 
| 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 = new_esp; | 
|  | } | 
 |  |  | 
 | load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); | load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->desc.dpl); | 
 | SET_EIP(callgate_sel->desc.u.gate.offset); | SET_EIP(callgate_sel->desc.u.gate.offset); | 
| Line 713  CALLfar_pm_call_gate_more_privilege(sele | Line 683  CALLfar_pm_call_gate_more_privilege(sele | 
 | 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 751  CALLfar_pm_task_gate(selector_t *taskgat | Line 721  CALLfar_pm_task_gate(selector_t *taskgat | 
 | } | } | 
 |  |  | 
 | /* tss descriptor */ | /* tss descriptor */ | 
| rv = parse_selector(&tss_sel, taskgate_sel->desc.u.gate.selector, CPU_IS_USER_MODE()); | 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 815  CALLfar_pm_tss(selector_t *tss_sel) | Line 785  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(DWORD nbytes) | 
 | { | { | 
| selector_t ret_sel, ss_sel, temp_sel; | selector_t cs_sel, ss_sel, temp_sel; | 
 | DWORD sp; | DWORD sp; | 
 | DWORD new_ip, new_sp; | DWORD new_ip, new_sp; | 
 | WORD new_cs, new_ss; | WORD new_cs, new_ss; | 
| Line 855  RETfar_pm(DWORD nbytes) | Line 805  RETfar_pm(DWORD nbytes) | 
 | if (CPU_INST_OP32) { | if (CPU_INST_OP32) { | 
 | CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 8); | CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 8); | 
 | new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); | new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp); | 
| new_cs = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 4); | new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); | 
 | } else { | } else { | 
 | CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 4); | CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 4); | 
 | new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); | new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp); | 
 | 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, CPU_IS_USER_MODE()); | 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, %s)", 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 (!cs_sel.desc.s) { | 
 | 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 (!cs_sel.desc.u.seg.c) { | 
 | 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 (!cs_sel.desc.u.seg.ec && (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 916  RETfar_pm(DWORD nbytes) | Line 866  RETfar_pm(DWORD nbytes) | 
 | CPU_SP += nbytes; | CPU_SP += 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); | SET_EIP(new_ip); | 
 | } else { | } else { | 
 | VERBOSE(("RETfar_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); | VERBOSE(("RETfar_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); | 
| Line 931  RETfar_pm(DWORD nbytes) | Line 881  RETfar_pm(DWORD nbytes) | 
 | new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes + 2); | new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes + 2); | 
 | } | } | 
 |  |  | 
| rv = parse_selector(&ss_sel, new_ss, CPU_IS_USER_MODE()); | 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, %s)", ss_sel.selector, rv)); | 
 | EXCEPTION(GP_EXCEPTION, ss_sel.idx); | EXCEPTION(GP_EXCEPTION, ss_sel.idx); | 
| Line 940  RETfar_pm(DWORD nbytes) | Line 890  RETfar_pm(DWORD nbytes) | 
 | /* check stack segment descriptor */ | /* check stack segment descriptor */ | 
 | if (!ss_sel.desc.s) { | if (!ss_sel.desc.s) { | 
 | 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 (ss_sel.desc.u.seg.c) { | 
 | 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 (!ss_sel.desc.u.seg.wr) { | 
 | 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: 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: 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 918  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_cs(cs_sel.selector, &cs_sel.desc, cs_sel.rpl); | 
 | SET_EIP(new_ip); | SET_EIP(new_ip); | 
 |  |  | 
| load_ss(ss_sel.selector, &ss_sel.desc, ret_sel.rpl); | load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.rpl); | 
| CPU_ESP = new_sp + nbytes; | if (CPU_STAT_SS32) { | 
|  | CPU_ESP = new_sp + nbytes; | 
|  | } else { | 
|  | CPU_SP = new_sp + nbytes; | 
|  | } | 
 |  |  | 
 | /* check segment register */ | /* check segment register */ | 
 | for (i = 0; i < CPU_SEGREG_NUM; i++) { | for (i = 0; i < CPU_SEGREG_NUM; i++) { | 
| Line 996  RETfar_pm(DWORD nbytes) | Line 950  RETfar_pm(DWORD nbytes) | 
 | continue; | continue; | 
 | } | } | 
 |  |  | 
| rv = parse_selector(&temp_sel, CPU_REGS_SREG(i), CPU_IS_USER_MODE()); | 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; | 
| Line 1035  RETfar_pm(DWORD nbytes) | Line 989  RETfar_pm(DWORD nbytes) | 
 | * IRET_pm | * IRET_pm | 
 | */ | */ | 
 | static void IRET_pm_nested_task(void); | static void IRET_pm_nested_task(void); | 
| static void IRET_pm_return_to_vm86(DWORD new_ip, DWORD new_cs, DWORD new_flags); | static void IRET_pm_protected_mode_return(DWORD new_cs, DWORD new_ip, DWORD 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_same_privilege(selector_t *cs_sel, DWORD new_ip, DWORD new_flags); | 
|  | static void IRET_pm_protected_mode_return_outer_privilege(selector_t *cs_sel, DWORD new_ip, DWORD new_flags); | 
|  | static void IRET_pm_return_to_vm86(DWORD new_cs, DWORD new_ip, DWORD new_flags); | 
|  | static void IRET_pm_return_from_vm86(DWORD new_cs, DWORD new_ip, DWORD new_flags); | 
 |  |  | 
 | void | void | 
 | IRET_pm(void) | IRET_pm(void) | 
 | { | { | 
 | selector_t iret_sel, ss_sel; |  | 
 | descriptor_t *dp; |  | 
 | DWORD sp; | DWORD sp; | 
| DWORD stacksize;        /* for RETURN-TO-SAME-PRIVILEGE-LEVEL */ | DWORD new_ip, new_flags; | 
| DWORD mask = 0; | WORD new_cs; | 
| DWORD new_ip, new_sp, new_flags; |  | 
| WORD new_cs, new_ss; |  | 
| int old_cpl; |  | 
 | int rv; | int rv; | 
 | int i; |  | 
 |  |  | 
| VERBOSE(("IRET_pm: old EIP = %04x:%08x, old ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP)); | VERBOSE(("IRET_pm: old EIP = %04x:%08x, 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) { | 
|  | 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); | 
|  | } | 
|  |  | 
|  | 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) { | 
|  | /* 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; | 
|  | int rv; | 
|  | WORD new_tss; | 
|  |  | 
|  | 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 (tss_sel.desc.s) { | 
| new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4); | VERBOSE(("IRET_pm: task segment is %d 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)); |  | 
 |  |  | 
| if (CPU_EFLAG & VM_FLAG) { | switch (tss_sel.desc.type) { | 
| /* RETURN-FROM-VIRTUAL-8086-MODE */ | case CPU_SYSDESC_TYPE_TSS_BUSY_16: | 
| IRET_pm_return_from_vm86(new_ip, new_cs, new_flags); | case CPU_SYSDESC_TYPE_TSS_BUSY_32: | 
| VERBOSE(("IRET_pm: new EIP = %04x:%08x, new ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP)); | break; | 
| 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) { | /* 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); | 
 |  | } | 
 |  |  | 
 |  | /*--- | 
 |  | * IRET_pm: PROTECTED-MODE-RETURN | 
 |  | */ | 
 |  | static void | 
 |  | IRET_pm_protected_mode_return(DWORD new_cs, DWORD new_ip, DWORD 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, CPU_IS_USER_MODE()); | rv = parse_selector(&cs_sel, new_cs); | 
 | if (rv < 0) { | if (rv < 0) { | 
| VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", iret_sel.selector, rv)); | VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", cs_sel.selector, rv)); | 
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 |  |  | 
 | /* check code segment descriptor */ | /* check code segment descriptor */ | 
| if (!iret_sel.desc.s) { | if (!cs_sel.desc.s) { | 
 | VERBOSE(("IRET_pm: return code segment is system segment")); | VERBOSE(("IRET_pm: return code segment is system segment")); | 
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
| if (!iret_sel.desc.u.seg.c) { | if (!cs_sel.desc.u.seg.c) { | 
 | VERBOSE(("IRET_pm: return code segment is data segment")); | VERBOSE(("IRET_pm: return code segment is data segment")); | 
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 |  |  | 
 | /* check privilege level */ | /* check privilege level */ | 
| if (iret_sel.rpl < CPU_STAT_CPL) { | if (cs_sel.rpl < CPU_STAT_CPL) { | 
| VERBOSE(("IRET_pm: RPL(%d) < CPL(%d)", iret_sel.rpl, CPU_STAT_CPL)); | VERBOSE(("IRET_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL)); | 
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
| } | } | 
| if (iret_sel.desc.u.seg.ec && (iret_sel.desc.dpl > iret_sel.rpl)) { | if (cs_sel.desc.u.seg.ec && (cs_sel.desc.dpl > cs_sel.rpl)) { | 
| VERBOSE(("IRET_pm: CONFORMING-CODE-SEGMENT and DPL(%d) != RPL(%d)", iret_sel.desc.dpl, iret_sel.rpl)); | VERBOSE(("IRET_pm: CONFORMING-CODE-SEGMENT and DPL(%d) != RPL(%d)", cs_sel.desc.dpl, cs_sel.rpl)); | 
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | EXCEPTION(GP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 |  |  | 
 | /* not present */ | /* not present */ | 
| if (selector_is_not_present(&iret_sel)) { | if (selector_is_not_present(&cs_sel)) { | 
 | VERBOSE(("IRET_pm: code segment is not present")); | VERBOSE(("IRET_pm: code segment is not present")); | 
| EXCEPTION(NP_EXCEPTION, iret_sel.idx); | EXCEPTION(NP_EXCEPTION, cs_sel.idx); | 
 | } | } | 
 |  |  | 
| if (iret_sel.rpl > CPU_STAT_CPL) { | if (cs_sel.rpl > CPU_STAT_CPL) { | 
| VERBOSE(("IRET_pm: RETURN-OUTER-PRIVILEGE-LEVEL")); | 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, CPU_IS_USER_MODE()); |  | 
| 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(selector_t *cs_sel, DWORD new_ip, DWORD new_flags) | 
|  | { | 
|  | DWORD mask; | 
|  | DWORD 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 1220  IRET_pm(void) | Line 1172  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) { | /* set new register */ | 
| /* RETURN-OUTER-PRIVILEGE-LEVEL */ | load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL); | 
|  | SET_EIP(new_ip); | 
 |  |  | 
| load_ss(ss_sel.selector, &ss_sel.desc, iret_sel.rpl); | set_eflags(new_flags, mask); | 
| CPU_ESP = new_sp; |  | 
 |  |  | 
| /* check segment register */ | if (CPU_INST_OP32) { | 
| for (i = 0; i < CPU_SEGREG_NUM; i++) { | stacksize = 12; | 
| 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 */ | stacksize = 6; | 
| if (CPU_STAT_SS32) { | } | 
| CPU_ESP += stacksize; | if (CPU_STAT_SS32) { | 
| } else { | CPU_ESP += stacksize; | 
| CPU_SP += 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)); |  | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
| * IRET_pm: NT_FLAG | * IRET_pm: OUTER-PRIVILEGE | 
 | */ | */ | 
 | static void | static void | 
| IRET_pm_nested_task(void) | IRET_pm_protected_mode_return_outer_privilege(selector_t *cs_sel, DWORD new_ip, DWORD new_flags) | 
 | { | { | 
| selector_t iret_sel; | descriptor_t *dp; | 
|  | selector_t ss_sel; | 
|  | DWORD mask; | 
|  | DWORD sp; | 
|  | DWORD new_sp; | 
|  | WORD 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, CPU_IS_USER_MODE()); | 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) { | 
 |  | 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)); | 
 |  |  | 
| /* 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, 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: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel->rpl)); | 
| break; | 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); | 
|  | } | 
 |  |  | 
| case CPU_SYSDESC_TYPE_TSS_16: | /* check stack segment descriptor */ | 
| case CPU_SYSDESC_TYPE_TSS_32: | if (!ss_sel.desc.s) { | 
| 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 (ss_sel.desc.u.seg.c) { | 
| EXCEPTION(GP_EXCEPTION, iret_sel.idx); | VERBOSE(("IRET_pm: stack segment is code segment")); | 
| break; | 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 */ | /* 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); | 
|  | } | 
|  |  | 
|  | /* 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); | 
 | } | } | 
 |  |  | 
| task_switch(&iret_sel, TASK_SWITCH_IRET); | 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); | 
|  | SET_EIP(new_ip); | 
|  |  | 
|  | set_eflags(new_flags, mask); | 
|  |  | 
|  | load_ss(ss_sel.selector, &ss_sel.desc, cs_sel->rpl); | 
|  | if (CPU_STAT_SS32) { | 
|  | CPU_ESP = new_sp; | 
|  | } else { | 
|  | CPU_SP = new_sp; | 
|  | } | 
|  |  | 
|  | /* 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; | 
|  | } | 
|  | } | 
|  | } | 
 | } | } | 
 |  |  | 
 | /*--- | /*--- | 
 | * 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(DWORD new_cs, DWORD new_ip, DWORD new_flags) | 
 | { | { | 
 | WORD segsel[CPU_SEGREG_NUM]; | WORD segsel[CPU_SEGREG_NUM]; | 
 | DWORD sp; | DWORD sp; | 
| Line 1320  IRET_pm_return_to_vm86(DWORD new_ip, DWO | Line 1323  IRET_pm_return_to_vm86(DWORD new_ip, DWO | 
 | ia32_panic("IRET_pm: CPL != 0"); | ia32_panic("IRET_pm: CPL != 0"); | 
 | } | } | 
 |  |  | 
 |  | if (!CPU_INST_OP32) { | 
 |  | ia32_panic("IRET_pm: 16bit mode"); | 
 |  | } | 
 |  |  | 
 | if (CPU_STAT_SS32) { | if (CPU_STAT_SS32) { | 
 | sp = CPU_ESP; | sp = CPU_ESP; | 
 | } else { | } else { | 
 | sp = CPU_SP; | sp = CPU_SP; | 
 | } | } | 
 | if (!CPU_INST_OP32) { |  | 
 | ia32_panic("IRET_pm: 16bit mode"); |  | 
 | } |  | 
 |  |  | 
 | CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 36); | CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 36); | 
 | new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); | new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12); | 
 | segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); | segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16); | 
| Line 1340  IRET_pm_return_to_vm86(DWORD new_ip, DWO | Line 1343  IRET_pm_return_to_vm86(DWORD new_ip, DWO | 
 |  |  | 
 | for (i = 0; i < CPU_SEGREG_NUM; i++) { | for (i = 0; i < CPU_SEGREG_NUM; i++) { | 
 | CPU_REGS_SREG(i) = segsel[i]; | CPU_REGS_SREG(i) = segsel[i]; | 
 |  | CPU_STAT_SREG_INIT(i); | 
 | } | } | 
 |  |  | 
 |  | /* to VM86 mode */ | 
 | set_eflags(new_flags, IOPL_FLAG|I_FLAG|VM_FLAG|RF_FLAG); | set_eflags(new_flags, IOPL_FLAG|I_FLAG|VM_FLAG|RF_FLAG); | 
 |  |  | 
 |  | new_sp &= 0xffff; | 
 |  | new_ip &= 0xffff; | 
 |  |  | 
 | CPU_ESP = new_sp; | CPU_ESP = new_sp; | 
 | SET_EIP(new_ip); | SET_EIP(new_ip); | 
 | } | } | 
| Line 1352  IRET_pm_return_to_vm86(DWORD new_ip, DWO | Line 1360  IRET_pm_return_to_vm86(DWORD new_ip, DWO | 
 | * 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(DWORD new_cs, DWORD new_ip, DWORD new_flags) | 
 | { | { | 
 | DWORD stacksize; | DWORD stacksize; | 
 |  |  |