ebcexecute.c

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

C
2,978
字号
  // Advance IP
  //
  VmPtr->Ip += 2;
  return EFI_SUCCESS;
}

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

Routine Description:
  Execute the JMP instruction

Arguments:
  VmPtr      - pointer to VM context

Returns:
  Standard EFI_STATUS

Instruction syntax:
  JMP64{cs|cc} Immed64
  JMP32{cs|cc} {@}R1 {Immed32|Index32}

Encoding:
  b0.7 -  immediate data present
  b0.6 -  1 = 64 bit immediate data
          0 = 32 bit immediate data
  b1.7 -  1 = conditional
  b1.6    1 = CS (condition set)
          0 = CC (condition clear)
  b1.4    1 = relative address
          0 = absolute address
  b1.3    1 = operand1 indirect
  b1.2-0  operand 1

--*/
{
  UINT8   Opcode;
  UINT8   CompareSet;
  UINT8   ConditionFlag;
  UINT8   Size;
  UINT8   Operand;
  UINT64  Data64;
  INT32   Index32;
  UINTN   Addr;

  Operand = GETOPERANDS (VmPtr);
  Opcode  = GETOPCODE (VmPtr);

  //
  // Get instruction length from the opcode. The upper two bits are used here
  // to index into the length array.
  //
  Size = mJMPLen[(Opcode >> 6) & 0x03];

  //
  // Decode instruction conditions
  // If we haven't met the condition, then simply advance the IP and return.
  //
  CompareSet    = (UINT8) ((Operand & JMP_M_CS) ? 1 : 0);
  ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);
  if (Operand & CONDITION_M_CONDITIONAL) {
    if (CompareSet != ConditionFlag) {
      VmPtr->Ip += Size;
      return EFI_SUCCESS;
    }
  }
  //
  // Check for 64-bit form and do it right away since it's the most
  // straight-forward form.
  //
  if (Opcode & OPCODE_M_IMMDATA64) {
    //
    // Double check for immediate-data, which is required. If not there,
    // then signal an exception
    //
    if (!(Opcode & OPCODE_M_IMMDATA)) {
      EbcDebugSignalException (
        EXCEPT_EBC_INSTRUCTION_ENCODING,
        EXCEPTION_FLAG_ERROR,
        VmPtr
        );
      return EFI_UNSUPPORTED;
    }
    //
    // 64-bit immediate data is full address. Read the immediate data,
    // check for alignment, and jump absolute.
    //
    Data64 = VmReadImmed64 (VmPtr, 2);
    if (!IS_ALIGNED ((UINTN) Data64, sizeof (UINT16))) {
      EbcDebugSignalException (
        EXCEPT_EBC_ALIGNMENT_CHECK,
        EXCEPTION_FLAG_FATAL,
        VmPtr
        );

      return EFI_UNSUPPORTED;
    }

    //
    // Take jump -- relative or absolute
    //
    if (Operand & JMP_M_RELATIVE) {
      VmPtr->Ip += (UINTN) Data64 + Size;
    } else {
      VmPtr->Ip = (VMIP) (UINTN) Data64;
    }

    return EFI_SUCCESS;
  }
  //
  // 32-bit forms:
  // Get the index if there is one. May be either an index, or an immediate
  // offset depending on indirect operand.
  //   JMP32 @R1 Index32 -- immediate data is an index
  //   JMP32 R1 Immed32  -- immedate data is an offset
  //
  if (Opcode & OPCODE_M_IMMDATA) {
    if (OPERAND1_INDIRECT (Operand)) {
      Index32 = VmReadIndex32 (VmPtr, 2);
    } else {
      Index32 = VmReadImmed32 (VmPtr, 2);
    }
  } else {
    Index32 = 0;
  }
  //
  // Get the register data. If R == 0, then special case where it's ignored.
  //
  if (OPERAND1_REGNUM (Operand) == 0) {
    Data64 = 0;
  } else {
    Data64 = OPERAND1_REGDATA (VmPtr, Operand);
  }
  //
  // Decode the forms
  //
  if (OPERAND1_INDIRECT (Operand)) {
    //
    // Form: JMP32 @Rx {Index32}
    //
    Addr = VmReadMemN (VmPtr, (UINTN) Data64 + Index32);
    if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
      EbcDebugSignalException (
        EXCEPT_EBC_ALIGNMENT_CHECK,
        EXCEPTION_FLAG_FATAL,
        VmPtr
        );

      return EFI_UNSUPPORTED;
    }

    if (Operand & JMP_M_RELATIVE) {
      VmPtr->Ip += (UINTN) Addr + Size;
    } else {
      VmPtr->Ip = (VMIP) Addr;
    }
  } else {
    //
    // Form: JMP32 Rx {Immed32}
    //
    Addr = (UINTN) (Data64 + Index32);
    if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
      EbcDebugSignalException (
        EXCEPT_EBC_ALIGNMENT_CHECK,
        EXCEPTION_FLAG_FATAL,
        VmPtr
        );

      return EFI_UNSUPPORTED;
    }

    if (Operand & JMP_M_RELATIVE) {
      VmPtr->Ip += (UINTN) Addr + Size;
    } else {
      VmPtr->Ip = (VMIP) Addr;
    }
  }

  return EFI_SUCCESS;
}

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

Routine Description:
  Execute the EBC JMP8 instruction

Arguments:
  VmPtr   - pointer to a VM context  

Returns:
  Standard EFI_STATUS

Instruction syntax:
  JMP8{cs|cc}  Offset/2

--*/
{
  UINT8 Opcode;
  UINT8 ConditionFlag;
  UINT8 CompareSet;
  INT8  Offset;

  //
  // Decode instruction.
  //
  Opcode        = GETOPCODE (VmPtr);
  CompareSet    = (UINT8) ((Opcode & JMP_M_CS) ? 1 : 0);
  ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);

  //
  // If we haven't met the condition, then simply advance the IP and return
  //
  if (Opcode & CONDITION_M_CONDITIONAL) {
    if (CompareSet != ConditionFlag) {
      VmPtr->Ip += 2;
      return EFI_SUCCESS;
    }
  }
  //
  // Get the offset from the instruction stream. It's relative to the
  // following instruction, and divided by 2.
  //
  Offset = VmReadImmed8 (VmPtr, 1);
  //
  // Want to check for offset == -2 and then raise an exception?
  //
  VmPtr->Ip += (Offset * 2) + 2;
  return EFI_SUCCESS;
}

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

Routine Description:
  
  Execute the EBC MOVI 

Arguments:

  VmPtr   - pointer to a VM context  

Returns:

  Standard EFI_STATUS

Instruction syntax:

  MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64

  First variable character specifies the move size
  Second variable character specifies size of the immediate data

  Sign-extend the immediate data to the size of the operation, and zero-extend
  if storing to a register.

  Operand1 direct with index/immed is invalid.
    
--*/
{
  UINT8   Opcode;
  UINT8   Operands;
  UINT8   Size;
  INT16   Index16;
  INT64   ImmData64;
  UINT64  Op1;
  UINT64  Mask64;

  //
  // Get the opcode and operands byte so we can get R1 and R2
  //
  Opcode    = GETOPCODE (VmPtr);
  Operands  = GETOPERANDS (VmPtr);

  //
  // Get the index (16-bit) if present
  //
  if (Operands & MOVI_M_IMMDATA) {
    Index16 = VmReadIndex16 (VmPtr, 2);
    Size    = 4;
  } else {
    Index16 = 0;
    Size    = 2;
  }
  //
  // Extract the immediate data. Sign-extend always.
  //
  if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
    ImmData64 = (INT64) (INT16) VmReadImmed16 (VmPtr, Size);
    Size += 2;
  } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
    ImmData64 = (INT64) (INT32) VmReadImmed32 (VmPtr, Size);
    Size += 4;
  } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
    ImmData64 = (INT64) VmReadImmed64 (VmPtr, Size);
    Size += 8;
  } else {
    //
    // Invalid encoding
    //
    EbcDebugSignalException (
      EXCEPT_EBC_INSTRUCTION_ENCODING,
      EXCEPTION_FLAG_FATAL,
      VmPtr
      );
    return EFI_UNSUPPORTED;
  }
  //
  // Now write back the result
  //
  if (!OPERAND1_INDIRECT (Operands)) {
    //
    // Operand1 direct. Make sure it didn't have an index.
    //
    if (Operands & MOVI_M_IMMDATA) {
      EbcDebugSignalException (
        EXCEPT_EBC_INSTRUCTION_ENCODING,
        EXCEPTION_FLAG_FATAL,
        VmPtr
        );
      return EFI_UNSUPPORTED;
    }
    //
    // Writing directly to a register. Clear unused bits.
    //
    if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {
      Mask64 = 0x000000FF;
    } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {
      Mask64 = 0x0000FFFF;
    } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {
      Mask64 = 0x00000000FFFFFFFF;
    } else {
      Mask64 = (UINT64)~0;
    }

    VmPtr->R[OPERAND1_REGNUM (Operands)] = ImmData64 & Mask64;
  } else {
    //
    // Get the address then write back based on size of the move
    //
    Op1 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;
    if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {
      VmWriteMem8 (VmPtr, (UINTN) Op1, (UINT8) ImmData64);
    } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {
      VmWriteMem16 (VmPtr, (UINTN) Op1, (UINT16) ImmData64);
    } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {
      VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) ImmData64);
    } else {
      VmWriteMem64 (VmPtr, (UINTN) Op1, ImmData64);
    }
  }
  //
  // Advance the instruction pointer
  //
  VmPtr->Ip += Size;
  return EFI_SUCCESS;
}

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

Routine Description:
  
  Execute the EBC MOV immediate natural. This instruction moves an immediate
  index value into a register or memory location.

Arguments:

  VmPtr   - pointer to a VM context  

Returns:

  Standard EFI_STATUS

Instruction syntax:

  MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64

--*/
{
  UINT8   Opcode;
  UINT8   Operands;
  UINT8   Size;
  INT16   Index16;
  INT16   ImmedIndex16;
  INT32   ImmedIndex32;
  INT64   ImmedIndex64;
  UINT64  Op1;

  //
  // Get the opcode and operands byte so we can get R1 and R2
  //
  Opcode    = GETOPCODE (VmPtr);
  Operands  = GETOPERANDS (VmPtr);

  //
  // Get the operand1 index (16-bit) if present
  //
  if (Operands & MOVI_M_IMMDATA) {
    Index16 = VmReadIndex16 (VmPtr, 2);
    Size    = 4;
  } else {
    Index16 = 0;
    Size    = 2;
  }
  //
  // Extract the immediate data and convert to a 64-bit index.
  //
  if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
    ImmedIndex16  = VmReadIndex16 (VmPtr, Size);
    ImmedIndex64  = (INT64) ImmedIndex16;
    Size += 2;
  } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
    ImmedIndex32  = VmReadIndex32 (VmPtr, Size);
    ImmedIndex64  = (INT64) ImmedIndex32;
    Size += 4;
  } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
    ImmedIndex64 = VmReadIndex64 (VmPtr, Size);
    Size += 8;
  } else {
    //
    // Invalid encoding
    //
    EbcDebugSignalException (
      EXCEPT_EBC_INSTRUCTION_ENCODING,
      EXCEPTION_FLAG_FATAL,
      VmPtr
      );
    return EFI_UNSUPPORTED;
  }
  //
  // Now write back the result
  //
  if (!OPERAND1_INDIRECT (Operands)) {
    //
    // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
    // is illegal
    //
    if (Operands & MOVI_M_IMMDATA) {
      EbcDebugSignalException (
        EXCEPT_EBC_INSTRUCTION_ENCODING,
        EXCEPTION_FLAG_FATAL,
        VmPtr
        );
      return EFI_UNSUPPORTED;
    }

    VmPtr->R[OPERAND1_REGNUM (Operands)] = ImmedIndex64;
  } else {
    //
    // Get the address
    //
    Op1 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;
    VmWriteMemN (VmPtr, (UINTN) Op1, (INTN) ImmedIndex64);
  }
  //
  // Advance the instruction pointer
  //
  VmPtr->Ip += Size;
  return EFI_SUCCESS;
}

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

Routine Description:
  
  Execute the EBC MOVREL instruction.
  Dest <- Ip + ImmData

Arguments:

  VmPtr   - pointer to a VM context  

Returns:

  Standard EFI_STATUS

Instruction syntax:

  MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64

--*/
{
  UINT8   Opcode;
  UINT8   Operands;
  UINT8   Size;
  INT16   Index16;
  INT64   ImmData64;
  UINT64  Op1;
  UINT64  Op2;

  //
  // Get the opcode and operands byte so we can get R1 and R2
  //
  Opcode    = GETOPCODE (VmPtr);
  Operands  = GETOPERANDS (VmPtr);

  //
  // Get the Operand 1 index (16-bit) if present
  //
  if (Operands & MOVI_M_IMMDATA) {
    Index16 = VmReadIndex16 (VmPtr, 2);
    Size    = 4;
  } else {
    Index16 = 0;
    Size    = 2;
  }
  //
  // Get the immediate data.
  //
  if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
    ImmData64 = (INT64) VmReadImmed16 (VmPtr, Size);
    Size += 2;
  } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
    ImmData64 = (INT64) VmReadImmed32 (VmPtr, Size);
    Size += 4;
  } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
    ImmData64 = VmReadImmed64 (VmPtr, Size);
    Size += 8;
  } else {
    //
    // Invalid encoding
    //
    EbcDebugSignalException (
      EXCEPT_EBC_INSTRUCTION_ENCODING,
      EXCEPTION_FLAG_FATAL,
      VmPtr
      );
    return EFI_UNSUPPORTED;
  }
  //
  // Compute the value and write back the result
  //
  Op2 = (UINT64) ((INT64) ((UINT64) (UINTN) VmPtr->Ip) + (INT64) ImmData64 + Size);
  if (!OPERAND1_INDIRECT (Operands)) {
    //
    // Check for illegal combination of operand1 direct with immediate data
    //
    if (Operands & MOVI_M_IMMDATA) {
      EbcDebugSignalException (
        EXCEPT_EBC_INSTRUCTION_ENCODING,
        EXCEPTION_FLAG_FATAL,
        VmPtr
        );
      return EFI_UNSUPPORTED;
    }

    VmPtr->R[OPERAND1_REGNUM (Operands)] = (VM_REGISTER) Op2;
  } else {
    //
    // Get the address = [Rx] + Index16
    // Write back the result. Always a natural size write, since
    // we're talking addresses here.
    //
    Op1 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;
    VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN) Op2);
  }
  //
  // Advance the instruction pointer
  //
  VmPtr->Ip += Size;
  return EFI_SUCCESS;
}

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

Routine Description:
  
  Execute the EBC MOVsnw instruction. This instruction loads a signed 
  natural value from memory or register to another memory or register. On

⌨️ 快捷键说明

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