ebcexecute.c

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

C
2,978
字号
  32-bit machines, the value gets sign-extended to 64 bits if the destination
  is a register.

Arguments:

  VmPtr   - pointer to a VM context  

Returns:

  Standard EFI_STATUS

Instruction syntax:

  MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}

  0:7 1=>operand1 index present
  0:6 1=>operand2 index present

--*/
{
  UINT8   Opcode;
  UINT8   Operands;
  UINT8   Size;
  INT16   Op1Index;
  INT16   Op2Index;
  UINT64  Op2;

  //
  // Get the opcode and operand bytes
  //
  Opcode              = GETOPCODE (VmPtr);
  Operands            = GETOPERANDS (VmPtr);

  Op1Index            = Op2Index = 0;

  //
  // Get the indexes if present.
  //
  Size = 2;
  if (Opcode & OPCODE_M_IMMED_OP1) {
    if (OPERAND1_INDIRECT (Operands)) {
      Op1Index = VmReadIndex16 (VmPtr, 2);
    } else {
      //
      // Illegal form operand1 direct with index:  MOVsnw R1 Index16, {@}R2
      //
      EbcDebugSignalException (
        EXCEPT_EBC_INSTRUCTION_ENCODING,
        EXCEPTION_FLAG_FATAL,
        VmPtr
        );
      return EFI_UNSUPPORTED;
    }

    Size += sizeof (UINT16);
  }

  if (Opcode & OPCODE_M_IMMED_OP2) {
    if (OPERAND2_INDIRECT (Operands)) {
      Op2Index = VmReadIndex16 (VmPtr, Size);
    } else {
      Op2Index = VmReadImmed16 (VmPtr, Size);
    }

    Size += sizeof (UINT16);
  }
  //
  // Get the data from the source.
  //
  Op2 = (INT64) ((INTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Op2Index));
  if (OPERAND2_INDIRECT (Operands)) {
    Op2 = (INT64) (INTN) VmReadMemN (VmPtr, (UINTN) Op2);
  }
  //
  // Now write back the result.
  //
  if (!OPERAND1_INDIRECT (Operands)) {
    VmPtr->R[OPERAND1_REGNUM (Operands)] = Op2;
  } else {
    VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);
  }
  //
  // Advance the instruction pointer
  //
  VmPtr->Ip += Size;
  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
ExecuteMOVsnd (
  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
  32-bit machines, the value gets sign-extended to 64 bits if the destination
  is a register.

Arguments:

  VmPtr   - pointer to a VM context  

Returns:

  Standard EFI_STATUS

Instruction syntax:

  MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}

  0:7 1=>operand1 index present
  0:6 1=>operand2 index present

--*/
{
  UINT8   Opcode;
  UINT8   Operands;
  UINT8   Size;
  INT32   Op1Index;
  INT32   Op2Index;
  UINT64  Op2;

  //
  // Get the opcode and operand bytes
  //
  Opcode              = GETOPCODE (VmPtr);
  Operands            = GETOPERANDS (VmPtr);

  Op1Index            = Op2Index = 0;

  //
  // Get the indexes if present.
  //
  Size = 2;
  if (Opcode & OPCODE_M_IMMED_OP1) {
    if (OPERAND1_INDIRECT (Operands)) {
      Op1Index = VmReadIndex32 (VmPtr, 2);
    } else {
      //
      // Illegal form operand1 direct with index:  MOVsnd R1 Index16,..
      //
      EbcDebugSignalException (
        EXCEPT_EBC_INSTRUCTION_ENCODING,
        EXCEPTION_FLAG_FATAL,
        VmPtr
        );
      return EFI_UNSUPPORTED;
    }

    Size += sizeof (UINT32);
  }

  if (Opcode & OPCODE_M_IMMED_OP2) {
    if (OPERAND2_INDIRECT (Operands)) {
      Op2Index = VmReadIndex32 (VmPtr, Size);
    } else {
      Op2Index = VmReadImmed32 (VmPtr, Size);
    }

    Size += sizeof (UINT32);
  }
  //
  // Get the data from the source.
  //
  Op2 = (INT64) ((INTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Op2Index));
  if (OPERAND2_INDIRECT (Operands)) {
    Op2 = (INT64) (INTN) VmReadMemN (VmPtr, (UINTN) Op2);
  }
  //
  // Now write back the result.
  //
  if (!OPERAND1_INDIRECT (Operands)) {
    VmPtr->R[OPERAND1_REGNUM (Operands)] = Op2;
  } else {
    VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);
  }
  //
  // Advance the instruction pointer
  //
  VmPtr->Ip += Size;
  return EFI_SUCCESS;
}

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

Routine Description:
  Execute the EBC PUSHn instruction

Arguments:
  VmPtr   - pointer to a VM context  

Returns:
  Standard EFI_STATUS

Instruction syntax:
   PUSHn {@}R1 {Index16|Immed16}

--*/
{
  UINT8 Opcode;
  UINT8 Operands;
  INT16 Index16;
  UINTN DataN;

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

  //
  // Get index if present
  //
  if (Opcode & PUSHPOP_M_IMMDATA) {
    if (OPERAND1_INDIRECT (Operands)) {
      Index16 = VmReadIndex16 (VmPtr, 2);
    } else {
      Index16 = VmReadImmed16 (VmPtr, 2);
    }

    VmPtr->Ip += 4;
  } else {
    Index16 = 0;
    VmPtr->Ip += 2;
  }
  //
  // Get the data to push
  //
  if (OPERAND1_INDIRECT (Operands)) {
    DataN = VmReadMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16));
  } else {
    DataN = (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16);
  }
  //
  // Adjust the stack down.
  //
  VmPtr->R[0] -= sizeof (UINTN);
  VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], DataN);
  return EFI_SUCCESS;
}

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

Routine Description:
  Execute the EBC PUSH instruction

Arguments:
  VmPtr   - pointer to a VM context  

Returns:
  Standard EFI_STATUS

Instruction syntax:
   PUSH[32|64] {@}R1 {Index16|Immed16}

--*/
{
  UINT8   Opcode;
  UINT8   Operands;
  UINT32  Data32;
  UINT64  Data64;
  INT16   Index16;

  //
  // Get opcode and operands
  //
  Opcode    = GETOPCODE (VmPtr);
  Operands  = GETOPERANDS (VmPtr);
  //
  // Get immediate index if present, then advance the IP.
  //
  if (Opcode & PUSHPOP_M_IMMDATA) {
    if (OPERAND1_INDIRECT (Operands)) {
      Index16 = VmReadIndex16 (VmPtr, 2);
    } else {
      Index16 = VmReadImmed16 (VmPtr, 2);
    }

    VmPtr->Ip += 4;
  } else {
    Index16 = 0;
    VmPtr->Ip += 2;
  }
  //
  // Get the data to push
  //
  if (Opcode & PUSHPOP_M_64) {
    if (OPERAND1_INDIRECT (Operands)) {
      Data64 = VmReadMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16));
    } else {
      Data64 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;
    }
    //
    // Adjust the stack down, then write back the data
    //
    VmPtr->R[0] -= sizeof (UINT64);
    VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], Data64);
  } else {
    //
    // 32-bit data
    //
    if (OPERAND1_INDIRECT (Operands)) {
      Data32 = VmReadMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16));
    } else {
      Data32 = (UINT32) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;
    }
    //
    // Adjust the stack down and write the data
    //
    VmPtr->R[0] -= sizeof (UINT32);
    VmWriteMem32 (VmPtr, (UINTN) VmPtr->R[0], Data32);
  }

  return EFI_SUCCESS;
}

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

Routine Description:
  Execute the EBC POPn instruction

Arguments:
  VmPtr   - pointer to a VM context  

Returns:
  Standard EFI_STATUS

Instruction syntax:
   POPn {@}R1 {Index16|Immed16}

--*/
{
  UINT8 Opcode;
  UINT8 Operands;
  INT16 Index16;
  UINTN DataN;

  //
  // Get opcode and operands
  //
  Opcode    = GETOPCODE (VmPtr);
  Operands  = GETOPERANDS (VmPtr);
  //
  // Get immediate data if present, and advance the IP
  //
  if (Opcode & PUSHPOP_M_IMMDATA) {
    if (OPERAND1_INDIRECT (Operands)) {
      Index16 = VmReadIndex16 (VmPtr, 2);
    } else {
      Index16 = VmReadImmed16 (VmPtr, 2);
    }

    VmPtr->Ip += 4;
  } else {
    Index16 = 0;
    VmPtr->Ip += 2;
  }
  //
  // Read the data off the stack, then adjust the stack pointer
  //
  DataN = VmReadMemN (VmPtr, (UINTN) VmPtr->R[0]);
  VmPtr->R[0] += sizeof (UINTN);
  //
  // Do the write-back
  //
  if (OPERAND1_INDIRECT (Operands)) {
    VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), DataN);
  } else {
    VmPtr->R[OPERAND1_REGNUM (Operands)] = (INT64) (UINT64) ((UINTN) DataN + Index16);
  }

  return EFI_SUCCESS;
}

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

Routine Description:
  Execute the EBC POP instruction

Arguments:
  VmPtr   - pointer to a VM context  

Returns:
  Standard EFI_STATUS

Instruction syntax:
  POP {@}R1 {Index16|Immed16}

--*/
{
  UINT8   Opcode;
  UINT8   Operands;
  INT16   Index16;
  INT32   Data32;
  UINT64  Data64;

  //
  // Get opcode and operands
  //
  Opcode    = GETOPCODE (VmPtr);
  Operands  = GETOPERANDS (VmPtr);
  //
  // Get immediate data if present, and advance the IP.
  //
  if (Opcode & PUSHPOP_M_IMMDATA) {
    if (OPERAND1_INDIRECT (Operands)) {
      Index16 = VmReadIndex16 (VmPtr, 2);
    } else {
      Index16 = VmReadImmed16 (VmPtr, 2);
    }

    VmPtr->Ip += 4;
  } else {
    Index16 = 0;
    VmPtr->Ip += 2;
  }
  //
  // Get the data off the stack, then write it to the appropriate location
  //
  if (Opcode & PUSHPOP_M_64) {
    //
    // Read the data off the stack, then adjust the stack pointer
    //
    Data64 = VmReadMem64 (VmPtr, (UINTN) VmPtr->R[0]);
    VmPtr->R[0] += sizeof (UINT64);
    //
    // Do the write-back
    //
    if (OPERAND1_INDIRECT (Operands)) {
      VmWriteMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), Data64);
    } else {
      VmPtr->R[OPERAND1_REGNUM (Operands)] = Data64 + Index16;
    }
  } else {
    //
    // 32-bit pop. Read it off the stack and adjust the stack pointer
    //
    Data32 = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->R[0]);
    VmPtr->R[0] += sizeof (UINT32);
    //
    // Do the write-back
    //
    if (OPERAND1_INDIRECT (Operands)) {
      VmWriteMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), Data32);
    } else {
      VmPtr->R[OPERAND1_REGNUM (Operands)] = (INT64) Data32 + Index16;
    }
  }

  return EFI_SUCCESS;
}

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

Routine Description:
  Implements the EBC CALL instruction.

  Instruction format:  

    CALL64 Immed64
    CALL32 {@}R1 {Immed32|Index32}
    CALLEX64 Immed64
    CALLEX16 {@}R1 {Immed32}

  If Rx == R0, then it's a PC relative call to PC = PC + imm32.
  
Arguments:
  VmPtr - pointer to a VM context.

Returns:
  Standard EFI_STATUS

--*/
{
  UINT8 Opcode;
  UINT8 Operands;
  INT32 Immed32;
  UINT8 Size;
  INT64 Immed64;
  VOID  *FramePtr;

  //
  // Get opcode and operands
  //
  Opcode    = GETOPCODE (VmPtr);
  Operands  = GETOPERANDS (VmPtr);
  //
  // Assign these as well to avoid compiler warnings
  //
  Immed64   = 0;
  Immed32   = 0;

  FramePtr  = VmPtr->FramePtr;
  //
  // Determine the instruction size, and get immediate data if present
  //
  if (Opcode & OPCODE_M_IMMDATA) {
    if (Opcode & OPCODE_M_IMMDATA64) {
      Immed64 = VmReadImmed64 (VmPtr, 2);
      Size    = 10;
    } else {
      //
      // If register operand is indirect, then the immediate data is an index
      //
      if (OPERAND1_INDIRECT (Operands)) {
        Immed32 = VmReadIndex32 (VmPtr, 2);
      } else {
        Immed32 = VmReadImmed32 (VmPtr, 2);
      }

      Size = 6;
    }
  } else {
    Size = 2;
  }
  //
  // If it's a call to EBC, adjust the stack pointer down 16 bytes and
  // put our return address and frame pointer on the VM stack.
  //
  if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
    VmPtr->R[0] -= 8;
    VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr);
    VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0];
    VmPtr->R[0] -= 8;
    VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (VmPtr->Ip + Size));
  }
  //
  // If 64-bit data, then absolute jump only
  //
  if (Opcode & OPCODE_M_IMMDATA64) {
    //
    // Native or EBC call?
    //
    if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
      VmPtr->Ip = (VMIP) (UINTN) Immed64;
    } else {
      //
      // Call external function, get the return value, and advance the IP
      //
      EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->R[0], FramePtr, Size);
    }
  } else {
    //
    // Get the register data. If operand1 == 0, then ignore register and
    // take immediate data as relative or absolute address.
    // Compiler should take care of upper bits if 32-bit machine.
    //
    if (OPERAND1_REGNUM (Operands) != 0) {
      Immed64 = (UINT64) (UINTN) VmPtr->R[OPERAND1_REGNUM (Operands)];
    }
    //
    // Get final address
    //
    if (OPERAND1_INDIRECT (Operands)) {
      Immed64 = (INT64) (UINT64) (UINTN) VmReadMemN (VmPtr, (UINTN) (Immed64 + Immed32));
    } else {
      Immed64 += Immed32;
    }
    //
    // Now determine if external call, and then if relative or absolute
    //
    if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
      //
      // EBC call. Relative or absolute? If relative, then it's relative to the
      // start of the next instruction.
      //
      if (Operands & OPERAND_M_RELATIVE_ADDR) {

⌨️ 快捷键说明

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