コード例 #1
0
ファイル: call_far.cpp プロジェクト: hack477/bochs4wii
BX_CPU_C::call_gate64(bx_selector_t *gate_selector)
{
  bx_selector_t cs_selector;
  Bit32u dword1, dword2, dword3;
  bx_descriptor_t cs_descriptor;
  bx_descriptor_t gate_descriptor;

  // examine code segment selector in call gate descriptor
  BX_DEBUG(("call_gate64: CALL 64bit call gate"));

  fetch_raw_descriptor_64(gate_selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
  parse_descriptor(dword1, dword2, &gate_descriptor);

  Bit16u dest_selector = gate_descriptor.u.gate.dest_selector;
  // selector must not be null else #GP(0)
  if ((dest_selector & 0xfffc) == 0) {
    BX_ERROR(("call_gate64: 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);

  // find the RIP in the gate_descriptor
  Bit64u new_RIP = gate_descriptor.u.gate.dest_offset;
  new_RIP |= ((Bit64u)dword3 << 32);

  // 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_gate64: selected descriptor is not code"));
    exception(BX_GP_EXCEPTION, dest_selector & 0xfffc, 0);
  }

  // In long mode, only 64-bit call gates are allowed, and they must point
  // to 64-bit code segments, else #GP(selector)
  if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b)
  {
    BX_ERROR(("call_gate64: not 64-bit code segment in call gate 64"));
    exception(BX_GP_EXCEPTION, dest_selector & 0xfffc, 0);
  }

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

  Bit64u old_CS  = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
  Bit64u old_RIP = RIP;

  // 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))
  {
    Bit64u RSP_for_cpl_x;

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

    // get new RSP for new privilege level from TSS
    get_RSP_from_TSS(cs_descriptor.dpl, &RSP_for_cpl_x);

    Bit64u old_SS  = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
    Bit64u old_RSP = RSP;

    if (! IsCanonical(RSP_for_cpl_x)) {
      // #SS(selector) when changing priviledge level
      BX_ERROR(("call_gate64: canonical address failure %08x%08x",
         GET32H(RSP_for_cpl_x), GET32L(RSP_for_cpl_x)));
      exception(BX_SS_EXCEPTION, old_SS & 0xfffc, 0);
    }

    // push old stack long pointer onto new stack
    write_new_stack_qword_64(RSP_for_cpl_x -  8, cs_descriptor.dpl, old_SS);
    write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP);
    // push long pointer to return address onto new stack
    write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, old_CS);
    write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_RIP);
    RSP_for_cpl_x -= 32;

    // prepare new stack null SS selector
    bx_selector_t ss_selector;
    bx_descriptor_t ss_descriptor;

    // set up a null descriptor
    parse_selector(0, &ss_selector);
    parse_descriptor(0, 0, &ss_descriptor);

    // load CS:RIP (guaranteed to be in 64 bit mode)
    branch_far64(&cs_selector, &cs_descriptor, new_RIP, cs_descriptor.dpl);

    // set up null SS descriptor
    load_ss(&ss_selector, &ss_descriptor, cs_descriptor.dpl);
    RSP = RSP_for_cpl_x;
  }
  else
  {
    BX_DEBUG(("CALL GATE TO SAME PRIVILEGE"));

    // push to 64-bit stack, switch to long64 guaranteed
    write_new_stack_qword_64(RSP -  8, CPL, old_CS);
    write_new_stack_qword_64(RSP - 16, CPL, old_RIP);
    RSP -= 16;

    // load CS:RIP (guaranteed to be in 64 bit mode)
    branch_far64(&cs_selector, &cs_descriptor, new_RIP, CPL);
  }
}
コード例 #2
0
ファイル: exception.cpp プロジェクト: iver6/BA
void BX_CPU_C::long_mode_int(Bit8u vector, unsigned soft_int, bx_bool push_error, Bit16u error_code)
{
  bx_descriptor_t gate_descriptor, cs_descriptor;
  bx_selector_t cs_selector;

  // interrupt vector must be within IDT table limits,
  // else #GP(vector*8 + 2 + EXT)
  if ((vector*16 + 15) > BX_CPU_THIS_PTR idtr.limit) {
    BX_ERROR(("interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x%x", BX_CPU_THIS_PTR idtr.limit));
    exception(BX_GP_EXCEPTION, vector*8 + 2);
  }

  Bit64u desctmp1 = system_read_qword(BX_CPU_THIS_PTR idtr.base + vector*16);
  Bit64u desctmp2 = system_read_qword(BX_CPU_THIS_PTR idtr.base + vector*16 + 8);

  if (desctmp2 & BX_CONST64(0x00001F0000000000)) {
    BX_ERROR(("interrupt(long mode): IDT entry extended attributes DWORD4 TYPE != 0"));
    exception(BX_GP_EXCEPTION, vector*8 + 2);
  }

  Bit32u dword1 = GET32L(desctmp1);
  Bit32u dword2 = GET32H(desctmp1);
  Bit32u dword3 = GET32L(desctmp2);

  parse_descriptor(dword1, dword2, &gate_descriptor);

  if ((gate_descriptor.valid==0) || gate_descriptor.segment)
  {
    BX_ERROR(("interrupt(long mode): gate descriptor is not valid sys seg"));
    exception(BX_GP_EXCEPTION, vector*8 + 2);
  }

  // descriptor AR byte must indicate interrupt gate, trap gate,
  // or task gate, else #GP(vector*8 + 2 + EXT)
  if (gate_descriptor.type != BX_386_INTERRUPT_GATE &&
      gate_descriptor.type != BX_386_TRAP_GATE)
  {
    BX_ERROR(("interrupt(long mode): unsupported gate type %u",
        (unsigned) gate_descriptor.type));
    exception(BX_GP_EXCEPTION, vector*8 + 2);
  }

  // if software interrupt, then gate descripor DPL must be >= CPL,
  // else #GP(vector * 8 + 2 + EXT)
  if (soft_int && gate_descriptor.dpl < CPL)
  {
    BX_ERROR(("interrupt(long mode): soft_int && gate.dpl < CPL"));
    exception(BX_GP_EXCEPTION, vector*8 + 2);
  }

  // Gate must be present, else #NP(vector * 8 + 2 + EXT)
  if (! IS_PRESENT(gate_descriptor)) {
    BX_ERROR(("interrupt(long mode): gate.p == 0"));
    exception(BX_NP_EXCEPTION, vector*8 + 2);
  }

  Bit16u gate_dest_selector = gate_descriptor.u.gate.dest_selector;
  Bit64u gate_dest_offset   = ((Bit64u)dword3 << 32) |
                       gate_descriptor.u.gate.dest_offset;

  unsigned ist = gate_descriptor.u.gate.param_count & 0x7;

  // examine CS selector and descriptor given in gate descriptor
  // selector must be non-null else #GP(EXT)
  if ((gate_dest_selector & 0xfffc) == 0) {
    BX_ERROR(("int_trap_gate(long mode): selector null"));
    exception(BX_GP_EXCEPTION, 0);
  }

  parse_selector(gate_dest_selector, &cs_selector);

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

  // descriptor AR byte must indicate code seg
  // and code segment descriptor DPL<=CPL, else #GP(selector+EXT)
  if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
      IS_DATA_SEGMENT(cs_descriptor.type) ||
      cs_descriptor.dpl > CPL)
  {
    BX_ERROR(("interrupt(long mode): not accessible or not code segment"));
    exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
  }

  // check that it's a 64 bit segment
  if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b)
  {
    BX_ERROR(("interrupt(long mode): must be 64 bit segment"));
    exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
  }

  // segment must be present, else #NP(selector + EXT)
  if (! IS_PRESENT(cs_descriptor)) {
    BX_ERROR(("interrupt(long mode): segment not present"));
    exception(BX_NP_EXCEPTION, cs_selector.value & 0xfffc);
  }
 
  Bit64u RSP_for_cpl_x;

  Bit64u old_CS  = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
  Bit64u old_RIP = RIP;
  Bit64u old_SS  = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
  Bit64u old_RSP = RSP;

  // if code segment is non-conforming and DPL < CPL then
  // INTERRUPT TO INNER PRIVILEGE:
  if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && cs_descriptor.dpl < CPL)
  {
    BX_DEBUG(("interrupt(long mode): INTERRUPT TO INNER PRIVILEGE"));

    // check selector and descriptor for new stack in current TSS
    if (ist > 0) {
      BX_DEBUG(("interrupt(long mode): trap to IST, vector = %d", ist));
      RSP_for_cpl_x = get_RSP_from_TSS(ist+3);
    }
    else {
      RSP_for_cpl_x = get_RSP_from_TSS(cs_descriptor.dpl);
    }

    // align stack
    RSP_for_cpl_x &= BX_CONST64(0xfffffffffffffff0);

    // push old stack long pointer onto new stack
    write_new_stack_qword_64(RSP_for_cpl_x -  8, cs_descriptor.dpl, old_SS);
    write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP);
    write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, read_eflags());
    // push long pointer to return address onto new stack
    write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_CS);
    write_new_stack_qword_64(RSP_for_cpl_x - 40, cs_descriptor.dpl, old_RIP);
    RSP_for_cpl_x -= 40;

    if (push_error) {
      RSP_for_cpl_x -= 8;
      write_new_stack_qword_64(RSP_for_cpl_x, cs_descriptor.dpl, error_code);
    }

    // load CS:RIP (guaranteed to be in 64 bit mode)
    branch_far64(&cs_selector, &cs_descriptor, gate_dest_offset, cs_descriptor.dpl);

    // set up null SS descriptor
    load_null_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], cs_descriptor.dpl);
  }
  else if(IS_CODE_SEGMENT_CONFORMING(cs_descriptor.type) || cs_descriptor.dpl==CPL) 
  {
    // if code segment is conforming OR code segment DPL = CPL then
    // INTERRUPT TO SAME PRIVILEGE LEVEL:

    BX_DEBUG(("interrupt(long mode): INTERRUPT TO SAME PRIVILEGE"));

    // check selector and descriptor for new stack in current TSS
    if (ist > 0) {
      BX_DEBUG(("interrupt(long mode): trap to IST, vector = %d", ist));
      RSP_for_cpl_x = get_RSP_from_TSS(ist+3);
    }
    else {
      RSP_for_cpl_x = RSP;
    }

    // align stack
    RSP_for_cpl_x &= BX_CONST64(0xfffffffffffffff0);

    // push flags onto stack
    // push current CS selector onto stack
    // push return offset onto stack
    write_new_stack_qword_64(RSP_for_cpl_x - 8,  cs_descriptor.dpl, old_SS);
    write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP);
    write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, read_eflags());
    // push long pointer to return address onto new stack
    write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_CS);
    write_new_stack_qword_64(RSP_for_cpl_x - 40, cs_descriptor.dpl, old_RIP);
    RSP_for_cpl_x -= 40;

    if (push_error) {
      RSP_for_cpl_x -= 8;
      write_new_stack_qword_64(RSP_for_cpl_x, cs_descriptor.dpl, error_code);
    }

    // set the RPL field of CS to CPL
    branch_far64(&cs_selector, &cs_descriptor, gate_dest_offset, CPL);
  }
  else {
    BX_ERROR(("interrupt(long mode): bad descriptor type %u (CS.DPL=%u CPL=%u)",
      (unsigned) cs_descriptor.type, (unsigned) cs_descriptor.dpl, (unsigned) CPL));
    exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
  }

  RSP = RSP_for_cpl_x;

  // if interrupt gate then set IF to 0
  if (!(gate_descriptor.type & 1)) // even is int-gate
    BX_CPU_THIS_PTR clear_IF();
  BX_CPU_THIS_PTR clear_TF();
//BX_CPU_THIS_PTR clear_VM(); // VM is clear in long mode
  BX_CPU_THIS_PTR clear_RF();
  BX_CPU_THIS_PTR clear_NT();
}
コード例 #3
0
ファイル: call_far.cpp プロジェクト: iver6/BA
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);
    }
  }
}