diff options
-rw-r--r-- | EmulatorPkg/Unix/Host/Host.c | 2572 |
1 files changed, 1286 insertions, 1286 deletions
diff --git a/EmulatorPkg/Unix/Host/Host.c b/EmulatorPkg/Unix/Host/Host.c index 2f01cf88a2..7d8e0e28b4 100644 --- a/EmulatorPkg/Unix/Host/Host.c +++ b/EmulatorPkg/Unix/Host/Host.c @@ -1,1286 +1,1286 @@ -/*++ @file - -Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> -Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<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 "Host.h" - -#ifdef __APPLE__ -#define MAP_ANONYMOUS MAP_ANON -#endif - - -// -// Globals -// - -EMU_THUNK_PPI mSecEmuThunkPpi = { - GasketSecUnixPeiAutoScan, - GasketSecUnixFdAddress, - GasketSecEmuThunkAddress -}; - -char *gGdbWorkingFileName = NULL; -unsigned int mScriptSymbolChangesCount = 0; - - -// -// Default information about where the FD is located. -// This array gets filled in with information from EFI_FIRMWARE_VOLUMES -// EFI_FIRMWARE_VOLUMES is a host environment variable set by system.cmd. -// The number of array elements is allocated base on parsing -// EFI_FIRMWARE_VOLUMES and the memory is never freed. -// -UINTN gFdInfoCount = 0; -EMU_FD_INFO *gFdInfo; - -// -// Array that supports seperate memory rantes. -// The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable. -// The number of array elements is allocated base on parsing -// EFI_MEMORY_SIZE and the memory is never freed. -// -UINTN gSystemMemoryCount = 0; -EMU_SYSTEM_MEMORY *gSystemMemory; - - - -UINTN mImageContextModHandleArraySize = 0; -IMAGE_CONTEXT_TO_MOD_HANDLE *mImageContextModHandleArray = NULL; - -EFI_PEI_PPI_DESCRIPTOR *gPpiList; - - -int gInXcode = 0; - - -/*++ - Breakpoint target for Xcode project. Set in the Xcode XML - - Xcode breakpoint will 'source Host.gdb' - gGdbWorkingFileName is set to Host.gdb - -**/ -VOID -SecGdbConfigBreak ( - VOID - ) -{ -} - - - -/*++ - -Routine Description: - Main entry point to SEC for Unix. This is a unix program - -Arguments: - Argc - Number of command line arguments - Argv - Array of command line argument strings - Envp - Array of environmemt variable strings - -Returns: - 0 - Normal exit - 1 - Abnormal exit - -**/ -int -main ( - IN int Argc, - IN char **Argv, - IN char **Envp - ) -{ - EFI_STATUS Status; - EFI_PHYSICAL_ADDRESS InitialStackMemory; - UINT64 InitialStackMemorySize; - UINTN Index; - UINTN Index1; - UINTN Index2; - UINTN PeiIndex; - CHAR8 *FileName; - BOOLEAN Done; - EFI_PEI_FILE_HANDLE FileHandle; - VOID *SecFile; - CHAR16 *MemorySizeStr; - CHAR16 *FirmwareVolumesStr; - UINTN *StackPointer; - FILE *GdbTempFile; - - // - // Xcode does not support sourcing gdb scripts directly, so the Xcode XML - // has a break point script to source the GdbRun script. - // - SecGdbConfigBreak (); - - // - // If dlopen doesn't work, then we build a gdb script to allow the - // symbols to be loaded. - // - Index = strlen (*Argv); - gGdbWorkingFileName = AllocatePool (Index + strlen(".gdb") + 1); - strcpy (gGdbWorkingFileName, *Argv); - strcat (gGdbWorkingFileName, ".gdb"); - - // - // Empty out the gdb symbols script file. - // - GdbTempFile = fopen (gGdbWorkingFileName, "w"); - if (GdbTempFile != NULL) { - fclose (GdbTempFile); - } - - printf ("\nEDK II UNIX Host Emulation Environment from edk2.sourceforge.net\n"); - - setbuf (stdout, 0); - setbuf (stderr, 0); - - MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize); - FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume); - - // - // PPIs pased into PEI_CORE - // - AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi); - - SecInitThunkProtocol (); - - // - // Emulator Bus Driver Thunks - // - AddThunkProtocol (&gX11ThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE); - AddThunkProtocol (&gPosixFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE); - AddThunkProtocol (&gBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE); - AddThunkProtocol (&gSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE); - - // - // Emulator other Thunks - // - AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE); - - // EmuSecLibConstructor (); - - gPpiList = GetThunkPpiList (); - - // - // Allocate space for gSystemMemory Array - // - gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1; - gSystemMemory = AllocateZeroPool (gSystemMemoryCount * sizeof (EMU_SYSTEM_MEMORY)); - if (gSystemMemory == NULL) { - printf ("ERROR : Can not allocate memory for system. Exiting.\n"); - exit (1); - } - // - // Allocate space for gSystemMemory Array - // - gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1; - gFdInfo = AllocateZeroPool (gFdInfoCount * sizeof (EMU_FD_INFO)); - if (gFdInfo == NULL) { - printf ("ERROR : Can not allocate memory for fd info. Exiting.\n"); - exit (1); - } - - printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode)); - - // - // Open up a 128K file to emulate temp memory for SEC. - // on a real platform this would be SRAM, or using the cache as RAM. - // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping - // - InitialStackMemorySize = STACK_SIZE; - InitialStackMemory = (UINTN)MapMemory ( - 0, (UINT32) InitialStackMemorySize, - PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE - ); - if (InitialStackMemory == 0) { - printf ("ERROR : Can not open SecStack Exiting\n"); - exit (1); - } - - printf (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n", - (unsigned int)(InitialStackMemorySize / 1024), - (unsigned long)InitialStackMemory - ); - - for (StackPointer = (UINTN*) (UINTN) InitialStackMemory; - StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize); - StackPointer ++) { - *StackPointer = 0x5AA55AA5; - } - - // - // Open All the firmware volumes and remember the info in the gFdInfo global - // - FileName = (CHAR8 *) AllocatePool (StrLen (FirmwareVolumesStr) + 1); - if (FileName == NULL) { - printf ("ERROR : Can not allocate memory for firmware volume string\n"); - exit (1); - } - - Index2 = 0; - for (Done = FALSE, Index = 0, PeiIndex = 0, SecFile = NULL; - FirmwareVolumesStr[Index2] != 0; - Index++) { - for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) { - FileName[Index1++] = FirmwareVolumesStr[Index2]; - } - if (FirmwareVolumesStr[Index2] == '!') { - Index2++; - } - FileName[Index1] = '\0'; - - if (Index == 0) { - // Map FV Recovery Read Only and other areas Read/Write - Status = MapFd0 ( - FileName, - &gFdInfo[0].Address, - &gFdInfo[0].Size - ); - } else { - // - // Open the FD and remmeber where it got mapped into our processes address space - // Maps Read Only - // - Status = MapFile ( - FileName, - &gFdInfo[Index].Address, - &gFdInfo[Index].Size - ); - } - if (EFI_ERROR (Status)) { - printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status); - exit (1); - } - - printf (" FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address); - - 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)(UINTN)gFdInfo[Index].Address, - &FileHandle - ); - if (!EFI_ERROR (Status)) { - Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile); - if (!EFI_ERROR (Status)) { - PeiIndex = Index; - printf (" contains SEC Core"); - } - } - } - - printf ("\n"); - } - - if (SecFile == NULL) { - printf ("ERROR : SEC not found!\n"); - exit (1); - } - - // - // 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. - // - Index1 = 0; - Index = 0; - while (1) { - UINTN val = 0; - // - // Save the size of the memory. - // - while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') { - val = val * 10 + MemorySizeStr[Index1] - '0'; - Index1++; - } - gSystemMemory[Index++].Size = val * 0x100000; - if (MemorySizeStr[Index1] == 0) { - break; - } - Index1++; - } - - printf ("\n"); - - // - // Hand off to SEC - // - SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, 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. - // - printf ("ERROR : SEC returned\n"); - exit (1); -} - - -EFI_PHYSICAL_ADDRESS * -MapMemory ( - IN INTN fd, - IN UINT64 length, - IN INTN prot, - IN INTN flags - ) -{ - STATIC UINTN base = 0x40000000; - CONST UINTN align = (1 << 24); - VOID *res = NULL; - BOOLEAN isAligned = 0; - - // - // Try to get an aligned block somewhere in the address space of this - // process. - // - while((!isAligned) && (base != 0)) { - res = mmap ((void *)base, length, prot, flags, fd, 0); - if (res == MAP_FAILED) { - return NULL; - } - if ((((UINTN)res) & ~(align-1)) == (UINTN)res) { - isAligned=1; - } else { - munmap(res, length); - base += align; - } - } - return res; -} - - -/*++ - -Routine Description: - Opens and memory maps a file using Unix 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 passed in as NULL the a new memory region is used. - If passed in as non NULL 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 - -**/ -EFI_STATUS -MapFile ( - IN CHAR8 *FileName, - IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, - OUT UINT64 *Length - ) -{ - int fd; - VOID *res; - UINTN FileSize; - - fd = open (FileName, O_RDWR); - if (fd < 0) { - return EFI_NOT_FOUND; - } - FileSize = lseek (fd, 0, SEEK_END); - - - res = MapMemory (fd, FileSize, PROT_READ | PROT_EXEC, MAP_PRIVATE); - - close (fd); - - if (res == NULL) { - perror ("MapFile() Failed"); - return EFI_DEVICE_ERROR; - } - - *Length = (UINT64) FileSize; - *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res; - - return EFI_SUCCESS; -} - -EFI_STATUS -MapFd0 ( - IN CHAR8 *FileName, - IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, - OUT UINT64 *Length - ) -{ - int fd; - void *res, *res2, *res3; - UINTN FileSize; - UINTN FvSize; - void *EmuMagicPage; - - fd = open (FileName, O_RDWR); - if (fd < 0) { - return EFI_NOT_FOUND; - } - FileSize = lseek (fd, 0, SEEK_END); - - FvSize = FixedPcdGet64 (PcdEmuFlashFvRecoverySize); - - // Assume start of FD is Recovery FV, and make it write protected - res = mmap ( - (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase), - FvSize, - PROT_READ | PROT_EXEC, - MAP_PRIVATE, - fd, - 0 - ); - if (res == MAP_FAILED) { - perror ("MapFd0() Failed res ="); - close (fd); - return EFI_DEVICE_ERROR; - } else if (res != (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase)) { - // We could not load at the build address, so we need to allow writes - munmap (res, FvSize); - res = mmap ( - (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase), - FvSize, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE, - fd, - 0 - ); - if (res == MAP_FAILED) { - perror ("MapFd0() Failed res ="); - close (fd); - return EFI_DEVICE_ERROR; - } - } - - // Map the rest of the FD as read/write - res2 = mmap ( - (void *)(UINTN)(FixedPcdGet64 (PcdEmuFlashFvRecoveryBase) + FvSize), - FileSize - FvSize, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_SHARED, - fd, - FvSize - ); - close (fd); - if (res2 == MAP_FAILED) { - perror ("MapFd0() Failed res2 ="); - return EFI_DEVICE_ERROR; - } - - // - // 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); - if (EmuMagicPage != NULL) { - res3 = mmap ( - (void *)EmuMagicPage, - 4096, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - 0, - 0 - ); - if (res3 != EmuMagicPage) { - printf ("MapFd0(): Could not allocate PeiServicesTablePage @ %lx\n", (long unsigned int)EmuMagicPage); - return EFI_DEVICE_ERROR; - } - } - - *Length = (UINT64) FileSize; - *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res; - - return EFI_SUCCESS; -} - - -/*++ - -Routine Description: - This is the service to load the SEC Core from the Firmware Volume - -Arguments: - LargestRegion - Memory to use for SEC. - LargestRegionSize - Size of Memory to use for PEI - BootFirmwareVolumeBase - Start of the Boot FV - PeiCorePe32File - SEC PE32 - -Returns: - Success means control is transfered and thus we should never return - -**/ -VOID -SecLoadFromCore ( - IN UINTN LargestRegion, - IN UINTN LargestRegionSize, - IN UINTN BootFirmwareVolumeBase, - IN VOID *PeiCorePe32File - ) -{ - EFI_STATUS Status; - EFI_PHYSICAL_ADDRESS TopOfMemory; - VOID *TopOfStack; - EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint; - EFI_SEC_PEI_HAND_OFF *SecCoreData; - UINTN PeiStackSize; - - // - // Compute Top Of Memory for Stack and PEI Core Allocations - // - TopOfMemory = LargestRegion + LargestRegionSize; - PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1); - - // - // |-----------| <---- TemporaryRamBase + TemporaryRamSize - // | Heap | - // | | - // |-----------| <---- StackBase / PeiTemporaryMemoryBase - // | | - // | Stack | - // |-----------| <---- TemporaryRamBase - // - TopOfStack = (VOID *)(LargestRegion + PeiStackSize); - TopOfMemory = LargestRegion + PeiStackSize; - - // - // 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 = (VOID*)BootFirmwareVolumeBase; - SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdEmuFirmwareFdSize); - SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion; - SecCoreData->TemporaryRamSize = STACK_SIZE; - SecCoreData->StackBase = SecCoreData->TemporaryRamBase; - SecCoreData->StackSize = PeiStackSize; - SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize); - SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize; - - // - // Find the SEC Core Entry Point - // - Status = SecPeCoffGetEntryPoint (PeiCorePe32File, (VOID **)&PeiCoreEntryPoint); - if (EFI_ERROR (Status)) { - return ; - } - - // - // Transfer control to the SEC Core - // - PeiSwitchStacks ( - (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint, - SecCoreData, - (VOID *)gPpiList, - TopOfStack - ); - // - // If we get here, then the SEC Core returned. This is an error - // - return ; -} - - -/*++ - -Routine Description: - This service is called from Index == 0 until it returns EFI_UNSUPPORTED. - It allows discontiguous 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 -SecUnixPeiAutoScan ( - IN UINTN Index, - OUT EFI_PHYSICAL_ADDRESS *MemoryBase, - OUT UINT64 *MemorySize - ) -{ - void *res; - - if (Index >= gSystemMemoryCount) { - return EFI_UNSUPPORTED; - } - - *MemoryBase = 0; - res = MapMemory ( - 0, gSystemMemory[Index].Size, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS - ); - if (res == MAP_FAILED) { - return EFI_DEVICE_ERROR; - } - *MemorySize = gSystemMemory[Index].Size; - *MemoryBase = (UINTN)res; - gSystemMemory[Index].Memory = *MemoryBase; - - return EFI_SUCCESS; -} - - -/*++ - -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; -} - - -/*++ - -Routine Description: - Since the SEC is the only Unix program in stack it must export - an interface to do POSIX calls. gUnix is initailized in UnixThunk.c. - -Arguments: - InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL); - InterfaceBase - Address of the gUnix global - -Returns: - EFI_SUCCESS - Data returned - -**/ -VOID * -SecEmuThunkAddress ( - VOID - ) -{ - return &gEmuThunkProtocol; -} - - - -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; - } - - if (ImageContext.ImageAddress != (UINTN)Pe32Data) { - // - // Relocate image to match the address where it resides - // - ImageContext.ImageAddress = (UINTN)Pe32Data; - Status = PeCoffLoaderLoadImage (&ImageContext); - if (EFI_ERROR (Status)) { - return Status; - } - - Status = PeCoffLoaderRelocateImage (&ImageContext); - if (EFI_ERROR (Status)) { - return Status; - } - } else { - // - // Or just return image entry point - // - ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data); - Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint); - if (EFI_ERROR (Status)) { - return Status; - } - ImageContext.EntryPoint = (UINTN)*EntryPoint; - } - - // On Unix a dlopen is done that will change the entry point - SecPeCoffRelocateImageExtraAction (&ImageContext); - *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint; - - return Status; -} - - - -/*++ - -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 -SecUnixFdAddress ( - 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 = gFdInfo[Index].Address; - *FdSize = 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: - Count the number of seperators in String - -Arguments: - String - String to process - Seperator - Item to count - -Returns: - Number of Seperator in String - -**/ -UINTN -CountSeperatorsInString ( - IN const CHAR16 *String, - IN CHAR16 Seperator - ) -{ - UINTN Count; - - for (Count = 0; *String != '\0'; String++) { - if (*String == Seperator) { - Count++; - } - } - - return Count; -} - - -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; -} - - -/*++ - -Routine Description: - Store the ModHandle in an array indexed by the Pdb File name. - The ModHandle is needed to unload the image. - -Arguments: - ImageContext - Input data returned from PE Laoder Library. Used to find the - .PDB file name of the PE Image. - ModHandle - Returned from LoadLibraryEx() and stored for call to - FreeLibrary(). - -Returns: - EFI_SUCCESS - ModHandle was stored. - -**/ -EFI_STATUS -AddHandle ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, - IN VOID *ModHandle - ) -{ - UINTN Index; - IMAGE_CONTEXT_TO_MOD_HANDLE *Array; - UINTN PreviousSize; - - - Array = mImageContextModHandleArray; - for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) { - if (Array->ImageContext == NULL) { - // - // Make a copy of the stirng and store the ModHandle - // - Array->ImageContext = ImageContext; - Array->ModHandle = ModHandle; - return EFI_SUCCESS; - } - } - - // - // No free space in mImageContextModHandleArray so grow it by - // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will - // copy the old values to the new locaiton. But it does - // not zero the new memory area. - // - PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE); - mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE; - - mImageContextModHandleArray = ReallocatePool ( - (mImageContextModHandleArraySize - 1) * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE), - mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE), - mImageContextModHandleArray - ); - if (mImageContextModHandleArray == NULL) { - ASSERT (FALSE); - return EFI_OUT_OF_RESOURCES; - } - - memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE)); - - return AddHandle (ImageContext, ModHandle); -} - - -/*++ - -Routine Description: - Return the ModHandle and delete the entry in the array. - -Arguments: - ImageContext - Input data returned from PE Laoder Library. Used to find the - .PDB file name of the PE Image. - -Returns: - ModHandle - ModHandle assoicated with ImageContext is returned - NULL - No ModHandle associated with ImageContext - -**/ -VOID * -RemoveHandle ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext - ) -{ - UINTN Index; - IMAGE_CONTEXT_TO_MOD_HANDLE *Array; - - if (ImageContext->PdbPointer == NULL) { - // - // If no PDB pointer there is no ModHandle so return NULL - // - return NULL; - } - - Array = mImageContextModHandleArray; - for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) { - if (Array->ImageContext == ImageContext) { - // - // If you find a match return it and delete the entry - // - Array->ImageContext = NULL; - return Array->ModHandle; - } - } - - return NULL; -} - - - -BOOLEAN -IsPdbFile ( - IN CHAR8 *PdbFileName - ) -{ - UINTN Len; - - if (PdbFileName == NULL) { - return FALSE; - } - - Len = strlen (PdbFileName); - if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) { - return FALSE; - } - - if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') && - (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') && - (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) { - return TRUE; - } - - return FALSE; -} - - -#define MAX_SPRINT_BUFFER_SIZE 0x200 - -void -PrintLoadAddress ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext - ) -{ - if (ImageContext->PdbPointer == NULL) { - fprintf (stderr, - "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n", - (unsigned long)(ImageContext->ImageAddress), - (unsigned long)ImageContext->EntryPoint - ); - } else { - fprintf (stderr, - "0x%08lx Loading %s with entry point 0x%08lx\n", - (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), - ImageContext->PdbPointer, - (unsigned long)ImageContext->EntryPoint - ); - } - // Keep output synced up - fflush (stderr); -} - - -/** - Loads the image using dlopen so symbols will be automatically - loaded by gdb. - - @param ImageContext The PE/COFF image context - - @retval TRUE - The image was successfully loaded - @retval FALSE - The image was successfully loaded - -**/ -BOOLEAN -DlLoadImage ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext - ) -{ - -#ifdef __APPLE__ - - return FALSE; - -#else - - void *Handle = NULL; - void *Entry = NULL; - - if (ImageContext->PdbPointer == NULL) { - return FALSE; - } - - if (!IsPdbFile (ImageContext->PdbPointer)) { - return FALSE; - } - - fprintf ( - stderr, - "Loading %s 0x%08lx - entry point 0x%08lx\n", - ImageContext->PdbPointer, - (unsigned long)ImageContext->ImageAddress, - (unsigned long)ImageContext->EntryPoint - ); - - Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW); - if (Handle != NULL) { - Entry = dlsym (Handle, "_ModuleEntryPoint"); - AddHandle (ImageContext, Handle); - } else { - printf("%s\n", dlerror()); - } - - if (Entry != NULL) { - ImageContext->EntryPoint = (UINTN)Entry; - printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry); - return TRUE; - } else { - return FALSE; - } - -#endif -} - - -VOID -SecGdbScriptBreak ( - char *FileName, - int FileNameLength, - long unsigned int LoadAddress, - int AddSymbolFlag - ) -{ - return; -} - - -/** - Adds the image to a gdb script so it's symbols can be loaded. - The AddFirmwareSymbolFile helper macro is used. - - @param ImageContext The PE/COFF image context - -**/ -VOID -GdbScriptAddImage ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext - ) -{ - - PrintLoadAddress (ImageContext); - - if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) { - FILE *GdbTempFile; - if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) { - GdbTempFile = fopen (gGdbWorkingFileName, "a"); - if (GdbTempFile != NULL) { - long unsigned int SymbolsAddr = (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders); - mScriptSymbolChangesCount++; - fprintf ( - GdbTempFile, - "AddFirmwareSymbolFile 0x%x %s 0x%08lx\n", - mScriptSymbolChangesCount, - ImageContext->PdbPointer, - SymbolsAddr - ); - fclose (GdbTempFile); - // This is for the lldb breakpoint only - SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1); - } else { - ASSERT (FALSE); - } - } else { - GdbTempFile = fopen (gGdbWorkingFileName, "w"); - if (GdbTempFile != NULL) { - fprintf ( - GdbTempFile, - "add-symbol-file %s 0x%08lx\n", - ImageContext->PdbPointer, - (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders) - ); - fclose (GdbTempFile); - - // - // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint. - // Hey what can you say scripting in gdb is not that great.... - // Also used for the lldb breakpoint script. The lldb breakpoint script does - // not use the file, it uses the arguments. - // - SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1); - } else { - ASSERT (FALSE); - } - } - } -} - - -VOID -EFIAPI -SecPeCoffRelocateImageExtraAction ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext - ) -{ - if (!DlLoadImage (ImageContext)) { - GdbScriptAddImage (ImageContext); - } -} - - -/** - Adds the image to a gdb script so it's symbols can be unloaded. - The RemoveFirmwareSymbolFile helper macro is used. - - @param ImageContext The PE/COFF image context - -**/ -VOID -GdbScriptRemoveImage ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext - ) -{ - FILE *GdbTempFile; - - // - // Need to skip .PDB files created from VC++ - // - if (IsPdbFile (ImageContext->PdbPointer)) { - return; - } - - if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) { - // - // Write the file we need for the gdb script - // - GdbTempFile = fopen (gGdbWorkingFileName, "a"); - if (GdbTempFile != NULL) { - mScriptSymbolChangesCount++; - fprintf ( - GdbTempFile, - "RemoveFirmwareSymbolFile 0x%x %s\n", - mScriptSymbolChangesCount, - ImageContext->PdbPointer - ); - fclose (GdbTempFile); - SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0); - } else { - ASSERT (FALSE); - } - } else { - GdbTempFile = fopen (gGdbWorkingFileName, "w"); - if (GdbTempFile != NULL) { - fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer); - fclose (GdbTempFile); - - // - // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint. - // Hey what can you say scripting in gdb is not that great.... - // - SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0); - } else { - ASSERT (FALSE); - } - } -} - - -VOID -EFIAPI -SecPeCoffUnloadImageExtraAction ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext - ) -{ - VOID *Handle; - - // - // Check to see if the image symbols were loaded with gdb script, or dlopen - // - Handle = RemoveHandle (ImageContext); - if (Handle != NULL) { -#ifndef __APPLE__ - dlclose (Handle); -#endif - return; - } - - GdbScriptRemoveImage (ImageContext); -} - - +/*++ @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<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 "Host.h"
+
+#ifdef __APPLE__
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+
+//
+// Globals
+//
+
+EMU_THUNK_PPI mSecEmuThunkPpi = {
+ GasketSecUnixPeiAutoScan,
+ GasketSecUnixFdAddress,
+ GasketSecEmuThunkAddress
+};
+
+char *gGdbWorkingFileName = NULL;
+unsigned int mScriptSymbolChangesCount = 0;
+
+
+//
+// Default information about where the FD is located.
+// This array gets filled in with information from EFI_FIRMWARE_VOLUMES
+// EFI_FIRMWARE_VOLUMES is a host environment variable set by system.cmd.
+// The number of array elements is allocated base on parsing
+// EFI_FIRMWARE_VOLUMES and the memory is never freed.
+//
+UINTN gFdInfoCount = 0;
+EMU_FD_INFO *gFdInfo;
+
+//
+// Array that supports seperate memory rantes.
+// The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable.
+// The number of array elements is allocated base on parsing
+// EFI_MEMORY_SIZE and the memory is never freed.
+//
+UINTN gSystemMemoryCount = 0;
+EMU_SYSTEM_MEMORY *gSystemMemory;
+
+
+
+UINTN mImageContextModHandleArraySize = 0;
+IMAGE_CONTEXT_TO_MOD_HANDLE *mImageContextModHandleArray = NULL;
+
+EFI_PEI_PPI_DESCRIPTOR *gPpiList;
+
+
+int gInXcode = 0;
+
+
+/*++
+ Breakpoint target for Xcode project. Set in the Xcode XML
+
+ Xcode breakpoint will 'source Host.gdb'
+ gGdbWorkingFileName is set to Host.gdb
+
+**/
+VOID
+SecGdbConfigBreak (
+ VOID
+ )
+{
+}
+
+
+
+/*++
+
+Routine Description:
+ Main entry point to SEC for Unix. This is a unix program
+
+Arguments:
+ Argc - Number of command line arguments
+ Argv - Array of command line argument strings
+ Envp - Array of environmemt variable strings
+
+Returns:
+ 0 - Normal exit
+ 1 - Abnormal exit
+
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv,
+ IN char **Envp
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS InitialStackMemory;
+ UINT64 InitialStackMemorySize;
+ UINTN Index;
+ UINTN Index1;
+ UINTN Index2;
+ UINTN PeiIndex;
+ CHAR8 *FileName;
+ BOOLEAN Done;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *SecFile;
+ CHAR16 *MemorySizeStr;
+ CHAR16 *FirmwareVolumesStr;
+ UINTN *StackPointer;
+ FILE *GdbTempFile;
+
+ //
+ // Xcode does not support sourcing gdb scripts directly, so the Xcode XML
+ // has a break point script to source the GdbRun script.
+ //
+ SecGdbConfigBreak ();
+
+ //
+ // If dlopen doesn't work, then we build a gdb script to allow the
+ // symbols to be loaded.
+ //
+ Index = strlen (*Argv);
+ gGdbWorkingFileName = AllocatePool (Index + strlen(".gdb") + 1);
+ strcpy (gGdbWorkingFileName, *Argv);
+ strcat (gGdbWorkingFileName, ".gdb");
+
+ //
+ // Empty out the gdb symbols script file.
+ //
+ GdbTempFile = fopen (gGdbWorkingFileName, "w");
+ if (GdbTempFile != NULL) {
+ fclose (GdbTempFile);
+ }
+
+ printf ("\nEDK II UNIX Host Emulation Environment from edk2.sourceforge.net\n");
+
+ setbuf (stdout, 0);
+ setbuf (stderr, 0);
+
+ MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);
+ FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);
+
+ //
+ // PPIs pased into PEI_CORE
+ //
+ AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
+
+ SecInitThunkProtocol ();
+
+ //
+ // Emulator Bus Driver Thunks
+ //
+ AddThunkProtocol (&gX11ThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
+ AddThunkProtocol (&gPosixFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
+ AddThunkProtocol (&gBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);
+ AddThunkProtocol (&gSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);
+
+ //
+ // Emulator other Thunks
+ //
+ AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE);
+
+ // EmuSecLibConstructor ();
+
+ gPpiList = GetThunkPpiList ();
+
+ //
+ // Allocate space for gSystemMemory Array
+ //
+ gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;
+ gSystemMemory = AllocateZeroPool (gSystemMemoryCount * sizeof (EMU_SYSTEM_MEMORY));
+ if (gSystemMemory == NULL) {
+ printf ("ERROR : Can not allocate memory for system. Exiting.\n");
+ exit (1);
+ }
+ //
+ // Allocate space for gSystemMemory Array
+ //
+ gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
+ gFdInfo = AllocateZeroPool (gFdInfoCount * sizeof (EMU_FD_INFO));
+ if (gFdInfo == NULL) {
+ printf ("ERROR : Can not allocate memory for fd info. Exiting.\n");
+ exit (1);
+ }
+
+ printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode));
+
+ //
+ // Open up a 128K file to emulate temp memory for SEC.
+ // on a real platform this would be SRAM, or using the cache as RAM.
+ // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping
+ //
+ InitialStackMemorySize = STACK_SIZE;
+ InitialStackMemory = (UINTN)MapMemory (
+ 0, (UINT32) InitialStackMemorySize,
+ PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE
+ );
+ if (InitialStackMemory == 0) {
+ printf ("ERROR : Can not open SecStack Exiting\n");
+ exit (1);
+ }
+
+ printf (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",
+ (unsigned int)(InitialStackMemorySize / 1024),
+ (unsigned long)InitialStackMemory
+ );
+
+ for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
+ StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
+ StackPointer ++) {
+ *StackPointer = 0x5AA55AA5;
+ }
+
+ //
+ // Open All the firmware volumes and remember the info in the gFdInfo global
+ //
+ FileName = (CHAR8 *) AllocatePool (StrLen (FirmwareVolumesStr) + 1);
+ if (FileName == NULL) {
+ printf ("ERROR : Can not allocate memory for firmware volume string\n");
+ exit (1);
+ }
+
+ Index2 = 0;
+ for (Done = FALSE, Index = 0, PeiIndex = 0, SecFile = NULL;
+ FirmwareVolumesStr[Index2] != 0;
+ Index++) {
+ for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) {
+ FileName[Index1++] = FirmwareVolumesStr[Index2];
+ }
+ if (FirmwareVolumesStr[Index2] == '!') {
+ Index2++;
+ }
+ FileName[Index1] = '\0';
+
+ if (Index == 0) {
+ // Map FV Recovery Read Only and other areas Read/Write
+ Status = MapFd0 (
+ FileName,
+ &gFdInfo[0].Address,
+ &gFdInfo[0].Size
+ );
+ } else {
+ //
+ // Open the FD and remmeber where it got mapped into our processes address space
+ // Maps Read Only
+ //
+ Status = MapFile (
+ FileName,
+ &gFdInfo[Index].Address,
+ &gFdInfo[Index].Size
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status);
+ exit (1);
+ }
+
+ printf (" FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address);
+
+ 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)(UINTN)gFdInfo[Index].Address,
+ &FileHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
+ if (!EFI_ERROR (Status)) {
+ PeiIndex = Index;
+ printf (" contains SEC Core");
+ }
+ }
+ }
+
+ printf ("\n");
+ }
+
+ if (SecFile == NULL) {
+ printf ("ERROR : SEC not found!\n");
+ exit (1);
+ }
+
+ //
+ // 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.
+ //
+ Index1 = 0;
+ Index = 0;
+ while (1) {
+ UINTN val = 0;
+ //
+ // Save the size of the memory.
+ //
+ while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
+ val = val * 10 + MemorySizeStr[Index1] - '0';
+ Index1++;
+ }
+ gSystemMemory[Index++].Size = val * 0x100000;
+ if (MemorySizeStr[Index1] == 0) {
+ break;
+ }
+ Index1++;
+ }
+
+ printf ("\n");
+
+ //
+ // Hand off to SEC
+ //
+ SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, 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.
+ //
+ printf ("ERROR : SEC returned\n");
+ exit (1);
+}
+
+
+EFI_PHYSICAL_ADDRESS *
+MapMemory (
+ IN INTN fd,
+ IN UINT64 length,
+ IN INTN prot,
+ IN INTN flags
+ )
+{
+ STATIC UINTN base = 0x40000000;
+ CONST UINTN align = (1 << 24);
+ VOID *res = NULL;
+ BOOLEAN isAligned = 0;
+
+ //
+ // Try to get an aligned block somewhere in the address space of this
+ // process.
+ //
+ while((!isAligned) && (base != 0)) {
+ res = mmap ((void *)base, length, prot, flags, fd, 0);
+ if (res == MAP_FAILED) {
+ return NULL;
+ }
+ if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
+ isAligned=1;
+ } else {
+ munmap(res, length);
+ base += align;
+ }
+ }
+ return res;
+}
+
+
+/*++
+
+Routine Description:
+ Opens and memory maps a file using Unix 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 passed in as NULL the a new memory region is used.
+ If passed in as non NULL 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
+
+**/
+EFI_STATUS
+MapFile (
+ IN CHAR8 *FileName,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ OUT UINT64 *Length
+ )
+{
+ int fd;
+ VOID *res;
+ UINTN FileSize;
+
+ fd = open (FileName, O_RDWR);
+ if (fd < 0) {
+ return EFI_NOT_FOUND;
+ }
+ FileSize = lseek (fd, 0, SEEK_END);
+
+
+ res = MapMemory (fd, FileSize, PROT_READ | PROT_EXEC, MAP_PRIVATE);
+
+ close (fd);
+
+ if (res == NULL) {
+ perror ("MapFile() Failed");
+ return EFI_DEVICE_ERROR;
+ }
+
+ *Length = (UINT64) FileSize;
+ *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MapFd0 (
+ IN CHAR8 *FileName,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ OUT UINT64 *Length
+ )
+{
+ int fd;
+ void *res, *res2, *res3;
+ UINTN FileSize;
+ UINTN FvSize;
+ void *EmuMagicPage;
+
+ fd = open (FileName, O_RDWR);
+ if (fd < 0) {
+ return EFI_NOT_FOUND;
+ }
+ FileSize = lseek (fd, 0, SEEK_END);
+
+ FvSize = FixedPcdGet64 (PcdEmuFlashFvRecoverySize);
+
+ // Assume start of FD is Recovery FV, and make it write protected
+ res = mmap (
+ (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase),
+ FvSize,
+ PROT_READ | PROT_EXEC,
+ MAP_PRIVATE,
+ fd,
+ 0
+ );
+ if (res == MAP_FAILED) {
+ perror ("MapFd0() Failed res =");
+ close (fd);
+ return EFI_DEVICE_ERROR;
+ } else if (res != (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase)) {
+ // We could not load at the build address, so we need to allow writes
+ munmap (res, FvSize);
+ res = mmap (
+ (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase),
+ FvSize,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE,
+ fd,
+ 0
+ );
+ if (res == MAP_FAILED) {
+ perror ("MapFd0() Failed res =");
+ close (fd);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ // Map the rest of the FD as read/write
+ res2 = mmap (
+ (void *)(UINTN)(FixedPcdGet64 (PcdEmuFlashFvRecoveryBase) + FvSize),
+ FileSize - FvSize,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_SHARED,
+ fd,
+ FvSize
+ );
+ close (fd);
+ if (res2 == MAP_FAILED) {
+ perror ("MapFd0() Failed res2 =");
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // 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);
+ if (EmuMagicPage != NULL) {
+ res3 = mmap (
+ (void *)EmuMagicPage,
+ 4096,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ 0,
+ 0
+ );
+ if (res3 != EmuMagicPage) {
+ printf ("MapFd0(): Could not allocate PeiServicesTablePage @ %lx\n", (long unsigned int)EmuMagicPage);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ *Length = (UINT64) FileSize;
+ *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
+
+ return EFI_SUCCESS;
+}
+
+
+/*++
+
+Routine Description:
+ This is the service to load the SEC Core from the Firmware Volume
+
+Arguments:
+ LargestRegion - Memory to use for SEC.
+ LargestRegionSize - Size of Memory to use for PEI
+ BootFirmwareVolumeBase - Start of the Boot FV
+ PeiCorePe32File - SEC PE32
+
+Returns:
+ Success means control is transfered and thus we should never return
+
+**/
+VOID
+SecLoadFromCore (
+ IN UINTN LargestRegion,
+ IN UINTN LargestRegionSize,
+ IN UINTN BootFirmwareVolumeBase,
+ IN VOID *PeiCorePe32File
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS TopOfMemory;
+ VOID *TopOfStack;
+ EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ UINTN PeiStackSize;
+
+ //
+ // Compute Top Of Memory for Stack and PEI Core Allocations
+ //
+ TopOfMemory = LargestRegion + LargestRegionSize;
+ PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
+
+ //
+ // |-----------| <---- TemporaryRamBase + TemporaryRamSize
+ // | Heap |
+ // | |
+ // |-----------| <---- StackBase / PeiTemporaryMemoryBase
+ // | |
+ // | Stack |
+ // |-----------| <---- TemporaryRamBase
+ //
+ TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
+ TopOfMemory = LargestRegion + PeiStackSize;
+
+ //
+ // 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 = (VOID*)BootFirmwareVolumeBase;
+ SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdEmuFirmwareFdSize);
+ SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
+ SecCoreData->TemporaryRamSize = STACK_SIZE;
+ SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
+ SecCoreData->StackSize = PeiStackSize;
+ SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
+ SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
+
+ //
+ // Find the SEC Core Entry Point
+ //
+ Status = SecPeCoffGetEntryPoint (PeiCorePe32File, (VOID **)&PeiCoreEntryPoint);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Transfer control to the SEC Core
+ //
+ PeiSwitchStacks (
+ (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
+ SecCoreData,
+ (VOID *)gPpiList,
+ TopOfStack
+ );
+ //
+ // If we get here, then the SEC Core returned. This is an error
+ //
+ return ;
+}
+
+
+/*++
+
+Routine Description:
+ This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
+ It allows discontiguous 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
+SecUnixPeiAutoScan (
+ IN UINTN Index,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
+ OUT UINT64 *MemorySize
+ )
+{
+ void *res;
+
+ if (Index >= gSystemMemoryCount) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *MemoryBase = 0;
+ res = MapMemory (
+ 0, gSystemMemory[Index].Size,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS
+ );
+ if (res == MAP_FAILED) {
+ return EFI_DEVICE_ERROR;
+ }
+ *MemorySize = gSystemMemory[Index].Size;
+ *MemoryBase = (UINTN)res;
+ gSystemMemory[Index].Memory = *MemoryBase;
+
+ return EFI_SUCCESS;
+}
+
+
+/*++
+
+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;
+}
+
+
+/*++
+
+Routine Description:
+ Since the SEC is the only Unix program in stack it must export
+ an interface to do POSIX calls. gUnix is initailized in UnixThunk.c.
+
+Arguments:
+ InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
+ InterfaceBase - Address of the gUnix global
+
+Returns:
+ EFI_SUCCESS - Data returned
+
+**/
+VOID *
+SecEmuThunkAddress (
+ VOID
+ )
+{
+ return &gEmuThunkProtocol;
+}
+
+
+
+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;
+ }
+
+ if (ImageContext.ImageAddress != (UINTN)Pe32Data) {
+ //
+ // Relocate image to match the address where it resides
+ //
+ ImageContext.ImageAddress = (UINTN)Pe32Data;
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Or just return image entry point
+ //
+ ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data);
+ Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ImageContext.EntryPoint = (UINTN)*EntryPoint;
+ }
+
+ // On Unix a dlopen is done that will change the entry point
+ SecPeCoffRelocateImageExtraAction (&ImageContext);
+ *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
+
+ return Status;
+}
+
+
+
+/*++
+
+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
+SecUnixFdAddress (
+ 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 = gFdInfo[Index].Address;
+ *FdSize = 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:
+ Count the number of seperators in String
+
+Arguments:
+ String - String to process
+ Seperator - Item to count
+
+Returns:
+ Number of Seperator in String
+
+**/
+UINTN
+CountSeperatorsInString (
+ IN const CHAR16 *String,
+ IN CHAR16 Seperator
+ )
+{
+ UINTN Count;
+
+ for (Count = 0; *String != '\0'; String++) {
+ if (*String == Seperator) {
+ Count++;
+ }
+ }
+
+ return Count;
+}
+
+
+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;
+}
+
+
+/*++
+
+Routine Description:
+ Store the ModHandle in an array indexed by the Pdb File name.
+ The ModHandle is needed to unload the image.
+
+Arguments:
+ ImageContext - Input data returned from PE Laoder Library. Used to find the
+ .PDB file name of the PE Image.
+ ModHandle - Returned from LoadLibraryEx() and stored for call to
+ FreeLibrary().
+
+Returns:
+ EFI_SUCCESS - ModHandle was stored.
+
+**/
+EFI_STATUS
+AddHandle (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN VOID *ModHandle
+ )
+{
+ UINTN Index;
+ IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
+ UINTN PreviousSize;
+
+
+ Array = mImageContextModHandleArray;
+ for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
+ if (Array->ImageContext == NULL) {
+ //
+ // Make a copy of the stirng and store the ModHandle
+ //
+ Array->ImageContext = ImageContext;
+ Array->ModHandle = ModHandle;
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // No free space in mImageContextModHandleArray so grow it by
+ // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
+ // copy the old values to the new locaiton. But it does
+ // not zero the new memory area.
+ //
+ PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
+ mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
+
+ mImageContextModHandleArray = ReallocatePool (
+ (mImageContextModHandleArraySize - 1) * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE),
+ mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE),
+ mImageContextModHandleArray
+ );
+ if (mImageContextModHandleArray == NULL) {
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
+
+ return AddHandle (ImageContext, ModHandle);
+}
+
+
+/*++
+
+Routine Description:
+ Return the ModHandle and delete the entry in the array.
+
+Arguments:
+ ImageContext - Input data returned from PE Laoder Library. Used to find the
+ .PDB file name of the PE Image.
+
+Returns:
+ ModHandle - ModHandle assoicated with ImageContext is returned
+ NULL - No ModHandle associated with ImageContext
+
+**/
+VOID *
+RemoveHandle (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UINTN Index;
+ IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
+
+ if (ImageContext->PdbPointer == NULL) {
+ //
+ // If no PDB pointer there is no ModHandle so return NULL
+ //
+ return NULL;
+ }
+
+ Array = mImageContextModHandleArray;
+ for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
+ if (Array->ImageContext == ImageContext) {
+ //
+ // If you find a match return it and delete the entry
+ //
+ Array->ImageContext = NULL;
+ return Array->ModHandle;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+BOOLEAN
+IsPdbFile (
+ IN CHAR8 *PdbFileName
+ )
+{
+ UINTN Len;
+
+ if (PdbFileName == NULL) {
+ return FALSE;
+ }
+
+ Len = strlen (PdbFileName);
+ if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
+ return FALSE;
+ }
+
+ if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
+ (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
+ (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+#define MAX_SPRINT_BUFFER_SIZE 0x200
+
+void
+PrintLoadAddress (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ if (ImageContext->PdbPointer == NULL) {
+ fprintf (stderr,
+ "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n",
+ (unsigned long)(ImageContext->ImageAddress),
+ (unsigned long)ImageContext->EntryPoint
+ );
+ } else {
+ fprintf (stderr,
+ "0x%08lx Loading %s with entry point 0x%08lx\n",
+ (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
+ ImageContext->PdbPointer,
+ (unsigned long)ImageContext->EntryPoint
+ );
+ }
+ // Keep output synced up
+ fflush (stderr);
+}
+
+
+/**
+ Loads the image using dlopen so symbols will be automatically
+ loaded by gdb.
+
+ @param ImageContext The PE/COFF image context
+
+ @retval TRUE - The image was successfully loaded
+ @retval FALSE - The image was successfully loaded
+
+**/
+BOOLEAN
+DlLoadImage (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+
+#ifdef __APPLE__
+
+ return FALSE;
+
+#else
+
+ void *Handle = NULL;
+ void *Entry = NULL;
+
+ if (ImageContext->PdbPointer == NULL) {
+ return FALSE;
+ }
+
+ if (!IsPdbFile (ImageContext->PdbPointer)) {
+ return FALSE;
+ }
+
+ fprintf (
+ stderr,
+ "Loading %s 0x%08lx - entry point 0x%08lx\n",
+ ImageContext->PdbPointer,
+ (unsigned long)ImageContext->ImageAddress,
+ (unsigned long)ImageContext->EntryPoint
+ );
+
+ Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
+ if (Handle != NULL) {
+ Entry = dlsym (Handle, "_ModuleEntryPoint");
+ AddHandle (ImageContext, Handle);
+ } else {
+ printf("%s\n", dlerror());
+ }
+
+ if (Entry != NULL) {
+ ImageContext->EntryPoint = (UINTN)Entry;
+ printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+#endif
+}
+
+
+VOID
+SecGdbScriptBreak (
+ char *FileName,
+ int FileNameLength,
+ long unsigned int LoadAddress,
+ int AddSymbolFlag
+ )
+{
+ return;
+}
+
+
+/**
+ Adds the image to a gdb script so it's symbols can be loaded.
+ The AddFirmwareSymbolFile helper macro is used.
+
+ @param ImageContext The PE/COFF image context
+
+**/
+VOID
+GdbScriptAddImage (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+
+ PrintLoadAddress (ImageContext);
+
+ if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
+ FILE *GdbTempFile;
+ if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) {
+ GdbTempFile = fopen (gGdbWorkingFileName, "a");
+ if (GdbTempFile != NULL) {
+ long unsigned int SymbolsAddr = (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders);
+ mScriptSymbolChangesCount++;
+ fprintf (
+ GdbTempFile,
+ "AddFirmwareSymbolFile 0x%x %s 0x%08lx\n",
+ mScriptSymbolChangesCount,
+ ImageContext->PdbPointer,
+ SymbolsAddr
+ );
+ fclose (GdbTempFile);
+ // This is for the lldb breakpoint only
+ SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1);
+ } else {
+ ASSERT (FALSE);
+ }
+ } else {
+ GdbTempFile = fopen (gGdbWorkingFileName, "w");
+ if (GdbTempFile != NULL) {
+ fprintf (
+ GdbTempFile,
+ "add-symbol-file %s 0x%08lx\n",
+ ImageContext->PdbPointer,
+ (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)
+ );
+ fclose (GdbTempFile);
+
+ //
+ // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
+ // Hey what can you say scripting in gdb is not that great....
+ // Also used for the lldb breakpoint script. The lldb breakpoint script does
+ // not use the file, it uses the arguments.
+ //
+ SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1);
+ } else {
+ ASSERT (FALSE);
+ }
+ }
+ }
+}
+
+
+VOID
+EFIAPI
+SecPeCoffRelocateImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ if (!DlLoadImage (ImageContext)) {
+ GdbScriptAddImage (ImageContext);
+ }
+}
+
+
+/**
+ Adds the image to a gdb script so it's symbols can be unloaded.
+ The RemoveFirmwareSymbolFile helper macro is used.
+
+ @param ImageContext The PE/COFF image context
+
+**/
+VOID
+GdbScriptRemoveImage (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ FILE *GdbTempFile;
+
+ //
+ // Need to skip .PDB files created from VC++
+ //
+ if (IsPdbFile (ImageContext->PdbPointer)) {
+ return;
+ }
+
+ if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) {
+ //
+ // Write the file we need for the gdb script
+ //
+ GdbTempFile = fopen (gGdbWorkingFileName, "a");
+ if (GdbTempFile != NULL) {
+ mScriptSymbolChangesCount++;
+ fprintf (
+ GdbTempFile,
+ "RemoveFirmwareSymbolFile 0x%x %s\n",
+ mScriptSymbolChangesCount,
+ ImageContext->PdbPointer
+ );
+ fclose (GdbTempFile);
+ SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0);
+ } else {
+ ASSERT (FALSE);
+ }
+ } else {
+ GdbTempFile = fopen (gGdbWorkingFileName, "w");
+ if (GdbTempFile != NULL) {
+ fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
+ fclose (GdbTempFile);
+
+ //
+ // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
+ // Hey what can you say scripting in gdb is not that great....
+ //
+ SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0);
+ } else {
+ ASSERT (FALSE);
+ }
+ }
+}
+
+
+VOID
+EFIAPI
+SecPeCoffUnloadImageExtraAction (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ VOID *Handle;
+
+ //
+ // Check to see if the image symbols were loaded with gdb script, or dlopen
+ //
+ Handle = RemoveHandle (ImageContext);
+ if (Handle != NULL) {
+#ifndef __APPLE__
+ dlclose (Handle);
+#endif
+ return;
+ }
+
+ GdbScriptRemoveImage (ImageContext);
+}
+
+
|