void gcomm::AsioUdpSocket::read_handler(const asio::error_code& ec,
                                        size_t bytes_transferred)
{
    if (ec)
    {
        //
        return;
    }

    if (bytes_transferred >= NetHeader::serial_size_)
    {
        Critical<AsioProtonet> crit(net_);
        NetHeader hdr;
        try
        {
            unserialize(&recv_buf_[0], NetHeader::serial_size_, 0, hdr);
        }
        catch (gu::Exception& e)
        {
            log_warn << "hdr unserialize failed: " << e.get_errno();
            return;
        }
        if (NetHeader::serial_size_ + hdr.len() != bytes_transferred)
        {
            log_warn << "len " << hdr.len()
                     << " does not match to bytes transferred"
                     << bytes_transferred;
        }
        else
        {
            Datagram dg(
                gu::SharedBuffer(
                    new gu::Buffer(&recv_buf_[0] + NetHeader::serial_size_,
                                   &recv_buf_[0] + NetHeader::serial_size_
                                   + hdr.len())));
            if (net_.checksum_ == true && check_cs(hdr, dg))
            {
                log_warn << "checksum failed, hdr: len=" << hdr.len()
                         << " has_crc32="  << hdr.has_crc32()
                         << " has_crc32c=" << hdr.has_crc32c()
                         << " crc32=" << hdr.crc32();
            }
            else
            {
                net_.dispatch(id(), dg, ProtoUpMeta());
            }
        }
    }
    else
    {
        log_warn << "short read of " << bytes_transferred;
    }
    async_receive();
}
Esempio n. 2
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);
    }
  }
}
Esempio n. 3
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();
  }
}
Esempio n. 4
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);
  }

  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);
  }

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

#if BX_SUPPORT_X86_64
    if (long_mode() && cs_descriptor.u.segment.l) {
      Bit64u temp_rsp = RSP; 
      // moving to long mode, push return address onto 64-bit stack
      if (i->os64L()) {
        write_new_stack_qword_64(temp_rsp -  8, cs_descriptor.dpl,
             BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
        write_new_stack_qword_64(temp_rsp - 16, cs_descriptor.dpl, RIP);
        temp_rsp -= 16;
      }
      else if (i->os32L()) {
        write_new_stack_dword_64(temp_rsp - 4, cs_descriptor.dpl,
             BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
        write_new_stack_dword_64(temp_rsp - 8, cs_descriptor.dpl, EIP);
        temp_rsp -= 8;
      }
      else {
        write_new_stack_word_64(temp_rsp - 2, cs_descriptor.dpl,
             BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
        write_new_stack_word_64(temp_rsp - 4, cs_descriptor.dpl, IP);
        temp_rsp -= 4;
      }

      // 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);

      RSP = temp_rsp;
    }
    else
#endif
    {
      Bit32u temp_RSP;

      // moving to legacy mode, push return address onto 32-bit stack
      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()) {
        write_new_stack_qword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
             temp_RSP -  8, cs_descriptor.dpl,
             BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
        write_new_stack_qword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
             temp_RSP - 16, cs_descriptor.dpl, RIP);
        temp_RSP -= 16;
      }
      else
#endif
      if (i->os32L()) {
        write_new_stack_dword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
             temp_RSP - 4, cs_descriptor.dpl,
             BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
        write_new_stack_dword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
             temp_RSP - 8, cs_descriptor.dpl, EIP);
        temp_RSP -= 8;
      }
      else {
        write_new_stack_word_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
             temp_RSP - 2, cs_descriptor.dpl,
             BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
        write_new_stack_word_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
             temp_RSP - 4, cs_descriptor.dpl, IP);
        temp_RSP -= 4;
      }

      // 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);

      if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
        ESP = (Bit32u) temp_RSP;
      else
         SP = (Bit16u) temp_RSP;
    }

    return;
  }
  else { // gate & special segment
    bx_descriptor_t  gate_descriptor = cs_descriptor;
    bx_selector_t    gate_selector = cs_selector;

    // 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);
    }

    // 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);
    }

#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);
      }
      // gate descriptor must be present else #NP(gate selector)
      if (! IS_PRESENT(gate_descriptor)) {
        BX_ERROR(("call_protected: call gate not present"));
        exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
      }

      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"));

        if (gate_descriptor.valid==0 || gate_selector.ti) {
          BX_ERROR(("call_protected: call bad TSS selector !"));
          exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
        }

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

        // SWITCH_TASKS _without_ nesting to TSS
        task_switch(i, &gate_selector, &gate_descriptor,
          BX_TASK_FROM_CALL, 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);
        }
        return;

      case BX_TASK_GATE:
        task_gate(i, &gate_selector, &gate_descriptor, BX_TASK_FROM_CALL);
        return;

      case BX_286_CALL_GATE:
      case BX_386_CALL_GATE:
        // 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);
        }
        call_gate(&gate_descriptor);
        return;

      default: // can't get here
        BX_ERROR(("call_protected(): gate.type(%u) unsupported", (unsigned) gate_descriptor.type));
        exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
    }
  }
}