ebcexecute.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,978 行 · 第 1/5 页

C
2,978
字号
        VmPtr->Ip += Immed64 + Size;
      } else {
        VmPtr->Ip = (VMIP) (UINTN) Immed64;
      }
    } else {
      //
      // Native call. Relative or absolute?
      //
      if (Operands & OPERAND_M_RELATIVE_ADDR) {
        EbcLLCALLEX (VmPtr, (UINTN) (Immed64 + VmPtr->Ip + Size), (UINTN) VmPtr->R[0], FramePtr, Size);
      } else {
        if (VmPtr->StopFlags & STOPFLAG_BREAK_ON_CALLEX) {
          EFI_BREAKPOINT ();
        }

        EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->R[0], FramePtr, Size);
      }
    }
  }

  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
ExecuteRET (
  IN VM_CONTEXT *VmPtr
  )
/*++

Routine Description:
  Execute the EBC RET instruction

Arguments:
  VmPtr   - pointer to a VM context  

Returns:
  Standard EFI_STATUS

Instruction syntax:
   RET

--*/
{
  //
  // If we're at the top of the stack, then simply set the done
  // flag and return
  //
  if (VmPtr->StackRetAddr == (UINT64) VmPtr->R[0]) {
    VmPtr->StopFlags |= STOPFLAG_APP_DONE;
  } else {
    //
    // Pull the return address off the VM app's stack and set the IP
    // to it
    //
    if (!IS_ALIGNED ((UINTN) VmPtr->R[0], sizeof (UINT16))) {
      EbcDebugSignalException (
        EXCEPT_EBC_ALIGNMENT_CHECK,
        EXCEPTION_FLAG_FATAL,
        VmPtr
        );
    }
    //
    // Restore the IP and frame pointer from the stack
    //
    VmPtr->Ip = (VMIP) (UINTN) VmReadMem64 (VmPtr, (UINTN) VmPtr->R[0]);
    VmPtr->R[0] += 8;
    VmPtr->FramePtr = (VOID *) VmReadMemN (VmPtr, (UINTN) VmPtr->R[0]);
    VmPtr->R[0] += 8;
  }

  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
ExecuteCMP (
  IN VM_CONTEXT *VmPtr
  )
/*++

Routine Description:
  Execute the EBC CMP instruction

Arguments:
  VmPtr   - pointer to a VM context  

Returns:
  Standard EFI_STATUS

Instruction syntax:
   CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}

--*/
{
  UINT8   Opcode;
  UINT8   Operands;
  UINT8   Size;
  INT16   Index16;
  UINT32  Flag;
  INT64   Op2;
  INT64   Op1;

  //
  // Get opcode and operands
  //
  Opcode    = GETOPCODE (VmPtr);
  Operands  = GETOPERANDS (VmPtr);
  //
  // Get the register data we're going to compare to
  //
  Op1 = VmPtr->R[OPERAND1_REGNUM (Operands)];
  //
  // Get immediate data
  //
  if (Opcode & OPCODE_M_IMMDATA) {
    if (OPERAND2_INDIRECT (Operands)) {
      Index16 = VmReadIndex16 (VmPtr, 2);
    } else {
      Index16 = VmReadImmed16 (VmPtr, 2);
    }

    Size = 4;
  } else {
    Index16 = 0;
    Size    = 2;
  }
  //
  // Now get Op2
  //
  if (OPERAND2_INDIRECT (Operands)) {
    if (Opcode & OPCODE_M_64BIT) {
      Op2 = (INT64) VmReadMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16));
    } else {
      //
      // 32-bit operations. 0-extend the values for all cases.
      //
      Op2 = (INT64) (UINT64) ((UINT32) VmReadMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16)));
    }
  } else {
    Op2 = VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16;
  }
  //
  // Now do the compare
  //
  Flag = 0;
  if (Opcode & OPCODE_M_64BIT) {
    //
    // 64-bit compares
    //
    switch (Opcode & OPCODE_M_OPCODE) {
    case OPCODE_CMPEQ:
      if (Op1 == Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPLTE:
      if (Op1 <= Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPGTE:
      if (Op1 >= Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPULTE:
      if ((UINT64) Op1 <= (UINT64) Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPUGTE:
      if ((UINT64) Op1 >= (UINT64) Op2) {
        Flag = 1;
      }
      break;

    default:
      ASSERT (0);
    }
  } else {
    //
    // 32-bit compares
    //
    switch (Opcode & OPCODE_M_OPCODE) {
    case OPCODE_CMPEQ:
      if ((INT32) Op1 == (INT32) Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPLTE:
      if ((INT32) Op1 <= (INT32) Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPGTE:
      if ((INT32) Op1 >= (INT32) Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPULTE:
      if ((UINT32) Op1 <= (UINT32) Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPUGTE:
      if ((UINT32) Op1 >= (UINT32) Op2) {
        Flag = 1;
      }
      break;

    default:
      ASSERT (0);
    }
  }
  //
  // Now set the flag accordingly for the comparison
  //
  if (Flag) {
    VMFLAG_SET (VmPtr, VMFLAGS_CC);
  } else {
    VMFLAG_CLEAR (VmPtr, VMFLAGS_CC);
  }
  //
  // Advance the IP
  //
  VmPtr->Ip += Size;
  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
ExecuteCMPI (
  IN VM_CONTEXT *VmPtr
  )
/*++

Routine Description:
  Execute the EBC CMPI instruction

Arguments:
  VmPtr   - pointer to a VM context  

Returns:
  Standard EFI_STATUS

Instruction syntax:
   CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32

--*/
{
  UINT8   Opcode;
  UINT8   Operands;
  UINT8   Size;
  INT64   Op1;
  INT64   Op2;
  INT16   Index16;
  UINT32  Flag;

  //
  // Get opcode and operands
  //
  Opcode    = GETOPCODE (VmPtr);
  Operands  = GETOPERANDS (VmPtr);

  //
  // Get operand1 index if present
  //
  Size = 2;
  if (Operands & OPERAND_M_CMPI_INDEX) {
    Index16 = VmReadIndex16 (VmPtr, 2);
    Size += 2;
  } else {
    Index16 = 0;
  }
  //
  // Get operand1 data we're going to compare to
  //
  Op1 = (INT64) VmPtr->R[OPERAND1_REGNUM (Operands)];
  if (OPERAND1_INDIRECT (Operands)) {
    //
    // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
    //
    if (Opcode & OPCODE_M_CMPI64) {
      Op1 = (INT64) VmReadMem64 (VmPtr, (UINTN) Op1 + Index16);
    } else {
      Op1 = (INT64) VmReadMem32 (VmPtr, (UINTN) Op1 + Index16);
    }
  } else {
    //
    // Better not have been an index with direct. That is, CMPI R1 Index,...
    // is illegal.
    //
    if (Operands & OPERAND_M_CMPI_INDEX) {
      EbcDebugSignalException (
        EXCEPT_EBC_INSTRUCTION_ENCODING,
        EXCEPTION_FLAG_ERROR,
        VmPtr
        );
      VmPtr->Ip += Size;
      return EFI_UNSUPPORTED;
    }
  }
  //
  // Get immediate data -- 16- or 32-bit sign extended
  //
  if (Opcode & OPCODE_M_CMPI32_DATA) {
    Op2 = (INT64) VmReadImmed32 (VmPtr, Size);
    Size += 4;
  } else {
    //
    // 16-bit immediate data. Sign extend always.
    //
    Op2 = (INT64) ((INT16) VmReadImmed16 (VmPtr, Size));
    Size += 2;
  }
  //
  // Now do the compare
  //
  Flag = 0;
  if (Opcode & OPCODE_M_CMPI64) {
    //
    // 64 bit comparison
    //
    switch (Opcode & OPCODE_M_OPCODE) {
    case OPCODE_CMPIEQ:
      if (Op1 == (INT64) Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPILTE:
      if (Op1 <= (INT64) Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPIGTE:
      if (Op1 >= (INT64) Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPIULTE:
      if ((UINT64) Op1 <= (UINT64) ((UINT32) Op2)) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPIUGTE:
      if ((UINT64) Op1 >= (UINT64) ((UINT32) Op2)) {
        Flag = 1;
      }
      break;

    default:
      ASSERT (0);
    }
  } else {
    //
    // 32-bit comparisons
    //
    switch (Opcode & OPCODE_M_OPCODE) {
    case OPCODE_CMPIEQ:
      if ((INT32) Op1 == Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPILTE:
      if ((INT32) Op1 <= Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPIGTE:
      if ((INT32) Op1 >= Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPIULTE:
      if ((UINT32) Op1 <= (UINT32) Op2) {
        Flag = 1;
      }
      break;

    case OPCODE_CMPIUGTE:
      if ((UINT32) Op1 >= (UINT32) Op2) {
        Flag = 1;
      }
      break;

    default:
      ASSERT (0);
    }
  }
  //
  // Now set the flag accordingly for the comparison
  //
  if (Flag) {
    VMFLAG_SET (VmPtr, VMFLAGS_CC);
  } else {
    VMFLAG_CLEAR (VmPtr, VMFLAGS_CC);
  }
  //
  // Advance the IP
  //
  VmPtr->Ip += Size;
  return EFI_SUCCESS;
}

STATIC
UINT64
ExecuteNOT (
  IN VM_CONTEXT     *VmPtr,
  IN UINT64         Op1,
  IN UINT64         Op2
  )
/*++

Routine Description:
  Execute the EBC NOT instruction

Arguments:
  VmPtr     - pointer to a VM context  
  Op1       - Operand 1 from the instruction 
  Op2       - Operand 2 from the instruction

Returns:
  ~Op2

Instruction syntax:
  NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
  
--*/
{
  return ~Op2;
}

STATIC
UINT64
ExecuteNEG (
  IN VM_CONTEXT   *VmPtr,
  IN UINT64       Op1,
  IN UINT64       Op2
  )
/*++

Routine Description:
  Execute the EBC NEG instruction

Arguments:
  VmPtr     - pointer to a VM context  
  Op1       - Operand 1 from the instruction 
  Op2       - Operand 2 from the instruction

Returns:
  Op2 * -1

Instruction syntax:
  NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}

--*/
{
  return ~Op2 + 1;
}

STATIC
UINT64
ExecuteADD (
  IN VM_CONTEXT   *VmPtr,
  IN UINT64       Op1,
  IN UINT64       Op2
  )
/*++

Routine Description:
  
  Execute the EBC ADD instruction

Arguments:
  VmPtr     - pointer to a VM context  
  Op1       - Operand 1 from the instruction 
  Op2       - Operand 2 from the instruction

Returns:
  Op1 + Op2

Instruction syntax:
   ADD[32|64] {@}R1, {@}R2 {Index16}

--*/
{
  return Op1 + Op2;
}

STATIC
UINT64
ExecuteSUB (
  IN VM_CONTEXT   *VmPtr,
  IN UINT64       Op1,
  IN UINT64       Op2
  )
/*++

Routine Description:
  Execute the EBC SUB instruction

Arguments:
  VmPtr     - pointer to a VM context  
  Op1       - Operand 1 from the instruction 
  Op2       - Operand 2 from the instruction

Returns:
  Op1 - Op2
  Standard EFI_STATUS

Instruction syntax:
  SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}

--*/
{
  if (*VmPtr->Ip & DATAMANIP_M_64) {
    return (UINT64) ((INT64) ((INT64) Op1 - (INT64) Op2));
  } else {
    return (UINT64) ((INT64) ((INT32) Op1 - (INT32) Op2));
  }
}

STATIC
UINT64
ExecuteMUL (
  IN VM_CONTEXT   *VmPtr,
  IN UINT64       Op1,
  IN UINT64       Op2
  )
/*++

Routine Description:
  
  Execute the EBC MUL instruction

Arguments:
  VmPtr   - pointer to a VM context  
  Op1       - Operand 1 from the instruction 
  Op2       - Operand 2 from the instruction

Returns:
  Op1 * Op2

Instruction syntax:
  MUL[32|64] {@}R1, {@}R2 {Index16|Immed16}

--*/
{
  INT64 ResultHigh;

  if (*VmPtr->Ip & DATAMANIP_M_64) {
    return MulS64x64 (Op1, Op2, &ResultHigh);
  } else {
    return (UINT64) ((INT64) ((INT32) Op1 * (INT32) Op2));
  }
}

STATIC
UINT64
ExecuteMULU (
  IN VM_CONTEXT   *VmPtr,
  IN UINT64       Op1,
  IN UINT64       Op2
  )
/*++

Routine Description:
  Execute the EBC MULU instruction

Arguments:
  VmPtr   - pointer to a VM context  
  Op1       - Operand 1 from the instruction 
  Op2       - Operand 2 from the instruction

Returns:
  (unsigned)Op1 * (unsigned)Op2 

Instruction

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?