示例#1
0
/* DF /0 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_WORD_INTEGER(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  Bit16s load_reg = (Bit16s) read_virtual_word(i->seg(), RMAddr(i));

  clear_C1();

  if (! IS_TAG_EMPTY(-1)) {
    BX_CPU_THIS_PTR FPU_stack_overflow();
    return;
  }

  floatx80 result = int32_to_floatx80((Bit32s) load_reg);
  BX_CPU_THIS_PTR the_i387.FPU_push();
  BX_WRITE_FPU_REG(result, 0);
#else
  BX_INFO(("FILD_WORD_INTEGER: required FPU, configure --enable-fpu"));
#endif
}
示例#2
0
文件: fpu_compare.cpp 项目: iver6/BA
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FICOM_WORD_INTEGER(bxInstruction_c *i)
{
  BX_CPU_THIS_PTR prepareFPU(i);

  int pop_stack = i->nnn() & 1;

  RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
  Bit16s load_reg = (Bit16s) read_virtual_word(i->seg(), RMAddr(i));

  BX_CPU_THIS_PTR FPU_update_last_instruction(i);

  clear_C1();

  if (IS_TAG_EMPTY(0))
  {
      FPU_exception(FPU_EX_Stack_Underflow);
      setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);

      if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
      {
          if (pop_stack)
              BX_CPU_THIS_PTR the_i387.FPU_pop();
      }
      BX_NEXT_INSTR(i);
  }

  float_status_t status =
      FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());

  int rc = floatx80_compare(BX_READ_FPU_REG(0),
                      int32_to_floatx80((Bit32s)(load_reg)), status);
  setcc(status_word_flags_fpu_compare(rc));

  if (! FPU_exception(status.float_exception_flags)) {
     if (pop_stack)
         BX_CPU_THIS_PTR the_i387.FPU_pop();
  }

  BX_NEXT_INSTR(i);
}
示例#3
0
/* DF /0 */
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_WORD_INTEGER(bxInstruction_c *i)
{
  BX_CPU_THIS_PTR prepareFPU(i);

  RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
  Bit16s load_reg = (Bit16s) read_virtual_word(i->seg(), RMAddr(i));

  FPU_update_last_instruction(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1)) {
    FPU_stack_overflow();
  }
  else {
    floatx80 result = int32_to_floatx80((Bit32s) load_reg);
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(result, 0);
  }

  BX_NEXT_INSTR(i);
}
示例#4
0
  void
bx_cpu_c::CALL32_Ep(BxInstruction_t *i)
{
  Bit16u cs_raw;
  Bit32u op1_32;

#if BX_DEBUGGER
  bx_cpu. show_flag |= Flag_call;
#endif

    /* op1_32 is a register or memory reference */
    if (i->mod == 0xc0) {
      BX_PANIC(("CALL_Ep: op1 is a register"));
      }

    /* pointer, segment address pair */
    read_virtual_dword(i->seg, i->rm_addr, &op1_32);
    read_virtual_word(i->seg, i->rm_addr+4, &cs_raw);
    invalidate_prefetch_q();

    if ( protected_mode() ) {
      bx_cpu. call_protected(i, cs_raw, op1_32);
      goto done;
      }

    push_32(bx_cpu. sregs[BX_SEG_REG_CS].selector.value);
    push_32(bx_cpu. eip);

    bx_cpu. eip = op1_32;
    load_seg_reg(&bx_cpu. sregs[BX_SEG_REG_CS], cs_raw);

done:
  BX_INSTR_FAR_BRANCH(BX_INSTR_IS_CALL,
                      bx_cpu. sregs[BX_SEG_REG_CS].selector.value, bx_cpu. eip);
  return;
}
示例#5
0
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_EXTENDED_REAL(bxInstruction_c *i)
{
  BX_CPU_THIS_PTR prepareFPU(i);

  floatx80 result;

  RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
  result.fraction = read_virtual_qword(i->seg(), RMAddr(i));
  result.exp      = read_virtual_word(i->seg(), (RMAddr(i)+8) & i->asize_mask());

  FPU_update_last_instruction(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1)) {
    FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(result, 0);
  }

  BX_NEXT_INSTR(i);
}
示例#6
0
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_AXOd(bxInstruction_c *i)
{
  AX = read_virtual_word(i->seg(), i->Id());
}
示例#7
0
BX_CPU_C::return_protected(bxInstruction_c *i, Bit16u pop_bytes)
{
  Bit16u raw_cs_selector, raw_ss_selector;
  bx_selector_t cs_selector, ss_selector;
  bx_descriptor_t cs_descriptor, ss_descriptor;
  Bit32u stack_param_offset;
  bx_address return_RIP, return_RSP, temp_RSP;
  Bit32u dword1, dword2;

  /* + 6+N*2: SS      | +12+N*4:     SS | +24+N*8      SS */
  /* + 4+N*2: SP      | + 8+N*4:    ESP | +16+N*8     RSP */
  /*          parm N  | +        parm N | +        parm N */
  /*          parm 3  | +        parm 3 | +        parm 3 */
  /*          parm 2  | +        parm 2 | +        parm 2 */
  /* + 4:     parm 1  | + 8:     parm 1 | +16:     parm 1 */
  /* + 2:     CS      | + 4:         CS | + 8:         CS */
  /* + 0:     IP      | + 0:        EIP | + 0:        RIP */

#if BX_SUPPORT_X86_64
  if (StackAddrSize64()) temp_RSP = RSP;
  else
#endif
  {
    if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) temp_RSP = ESP;
    else temp_RSP = SP;
  }

#if BX_SUPPORT_X86_64
  if (i->os64L()) {
    raw_cs_selector = (Bit16u) read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 8);
    return_RIP      =          read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP);
    stack_param_offset = 16;
  }
  else
#endif
  if (i->os32L()) {
    raw_cs_selector = (Bit16u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 4);
    return_RIP      =          read_virtual_dword(BX_SEG_REG_SS, temp_RSP);
    stack_param_offset = 8;
  }
  else {
    raw_cs_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 2);
    return_RIP      = read_virtual_word(BX_SEG_REG_SS, temp_RSP);
    stack_param_offset = 4;
  }

  // selector must be non-null else #GP(0)
  if ((raw_cs_selector & 0xfffc) == 0) {
    BX_ERROR(("return_protected: CS selector null"));
    exception(BX_GP_EXCEPTION, 0, 0);
  }

  parse_selector(raw_cs_selector, &cs_selector);

  // selector index must be within its descriptor table limits,
  // else #GP(selector)
  fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);

  // descriptor AR byte must indicate code segment, else #GP(selector)
  parse_descriptor(dword1, dword2, &cs_descriptor);

  // return selector RPL must be >= CPL, else #GP(return selector)
  if (cs_selector.rpl < CPL) {
    BX_ERROR(("return_protected: CS.rpl < CPL"));
    exception(BX_GP_EXCEPTION, raw_cs_selector & 0xfffc, 0);
  }

  // check code-segment descriptor
  check_cs(&cs_descriptor, raw_cs_selector, 0, cs_selector.rpl);

  // if return selector RPL == CPL then
  // RETURN TO SAME PRIVILEGE LEVEL
  if (cs_selector.rpl == CPL)
  {
    BX_DEBUG(("return_protected: return to SAME PRIVILEGE LEVEL"));

    branch_far64(&cs_selector, &cs_descriptor, return_RIP, CPL);

#if BX_SUPPORT_X86_64
    if (StackAddrSize64())
      RSP += stack_param_offset + pop_bytes;
    else
#endif
    {
      if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
        RSP = ESP + stack_param_offset + pop_bytes;
      else
         SP += stack_param_offset + pop_bytes;
    }
    return;
  }
  /* RETURN TO OUTER PRIVILEGE LEVEL */
  else {
    /* + 6+N*2: SS      | +12+N*4:     SS | +24+N*8      SS */
    /* + 4+N*2: SP      | + 8+N*4:    ESP | +16+N*8     RSP */
    /*          parm N  | +        parm N | +        parm N */
    /*          parm 3  | +        parm 3 | +        parm 3 */
    /*          parm 2  | +        parm 2 | +        parm 2 */
    /* + 4:     parm 1  | + 8:     parm 1 | +16:     parm 1 */
    /* + 2:     CS      | + 4:         CS | + 8:         CS */
    /* + 0:     IP      | + 0:        EIP | + 0:        RIP */

    BX_DEBUG(("return_protected: return to OUTER PRIVILEGE LEVEL"));

#if BX_SUPPORT_X86_64
    if (i->os64L()) {
      raw_ss_selector = read_virtual_word_64 (BX_SEG_REG_SS, temp_RSP + 24 + pop_bytes);
      return_RSP      = read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 16 + pop_bytes);
    }
    else
#endif
    if (i->os32L()) {
      raw_ss_selector = read_virtual_word (BX_SEG_REG_SS, temp_RSP + 12 + pop_bytes);
      return_RSP      = read_virtual_dword(BX_SEG_REG_SS, temp_RSP +  8 + pop_bytes);
    }
    else {
      raw_ss_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 6 + pop_bytes);
      return_RSP      = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 4 + pop_bytes);
    }

    /* selector index must be within its descriptor table limits,
     * else #GP(selector) */
    parse_selector(raw_ss_selector, &ss_selector);

    if ((raw_ss_selector & 0xfffc) == 0) {
      if (long_mode()) {
        if (! IS_LONG64_SEGMENT(cs_descriptor) || (cs_selector.rpl == 3)) {
          BX_ERROR(("return_protected: SS selector null"));
          exception(BX_GP_EXCEPTION, 0, 0);
        }
      }
      else // not in long or compatibility mode
      {
        BX_ERROR(("return_protected: SS selector null"));
        exception(BX_GP_EXCEPTION, 0, 0);
      }
    }

    fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
    parse_descriptor(dword1, dword2, &ss_descriptor);

    /* selector RPL must = RPL of the return CS selector,
     * else #GP(selector) */
    if (ss_selector.rpl != cs_selector.rpl) {
      BX_ERROR(("return_protected: ss.rpl != cs.rpl"));
      exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc, 0);
    }

    /* descriptor AR byte must indicate a writable data segment,
     * else #GP(selector) */
    if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
         IS_CODE_SEGMENT(ss_descriptor.type) ||
        !IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
    {
      BX_ERROR(("return_protected: SS.AR byte not writable data"));
      exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc, 0);
    }

    /* descriptor dpl must = RPL of the return CS selector,
     * else #GP(selector) */
    if (ss_descriptor.dpl != cs_selector.rpl) {
      BX_ERROR(("return_protected: SS.dpl != cs.rpl"));
      exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc, 0);
    }

    /* segment must be present else #SS(selector) */
    if (! IS_PRESENT(ss_descriptor)) {
      BX_ERROR(("return_protected: ss.present == 0"));
      exception(BX_SS_EXCEPTION, raw_ss_selector & 0xfffc, 0);
    }

    branch_far64(&cs_selector, &cs_descriptor, return_RIP, cs_selector.rpl);

    /* load SS:SP from stack */
    /* load SS-cache with return SS descriptor */
    load_ss(&ss_selector, &ss_descriptor, cs_selector.rpl);

#if BX_SUPPORT_X86_64
    if (StackAddrSize64())
      RSP = return_RSP + pop_bytes;
    else
#endif
    if (ss_descriptor.u.segment.d_b)
      RSP = (Bit32u) return_RSP + pop_bytes;
    else
      SP  = (Bit16u) return_RSP + pop_bytes;

    /* check ES, DS, FS, GS for validity */
    validate_seg_regs();
  }
}
示例#8
0
BX_CPU_C::call_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
{
  bx_selector_t cs_selector;
  Bit32u dword1, dword2;
  bx_descriptor_t cs_descriptor;

  /* new cs selector must not be null, else #GP(0) */
  if ((cs_raw & 0xfffc) == 0) {
    BX_ERROR(("call_protected: CS selector null"));
    exception(BX_GP_EXCEPTION, 0, 0);
  }

  parse_selector(cs_raw, &cs_selector);
  // check new CS selector index within its descriptor limits,
  // else #GP(new CS selector)
  fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
  parse_descriptor(dword1, dword2, &cs_descriptor);

  // examine AR byte of selected descriptor for various legal values
  if (cs_descriptor.valid==0) {
    BX_ERROR(("call_protected: invalid CS descriptor"));
    exception(BX_GP_EXCEPTION, cs_raw & 0xfffc, 0);
  }

  if (cs_descriptor.segment)   // normal segment
  {
    check_cs(&cs_descriptor, cs_raw, BX_SELECTOR_RPL(cs_raw), CPL);

#if BX_SUPPORT_X86_64
    if (i->os64L()) {
      // push return address onto stack (CS padded to 64bits)
      push_64((Bit64u) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
      push_64(RIP);
    }
    else
#endif
    if (i->os32L()) {
      // push return address onto stack (CS padded to 32bits)
      push_32((Bit32u) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
      push_32(EIP);
    }
    else {
      // push return address onto stack
      push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
      push_16(IP);
    }

    // load code segment descriptor into CS cache
    // load CS with new code segment selector
    // set RPL of CS to CPL
    branch_far64(&cs_selector, &cs_descriptor, disp, CPL);

    return;
  }
  else { // gate & special segment
    bx_descriptor_t  gate_descriptor = cs_descriptor;
    bx_selector_t    gate_selector = cs_selector;
    Bit32u new_EIP;
    Bit16u dest_selector;
    Bit16u          raw_tss_selector;
    bx_selector_t   tss_selector;
    bx_descriptor_t tss_descriptor;
    Bit32u temp_eIP;

    // descriptor DPL must be >= CPL else #GP(gate selector)
    if (gate_descriptor.dpl < CPL) {
      BX_ERROR(("call_protected: descriptor.dpl < CPL"));
      exception(BX_GP_EXCEPTION, cs_raw & 0xfffc, 0);
    }

    // descriptor DPL must be >= gate selector RPL else #GP(gate selector)
    if (gate_descriptor.dpl < gate_selector.rpl) {
      BX_ERROR(("call_protected: descriptor.dpl < selector.rpl"));
      exception(BX_GP_EXCEPTION, cs_raw & 0xfffc, 0);
    }

#if BX_SUPPORT_X86_64
    if (long_mode()) {
      // call gate type is higher priority than non-present bit check
      if (gate_descriptor.type != BX_386_CALL_GATE) {
        BX_ERROR(("call_protected: gate type %u unsupported in long mode", (unsigned) gate_descriptor.type));
        exception(BX_GP_EXCEPTION, cs_raw & 0xfffc, 0);
      }
    }
    else
#endif
    {
      switch (gate_descriptor.type) {
        case BX_SYS_SEGMENT_AVAIL_286_TSS:
        case BX_SYS_SEGMENT_AVAIL_386_TSS:
        case BX_TASK_GATE:
        case BX_286_CALL_GATE:
        case BX_386_CALL_GATE:
          break;
        default:
          BX_ERROR(("call_protected(): gate.type(%u) unsupported", (unsigned) gate_descriptor.type));
          exception(BX_GP_EXCEPTION, cs_raw & 0xfffc, 0);
      }
    }

    // gate descriptor must be present else #NP(gate selector)
    if (! IS_PRESENT(gate_descriptor)) {
      BX_ERROR(("call_protected: gate not present"));
      exception(BX_NP_EXCEPTION, cs_raw & 0xfffc, 0);
    }

#if BX_SUPPORT_X86_64
    if (long_mode()) {
      call_gate64(&gate_selector);
      return;
    }
#endif

    switch (gate_descriptor.type) {
      case BX_SYS_SEGMENT_AVAIL_286_TSS:
      case BX_SYS_SEGMENT_AVAIL_386_TSS:

        if (gate_descriptor.type==BX_SYS_SEGMENT_AVAIL_286_TSS)
          BX_DEBUG(("call_protected: 16bit available TSS"));
        else
          BX_DEBUG(("call_protected: 32bit available TSS"));

        // SWITCH_TASKS _without_ nesting to TSS
        task_switch(&gate_selector, &gate_descriptor,
          BX_TASK_FROM_CALL_OR_INT, dword1, dword2);

        // EIP must be in code seg limit, else #GP(0)
        if (EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
          BX_ERROR(("call_protected: EIP not within CS limits"));
          exception(BX_GP_EXCEPTION, 0, 0);
        }
        return;

      case BX_TASK_GATE:
        // examine selector to TSS, given in Task Gate descriptor
        // must specify global in the local/global bit else #TS(TSS selector)
        raw_tss_selector = gate_descriptor.u.taskgate.tss_selector;
        parse_selector(raw_tss_selector, &tss_selector);

        if (tss_selector.ti) {
          BX_ERROR(("call_protected: tss_selector.ti=1"));
          exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc, 0);
        }

        // index must be within GDT limits else #TS(TSS selector)
        fetch_raw_descriptor(&tss_selector, &dword1, &dword2, BX_GP_EXCEPTION);

        parse_descriptor(dword1, dword2, &tss_descriptor);

        // descriptor AR byte must specify available TSS
        //   else #GP(TSS selector)
        if (tss_descriptor.valid==0 || tss_descriptor.segment) {
          BX_ERROR(("call_protected: TSS selector points to bad TSS"));
          exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc, 0);
        }
        if (tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_286_TSS &&
            tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS)
        {
          BX_ERROR(("call_protected: TSS selector points to bad TSS"));
          exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc, 0);
        }

        // task state segment must be present, else #NP(tss selector)
        if (! IS_PRESENT(tss_descriptor)) {
          BX_ERROR(("call_protected: task descriptor.p == 0"));
          exception(BX_NP_EXCEPTION, raw_tss_selector & 0xfffc, 0);
        }

        // SWITCH_TASKS without nesting to TSS
        task_switch(&tss_selector, &tss_descriptor,
                    BX_TASK_FROM_CALL_OR_INT, dword1, dword2);

        // EIP must be within code segment limit, else #TS(0)
        if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b)
          temp_eIP = EIP;
        else
          temp_eIP =  IP;

        if (temp_eIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
        {
          BX_ERROR(("call_protected: EIP > CS.limit"));
          exception(BX_GP_EXCEPTION, 0, 0);
        }
        return;

      case BX_286_CALL_GATE:
      case BX_386_CALL_GATE:
        // examine code segment selector in call gate descriptor
        BX_DEBUG(("call_protected: call gate"));
        dest_selector = gate_descriptor.u.gate.dest_selector;
        new_EIP       = gate_descriptor.u.gate.dest_offset;

        // selector must not be null else #GP(0)
        if ((dest_selector & 0xfffc) == 0) {
          BX_ERROR(("call_protected: selector in gate null"));
          exception(BX_GP_EXCEPTION, 0, 0);
        }

        parse_selector(dest_selector, &cs_selector);
        // selector must be within its descriptor table limits,
        //   else #GP(code segment selector)
        fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
        parse_descriptor(dword1, dword2, &cs_descriptor);

        // AR byte of selected descriptor must indicate code segment,
        //   else #GP(code segment selector)
        // DPL of selected descriptor must be <= CPL,
        // else #GP(code segment selector)
        if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
            IS_DATA_SEGMENT(cs_descriptor.type) ||
            cs_descriptor.dpl > CPL)
        {
          BX_ERROR(("call_protected: selected descriptor is not code"));
          exception(BX_GP_EXCEPTION, dest_selector & 0xfffc, 0);
        }

        // code segment must be present else #NP(selector)
        if (! IS_PRESENT(cs_descriptor)) {
          BX_ERROR(("call_protected: code segment not present !"));
          exception(BX_NP_EXCEPTION, dest_selector & 0xfffc, 0);
        }

        // CALL GATE TO MORE PRIVILEGE
        // if non-conforming code segment and DPL < CPL then
        if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && (cs_descriptor.dpl < CPL))
        {
          Bit16u SS_for_cpl_x;
          Bit32u ESP_for_cpl_x;
          bx_selector_t   ss_selector;
          bx_descriptor_t ss_descriptor;
          Bit16u   return_SS, return_CS;
          Bit32u   return_ESP, return_EIP;
          Bit16u   parameter_word[32];
          Bit32u   parameter_dword[32];

          BX_DEBUG(("CALL GATE TO MORE PRIVILEGE LEVEL"));

          // get new SS selector for new privilege level from TSS
          get_SS_ESP_from_TSS(cs_descriptor.dpl, &SS_for_cpl_x, &ESP_for_cpl_x);

          // check selector & descriptor for new SS:
          // selector must not be null, else #TS(0)
          if ((SS_for_cpl_x & 0xfffc) == 0) {
            BX_ERROR(("call_protected: new SS null"));
            exception(BX_TS_EXCEPTION, 0, 0);
          }

          // selector index must be within its descriptor table limits,
          //   else #TS(SS selector)
          parse_selector(SS_for_cpl_x, &ss_selector);
          fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_TS_EXCEPTION);
          parse_descriptor(dword1, dword2, &ss_descriptor);

          // selector's RPL must equal DPL of code segment,
          //   else #TS(SS selector)
          if (ss_selector.rpl != cs_descriptor.dpl) {
            BX_ERROR(("call_protected: SS selector.rpl != CS descr.dpl"));
            exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc, 0);
          }

          // stack segment DPL must equal DPL of code segment,
          //   else #TS(SS selector)
          if (ss_descriptor.dpl != cs_descriptor.dpl) {
            BX_ERROR(("call_protected: SS descr.rpl != CS descr.dpl"));
            exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc, 0);
          }

          // descriptor must indicate writable data segment,
          //   else #TS(SS selector)
          if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
               IS_CODE_SEGMENT(ss_descriptor.type) ||
              !IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
          {
            BX_ERROR(("call_protected: ss descriptor is not writable data seg"));
            exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc, 0);
          }

          // segment must be present, else #SS(SS selector)
          if (! IS_PRESENT(ss_descriptor)) {
            BX_ERROR(("call_protected: ss descriptor not present"));
            exception(BX_SS_EXCEPTION, SS_for_cpl_x & 0xfffc, 0);
          }

          // get word count from call gate, mask to 5 bits
          unsigned param_count = gate_descriptor.u.gate.param_count & 0x1f;

          // save return SS:eSP to be pushed on new stack
          return_SS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
          if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
            return_ESP = ESP;
          else
            return_ESP =  SP;

          // save return CS:eIP to be pushed on new stack
          return_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
          if (cs_descriptor.u.segment.d_b)
            return_EIP = EIP;
          else
            return_EIP = IP;

          if (gate_descriptor.type==BX_286_CALL_GATE) {
            for (unsigned i=0; i<param_count; i++) {
              parameter_word[i] = read_virtual_word(BX_SEG_REG_SS, return_ESP + i*2);
            }
          }
          else {
            for (unsigned i=0; i<param_count; i++) {
              parameter_dword[i] = read_virtual_dword(BX_SEG_REG_SS, return_ESP + i*4);
            }
          }

          // Prepare new stack segment
          bx_segment_reg_t new_stack;
          new_stack.selector = ss_selector;
          new_stack.cache = ss_descriptor;
          new_stack.selector.rpl = cs_descriptor.dpl;
          // add cpl to the selector value
          new_stack.selector.value = (0xfffc & new_stack.selector.value) |
            new_stack.selector.rpl;

          /* load new SS:SP value from TSS */
          if (ss_descriptor.u.segment.d_b) {
            Bit32u temp_ESP = ESP_for_cpl_x;

            // push pointer of old stack onto new stack
            if (gate_descriptor.type==BX_386_CALL_GATE) {
              write_new_stack_dword_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, return_SS);
              write_new_stack_dword_32(&new_stack, temp_ESP-8, cs_descriptor.dpl, return_ESP);
              temp_ESP -= 8;

              for (unsigned i=param_count; i>0; i--) {
                temp_ESP -= 4;
                write_new_stack_dword_32(&new_stack, temp_ESP, cs_descriptor.dpl, parameter_dword[i-1]);
              }
              // push return address onto new stack
              write_new_stack_dword_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, return_CS);
              write_new_stack_dword_32(&new_stack, temp_ESP-8, cs_descriptor.dpl, return_EIP);
              temp_ESP -= 8;
            }
            else {
              write_new_stack_word_32(&new_stack, temp_ESP-2, cs_descriptor.dpl, return_SS);
              write_new_stack_word_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, (Bit16u) return_ESP);
              temp_ESP -= 4;

              for (unsigned i=param_count; i>0; i--) {
                temp_ESP -= 2;
                write_new_stack_word_32(&new_stack, temp_ESP, cs_descriptor.dpl, parameter_word[i-1]);
              }
              // push return address onto new stack
              write_new_stack_word_32(&new_stack, temp_ESP-2, cs_descriptor.dpl, return_CS);
              write_new_stack_word_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, (Bit16u) return_EIP);
              temp_ESP -= 4;
            }

            ESP = temp_ESP;
          }
          else {
            Bit16u temp_SP = (Bit16u) ESP_for_cpl_x;

            // push pointer of old stack onto new stack
            if (gate_descriptor.type==BX_386_CALL_GATE) {
              write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, return_SS);
              write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl, return_ESP);
              temp_SP -= 8;

              for (unsigned i=param_count; i>0; i--) {
                temp_SP -= 4;
                write_new_stack_dword_32(&new_stack, temp_SP, cs_descriptor.dpl, parameter_dword[i-1]);
              }
              // push return address onto new stack
              write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, return_CS);
              write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl, return_EIP);
              temp_SP -= 8;
            }
            else {
              write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-2), cs_descriptor.dpl, return_SS);
              write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, (Bit16u) return_ESP);
              temp_SP -= 4;

              for (unsigned i=param_count; i>0; i--) {
                temp_SP -= 2;
                write_new_stack_word_32(&new_stack, temp_SP, cs_descriptor.dpl, parameter_word[i-1]);
              }
              // push return address onto new stack
              write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-2), cs_descriptor.dpl, return_CS);
              write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, (Bit16u) return_EIP);
              temp_SP -= 4;
            }

            SP = temp_SP;
          }

          // new eIP must be in code segment limit else #GP(0)
          if (new_EIP > cs_descriptor.u.segment.limit_scaled) {
            BX_ERROR(("call_protected: EIP not within CS limits"));
            exception(BX_GP_EXCEPTION, 0, 0);
          }

          /* load SS descriptor */
          load_ss(&ss_selector, &ss_descriptor, cs_descriptor.dpl);

          /* load new CS:IP value from gate */
          /* load CS descriptor */
          /* set CPL to stack segment DPL */
          /* set RPL of CS to CPL */
          load_cs(&cs_selector, &cs_descriptor, cs_descriptor.dpl);
          EIP = new_EIP;
        }
        else   // CALL GATE TO SAME PRIVILEGE
        {
          BX_DEBUG(("CALL GATE TO SAME PRIVILEGE"));

          if (gate_descriptor.type == BX_386_CALL_GATE) {
            // call gate 32bit, push return address onto stack
            push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
            push_32(EIP);
          }
          else {
            // call gate 16bit, push return address onto stack
            push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
            push_16(IP);
          }

          // load CS:EIP from gate
          // load code segment descriptor into CS register
          // set RPL of CS to CPL
          branch_far32(&cs_selector, &cs_descriptor, new_EIP, CPL);
        }
        return;

      default: // can't get here
        BX_PANIC(("call_protected: gate type %u unsupported", (unsigned) cs_descriptor.type));
        exception(BX_GP_EXCEPTION, cs_raw & 0xfffc, 0);
    }
  }
}
示例#9
0
BX_CPU_C::read_virtual_tword(unsigned s, bx_address offset, floatx80 *data)
{
  // read floating point register
  read_virtual_qword(s, offset+0, &data->fraction);
  read_virtual_word (s, offset+8, &data->exp);
}