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 /** @file
This module contains EBC support routines that are customized based on 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> Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
@ -23,10 +23,47 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
// platform-specific configurations. // platform-specific configurations.
// //
#define VM_STACK_SIZE (1024 * 4) #define VM_STACK_SIZE (1024 * 4)
#define EBC_THUNK_SIZE 32
#define STACK_REMAIN_SIZE (1024 * 4) #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. Begin executing an EBC image.
This is used for Ebc Thunk call. This is used for Ebc Thunk call.
@ -79,54 +116,37 @@ EbcLLCALLEX (
{ {
UINTN IsThunk; UINTN IsThunk;
UINTN TargetEbcAddr; UINTN TargetEbcAddr;
UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];
UINTN Index;
UINTN IndexOfEbcEntrypoint;
IsThunk = 1; IsThunk = 1;
TargetEbcAddr = 0; TargetEbcAddr = 0;
IndexOfEbcEntrypoint = 0;
// //
// Processor specific code to check whether the callee is a thunk to EBC. // Processor specific code to check whether the callee is a thunk to EBC.
// //
if (*((UINT8 *)FuncAddr) != 0xB8) { CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));
IsThunk = 0; //
goto Action; // 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 (*((UINT8 *)FuncAddr + 1) != 0xBC) { if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
IsThunk = 0; *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;
goto Action;
} }
if (*((UINT8 *)FuncAddr + 2) != 0x2E) {
IsThunk = 0;
goto Action;
} }
if (*((UINT8 *)FuncAddr + 3) != 0x11) { //
// Check if we need thunk to native
//
if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {
IsThunk = 0; 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){ if (IsThunk == 1){
// //
// The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
@ -139,11 +159,12 @@ Action:
VmPtr->Gpr[0] -= 8; VmPtr->Gpr[0] -= 8;
VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (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; VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
} else { } else {
// //
// The callee is not a thunk to EBC, call native code, // 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); VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
@ -449,8 +470,6 @@ EbcCreateThunks (
UINT8 *Ptr; UINT8 *Ptr;
UINT8 *ThunkBase; UINT8 *ThunkBase;
UINT32 Index; UINT32 Index;
UINT32 Addr;
INT32 Size;
INT32 ThunkSize; INT32 ThunkSize;
// //
@ -460,10 +479,9 @@ EbcCreateThunks (
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
Size = EBC_THUNK_SIZE; ThunkSize = sizeof(mInstructionBufferTemplate);
ThunkSize = Size;
Ptr = AllocatePool (Size); Ptr = AllocatePool (sizeof(mInstructionBufferTemplate));
if (Ptr == NULL) { if (Ptr == NULL) {
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
@ -481,74 +499,26 @@ EbcCreateThunks (
*Thunk = (VOID *) Ptr; *Thunk = (VOID *) Ptr;
// //
// Add a magic code here to help the VM recognize the thunk.. // Copy whole thunk instruction buffer template
// mov eax, 0xca112ebc => B8 BC 2E 11 CA
// //
*Ptr = 0xB8; CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));
Ptr++;
Size--;
Addr = (UINT32) 0xCA112EBC;
for (Index = 0; Index < sizeof (Addr); Index++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
// //
// Add code bytes to load up a processor register with the EBC entry point. // Patch EbcEntryPoint and EbcLLEbcInterpret
// mov eax, 0xaa55aa55 => B8 55 AA 55 AA
// The first 8 bytes of the thunk entry is the address of the EBC
// entry point.
// //
*Ptr = 0xB8; for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
Ptr++; if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {
Size--; *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;
Addr = (UINT32) EbcEntryPoint;
for (Index = 0; Index < sizeof (Addr); Index++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
} }
// if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
// 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) { if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
Addr = (UINT32) (UINTN) EbcLLExecuteEbcImageEntryPoint; *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;
} else { } else {
Addr = (UINT32) (UINTN) EbcLLEbcInterpret; *(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 // Add the thunk to the list for this image. Do this last since the add
// function flushes the cache for us. // 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. // platform-specific configurations.
// //
#define VM_STACK_SIZE (1024 * 8) #define VM_STACK_SIZE (1024 * 8)
#define EBC_THUNK_SIZE 64
#define STACK_REMAIN_SIZE (1024 * 4) #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. Begin executing an EBC image.
This is used for Ebc Thunk call. This is used for Ebc Thunk call.
@ -382,8 +427,6 @@ EbcCreateThunks (
UINT8 *Ptr; UINT8 *Ptr;
UINT8 *ThunkBase; UINT8 *ThunkBase;
UINT32 Index; UINT32 Index;
UINT64 Addr;
INT32 Size;
INT32 ThunkSize; INT32 ThunkSize;
// //
@ -393,10 +436,9 @@ EbcCreateThunks (
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
Size = EBC_THUNK_SIZE; ThunkSize = sizeof(mInstructionBufferTemplate);
ThunkSize = Size;
Ptr = AllocatePool (Size); Ptr = AllocatePool (sizeof(mInstructionBufferTemplate));
if (Ptr == NULL) { if (Ptr == NULL) {
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
@ -414,89 +456,26 @@ EbcCreateThunks (
*Thunk = (VOID *) Ptr; *Thunk = (VOID *) Ptr;
// //
// Add a magic code here to help the VM recognize the thunk.. // Copy whole thunk instruction buffer template
// mov rax, ca112ebccall2ebch => 48 B8 BC 2E 11 CA BC 2E 11 CA
// //
*Ptr = 0x48; CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));
Ptr++;
Size--;
*Ptr = 0xB8;
Ptr++;
Size--;
Addr = (UINT64) 0xCA112EBCCA112EBCULL;
for (Index = 0; Index < sizeof (Addr); Index++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
// //
// Add code bytes to load up a processor register with the EBC entry point. // Patch EbcEntryPoint and EbcLLEbcInterpret
// 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.
// //
*Ptr = 0x49; for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
Ptr++; if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {
Size--; *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;
*Ptr = 0xBA;
Ptr++;
Size--;
Addr = (UINT64) EbcEntryPoint;
for (Index = 0; Index < sizeof (Addr); Index++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
} }
if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
//
// 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) { if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
Addr = (UINTN) EbcLLExecuteEbcImageEntryPoint; *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;
} else { } else {
Addr = (UINTN) EbcLLEbcInterpret; *(UINTN *)&Ptr[Index] = (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 // Add the thunk to the list for this image. Do this last since the add
// function flushes the cache for us. // function flushes the cache for us.
@ -533,65 +512,37 @@ EbcLLCALLEX (
{ {
UINTN IsThunk; UINTN IsThunk;
UINTN TargetEbcAddr; UINTN TargetEbcAddr;
UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];
UINTN Index;
UINTN IndexOfEbcEntrypoint;
IsThunk = 1; IsThunk = 1;
TargetEbcAddr = 0; TargetEbcAddr = 0;
IndexOfEbcEntrypoint = 0;
// //
// Processor specific code to check whether the callee is a thunk to EBC. // Processor specific code to check whether the callee is a thunk to EBC.
// //
if (*((UINT8 *)FuncAddr) != 0x48) { CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));
IsThunk = 0; //
goto Action; // 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 (*((UINT8 *)FuncAddr + 1) != 0xB8) { if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
IsThunk = 0; *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;
goto Action;
} }
if (*((UINT8 *)FuncAddr + 2) != 0xBC) {
IsThunk = 0;
goto Action;
} }
if (*((UINT8 *)FuncAddr + 3) != 0x2E) { //
// Check if we need thunk to native
//
if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {
IsThunk = 0; 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){ if (IsThunk == 1){
// //
// The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and // 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); VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0]; VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
VmPtr->Gpr[0] -= 8; 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; VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
} else { } else {
// //