Diff for /np2/i386c/ia32/ctrlxfer.c between versions 1.11 and 1.22

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

Removed from v.1.11  
changed lines
  Added in v.1.22


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