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 + -
显示快捷键?