summaryrefslogtreecommitdiffstats
path: root/EmulatorPkg/Win/Host/WinHost.c
diff options
context:
space:
mode:
Diffstat (limited to 'EmulatorPkg/Win/Host/WinHost.c')
-rw-r--r--EmulatorPkg/Win/Host/WinHost.c940
1 files changed, 940 insertions, 0 deletions
diff --git a/EmulatorPkg/Win/Host/WinHost.c b/EmulatorPkg/Win/Host/WinHost.c
new file mode 100644
index 0000000000..22399f18b9
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinHost.c
@@ -0,0 +1,940 @@
+/**@file
+ WinNt emulator of pre-SEC phase. It's really a Win32 application, but this is
+ Ok since all the other modules for NT32 are NOT Win32 applications.
+
+ This program gets NT32 PCD setting and figures out what the memory layout
+ will be, how may FD's will be loaded and also what the boot mode is.
+
+ This code produces 128 K of temporary memory for the SEC stack by directly
+ allocate memory space with ReadWrite and Execute attribute.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include "WinHost.h"
+
+#ifndef SE_TIME_ZONE_NAME
+#define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege")
+#endif
+
+//
+// Default information about where the FD is located.
+// This array gets filled in with information from PcdWinNtFirmwareVolume
+// The number of array elements is allocated base on parsing
+// PcdWinNtFirmwareVolume and the memory is never freed.
+//
+UINTN gFdInfoCount = 0;
+NT_FD_INFO *gFdInfo;
+
+//
+// Array that supports seperate memory rantes.
+// The memory ranges are set by PcdWinNtMemorySizeForSecMain.
+// The number of array elements is allocated base on parsing
+// PcdWinNtMemorySizeForSecMain value and the memory is never freed.
+//
+UINTN gSystemMemoryCount = 0;
+NT_SYSTEM_MEMORY *gSystemMemory;
+
+/*++
+
+Routine Description:
+ This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
+ It allows discontinuous memory regions to be supported by the emulator.
+ It uses gSystemMemory[] and gSystemMemoryCount that were created by
+ parsing the host environment variable EFI_MEMORY_SIZE.
+ The size comes from the varaible and the address comes from the call to
+ UnixOpenFile.
+
+Arguments:
+ Index - Which memory region to use
+ MemoryBase - Return Base address of memory region
+ MemorySize - Return size in bytes of the memory region
+
+Returns:
+ EFI_SUCCESS - If memory region was mapped
+ EFI_UNSUPPORTED - If Index is not supported
+
+**/
+EFI_STATUS
+WinPeiAutoScan (
+ IN UINTN Index,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
+ OUT UINT64 *MemorySize
+ )
+{
+ if (Index >= gSystemMemoryCount) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Allocate enough memory space for emulator
+ //
+ gSystemMemory[Index].Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (gSystemMemory[Index].Size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if (gSystemMemory[Index].Memory == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *MemoryBase = gSystemMemory[Index].Memory;
+ *MemorySize = gSystemMemory[Index].Size;
+
+ return EFI_SUCCESS;
+}
+
+/*++
+
+Routine Description:
+ Return the FD Size and base address. Since the FD is loaded from a
+ file into host memory only the SEC will know it's address.
+
+Arguments:
+ Index - Which FD, starts at zero.
+ FdSize - Size of the FD in bytes
+ FdBase - Start address of the FD. Assume it points to an FV Header
+ FixUp - Difference between actual FD address and build address
+
+Returns:
+ EFI_SUCCESS - Return the Base address and size of the FV
+ EFI_UNSUPPORTED - Index does nto map to an FD in the system
+
+**/
+EFI_STATUS
+WinFdAddress (
+ IN UINTN Index,
+ IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
+ IN OUT UINT64 *FdSize,
+ IN OUT EFI_PHYSICAL_ADDRESS *FixUp
+ )
+{
+ if (Index >= gFdInfoCount) {
+ return EFI_UNSUPPORTED;
+ }
+
+
+ *FdBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gFdInfo[Index].Address;
+ *FdSize = (UINT64)gFdInfo[Index].Size;
+ *FixUp = 0;
+
+ if (*FdBase == 0 && *FdSize == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Index == 0) {
+ //
+ // FD 0 has XIP code and well known PCD values
+ // If the memory buffer could not be allocated at the FD build address
+ // the Fixup is the difference.
+ //
+ *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*++
+
+Routine Description:
+ Since the SEC is the only Unix program in stack it must export
+ an interface to do POSIX calls. gUnix is initialized in UnixThunk.c.
+
+Arguments:
+ InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
+ InterfaceBase - Address of the gUnix global
+
+Returns:
+ EFI_SUCCESS - Data returned
+
+**/
+VOID *
+WinThunk (
+ VOID
+ )
+{
+ return &gEmuThunkProtocol;
+}
+
+
+EMU_THUNK_PPI mSecEmuThunkPpi = {
+ WinPeiAutoScan,
+ WinFdAddress,
+ WinThunk
+};
+
+VOID
+SecPrint (
+ CHAR8 *Format,
+ ...
+ )
+{
+ va_list Marker;
+ UINTN CharCount;
+ CHAR8 Buffer[0x1000];
+
+ va_start (Marker, Format);
+
+ _vsnprintf (Buffer, sizeof (Buffer), Format, Marker);
+
+ va_end (Marker);
+
+ CharCount = strlen (Buffer);
+ WriteFile (
+ GetStdHandle (STD_OUTPUT_HANDLE),
+ Buffer,
+ (DWORD)CharCount,
+ (LPDWORD)&CharCount,
+ NULL
+ );
+}
+
+/*++
+
+Routine Description:
+ Check to see if an address range is in the EFI GCD memory map.
+
+ This is all of GCD for system memory passed to DXE Core. FV
+ mapping and other device mapped into system memory are not
+ inlcuded in the check.
+
+Arguments:
+ Index - Which memory region to use
+ MemoryBase - Return Base address of memory region
+ MemorySize - Return size in bytes of the memory region
+
+Returns:
+ TRUE - Address is in the EFI GCD memory map
+ FALSE - Address is NOT in memory map
+
+**/
+BOOLEAN
+EfiSystemMemoryRange (
+ IN VOID *MemoryAddress
+ )
+{
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS MemoryBase;
+
+ MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
+ for (Index = 0; Index < gSystemMemoryCount; Index++) {
+ if ((MemoryBase >= gSystemMemory[Index].Memory) &&
+ (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)) ) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+EFI_STATUS
+WinNtOpenFile (
+ IN CHAR16 *FileName, OPTIONAL
+ IN UINT32 MapSize,
+ IN DWORD CreationDisposition,
+ IN OUT VOID **BaseAddress,
+ OUT UINTN *Length
+ )
+/*++
+
+Routine Description:
+ Opens and memory maps a file using WinNt services. If *BaseAddress is non zero
+ the process will try and allocate the memory starting at BaseAddress.
+
+Arguments:
+ FileName - The name of the file to open and map
+ MapSize - The amount of the file to map in bytes
+ CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
+ memory emulation, and exiting files for firmware volume emulation
+ BaseAddress - The base address of the mapped file in the user address space.
+ If *BaseAddress is 0, the new memory region is used.
+ If *BaseAddress is not 0, the request memory region is used for
+ the mapping of the file into the process space.
+ Length - The size of the mapped region in bytes
+
+Returns:
+ EFI_SUCCESS - The file was opened and mapped.
+ EFI_NOT_FOUND - FileName was not found in the current directory
+ EFI_DEVICE_ERROR - An error occured attempting to map the opened file
+
+--*/
+{
+ HANDLE NtFileHandle;
+ HANDLE NtMapHandle;
+ VOID *VirtualAddress;
+ UINTN FileSize;
+
+ //
+ // Use Win API to open/create a file
+ //
+ NtFileHandle = INVALID_HANDLE_VALUE;
+ if (FileName != NULL) {
+ NtFileHandle = CreateFile (
+ FileName,
+ GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
+ FILE_SHARE_READ,
+ NULL,
+ CreationDisposition,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+ if (NtFileHandle == INVALID_HANDLE_VALUE) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Map the open file into a memory range
+ //
+ NtMapHandle = CreateFileMapping (
+ NtFileHandle,
+ NULL,
+ PAGE_EXECUTE_READWRITE,
+ 0,
+ MapSize,
+ NULL
+ );
+ if (NtMapHandle == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Get the virtual address (address in the emulator) of the mapped file
+ //
+ VirtualAddress = MapViewOfFileEx (
+ NtMapHandle,
+ FILE_MAP_EXECUTE | FILE_MAP_ALL_ACCESS,
+ 0,
+ 0,
+ MapSize,
+ *BaseAddress
+ );
+ if (VirtualAddress == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (MapSize == 0) {
+ //
+ // Seek to the end of the file to figure out the true file size.
+ //
+ FileSize = SetFilePointer (
+ NtFileHandle,
+ 0,
+ NULL,
+ FILE_END
+ );
+ if (FileSize == -1) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ *Length = FileSize;
+ } else {
+ *Length = MapSize;
+ }
+
+ *BaseAddress = VirtualAddress;
+
+ return EFI_SUCCESS;
+}
+
+INTN
+EFIAPI
+main (
+ IN INTN Argc,
+ IN CHAR8 **Argv,
+ IN CHAR8 **Envp
+ )
+/*++
+
+Routine Description:
+ Main entry point to SEC for WinNt. This is a Windows program
+
+Arguments:
+ Argc - Number of command line arguments
+ Argv - Array of command line argument strings
+ Envp - Array of environment variable strings
+
+Returns:
+ 0 - Normal exit
+ 1 - Abnormal exit
+
+--*/
+{
+ EFI_STATUS Status;
+ HANDLE Token;
+ TOKEN_PRIVILEGES TokenPrivileges;
+ VOID *TemporaryRam;
+ UINT32 TemporaryRamSize;
+ VOID *EmuMagicPage;
+ UINTN Index;
+ UINTN Index1;
+ CHAR16 *FileName;
+ CHAR16 *FileNamePtr;
+ BOOLEAN Done;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *SecFile;
+ CHAR16 *MemorySizeStr;
+ CHAR16 *FirmwareVolumesStr;
+ UINT32 ProcessAffinityMask;
+ UINT32 SystemAffinityMask;
+ INT32 LowBit;
+
+ //
+ // Enable the privilege so that RTC driver can successfully run SetTime()
+ //
+ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &Token);
+ if (LookupPrivilegeValue(NULL, SE_TIME_ZONE_NAME, &TokenPrivileges.Privileges[0].Luid)) {
+ TokenPrivileges.PrivilegeCount = 1;
+ TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ AdjustTokenPrivileges(Token, FALSE, &TokenPrivileges, 0, (PTOKEN_PRIVILEGES) NULL, 0);
+ }
+
+ MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);
+ FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);
+
+ SecPrint ("\nEDK II WIN Host Emulation Environment from http://www.tianocore.org/edk2/\n");
+
+ //
+ // Determine the first thread available to this process.
+ //
+ if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {
+ LowBit = (INT32)LowBitSet32 (ProcessAffinityMask);
+ if (LowBit != -1) {
+ //
+ // Force the system to bind the process to a single thread to work
+ // around odd semaphore type crashes.
+ //
+ SetProcessAffinityMask (GetCurrentProcess (), (INTN)(BIT0 << LowBit));
+ }
+ }
+
+ //
+ // Make some Windows calls to Set the process to the highest priority in the
+ // idle class. We need this to have good performance.
+ //
+ SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS);
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
+
+ SecInitializeThunk ();
+ //
+ // PPIs pased into PEI_CORE
+ //
+ AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
+
+ //
+ // Allocate space for gSystemMemory Array
+ //
+ gSystemMemoryCount = CountSeparatorsInString (MemorySizeStr, '!') + 1;
+ gSystemMemory = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));
+ if (gSystemMemory == NULL) {
+ SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n", MemorySizeStr);
+ exit (1);
+ }
+
+ //
+ // Allocate space for gSystemMemory Array
+ //
+ gFdInfoCount = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;
+ gFdInfo = calloc (gFdInfoCount, sizeof (NT_FD_INFO));
+ if (gFdInfo == NULL) {
+ SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n", FirmwareVolumesStr);
+ exit (1);
+ }
+ //
+ // Setup Boot Mode.
+ //
+ SecPrint (" BootMode 0x%02x\n", PcdGet32 (PcdEmuBootMode));
+
+ //
+ // Allocate 128K memory to emulate temp memory for PEI.
+ // on a real platform this would be SRAM, or using the cache as RAM.
+ // Set TemporaryRam to zero so WinNtOpenFile will allocate a new mapping
+ //
+ TemporaryRamSize = TEMPORARY_RAM_SIZE;
+ TemporaryRam = VirtualAlloc (NULL, (SIZE_T) (TemporaryRamSize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if (TemporaryRam == NULL) {
+ SecPrint ("ERROR : Can not allocate enough space for SecStack\n");
+ exit (1);
+ }
+ SetMemN (TemporaryRam, TemporaryRamSize, PcdGet32 (PcdInitValueInTempStack));
+
+ SecPrint (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",
+ TemporaryRamSize / SIZE_1KB,
+ TemporaryRam
+ );
+
+ //
+ // If enabled use the magic page to communicate between modules
+ // This replaces the PI PeiServicesTable pointer mechanism that
+ // deos not work in the emulator. It also allows the removal of
+ // writable globals from SEC, PEI_CORE (libraries), PEIMs
+ //
+ EmuMagicPage = (VOID *)(UINTN)(FixedPcdGet64 (PcdPeiServicesTablePage) & MAX_UINTN);
+ if (EmuMagicPage != NULL) {
+ UINT64 Size;
+ Status = WinNtOpenFile (
+ NULL,
+ SIZE_4KB,
+ 0,
+ &EmuMagicPage,
+ &Size
+ );
+ if (EFI_ERROR (Status)) {
+ SecPrint ("ERROR : Could not allocate PeiServicesTablePage @ %p\n", EmuMagicPage);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Open All the firmware volumes and remember the info in the gFdInfo global
+ // Meanwhile, find the SEC Core.
+ //
+ FileNamePtr = AllocateCopyPool (StrSize (FirmwareVolumesStr), FirmwareVolumesStr);
+ if (FileNamePtr == NULL) {
+ SecPrint ("ERROR : Can not allocate memory for firmware volume string\n");
+ exit (1);
+ }
+
+ for (Done = FALSE, Index = 0, SecFile = NULL; !Done; Index++) {
+ FileName = FileNamePtr;
+ for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++)
+ ;
+ if (FileNamePtr[Index1] == 0) {
+ Done = TRUE;
+ } else {
+ FileNamePtr[Index1] = '\0';
+ FileNamePtr = &FileNamePtr[Index1 + 1];
+ }
+
+ //
+ // Open the FD and remember where it got mapped into our processes address space
+ //
+ Status = WinNtOpenFile (
+ FileName,
+ 0,
+ OPEN_EXISTING,
+ &gFdInfo[Index].Address,
+ &gFdInfo[Index].Size
+ );
+ if (EFI_ERROR (Status)) {
+ SecPrint ("ERROR : Can not open Firmware Device File %S (0x%X). Exiting.\n", FileName, Status);
+ exit (1);
+ }
+
+ SecPrint (" FD loaded from %S\n", FileName);
+
+ if (SecFile == NULL) {
+ //
+ // Assume the beginning of the FD is an FV and look for the SEC Core.
+ // Load the first one we find.
+ //
+ FileHandle = NULL;
+ Status = PeiServicesFfsFindNextFile (
+ EFI_FV_FILETYPE_SECURITY_CORE,
+ (EFI_PEI_FV_HANDLE)gFdInfo[Index].Address,
+ &FileHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
+ if (!EFI_ERROR (Status)) {
+ SecPrint (" contains SEC Core");
+ }
+ }
+ }
+
+ SecPrint ("\n");
+ }
+ //
+ // Calculate memory regions and store the information in the gSystemMemory
+ // global for later use. The autosizing code will use this data to
+ // map this memory into the SEC process memory space.
+ //
+ for (Index = 0, Done = FALSE; !Done; Index++) {
+ //
+ // Save the size of the memory and make a Unicode filename SystemMemory00, ...
+ //
+ gSystemMemory[Index].Size = _wtoi (MemorySizeStr) * SIZE_1MB;
+
+ //
+ // Find the next region
+ //
+ for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++)
+ ;
+ if (MemorySizeStr[Index1] == 0) {
+ Done = TRUE;
+ }
+
+ MemorySizeStr = MemorySizeStr + Index1 + 1;
+ }
+
+ SecPrint ("\n");
+
+ //
+ // Hand off to SEC Core
+ //
+ SecLoadSecCore ((UINTN)TemporaryRam, TemporaryRamSize, gFdInfo[0].Address, gFdInfo[0].Size, SecFile);
+
+ //
+ // If we get here, then the SEC Core returned. This is an error as SEC should
+ // always hand off to PEI Core and then on to DXE Core.
+ //
+ SecPrint ("ERROR : SEC returned\n");
+ exit (1);
+}
+
+VOID
+SecLoadSecCore (
+ IN UINTN TemporaryRam,
+ IN UINTN TemporaryRamSize,
+ IN VOID *BootFirmwareVolumeBase,
+ IN UINTN BootFirmwareVolumeSize,
+ IN VOID *SecCorePe32File
+ )
+/*++
+
+Routine Description:
+ This is the service to load the SEC Core from the Firmware Volume
+
+Arguments:
+ TemporaryRam - Memory to use for SEC.
+ TemporaryRamSize - Size of Memory to use for SEC
+ BootFirmwareVolumeBase - Start of the Boot FV
+ SecCorePe32File - SEC Core PE32
+
+Returns:
+ Success means control is transfered and thus we should never return
+
+--*/
+{
+ EFI_STATUS Status;
+ VOID *TopOfStack;
+ VOID *SecCoreEntryPoint;
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ UINTN SecStackSize;
+
+ //
+ // Compute Top Of Memory for Stack and PEI Core Allocations
+ //
+ SecStackSize = TemporaryRamSize >> 1;
+
+ //
+ // |-----------| <---- TemporaryRamBase + TemporaryRamSize
+ // | Heap |
+ // | |
+ // |-----------| <---- StackBase / PeiTemporaryMemoryBase
+ // | |
+ // | Stack |
+ // |-----------| <---- TemporaryRamBase
+ //
+ TopOfStack = (VOID *)(TemporaryRam + SecStackSize);
+
+ //
+ // Reservet space for storing PeiCore's parament in stack.
+ //
+ TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+
+ //
+ // Bind this information into the SEC hand-off state
+ //
+ SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN)TopOfStack;
+ SecCoreData->DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
+ SecCoreData->BootFirmwareVolumeBase = BootFirmwareVolumeBase;
+ SecCoreData->BootFirmwareVolumeSize = BootFirmwareVolumeSize;
+ SecCoreData->TemporaryRamBase = (VOID*)TemporaryRam;
+ SecCoreData->TemporaryRamSize = TemporaryRamSize;
+ SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
+ SecCoreData->StackSize = SecStackSize;
+ SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + SecStackSize);
+ SecCoreData->PeiTemporaryRamSize = TemporaryRamSize - SecStackSize;
+
+ //
+ // Load the PEI Core from a Firmware Volume
+ //
+ Status = SecPeCoffGetEntryPoint (
+ SecCorePe32File,
+ &SecCoreEntryPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Transfer control to the SEC Core
+ //
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)SecCoreEntryPoint,
+ SecCoreData,
+ GetThunkPpiList (),
+ TopOfStack
+ );
+ //
+ // If we get here, then the SEC Core returned. This is an error
+ //
+ return ;
+}
+
+RETURN_STATUS
+EFIAPI
+SecPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ IN OUT VOID **EntryPoint
+ )
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = Pe32Data;
+
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribute.
+ // Extra space is for alignment
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if (ImageContext.ImageAddress == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Align buffer on section boundary
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
+
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SecImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
+
+Arguments:
+ FileHandle - The handle to the PE/COFF file
+ FileOffset - The offset, in bytes, into the file to read
+ ReadSize - The number of bytes to read from the file starting at FileOffset
+ Buffer - A pointer to the buffer to read the data into.
+
+Returns:
+ EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+--*/
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+ UINTN Length;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
+ Length = *ReadSize;
+ while (Length--) {
+ *(Destination8++) = *(Source8++);
+ }
+
+ return EFI_SUCCESS;
+}
+
+CHAR16 *
+AsciiToUnicode (
+ IN CHAR8 *Ascii,
+ IN UINTN *StrLen OPTIONAL
+ )
+/*++
+
+Routine Description:
+ Convert the passed in Ascii string to Unicode.
+ Optionally return the length of the strings.
+
+Arguments:
+ Ascii - Ascii string to convert
+ StrLen - Length of string
+
+Returns:
+ Pointer to malloc'ed Unicode version of Ascii
+
+--*/
+{
+ UINTN Index;
+ CHAR16 *Unicode;
+
+ //
+ // Allocate a buffer for unicode string
+ //
+ for (Index = 0; Ascii[Index] != '\0'; Index++)
+ ;
+ Unicode = malloc ((Index + 1) * sizeof (CHAR16));
+ if (Unicode == NULL) {
+ return NULL;
+ }
+
+ for (Index = 0; Ascii[Index] != '\0'; Index++) {
+ Unicode[Index] = (CHAR16) Ascii[Index];
+ }
+
+ Unicode[Index] = '\0';
+
+ if (StrLen != NULL) {
+ *StrLen = Index;
+ }
+
+ return Unicode;
+}
+
+UINTN
+CountSeparatorsInString (
+ IN CONST CHAR16 *String,
+ IN CHAR16 Separator
+ )
+/*++
+
+Routine Description:
+ Count the number of separators in String
+
+Arguments:
+ String - String to process
+ Separator - Item to count
+
+Returns:
+ Number of Separator in String
+
+--*/
+{
+ UINTN Count;
+
+ for (Count = 0; *String != '\0'; String++) {
+ if (*String == Separator) {
+ Count++;
+ }
+ }
+
+ return Count;
+}
+
+
+VOID
+EFIAPI
+PeCoffLoaderRelocateImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ VOID *DllEntryPoint;
+ CHAR16 *DllFileName;
+ HMODULE Library;
+ UINTN Index;
+
+ ASSERT (ImageContext != NULL);
+ //
+ // If we load our own PE COFF images the Windows debugger can not source
+ // level debug our code. If a valid PDB pointer exists usw it to load
+ // the *.dll file as a library using Windows* APIs. This allows
+ // source level debug. The image is still loaded and relocated
+ // in the Framework memory space like on a real system (by the code above),
+ // but the entry point points into the DLL loaded by the code bellow.
+ //
+
+ DllEntryPoint = NULL;
+
+ //
+ // Load the DLL if it's not an EBC image.
+ //
+ if ((ImageContext->PdbPointer != NULL) &&
+ (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {
+ //
+ // Convert filename from ASCII to Unicode
+ //
+ DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);
+
+ //
+ // Check that we have a valid filename
+ //
+ if (Index < 5 || DllFileName[Index - 4] != '.') {
+ free (DllFileName);
+
+ //
+ // Never return an error if PeCoffLoaderRelocateImage() succeeded.
+ // The image will run, but we just can't source level debug. If we
+ // return an error the image will not run.
+ //
+ return;
+ }
+ //
+ // Replace .PDB with .DLL on the filename
+ //
+ DllFileName[Index - 3] = 'D';
+ DllFileName[Index - 2] = 'L';
+ DllFileName[Index - 1] = 'L';
+
+ //
+ // Load the .DLL file into the user process's address space for source
+ // level debug
+ //
+ Library = LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);
+ if (Library != NULL) {
+ //
+ // InitializeDriver is the entry point we put in all our EFI DLL's. The
+ // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() suppresses the
+ // normal DLL entry point of DllMain, and prevents other modules that are
+ // referenced in side the DllFileName from being loaded. There is no error
+ // checking as the we can point to the PE32 image loaded by Tiano. This
+ // step is only needed for source level debugging
+ //
+ DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver");
+
+ }
+
+ if ((Library != NULL) && (DllEntryPoint != NULL)) {
+ ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;
+ SecPrint ("LoadLibraryEx (%S,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName);
+ } else {
+ SecPrint ("WARNING: No source level debug %S. \n", DllFileName);
+ }
+
+ free (DllFileName);
+ }
+}
+
+VOID
+EFIAPI
+PeCoffLoaderUnloadImageExtraAction (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+)
+{
+ ASSERT (ImageContext != NULL);
+}
+
+
+VOID
+_ModuleEntryPoint (
+ VOID
+ )
+{
+}