--- /dev/null
+/**@file\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ PeiNt32PeCoffExtraActionLib.c\r
+\r
+Abstract:\r
+\r
+ Provides services to perform additional actions to relocate and unload\r
+ PE/Coff image for NT32 environment specific purpose such as souce level debug.\r
+ This version only works for DXE phase \r
+\r
+\r
+**/\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <FrameworkDxe.h>\r
+#include <FrameworkModuleDxe.h>\r
+#include <WinNtDxe.h>\r
+\r
+//\r
+// The protocols, PPI and GUID defintions for this module\r
+//\r
+#include <Protocol/WinNtThunk.h>\r
+\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeCoffExtraActionLib.h>\r
+\r
+#define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100\r
+\r
+typedef struct {\r
+ CHAR8 *PdbPointer;\r
+ VOID *ModHandle;\r
+} PDB_NAME_TO_MOD_HANDLE;\r
+\r
+\r
+//\r
+// Cache of WinNtThunk protocol\r
+//\r
+EFI_WIN_NT_THUNK_PROTOCOL *mWinNt = NULL;\r
+\r
+//\r
+// An Array to hold the ModHandle\r
+//\r
+PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL;\r
+UINTN mPdbNameModHandleArraySize = 0;\r
+\r
+\r
+/**\r
+ The constructor function gets the pointer of the WinNT thunk functions\r
+ It will ASSERT() if NT thunk protocol is not installed.\r
+\r
+ @retval EFI_SUCCESS WinNT thunk protocol is found and cached.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeNt32PeCoffLibExtraActionConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+\r
+ //\r
+ // Retrieve WinNtThunkProtocol from GUID'ed HOB\r
+ //\r
+ GuidHob = GetFirstGuidHob (&gEfiWinNtThunkProtocolGuid);\r
+ ASSERT (GuidHob != NULL);\r
+ mWinNt = (EFI_WIN_NT_THUNK_PROTOCOL *)(*(UINTN *)(GET_GUID_HOB_DATA (GuidHob)));\r
+ ASSERT (mWinNt != NULL);\r
+\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Convert the passed in Ascii string to Unicode.\r
+ \r
+ This function Convert the passed in Ascii string to Unicode.Optionally return\r
+ the length of the strings..\r
+\r
+ @param AsciiString Pointer to an AscII string\r
+ @param StrLen Length of string\r
+\r
+ @return Pointer to malloc'ed Unicode version of Ascii\r
+\r
+**/\r
+CHAR16 *\r
+AsciiToUnicode (\r
+ IN CHAR8 *Ascii,\r
+ IN UINTN *StrLen OPTIONAL\r
+ )\r
+{\r
+ UINTN Index;\r
+ CHAR16 *Unicode;\r
+\r
+ //\r
+ // Allocate a buffer for unicode string\r
+ //\r
+ for (Index = 0; Ascii[Index] != '\0'; Index++)\r
+ ;\r
+ Unicode = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),\r
+ HEAP_ZERO_MEMORY,\r
+ ((Index + 1) * sizeof (CHAR16))\r
+ ); \r
+ if (Unicode == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ for (Index = 0; Ascii[Index] != '\0'; Index++) {\r
+ Unicode[Index] = (CHAR16) Ascii[Index];\r
+ }\r
+\r
+ Unicode[Index] = '\0';\r
+\r
+ if (StrLen != NULL) {\r
+ *StrLen = Index;\r
+ }\r
+\r
+ return Unicode;\r
+}\r
+/**\r
+ Store the ModHandle in an array indexed by the Pdb File name.\r
+ The ModHandle is needed to unload the image. \r
+\r
+\r
+ @param ImageContext - Input data returned from PE Laoder Library. Used to find the \r
+ .PDB file name of the PE Image.\r
+ @param ModHandle - Returned from LoadLibraryEx() and stored for call to \r
+ FreeLibrary().\r
+\r
+ @return return EFI_SUCCESS when ModHandle was stored. \r
+\r
+--*/\r
+EFI_STATUS\r
+AddModHandle (\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
+ IN VOID *ModHandle\r
+ )\r
+\r
+{\r
+ UINTN Index;\r
+ PDB_NAME_TO_MOD_HANDLE *Array;\r
+ UINTN PreviousSize;\r
+ PDB_NAME_TO_MOD_HANDLE *TempArray;\r
+\r
+ Array = mPdbNameModHandleArray;\r
+ for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
+ if (Array->PdbPointer == NULL) {\r
+ //\r
+ // Make a copy of the stirng and store the ModHandle\r
+ //\r
+ Array->PdbPointer = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),\r
+ HEAP_ZERO_MEMORY,\r
+ AsciiStrLen (ImageContext->PdbPointer) + 1\r
+ ); \r
+ \r
+ ASSERT (Array->PdbPointer != NULL);\r
+\r
+ AsciiStrCpy (Array->PdbPointer, ImageContext->PdbPointer);\r
+ Array->ModHandle = ModHandle;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // No free space in mPdbNameModHandleArray so grow it by \r
+ // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires. \r
+ //\r
+ PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);\r
+ mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;\r
+ //\r
+ // re-allocate a new buffer and copy the old values to the new locaiton. \r
+ //\r
+ TempArray = mWinNt->HeapAlloc ( mWinNt->GetProcessHeap (),\r
+ HEAP_ZERO_MEMORY,\r
+ mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)\r
+ ); \r
+ \r
+ CopyMem ((VOID *) (UINTN) TempArray, (VOID *) (UINTN)mPdbNameModHandleArray, PreviousSize);\r
+ \r
+ mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, mPdbNameModHandleArray);\r
+ \r
+ mPdbNameModHandleArray = TempArray;\r
+ if (mPdbNameModHandleArray == NULL) {\r
+ ASSERT (FALSE);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ \r
+ \r
+ return AddModHandle (ImageContext, ModHandle);\r
+}\r
+/**\r
+ Return the ModHandle and delete the entry in the array.\r
+\r
+\r
+ @param ImageContext - Input data returned from PE Laoder Library. Used to find the \r
+ .PDB file name of the PE Image.\r
+\r
+ @return \r
+ ModHandle - ModHandle assoicated with ImageContext is returned\r
+ NULL - No ModHandle associated with ImageContext\r
+\r
+**/\r
+VOID *\r
+RemoveModeHandle (\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+ )\r
+{\r
+ UINTN Index;\r
+ PDB_NAME_TO_MOD_HANDLE *Array;\r
+\r
+ if (ImageContext->PdbPointer == NULL) {\r
+ //\r
+ // If no PDB pointer there is no ModHandle so return NULL\r
+ //\r
+ return NULL;\r
+ }\r
+\r
+ Array = mPdbNameModHandleArray;\r
+ for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
+ if ((Array->PdbPointer != NULL) && (AsciiStrCmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) {\r
+ //\r
+ // If you find a match return it and delete the entry\r
+ //\r
+ mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, Array->PdbPointer);\r
+ Array->PdbPointer = NULL;\r
+ return Array->ModHandle;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Applies additional actions to relocate fixups to a PE/COFF image.\r
+\r
+ Generally this function is called after sucessfully Applying relocation fixups \r
+ to a PE/COFF image for some specicial purpose. \r
+ As a example, For NT32 emulator, the function should be implemented and called\r
+ to support source level debug. \r
+ \r
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
+ image that is being relocated.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PeCoffLoaderRelocateImageExtraAction (\r
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+ )\r
+{\r
+ VOID *DllEntryPoint;\r
+ CHAR16 *DllFileName;\r
+ HMODULE Library;\r
+ UINTN Index;\r
+ \r
+ //\r
+ // If we load our own PE COFF images the Windows debugger can not source\r
+ // level debug our code. If a valid PDB pointer exists usw it to load\r
+ // the *.dll file as a library using Windows* APIs. This allows \r
+ // source level debug. The image is still loaded and reloaced\r
+ // in the Framework memory space like on a real system (by the code above),\r
+ // but the entry point points into the DLL loaded by the code bellow. \r
+ //\r
+\r
+ DllEntryPoint = NULL;\r
+\r
+ //\r
+ // Load the DLL if it's not an EBC image.\r
+ //\r
+ if ((ImageContext->PdbPointer != NULL) &&\r
+ (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {\r
+ //\r
+ // Convert filename from ASCII to Unicode\r
+ //\r
+ DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);\r
+\r
+ //\r
+ // Check that we have a valid filename\r
+ //\r
+ if (Index < 5 || DllFileName[Index - 4] != '.') {\r
+ mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName);\r
+\r
+ //\r
+ // Never return an error if PeCoffLoaderRelocateImage() succeeded.\r
+ // The image will run, but we just can't source level debug. If we\r
+ // return an error the image will not run.\r
+ //\r
+ return;\r
+ }\r
+ //\r
+ // Replace .PDB with .DLL on the filename\r
+ //\r
+ DllFileName[Index - 3] = 'D';\r
+ DllFileName[Index - 2] = 'L';\r
+ DllFileName[Index - 1] = 'L';\r
+\r
+ //\r
+ // Load the .DLL file into the user process's address space for source \r
+ // level debug\r
+ //\r
+ Library = mWinNt->LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);\r
+ if (Library != NULL) {\r
+ //\r
+ // InitializeDriver is the entry point we put in all our EFI DLL's. The\r
+ // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() supresses the \r
+ // normal DLL entry point of DllMain, and prevents other modules that are\r
+ // referenced in side the DllFileName from being loaded. There is no error \r
+ // checking as the we can point to the PE32 image loaded by Tiano. This \r
+ // step is only needed for source level debuging\r
+ //\r
+ DllEntryPoint = (VOID *) (UINTN) mWinNt->GetProcAddress (Library, "InitializeDriver");\r
+\r
+ }\r
+\r
+ if ((Library != NULL) && (DllEntryPoint != NULL)) {\r
+ AddModHandle (ImageContext, Library);\r
+ ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
+ DEBUG ((EFI_D_INFO, "LoadLibraryEx (%s,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName));\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "WARNING: No source level debug %s. \n", DllFileName));\r
+ }\r
+\r
+ mWinNt->HeapFree (mWinNt->GetProcessHeap (), 0, DllFileName);\r
+ }\r
+\r
+ //\r
+ // Never return an error if PeCoffLoaderRelocateImage() succeeded.\r
+ // The image will run, but we just can't source level debug. If we\r
+ // return an error the image will not run.\r
+ //\r
+ return;\r
+} \r
+\r
+/**\r
+ Unloads a loaded PE/COFF image from memory and releases its taken resource.\r
+ \r
+ Releases any environment specific resources that were allocated when the image \r
+ specified by ImageContext was loaded using PeCoffLoaderLoadImage(). \r
+ For NT32 emulator, the PE/COFF image loaded by system needs to release.\r
+ For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded, \r
+ \r
+ If ImageContext is NULL, then ASSERT().\r
+ \r
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
+ image to be unloaded.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PeCoffLoaderUnloadImageExtraAction (\r
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+ )\r
+{\r
+ VOID *ModHandle;\r
+\r
+ ModHandle = RemoveModeHandle (ImageContext);\r
+ if (ModHandle != NULL) {\r
+ mWinNt->FreeLibrary (ModHandle);\r
+ }\r
+ return;\r
+}
\ No newline at end of file