Diff for /np2/i386c/ia32/ctrlxfer.c between versions 1.3 and 1.15

version 1.3, 2004/01/23 14:33:26 version 1.15, 2004/02/20 16:09:04
Line 34 Line 34
 #include "ctrlxfer.h"  #include "ctrlxfer.h"
   
   
 static void check_segreg(void);  
   
 /*------------------------------------------------------------------------------  /*------------------------------------------------------------------------------
  * JMPfar_pm   * JMPfar_pm
  */   */
 static void JMPfar_pm_code_segment(selector_t *jmp_sel, DWORD new_ip);  static void JMPfar_pm_code_segment(selector_t *cs_sel, UINT32 new_ip);
 static void JMPfar_pm_call_gate(selector_t *jmp_sel);  static void JMPfar_pm_call_gate(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 100  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 107  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, UINT32 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 237  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 331  JMPfar_pm_tss(selector_t *tss_sel) Line 318  JMPfar_pm_tss(selector_t *tss_sel)
 /*------------------------------------------------------------------------------  /*------------------------------------------------------------------------------
  * CALLfar_pm   * CALLfar_pm
  */   */
 static void CALLfar_pm_code_segment(selector_t *call_sel, DWORD new_ip);  static void CALLfar_pm_code_segment(selector_t *cs_sel, UINT32 new_ip);
 static void CALLfar_pm_call_gate(selector_t *call_sel);  static void CALLfar_pm_call_gate(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 419  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, 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 (!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 459  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 470  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 479  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 561  CALLfar_pm_call_gate(selector_t *callgat Line 531  CALLfar_pm_call_gate(selector_t *callgat
 static void  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;          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 {
Line 580  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_same_privilege(sele Line 566  CALLfar_pm_call_gate_same_privilege(sele
 static void  static void
 CALLfar_pm_call_gate_more_privilege(selector_t *callgate_sel, selector_t *cs_sel)  CALLfar_pm_call_gate_more_privilege(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;          UINT32 old_eip, old_esp;
         DWORD old_eip, old_esp;          UINT32 new_esp;
         DWORD tss_esp;          UINT16 old_cs, old_ss;
         WORD old_cs, old_ss;          UINT16 new_ss;
         WORD tss_ss;  
         int param_count;          int param_count;
         int i;          int i;
         int rv;          int rv;
Line 620  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);          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 671  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 = (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);                  SET_EIP(callgate_sel->desc.u.gate.offset);
Line 689  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 697  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_SP = 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);                  SET_EIP(callgate_sel->desc.u.gate.offset);
Line 715  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 755  CALLfar_pm_task_gate(selector_t *taskgat Line 723  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 817  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(UINT nbytes)
 {  {
         selector_t ret_sel, ss_sel;          selector_t cs_sel, ss_sel, temp_sel;
         DWORD sp;          UINT32 sp;
         DWORD new_ip, new_sp;          UINT32 new_ip, new_sp;
         WORD new_cs, new_ss;          UINT16 new_cs, new_ss;
         int rv;          int rv;
           int i;
   
         VERBOSE(("RETfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x, nbytes = %d", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP, nbytes));          VERBOSE(("RETfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x, nbytes = %d", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP, nbytes));
   
Line 856  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);          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 914  RETfar_pm(DWORD nbytes) Line 863  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);                  SET_EIP(new_ip);
         } else {          } else {
                 VERBOSE(("RETfar_pm: RETURN-OUTER-PRIVILEGE-LEVEL"));                  VERBOSE(("RETfar_pm: RETURN-OUTER-PRIVILEGE-LEVEL"));
Line 941  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 969  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);
                 if (CPU_STAT_SS32) {                  if (CPU_STAT_SS32) {
                         CPU_ESP = new_sp + nbytes;                          CPU_ESP = new_sp + nbytes;
                 } else {                  } else {
                         CPU_SP = new_sp + nbytes;                          CPU_SP = (UINT16)(new_sp + nbytes);
                 }                  }
   
                 /* check segment register */                  /* check segment register */
                 check_segreg();                  for (i = 0; i < CPU_SEGREG_NUM; i++) {
                           descriptor_t *dp;
                           BOOL valid;
   
                           dp = &CPU_STAT_SREG(i);
                           if ((!dp->u.seg.c || !dp->u.seg.ec)
                            && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) {
                                   /* segment register is invalid */
                                   CPU_REGS_SREG(i) = 0;
                                   CPU_STAT_SREG_CLEAR(i);
                                   continue;
                           }
   
                           rv = parse_selector(&temp_sel, CPU_REGS_SREG(i));
                           if (rv < 0) {
                                   /* segment register is invalid */
                                   CPU_REGS_SREG(i) = 0;
                                   CPU_STAT_SREG_CLEAR(i);
                                   continue;
                           }
   
                           valid = TRUE;
                           if (!temp_sel.desc.s) {
                                   /* system segment */
                                   valid = FALSE;
                           }
                           if (temp_sel.desc.u.seg.c && !temp_sel.desc.u.seg.wr) {
                                   /* execute-only code segment */
                                   valid = FALSE;
                           }
                           if (!temp_sel.desc.u.seg.c || !temp_sel.desc.u.seg.ec) {
                                   if (CPU_STAT_CPL > temp_sel.desc.dpl) {
                                           valid = FALSE;
                                   }
                           }
   
                           if (!valid) {
                                   /* segment register is invalid */
                                   CPU_REGS_SREG(i) = 0;
                                   CPU_STAT_SREG(i).valid = 0;
                           }
                   }
         }          }
   
         VERBOSE(("RETfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP));          VERBOSE(("RETfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP));
Line 998  RETfar_pm(DWORD nbytes) Line 988  RETfar_pm(DWORD nbytes)
 /*------------------------------------------------------------------------------  /*------------------------------------------------------------------------------
  * IRET_pm   * IRET_pm
  */   */
   
 #undef  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);
 #ifdef  RETURN_FROM_VM86  static void IRET_pm_protected_mode_return_same_privilege(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(selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags);
 #endif  /* 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;
         DWORD sp;          UINT32 new_ip, new_flags;
         DWORD stacksize;        /* for RETURN-TO-SAME-PRIVILEGE-LEVEL */          UINT16 new_cs;
         DWORD mask = 0;  
         DWORD new_ip, new_sp, new_flags;  
         WORD new_cs, new_ss;  
         int rv;  
   
         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 & 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 {
                 return;                  if (CPU_STAT_SS32) {
                           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;
           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 (tss_sel.desc.s) {
                 new_cs = cpu_vmemoryread_d(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  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));  
                 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;
         }          }
 #endif  /* 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);
                 return;  
         }          }
   
           task_switch(&tss_sel, TASK_SWITCH_IRET);
   }
   
   /*---
    * 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 (!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_d(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);  
                 }  
   
                 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, 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);
         }          }
   
Line 1178  IRET_pm(void) Line 1171  IRET_pm(void)
                         mask |= VM_FLAG|VIF_FLAG|VIP_FLAG;                          mask |= VM_FLAG|VIF_FLAG|VIP_FLAG;
                 }                  }
         }          }
           if (CPU_INST_OP32) {
                   stacksize = 12;
           } else {
                   stacksize = 6;
           }
   
         /* set new register */          /* set new register */
         load_cs(iret_sel.selector, &iret_sel.desc, iret_sel.rpl);          load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL);
         SET_EIP(new_ip);          SET_EIP(new_ip);
   
         set_eflags(new_flags, mask);          set_eflags(new_flags, mask);
   
         if (iret_sel.rpl != CPU_STAT_CPL) {          if (CPU_STAT_SS32) {
                 /* RETURN-OUTER-PRIVILEGE-LEVEL */                  CPU_ESP += stacksize;
                 load_ss(new_ss, &ss_sel.desc, iret_sel.rpl);  
                 CPU_ESP = new_sp;  
   
                 /* check segment register */  
                 check_segreg();  
         } else {          } else {
                 /* RETURN-TO-SAME-PRIVILEGE-LEVEL */                  CPU_SP += (UINT16)stacksize;
                 if (CPU_STAT_SS32) {  
                         CPU_ESP += stacksize;  
                 } else {  
                         CPU_SP += stacksize;  
                 }  
         }          }
   
         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, UINT32 new_ip, UINT32 new_flags)
 {  {
         selector_t iret_sel;          descriptor_t *dp;
           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"));
   
         if (CPU_STAT_VM86) {          if (CPU_STAT_SS32) {
                 ia32_panic("IRET_pm: VM86");                  sp = CPU_ESP;
           } else {
                   sp = CPU_SP;
         }          }
           if (CPU_INST_OP32) {
         new_cs = get_link_selector_from_tss();                  CHECK_STACK_POP(&CPU_STAT_SREG(CPU_SS_INDEX), sp, 20);
         rv = parse_selector(&iret_sel, new_cs);                  new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12);
         if (rv < 0 || iret_sel.ldt) {                  new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16);
                 VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", iret_sel.selector, rv));          } else {
                 EXCEPTION(GP_EXCEPTION, iret_sel.idx);                  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);
         }          }
   
         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);
           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 = (UINT16)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);
                           }
                   }
           }
 }  }
   
 /*---  /*---
  * 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"));
Line 1274  IRET_pm_return_to_vm86(DWORD new_ip, DWO Line 1321  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_d(CPU_SS_INDEX, sp + 16);          segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16);
         segsel[CPU_ES_INDEX] = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 20);          segsel[CPU_ES_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 20);
         segsel[CPU_DS_INDEX] = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 24);          segsel[CPU_DS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 24);
         segsel[CPU_FS_INDEX] = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 28);          segsel[CPU_FS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 28);
         segsel[CPU_GS_INDEX] = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 32);          segsel[CPU_GS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 32);
         segsel[CPU_CS_INDEX] = new_cs;          segsel[CPU_CS_INDEX] = (UINT16)new_cs;
   
         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);
 }  }
   
 #ifdef  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 1323  IRET_pm_return_from_vm86(DWORD new_ip, D Line 1374  IRET_pm_return_from_vm86(DWORD new_ip, D
                 if (CPU_STAT_SS32) {                  if (CPU_STAT_SS32) {
                         CPU_ESP += stacksize;                          CPU_ESP += stacksize;
                 } else {                  } else {
                         CPU_SP += stacksize;                          CPU_SP += (UINT16)stacksize;
                 }                  }
   
                 set_eflags(new_flags, I_FLAG|RF_FLAG);                  set_eflags(new_flags, I_FLAG|RF_FLAG);
Line 1335  IRET_pm_return_from_vm86(DWORD new_ip, D Line 1386  IRET_pm_return_from_vm86(DWORD new_ip, D
         VERBOSE(("IRET_pm: trap to virtual-8086 monitor: VM=1, IOPL<3"));          VERBOSE(("IRET_pm: trap to virtual-8086 monitor: VM=1, IOPL<3"));
         EXCEPTION(GP_EXCEPTION, 0);          EXCEPTION(GP_EXCEPTION, 0);
 }  }
 #endif  /* RETURN_FROM_VM86 */  
   
   
 /*-----  
  * Misc.  
  */  
 static void  
 check_segreg(void)  
 {  
         selector_t temp_sel;  
         BOOL valid;  
         int rv;  
         int i;  
   
         /* check segment register */  
         for (i = 0; i < CPU_SEGREG_NUM; i++) {  
                 if (i == CPU_CS_INDEX || i == CPU_SS_INDEX)  
                         continue;  
   
                 rv = parse_selector(&temp_sel, CPU_REGS_SREG(i));  
                 if (rv < 0) {  
                         /* segment register is invalid */  
                         CPU_REGS_SREG(i) = 0;  
                         CPU_STAT_SREG(i).valid = 0;  
                         continue;  
                 }  
   
                 valid = TRUE;  
                 if (!temp_sel.desc.s) {  
                         /* system segment */  
                         valid = FALSE;  
                 }  
                 if (temp_sel.desc.u.seg.c && !temp_sel.desc.u.seg.wr) {  
                         /* execute-only code segment */  
                         valid = FALSE;  
                 }  
                 if (!temp_sel.desc.u.seg.c || !temp_sel.desc.u.seg.ec) {  
                         if (CPU_STAT_CPL > temp_sel.desc.dpl) {  
                                 valid = FALSE;  
                         }  
                 }  
   
                 if (!valid) {  
                         /* segment register is invalid */  
                         CPU_REGS_SREG(i) = 0;  
                         CPU_STAT_SREG(i).valid = 0;  
                 }  
         }  
 }  

Removed from v.1.3  
changed lines
  Added in v.1.15


RetroPC.NET-CVS <cvs@retropc.net>