Re-org the EBC thunk code for better code maintenance.

signed-off-by: jyao1
reviewed-by: lgao4


git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12769 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
jyao1 2011-11-23 13:23:34 +00:00
parent 6cf9230ff2
commit 21d13c6156
2 changed files with 161 additions and 239 deletions

View File

@ -1,6 +1,6 @@
/** @file
This module contains EBC support routines that are customized based on
the target processor.
the target ia32 processor.
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
@ -23,10 +23,47 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
// platform-specific configurations.
//
#define VM_STACK_SIZE (1024 * 4)
#define EBC_THUNK_SIZE 32
#define STACK_REMAIN_SIZE (1024 * 4)
//
// This is instruction buffer used to create EBC thunk
//
#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAF
#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFA
UINT8 mInstructionBufferTemplate[] = {
//
// Add a magic code here to help the VM recognize the thunk..
// mov eax, 0xca112ebc => B8 BC 2E 11 CA
//
0xB8, 0xBC, 0x2E, 0x11, 0xCA,
//
// Add code bytes to load up a processor register with the EBC entry point.
// mov eax, EbcEntryPoint => B8 XX XX XX XX (To be fixed at runtime)
// These 4 bytes of the thunk entry is the address of the EBC
// entry point.
//
0xB8,
(UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),
(UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
(UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
(UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
//
// Stick in a load of ecx with the address of appropriate VM function.
// mov ecx, EbcLLEbcInterpret => B9 XX XX XX XX (To be fixed at runtime)
//
0xB9,
(UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),
(UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
(UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
(UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
//
// Stick in jump opcode bytes
// jmp ecx => FF E1
//
0xFF, 0xE1,
};
/**
Begin executing an EBC image.
This is used for Ebc Thunk call.
@ -79,54 +116,37 @@ EbcLLCALLEX (
{
UINTN IsThunk;
UINTN TargetEbcAddr;
UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];
UINTN Index;
UINTN IndexOfEbcEntrypoint;
IsThunk = 1;
TargetEbcAddr = 0;
IndexOfEbcEntrypoint = 0;
//
// Processor specific code to check whether the callee is a thunk to EBC.
//
if (*((UINT8 *)FuncAddr) != 0xB8) {
IsThunk = 0;
goto Action;
CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));
//
// Fill the signature according to mInstructionBufferTemplate
//
for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {
*(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;
IndexOfEbcEntrypoint = Index;
}
if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
*(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;
}
}
if (*((UINT8 *)FuncAddr + 1) != 0xBC) {
//
// Check if we need thunk to native
//
if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 2) != 0x2E) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 3) != 0x11) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 4) != 0xCA) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 5) != 0xB8) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 10) != 0xB9) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 15) != 0xFF) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 16) != 0xE1) {
IsThunk = 0;
goto Action;
}
TargetEbcAddr = ((UINTN)(*((UINT8 *)FuncAddr + 9)) << 24) + ((UINTN)(*((UINT8 *)FuncAddr + 8)) << 16) +
((UINTN)(*((UINT8 *)FuncAddr + 7)) << 8) + ((UINTN)(*((UINT8 *)FuncAddr + 6)));
Action:
if (IsThunk == 1){
//
// The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
@ -139,11 +159,12 @@ Action:
VmPtr->Gpr[0] -= 8;
VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN));
VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
} else {
//
// The callee is not a thunk to EBC, call native code,
// and get return value
// and get return value.
//
VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
@ -449,8 +470,6 @@ EbcCreateThunks (
UINT8 *Ptr;
UINT8 *ThunkBase;
UINT32 Index;
UINT32 Addr;
INT32 Size;
INT32 ThunkSize;
//
@ -460,10 +479,9 @@ EbcCreateThunks (
return EFI_INVALID_PARAMETER;
}
Size = EBC_THUNK_SIZE;
ThunkSize = Size;
ThunkSize = sizeof(mInstructionBufferTemplate);
Ptr = AllocatePool (Size);
Ptr = AllocatePool (sizeof(mInstructionBufferTemplate));
if (Ptr == NULL) {
return EFI_OUT_OF_RESOURCES;
@ -481,74 +499,26 @@ EbcCreateThunks (
*Thunk = (VOID *) Ptr;
//
// Add a magic code here to help the VM recognize the thunk..
// mov eax, 0xca112ebc => B8 BC 2E 11 CA
// Copy whole thunk instruction buffer template
//
*Ptr = 0xB8;
Ptr++;
Size--;
Addr = (UINT32) 0xCA112EBC;
for (Index = 0; Index < sizeof (Addr); Index++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));
//
// Add code bytes to load up a processor register with the EBC entry point.
// mov eax, 0xaa55aa55 => B8 55 AA 55 AA
// The first 8 bytes of the thunk entry is the address of the EBC
// entry point.
// Patch EbcEntryPoint and EbcLLEbcInterpret
//
*Ptr = 0xB8;
Ptr++;
Size--;
Addr = (UINT32) EbcEntryPoint;
for (Index = 0; Index < sizeof (Addr); Index++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
//
// Stick in a load of ecx with the address of appropriate VM function.
// mov ecx 12345678h => 0xB9 0x78 0x56 0x34 0x12
//
if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
Addr = (UINT32) (UINTN) EbcLLExecuteEbcImageEntryPoint;
} else {
Addr = (UINT32) (UINTN) EbcLLEbcInterpret;
for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {
*(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;
}
if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
*(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;
} else {
*(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;
}
}
}
//
// MOV ecx
//
*Ptr = 0xB9;
Ptr++;
Size--;
for (Index = 0; Index < sizeof (Addr); Index++) {
*Ptr = (UINT8) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
//
// Stick in jump opcode bytes for jmp ecx => 0xFF 0xE1
//
*Ptr = 0xFF;
Ptr++;
Size--;
*Ptr = 0xE1;
Size--;
//
// Double check that our defined size is ok (application error)
//
if (Size < 0) {
ASSERT (FALSE);
return EFI_BUFFER_TOO_SMALL;
}
//
// Add the thunk to the list for this image. Do this last since the add
// function flushes the cache for us.

View File

@ -23,10 +23,55 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
// platform-specific configurations.
//
#define VM_STACK_SIZE (1024 * 8)
#define EBC_THUNK_SIZE 64
#define STACK_REMAIN_SIZE (1024 * 4)
//
// This is instruction buffer used to create EBC thunk
//
#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAFAFAFAFAFull
#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFAFAFAFAFAull
UINT8 mInstructionBufferTemplate[] = {
//
// Add a magic code here to help the VM recognize the thunk..
// mov rax, 0xca112ebcca112ebc => 48 B8 BC 2E 11 CA BC 2E 11 CA
//
0x48, 0xB8, 0xBC, 0x2E, 0x11, 0xCA, 0xBC, 0x2E, 0x11, 0xCA,
//
// Add code bytes to load up a processor register with the EBC entry point.
// mov r10, EbcEntryPoint => 49 BA XX XX XX XX XX XX XX XX (To be fixed at runtime)
// These 8 bytes of the thunk entry is the address of the EBC
// entry point.
//
0x49, 0xBA,
(UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),
(UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
(UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
(UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
(UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),
(UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),
(UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),
(UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),
//
// Stick in a load of r11 with the address of appropriate VM function.
// mov r11, EbcLLEbcInterpret => 49 BB XX XX XX XX XX XX XX XX (To be fixed at runtime)
//
0x49, 0xBB,
(UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),
(UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
(UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
(UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
(UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),
(UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),
(UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),
(UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),
//
// Stick in jump opcode bytes
// jmp r11 => 41 FF E3
//
0x41, 0xFF, 0xE3,
};
/**
Begin executing an EBC image.
This is used for Ebc Thunk call.
@ -382,8 +427,6 @@ EbcCreateThunks (
UINT8 *Ptr;
UINT8 *ThunkBase;
UINT32 Index;
UINT64 Addr;
INT32 Size;
INT32 ThunkSize;
//
@ -393,10 +436,9 @@ EbcCreateThunks (
return EFI_INVALID_PARAMETER;
}
Size = EBC_THUNK_SIZE;
ThunkSize = Size;
ThunkSize = sizeof(mInstructionBufferTemplate);
Ptr = AllocatePool (Size);
Ptr = AllocatePool (sizeof(mInstructionBufferTemplate));
if (Ptr == NULL) {
return EFI_OUT_OF_RESOURCES;
@ -414,89 +456,26 @@ EbcCreateThunks (
*Thunk = (VOID *) Ptr;
//
// Add a magic code here to help the VM recognize the thunk..
// mov rax, ca112ebccall2ebch => 48 B8 BC 2E 11 CA BC 2E 11 CA
// Copy whole thunk instruction buffer template
//
*Ptr = 0x48;
Ptr++;
Size--;
*Ptr = 0xB8;
Ptr++;
Size--;
Addr = (UINT64) 0xCA112EBCCA112EBCULL;
for (Index = 0; Index < sizeof (Addr); Index++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));
//
// Add code bytes to load up a processor register with the EBC entry point.
// mov r10, 123456789abcdef0h => 49 BA F0 DE BC 9A 78 56 34 12
// The first 8 bytes of the thunk entry is the address of the EBC
// entry point.
// Patch EbcEntryPoint and EbcLLEbcInterpret
//
*Ptr = 0x49;
Ptr++;
Size--;
*Ptr = 0xBA;
Ptr++;
Size--;
Addr = (UINT64) EbcEntryPoint;
for (Index = 0; Index < sizeof (Addr); Index++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {
*(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;
}
if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
*(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;
} else {
*(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;
}
}
}
//
// Stick in a load of ecx with the address of appropriate VM function.
// Using r11 because it's a volatile register and won't be used in this
// point.
// mov r11 123456789abcdef0h => 49 BB F0 DE BC 9A 78 56 34 12
//
if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
Addr = (UINTN) EbcLLExecuteEbcImageEntryPoint;
} else {
Addr = (UINTN) EbcLLEbcInterpret;
}
//
// mov r11 Addr => 0x49 0xBB
//
*Ptr = 0x49;
Ptr++;
Size--;
*Ptr = 0xBB;
Ptr++;
Size--;
for (Index = 0; Index < sizeof (Addr); Index++) {
*Ptr = (UINT8) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
//
// Stick in jump opcode bytes for jmp r11 => 0x41 0xFF 0xE3
//
*Ptr = 0x41;
Ptr++;
Size--;
*Ptr = 0xFF;
Ptr++;
Size--;
*Ptr = 0xE3;
Size--;
//
// Double check that our defined size is ok (application error)
//
if (Size < 0) {
ASSERT (FALSE);
return EFI_BUFFER_TOO_SMALL;
}
//
// Add the thunk to the list for this image. Do this last since the add
// function flushes the cache for us.
@ -533,65 +512,37 @@ EbcLLCALLEX (
{
UINTN IsThunk;
UINTN TargetEbcAddr;
UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];
UINTN Index;
UINTN IndexOfEbcEntrypoint;
IsThunk = 1;
TargetEbcAddr = 0;
IndexOfEbcEntrypoint = 0;
//
// Processor specific code to check whether the callee is a thunk to EBC.
//
if (*((UINT8 *)FuncAddr) != 0x48) {
IsThunk = 0;
goto Action;
CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));
//
// Fill the signature according to mInstructionBufferTemplate
//
for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {
*(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;
IndexOfEbcEntrypoint = Index;
}
if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
*(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;
}
}
if (*((UINT8 *)FuncAddr + 1) != 0xB8) {
//
// Check if we need thunk to native
//
if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 2) != 0xBC) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 3) != 0x2E) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 4) != 0x11) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 5) != 0xCA) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 6) != 0xBC) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 7) != 0x2E) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 8) != 0x11) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 9) != 0xCA) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 10) != 0x49) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 11) != 0xBA) {
IsThunk = 0;
goto Action;
}
CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + 12, 8);
Action:
if (IsThunk == 1){
//
// The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
@ -602,8 +553,9 @@ Action:
VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
VmPtr->Gpr[0] -= 8;
VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (VmPtr->Ip + Size));
VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN));
VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
} else {
//