From: jyao1 Date: Wed, 23 Nov 2011 13:23:34 +0000 (+0000) Subject: Re-org the EBC thunk code for better code maintenance. X-Git-Tag: edk2-stable201903~13847 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=21d13c61561c465a4d4cfe0f0d188765fc8ae3b9;p=mirror_edk2.git 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 --- diff --git a/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c b/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c index da1ad2cd5d..41dc3a8585 100644 --- a/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c +++ b/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c @@ -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.
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; - } - if (*((UINT8 *)FuncAddr + 1) != 0xBC) { - 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; + 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 + 16) != 0xE1) { + // + // Check if we need thunk to native + // + if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) { 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. diff --git a/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c b/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c index a31422b62a..3f99a1a6e2 100644 --- a/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c +++ b/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c @@ -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 - // - *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--; - } - + // Copy whole thunk instruction buffer template // - // 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. - // - *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--; - } + CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)); // - // 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 + // Patch EbcEntryPoint and EbcLLEbcInterpret // - if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) { - Addr = (UINTN) EbcLLExecuteEbcImageEntryPoint; - } else { - Addr = (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 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; - } - if (*((UINT8 *)FuncAddr + 1) != 0xB8) { - 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; + 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 + 11) != 0xBA) { + // + // Check if we need thunk to native + // + if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) { 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 { //