mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 02:40:26 +00:00 
			
		
		
		
	Fix various typos in comments and documentation. Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Andrew Fish <afish@apple.com> Cc: Ray Ni <ray.ni@intel.com> Signed-off-by: Antoine Coeur <coeur@gmx.fr> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Signed-off-by: Philippe Mathieu-Daude <philmd@redhat.com> Message-Id: <20200207010831.9046-6-philmd@redhat.com>
		
			
				
	
	
		
			1284 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1284 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*++ @file
 | 
						|
 | 
						|
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 | 
						|
Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#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 separate memory ranges.
 | 
						|
//  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 environment 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.sh 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 http://www.tianocore.org/edk2/\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  = CountSeparatorsInString (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  = CountSeparatorsInString (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 remember 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 occurred 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 transferred 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 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 variable 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
 | 
						|
 included 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 initialized 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 its 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 separators in String
 | 
						|
 | 
						|
Arguments:
 | 
						|
  String    - String to process
 | 
						|
  Separator - Item to count
 | 
						|
 | 
						|
Returns:
 | 
						|
  Number of Separator in String
 | 
						|
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
CountSeparatorsInString (
 | 
						|
  IN  const CHAR16   *String,
 | 
						|
  IN  CHAR16         Separator
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN Count;
 | 
						|
 | 
						|
  for (Count = 0; *String != '\0'; String++) {
 | 
						|
    if (*String == Separator) {
 | 
						|
      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 Loader 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 string 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 location. 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 Loader Library. Used to find the
 | 
						|
                 .PDB file name of the PE Image.
 | 
						|
 | 
						|
Returns:
 | 
						|
  ModHandle - ModHandle associated 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
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef __APPLE__
 | 
						|
__attribute__((noinline))
 | 
						|
#endif
 | 
						|
VOID
 | 
						|
SecGdbScriptBreak (
 | 
						|
  char                *FileName,
 | 
						|
  int                 FileNameLength,
 | 
						|
  long unsigned int   LoadAddress,
 | 
						|
  int                 AddSymbolFlag
 | 
						|
  )
 | 
						|
{
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Adds the image to a gdb script so its 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 its 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);
 | 
						|
}
 | 
						|
 | 
						|
 |