/** @file\r
This module contains EBC support routines that are customized based on\r
- the target processor.\r
+ the target ia32 processor.\r
\r
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
This program and the accompanying materials\r
// platform-specific configurations.\r
//\r
#define VM_STACK_SIZE (1024 * 4)\r
-#define EBC_THUNK_SIZE 32\r
\r
#define STACK_REMAIN_SIZE (1024 * 4)\r
\r
+//\r
+// This is instruction buffer used to create EBC thunk\r
+//\r
+#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAF\r
+#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFA\r
+UINT8 mInstructionBufferTemplate[] = {\r
+ //\r
+ // Add a magic code here to help the VM recognize the thunk..\r
+ // mov eax, 0xca112ebc => B8 BC 2E 11 CA\r
+ //\r
+ 0xB8, 0xBC, 0x2E, 0x11, 0xCA,\r
+ //\r
+ // Add code bytes to load up a processor register with the EBC entry point.\r
+ // mov eax, EbcEntryPoint => B8 XX XX XX XX (To be fixed at runtime)\r
+ // These 4 bytes of the thunk entry is the address of the EBC\r
+ // entry point.\r
+ //\r
+ 0xB8, \r
+ (UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),\r
+ //\r
+ // Stick in a load of ecx with the address of appropriate VM function.\r
+ // mov ecx, EbcLLEbcInterpret => B9 XX XX XX XX (To be fixed at runtime)\r
+ //\r
+ 0xB9,\r
+ (UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),\r
+ //\r
+ // Stick in jump opcode bytes\r
+ // jmp ecx => FF E1\r
+ //\r
+ 0xFF, 0xE1,\r
+};\r
+\r
/**\r
Begin executing an EBC image.\r
This is used for Ebc Thunk call.\r
{\r
UINTN IsThunk;\r
UINTN TargetEbcAddr;\r
+ UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];\r
+ UINTN Index;\r
+ UINTN IndexOfEbcEntrypoint;\r
\r
IsThunk = 1;\r
TargetEbcAddr = 0;\r
+ IndexOfEbcEntrypoint = 0;\r
\r
//\r
// Processor specific code to check whether the callee is a thunk to EBC.\r
//\r
- if (*((UINT8 *)FuncAddr) != 0xB8) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 1) != 0xBC) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 2) != 0x2E) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 3) != 0x11) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 4) != 0xCA) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 5) != 0xB8) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 10) != 0xB9) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 15) != 0xFF) {\r
- IsThunk = 0;\r
- goto Action;\r
+ CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));\r
+ //\r
+ // Fill the signature according to mInstructionBufferTemplate\r
+ //\r
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {\r
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {\r
+ *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;\r
+ IndexOfEbcEntrypoint = Index;\r
+ }\r
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {\r
+ *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;\r
+ }\r
}\r
- if (*((UINT8 *)FuncAddr + 16) != 0xE1) {\r
+ //\r
+ // Check if we need thunk to native\r
+ //\r
+ if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {\r
IsThunk = 0;\r
- goto Action;\r
}\r
\r
- TargetEbcAddr = ((UINTN)(*((UINT8 *)FuncAddr + 9)) << 24) + ((UINTN)(*((UINT8 *)FuncAddr + 8)) << 16) +\r
- ((UINTN)(*((UINT8 *)FuncAddr + 7)) << 8) + ((UINTN)(*((UINT8 *)FuncAddr + 6)));\r
-\r
-Action:\r
if (IsThunk == 1){\r
//\r
// The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and\r
VmPtr->Gpr[0] -= 8;\r
VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));\r
\r
+ CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN));\r
VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;\r
} else {\r
//\r
// The callee is not a thunk to EBC, call native code,\r
- // and get return value\r
+ // and get return value.\r
//\r
VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);\r
\r
UINT8 *Ptr;\r
UINT8 *ThunkBase;\r
UINT32 Index;\r
- UINT32 Addr;\r
- INT32 Size;\r
INT32 ThunkSize;\r
\r
//\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Size = EBC_THUNK_SIZE;\r
- ThunkSize = Size;\r
+ ThunkSize = sizeof(mInstructionBufferTemplate);\r
\r
- Ptr = AllocatePool (Size);\r
+ Ptr = AllocatePool (sizeof(mInstructionBufferTemplate));\r
\r
if (Ptr == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
*Thunk = (VOID *) Ptr;\r
\r
//\r
- // Add a magic code here to help the VM recognize the thunk..\r
- // mov eax, 0xca112ebc => B8 BC 2E 11 CA\r
+ // Copy whole thunk instruction buffer template\r
//\r
- *Ptr = 0xB8;\r
- Ptr++;\r
- Size--;\r
- Addr = (UINT32) 0xCA112EBC;\r
- for (Index = 0; Index < sizeof (Addr); Index++) {\r
- *Ptr = (UINT8) (UINTN) Addr;\r
- Addr >>= 8;\r
- Ptr++;\r
- Size--;\r
- }\r
+ CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));\r
\r
//\r
- // Add code bytes to load up a processor register with the EBC entry point.\r
- // mov eax, 0xaa55aa55 => B8 55 AA 55 AA\r
- // The first 8 bytes of the thunk entry is the address of the EBC\r
- // entry point.\r
+ // Patch EbcEntryPoint and EbcLLEbcInterpret\r
//\r
- *Ptr = 0xB8;\r
- Ptr++;\r
- Size--;\r
- Addr = (UINT32) EbcEntryPoint;\r
- for (Index = 0; Index < sizeof (Addr); Index++) {\r
- *Ptr = (UINT8) (UINTN) Addr;\r
- Addr >>= 8;\r
- Ptr++;\r
- Size--;\r
- }\r
- //\r
- // Stick in a load of ecx with the address of appropriate VM function.\r
- // mov ecx 12345678h => 0xB9 0x78 0x56 0x34 0x12\r
- //\r
- if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {\r
- Addr = (UINT32) (UINTN) EbcLLExecuteEbcImageEntryPoint;\r
- } else {\r
- Addr = (UINT32) (UINTN) EbcLLEbcInterpret;\r
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {\r
+ if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {\r
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;\r
+ }\r
+ if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {\r
+ if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {\r
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;\r
+ } else {\r
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;\r
+ }\r
+ }\r
}\r
\r
- //\r
- // MOV ecx\r
- //\r
- *Ptr = 0xB9;\r
- Ptr++;\r
- Size--;\r
- for (Index = 0; Index < sizeof (Addr); Index++) {\r
- *Ptr = (UINT8) Addr;\r
- Addr >>= 8;\r
- Ptr++;\r
- Size--;\r
- }\r
- //\r
- // Stick in jump opcode bytes for jmp ecx => 0xFF 0xE1\r
- //\r
- *Ptr = 0xFF;\r
- Ptr++;\r
- Size--;\r
- *Ptr = 0xE1;\r
- Size--;\r
-\r
- //\r
- // Double check that our defined size is ok (application error)\r
- //\r
- if (Size < 0) {\r
- ASSERT (FALSE);\r
- return EFI_BUFFER_TOO_SMALL;\r
- }\r
//\r
// Add the thunk to the list for this image. Do this last since the add\r
// function flushes the cache for us.\r
// platform-specific configurations.\r
//\r
#define VM_STACK_SIZE (1024 * 8)\r
-#define EBC_THUNK_SIZE 64\r
\r
#define STACK_REMAIN_SIZE (1024 * 4)\r
\r
+//\r
+// This is instruction buffer used to create EBC thunk\r
+//\r
+#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAFAFAFAFAFull\r
+#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFAFAFAFAFAull\r
+UINT8 mInstructionBufferTemplate[] = {\r
+ //\r
+ // Add a magic code here to help the VM recognize the thunk..\r
+ // mov rax, 0xca112ebcca112ebc => 48 B8 BC 2E 11 CA BC 2E 11 CA\r
+ //\r
+ 0x48, 0xB8, 0xBC, 0x2E, 0x11, 0xCA, 0xBC, 0x2E, 0x11, 0xCA,\r
+ //\r
+ // Add code bytes to load up a processor register with the EBC entry point.\r
+ // mov r10, EbcEntryPoint => 49 BA XX XX XX XX XX XX XX XX (To be fixed at runtime)\r
+ // These 8 bytes of the thunk entry is the address of the EBC\r
+ // entry point.\r
+ //\r
+ 0x49, 0xBA, \r
+ (UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),\r
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),\r
+ //\r
+ // Stick in a load of r11 with the address of appropriate VM function.\r
+ // mov r11, EbcLLEbcInterpret => 49 BB XX XX XX XX XX XX XX XX (To be fixed at runtime)\r
+ //\r
+ 0x49, 0xBB,\r
+ (UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),\r
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),\r
+ //\r
+ // Stick in jump opcode bytes\r
+ // jmp r11 => 41 FF E3\r
+ //\r
+ 0x41, 0xFF, 0xE3,\r
+};\r
+\r
/**\r
Begin executing an EBC image.\r
This is used for Ebc Thunk call.\r
UINT8 *Ptr;\r
UINT8 *ThunkBase;\r
UINT32 Index;\r
- UINT64 Addr;\r
- INT32 Size;\r
INT32 ThunkSize;\r
\r
//\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Size = EBC_THUNK_SIZE;\r
- ThunkSize = Size;\r
+ ThunkSize = sizeof(mInstructionBufferTemplate);\r
\r
- Ptr = AllocatePool (Size);\r
+ Ptr = AllocatePool (sizeof(mInstructionBufferTemplate));\r
\r
if (Ptr == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
*Thunk = (VOID *) Ptr;\r
\r
//\r
- // Add a magic code here to help the VM recognize the thunk..\r
- // mov rax, ca112ebccall2ebch => 48 B8 BC 2E 11 CA BC 2E 11 CA\r
- //\r
- *Ptr = 0x48;\r
- Ptr++;\r
- Size--;\r
- *Ptr = 0xB8;\r
- Ptr++;\r
- Size--;\r
- Addr = (UINT64) 0xCA112EBCCA112EBCULL;\r
- for (Index = 0; Index < sizeof (Addr); Index++) {\r
- *Ptr = (UINT8) (UINTN) Addr;\r
- Addr >>= 8;\r
- Ptr++;\r
- Size--;\r
- }\r
-\r
+ // Copy whole thunk instruction buffer template\r
//\r
- // Add code bytes to load up a processor register with the EBC entry point.\r
- // mov r10, 123456789abcdef0h => 49 BA F0 DE BC 9A 78 56 34 12\r
- // The first 8 bytes of the thunk entry is the address of the EBC\r
- // entry point.\r
- //\r
- *Ptr = 0x49;\r
- Ptr++;\r
- Size--;\r
- *Ptr = 0xBA;\r
- Ptr++;\r
- Size--;\r
- Addr = (UINT64) EbcEntryPoint;\r
- for (Index = 0; Index < sizeof (Addr); Index++) {\r
- *Ptr = (UINT8) (UINTN) Addr;\r
- Addr >>= 8;\r
- Ptr++;\r
- Size--;\r
- }\r
+ CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));\r
\r
//\r
- // Stick in a load of ecx with the address of appropriate VM function.\r
- // Using r11 because it's a volatile register and won't be used in this\r
- // point.\r
- // mov r11 123456789abcdef0h => 49 BB F0 DE BC 9A 78 56 34 12\r
+ // Patch EbcEntryPoint and EbcLLEbcInterpret\r
//\r
- if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {\r
- Addr = (UINTN) EbcLLExecuteEbcImageEntryPoint;\r
- } else {\r
- Addr = (UINTN) EbcLLEbcInterpret;\r
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {\r
+ if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {\r
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;\r
+ }\r
+ if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {\r
+ if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {\r
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;\r
+ } else {\r
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;\r
+ }\r
+ }\r
}\r
\r
- //\r
- // mov r11 Addr => 0x49 0xBB\r
- //\r
- *Ptr = 0x49;\r
- Ptr++;\r
- Size--;\r
- *Ptr = 0xBB;\r
- Ptr++;\r
- Size--;\r
- for (Index = 0; Index < sizeof (Addr); Index++) {\r
- *Ptr = (UINT8) Addr;\r
- Addr >>= 8;\r
- Ptr++;\r
- Size--;\r
- }\r
- //\r
- // Stick in jump opcode bytes for jmp r11 => 0x41 0xFF 0xE3\r
- //\r
- *Ptr = 0x41;\r
- Ptr++;\r
- Size--;\r
- *Ptr = 0xFF;\r
- Ptr++;\r
- Size--;\r
- *Ptr = 0xE3;\r
- Size--;\r
-\r
- //\r
- // Double check that our defined size is ok (application error)\r
- //\r
- if (Size < 0) {\r
- ASSERT (FALSE);\r
- return EFI_BUFFER_TOO_SMALL;\r
- }\r
//\r
// Add the thunk to the list for this image. Do this last since the add\r
// function flushes the cache for us.\r
{\r
UINTN IsThunk;\r
UINTN TargetEbcAddr;\r
+ UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];\r
+ UINTN Index;\r
+ UINTN IndexOfEbcEntrypoint;\r
\r
IsThunk = 1;\r
TargetEbcAddr = 0;\r
+ IndexOfEbcEntrypoint = 0;\r
\r
//\r
// Processor specific code to check whether the callee is a thunk to EBC.\r
//\r
- if (*((UINT8 *)FuncAddr) != 0x48) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 1) != 0xB8) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 2) != 0xBC) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 3) != 0x2E) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 4) != 0x11) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 5) != 0xCA) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 6) != 0xBC) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 7) != 0x2E) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 8) != 0x11) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 9) != 0xCA) {\r
- IsThunk = 0;\r
- goto Action;\r
- }\r
- if (*((UINT8 *)FuncAddr + 10) != 0x49) {\r
- IsThunk = 0;\r
- goto Action;\r
+ CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));\r
+ //\r
+ // Fill the signature according to mInstructionBufferTemplate\r
+ //\r
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {\r
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {\r
+ *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;\r
+ IndexOfEbcEntrypoint = Index;\r
+ }\r
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {\r
+ *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;\r
+ }\r
}\r
- if (*((UINT8 *)FuncAddr + 11) != 0xBA) {\r
+ //\r
+ // Check if we need thunk to native\r
+ //\r
+ if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {\r
IsThunk = 0;\r
- goto Action;\r
}\r
\r
- CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + 12, 8);\r
-\r
-Action:\r
if (IsThunk == 1){\r
//\r
// The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and\r
VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);\r
VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];\r
VmPtr->Gpr[0] -= 8;\r
- VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (VmPtr->Ip + Size));\r
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));\r
\r
+ CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN));\r
VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;\r
} else {\r
//\r