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