Home | History | Annotate | Download | only in Host
      1 /*++ @file
      2 
      3 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
      4 Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "Host.h"
     16 
     17 #ifdef __APPLE__
     18 #define MAP_ANONYMOUS MAP_ANON
     19 #endif
     20 
     21 
     22 //
     23 // Globals
     24 //
     25 
     26 EMU_THUNK_PPI mSecEmuThunkPpi = {
     27   GasketSecUnixPeiAutoScan,
     28   GasketSecUnixFdAddress,
     29   GasketSecEmuThunkAddress
     30 };
     31 
     32 char *gGdbWorkingFileName = NULL;
     33 unsigned int mScriptSymbolChangesCount = 0;
     34 
     35 
     36 //
     37 // Default information about where the FD is located.
     38 //  This array gets filled in with information from EFI_FIRMWARE_VOLUMES
     39 //  EFI_FIRMWARE_VOLUMES is a host environment variable set by system.cmd.
     40 //  The number of array elements is allocated base on parsing
     41 //  EFI_FIRMWARE_VOLUMES and the memory is never freed.
     42 //
     43 UINTN       gFdInfoCount = 0;
     44 EMU_FD_INFO *gFdInfo;
     45 
     46 //
     47 // Array that supports seperate memory rantes.
     48 //  The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable.
     49 //  The number of array elements is allocated base on parsing
     50 //  EFI_MEMORY_SIZE and the memory is never freed.
     51 //
     52 UINTN              gSystemMemoryCount = 0;
     53 EMU_SYSTEM_MEMORY  *gSystemMemory;
     54 
     55 
     56 
     57 UINTN                        mImageContextModHandleArraySize = 0;
     58 IMAGE_CONTEXT_TO_MOD_HANDLE  *mImageContextModHandleArray = NULL;
     59 
     60 EFI_PEI_PPI_DESCRIPTOR  *gPpiList;
     61 
     62 
     63 int gInXcode = 0;
     64 
     65 
     66 /*++
     67   Breakpoint target for Xcode project. Set in the Xcode XML
     68 
     69   Xcode breakpoint will 'source Host.gdb'
     70   gGdbWorkingFileName is set to Host.gdb
     71 
     72 **/
     73 VOID
     74 SecGdbConfigBreak (
     75   VOID
     76   )
     77 {
     78 }
     79 
     80 
     81 
     82 /*++
     83 
     84 Routine Description:
     85   Main entry point to SEC for Unix. This is a unix program
     86 
     87 Arguments:
     88   Argc - Number of command line arguments
     89   Argv - Array of command line argument strings
     90   Envp - Array of environment variable strings
     91 
     92 Returns:
     93   0 - Normal exit
     94   1 - Abnormal exit
     95 
     96 **/
     97 int
     98 main (
     99   IN  int   Argc,
    100   IN  char  **Argv,
    101   IN  char  **Envp
    102   )
    103 {
    104   EFI_STATUS            Status;
    105   EFI_PHYSICAL_ADDRESS  InitialStackMemory;
    106   UINT64                InitialStackMemorySize;
    107   UINTN                 Index;
    108   UINTN                 Index1;
    109   UINTN                 Index2;
    110   UINTN                 PeiIndex;
    111   CHAR8                 *FileName;
    112   BOOLEAN               Done;
    113   EFI_PEI_FILE_HANDLE   FileHandle;
    114   VOID                  *SecFile;
    115   CHAR16                *MemorySizeStr;
    116   CHAR16                *FirmwareVolumesStr;
    117   UINTN                 *StackPointer;
    118   FILE                  *GdbTempFile;
    119 
    120   //
    121   // Xcode does not support sourcing gdb scripts directly, so the Xcode XML
    122   // has a break point script to source the GdbRun script.
    123   //
    124   SecGdbConfigBreak ();
    125 
    126   //
    127   // If dlopen doesn't work, then we build a gdb script to allow the
    128   // symbols to be loaded.
    129   //
    130   Index = strlen (*Argv);
    131   gGdbWorkingFileName = AllocatePool (Index + strlen(".gdb") + 1);
    132   strcpy (gGdbWorkingFileName, *Argv);
    133   strcat (gGdbWorkingFileName, ".gdb");
    134 
    135   //
    136   // Empty out the gdb symbols script file.
    137   //
    138   GdbTempFile = fopen (gGdbWorkingFileName, "w");
    139   if (GdbTempFile != NULL) {
    140     fclose (GdbTempFile);
    141   }
    142 
    143   printf ("\nEDK II UNIX Host Emulation Environment from http://www.tianocore.org/edk2/\n");
    144 
    145   setbuf (stdout, 0);
    146   setbuf (stderr, 0);
    147 
    148   MemorySizeStr      = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);
    149   FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);
    150 
    151   //
    152   // PPIs pased into PEI_CORE
    153   //
    154   AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
    155 
    156   SecInitThunkProtocol ();
    157 
    158   //
    159   // Emulator Bus Driver Thunks
    160   //
    161   AddThunkProtocol (&gX11ThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
    162   AddThunkProtocol (&gPosixFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
    163   AddThunkProtocol (&gBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);
    164   AddThunkProtocol (&gSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);
    165 
    166   //
    167   // Emulator other Thunks
    168   //
    169   AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE);
    170 
    171   // EmuSecLibConstructor ();
    172 
    173   gPpiList = GetThunkPpiList ();
    174 
    175   //
    176   // Allocate space for gSystemMemory Array
    177   //
    178   gSystemMemoryCount  = CountSeparatorsInString (MemorySizeStr, '!') + 1;
    179   gSystemMemory       = AllocateZeroPool (gSystemMemoryCount * sizeof (EMU_SYSTEM_MEMORY));
    180   if (gSystemMemory == NULL) {
    181     printf ("ERROR : Can not allocate memory for system.  Exiting.\n");
    182     exit (1);
    183   }
    184   //
    185   // Allocate space for gSystemMemory Array
    186   //
    187   gFdInfoCount  = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;
    188   gFdInfo       = AllocateZeroPool (gFdInfoCount * sizeof (EMU_FD_INFO));
    189   if (gFdInfo == NULL) {
    190     printf ("ERROR : Can not allocate memory for fd info.  Exiting.\n");
    191     exit (1);
    192   }
    193 
    194   printf ("  BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode));
    195 
    196   //
    197   // Open up a 128K file to emulate temp memory for SEC.
    198   //  on a real platform this would be SRAM, or using the cache as RAM.
    199   //  Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping
    200   //
    201   InitialStackMemorySize  = STACK_SIZE;
    202   InitialStackMemory = (UINTN)MapMemory (
    203                                 0, (UINT32) InitialStackMemorySize,
    204                                 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE
    205                                 );
    206   if (InitialStackMemory == 0) {
    207     printf ("ERROR : Can not open SecStack Exiting\n");
    208     exit (1);
    209   }
    210 
    211   printf ("  OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",
    212     (unsigned int)(InitialStackMemorySize / 1024),
    213     (unsigned long)InitialStackMemory
    214     );
    215 
    216   for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
    217      StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
    218      StackPointer ++) {
    219     *StackPointer = 0x5AA55AA5;
    220   }
    221 
    222   //
    223   // Open All the firmware volumes and remember the info in the gFdInfo global
    224   //
    225   FileName = (CHAR8 *) AllocatePool (StrLen (FirmwareVolumesStr) + 1);
    226   if (FileName == NULL) {
    227     printf ("ERROR : Can not allocate memory for firmware volume string\n");
    228     exit (1);
    229   }
    230 
    231   Index2 = 0;
    232   for (Done = FALSE, Index = 0, PeiIndex = 0, SecFile = NULL;
    233        FirmwareVolumesStr[Index2] != 0;
    234        Index++) {
    235     for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) {
    236       FileName[Index1++] = FirmwareVolumesStr[Index2];
    237     }
    238     if (FirmwareVolumesStr[Index2] == '!') {
    239       Index2++;
    240     }
    241     FileName[Index1]  = '\0';
    242 
    243     if (Index == 0) {
    244       // Map FV Recovery Read Only and other areas Read/Write
    245       Status = MapFd0 (
    246                 FileName,
    247                 &gFdInfo[0].Address,
    248                 &gFdInfo[0].Size
    249                 );
    250     } else {
    251       //
    252       // Open the FD and remember where it got mapped into our processes address space
    253       // Maps Read Only
    254       //
    255       Status = MapFile (
    256                 FileName,
    257                 &gFdInfo[Index].Address,
    258                 &gFdInfo[Index].Size
    259                 );
    260     }
    261     if (EFI_ERROR (Status)) {
    262       printf ("ERROR : Can not open Firmware Device File %s (%x).  Exiting.\n", FileName, (unsigned int)Status);
    263       exit (1);
    264     }
    265 
    266     printf ("  FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address);
    267 
    268     if (SecFile == NULL) {
    269       //
    270       // Assume the beginning of the FD is an FV and look for the SEC Core.
    271       // Load the first one we find.
    272       //
    273       FileHandle = NULL;
    274       Status = PeiServicesFfsFindNextFile (
    275                   EFI_FV_FILETYPE_SECURITY_CORE,
    276                   (EFI_PEI_FV_HANDLE)(UINTN)gFdInfo[Index].Address,
    277                   &FileHandle
    278                   );
    279       if (!EFI_ERROR (Status)) {
    280         Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
    281         if (!EFI_ERROR (Status)) {
    282           PeiIndex = Index;
    283           printf (" contains SEC Core");
    284         }
    285       }
    286     }
    287 
    288     printf ("\n");
    289   }
    290 
    291   if (SecFile == NULL) {
    292     printf ("ERROR : SEC not found!\n");
    293     exit (1);
    294   }
    295 
    296   //
    297   // Calculate memory regions and store the information in the gSystemMemory
    298   //  global for later use. The autosizing code will use this data to
    299   //  map this memory into the SEC process memory space.
    300   //
    301   Index1 = 0;
    302   Index = 0;
    303   while (1) {
    304     UINTN val = 0;
    305     //
    306     // Save the size of the memory.
    307     //
    308     while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
    309       val = val * 10 + MemorySizeStr[Index1] - '0';
    310       Index1++;
    311     }
    312     gSystemMemory[Index++].Size = val * 0x100000;
    313     if (MemorySizeStr[Index1] == 0) {
    314       break;
    315     }
    316     Index1++;
    317   }
    318 
    319   printf ("\n");
    320 
    321   //
    322   // Hand off to SEC
    323   //
    324   SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, SecFile);
    325 
    326   //
    327   // If we get here, then the SEC Core returned. This is an error as SEC should
    328   //  always hand off to PEI Core and then on to DXE Core.
    329   //
    330   printf ("ERROR : SEC returned\n");
    331   exit (1);
    332 }
    333 
    334 
    335 EFI_PHYSICAL_ADDRESS *
    336 MapMemory (
    337   IN INTN   fd,
    338   IN UINT64 length,
    339   IN INTN   prot,
    340   IN INTN   flags
    341   )
    342 {
    343   STATIC UINTN base  = 0x40000000;
    344   CONST UINTN  align = (1 << 24);
    345   VOID         *res  = NULL;
    346   BOOLEAN      isAligned = 0;
    347 
    348   //
    349   // Try to get an aligned block somewhere in the address space of this
    350   // process.
    351   //
    352   while((!isAligned) && (base != 0)) {
    353     res = mmap ((void *)base, length, prot, flags, fd, 0);
    354     if (res == MAP_FAILED) {
    355       return NULL;
    356     }
    357     if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
    358       isAligned=1;
    359     } else {
    360       munmap(res, length);
    361       base += align;
    362     }
    363   }
    364   return res;
    365 }
    366 
    367 
    368 /*++
    369 
    370 Routine Description:
    371   Opens and memory maps a file using Unix services. If BaseAddress is non zero
    372   the process will try and allocate the memory starting at BaseAddress.
    373 
    374 Arguments:
    375   FileName            - The name of the file to open and map
    376   MapSize             - The amount of the file to map in bytes
    377   CreationDisposition - The flags to pass to CreateFile().  Use to create new files for
    378                         memory emulation, and exiting files for firmware volume emulation
    379   BaseAddress         - The base address of the mapped file in the user address space.
    380                          If passed in as NULL the a new memory region is used.
    381                          If passed in as non NULL the request memory region is used for
    382                           the mapping of the file into the process space.
    383   Length              - The size of the mapped region in bytes
    384 
    385 Returns:
    386   EFI_SUCCESS      - The file was opened and mapped.
    387   EFI_NOT_FOUND    - FileName was not found in the current directory
    388   EFI_DEVICE_ERROR - An error occured attempting to map the opened file
    389 
    390 **/
    391 EFI_STATUS
    392 MapFile (
    393   IN  CHAR8                     *FileName,
    394   IN OUT  EFI_PHYSICAL_ADDRESS  *BaseAddress,
    395   OUT UINT64                    *Length
    396   )
    397 {
    398   int     fd;
    399   VOID    *res;
    400   UINTN   FileSize;
    401 
    402   fd = open (FileName, O_RDWR);
    403   if (fd < 0) {
    404     return EFI_NOT_FOUND;
    405   }
    406   FileSize = lseek (fd, 0, SEEK_END);
    407 
    408 
    409   res = MapMemory (fd, FileSize, PROT_READ | PROT_EXEC, MAP_PRIVATE);
    410 
    411   close (fd);
    412 
    413   if (res == NULL) {
    414     perror ("MapFile() Failed");
    415     return EFI_DEVICE_ERROR;
    416   }
    417 
    418   *Length = (UINT64) FileSize;
    419   *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
    420 
    421   return EFI_SUCCESS;
    422 }
    423 
    424 EFI_STATUS
    425 MapFd0 (
    426   IN  CHAR8                     *FileName,
    427   IN OUT  EFI_PHYSICAL_ADDRESS  *BaseAddress,
    428   OUT UINT64                    *Length
    429   )
    430 {
    431   int     fd;
    432   void    *res, *res2, *res3;
    433   UINTN   FileSize;
    434   UINTN   FvSize;
    435   void    *EmuMagicPage;
    436 
    437   fd = open (FileName, O_RDWR);
    438   if (fd < 0) {
    439     return EFI_NOT_FOUND;
    440   }
    441   FileSize = lseek (fd, 0, SEEK_END);
    442 
    443   FvSize = FixedPcdGet64 (PcdEmuFlashFvRecoverySize);
    444 
    445   // Assume start of FD is Recovery FV, and make it write protected
    446   res = mmap (
    447           (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase),
    448           FvSize,
    449           PROT_READ | PROT_EXEC,
    450           MAP_PRIVATE,
    451           fd,
    452           0
    453           );
    454   if (res == MAP_FAILED) {
    455     perror ("MapFd0() Failed res =");
    456     close (fd);
    457     return EFI_DEVICE_ERROR;
    458   } else if (res != (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase)) {
    459     // We could not load at the build address, so we need to allow writes
    460     munmap (res, FvSize);
    461     res = mmap (
    462             (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase),
    463             FvSize,
    464             PROT_READ | PROT_WRITE | PROT_EXEC,
    465             MAP_PRIVATE,
    466             fd,
    467             0
    468             );
    469     if (res == MAP_FAILED) {
    470       perror ("MapFd0() Failed res =");
    471       close (fd);
    472       return EFI_DEVICE_ERROR;
    473     }
    474   }
    475 
    476   // Map the rest of the FD as read/write
    477   res2 = mmap (
    478           (void *)(UINTN)(FixedPcdGet64 (PcdEmuFlashFvRecoveryBase) + FvSize),
    479           FileSize - FvSize,
    480           PROT_READ | PROT_WRITE | PROT_EXEC,
    481           MAP_SHARED,
    482           fd,
    483           FvSize
    484           );
    485   close (fd);
    486   if (res2 == MAP_FAILED) {
    487     perror ("MapFd0() Failed res2 =");
    488     return EFI_DEVICE_ERROR;
    489   }
    490 
    491   //
    492   // If enabled use the magic page to communicate between modules
    493   // This replaces the PI PeiServicesTable pointer mechanism that
    494   // deos not work in the emulator. It also allows the removal of
    495   // writable globals from SEC, PEI_CORE (libraries), PEIMs
    496   //
    497   EmuMagicPage = (void *)(UINTN)FixedPcdGet64 (PcdPeiServicesTablePage);
    498   if (EmuMagicPage != NULL) {
    499     res3 =  mmap (
    500               (void *)EmuMagicPage,
    501               4096,
    502               PROT_READ | PROT_WRITE,
    503               MAP_PRIVATE | MAP_ANONYMOUS,
    504               0,
    505               0
    506               );
    507     if (res3 != EmuMagicPage) {
    508       printf ("MapFd0(): Could not allocate PeiServicesTablePage @ %lx\n", (long unsigned int)EmuMagicPage);
    509       return EFI_DEVICE_ERROR;
    510     }
    511   }
    512 
    513   *Length = (UINT64) FileSize;
    514   *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
    515 
    516   return EFI_SUCCESS;
    517 }
    518 
    519 
    520 /*++
    521 
    522 Routine Description:
    523   This is the service to load the SEC Core from the Firmware Volume
    524 
    525 Arguments:
    526   LargestRegion           - Memory to use for SEC.
    527   LargestRegionSize       - Size of Memory to use for PEI
    528   BootFirmwareVolumeBase  - Start of the Boot FV
    529   PeiCorePe32File         - SEC PE32
    530 
    531 Returns:
    532   Success means control is transfered and thus we should never return
    533 
    534 **/
    535 VOID
    536 SecLoadFromCore (
    537   IN  UINTN   LargestRegion,
    538   IN  UINTN   LargestRegionSize,
    539   IN  UINTN   BootFirmwareVolumeBase,
    540   IN  VOID    *PeiCorePe32File
    541   )
    542 {
    543   EFI_STATUS                  Status;
    544   EFI_PHYSICAL_ADDRESS        TopOfMemory;
    545   VOID                        *TopOfStack;
    546   EFI_PHYSICAL_ADDRESS        PeiCoreEntryPoint;
    547   EFI_SEC_PEI_HAND_OFF        *SecCoreData;
    548   UINTN                       PeiStackSize;
    549 
    550   //
    551   // Compute Top Of Memory for Stack and PEI Core Allocations
    552   //
    553   TopOfMemory  = LargestRegion + LargestRegionSize;
    554   PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
    555 
    556   //
    557   // |-----------| <---- TemporaryRamBase + TemporaryRamSize
    558   // |   Heap    |
    559   // |           |
    560   // |-----------| <---- StackBase / PeiTemporaryMemoryBase
    561   // |           |
    562   // |  Stack    |
    563   // |-----------| <---- TemporaryRamBase
    564   //
    565   TopOfStack  = (VOID *)(LargestRegion + PeiStackSize);
    566   TopOfMemory = LargestRegion + PeiStackSize;
    567 
    568   //
    569   // Reservet space for storing PeiCore's parament in stack.
    570   //
    571   TopOfStack  = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
    572   TopOfStack  = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
    573 
    574 
    575   //
    576   // Bind this information into the SEC hand-off state
    577   //
    578   SecCoreData                         = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
    579   SecCoreData->DataSize               = sizeof(EFI_SEC_PEI_HAND_OFF);
    580   SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
    581   SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdEmuFirmwareFdSize);
    582   SecCoreData->TemporaryRamBase       = (VOID*)(UINTN)LargestRegion;
    583   SecCoreData->TemporaryRamSize       = STACK_SIZE;
    584   SecCoreData->StackBase              = SecCoreData->TemporaryRamBase;
    585   SecCoreData->StackSize              = PeiStackSize;
    586   SecCoreData->PeiTemporaryRamBase    = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
    587   SecCoreData->PeiTemporaryRamSize    = STACK_SIZE - PeiStackSize;
    588 
    589   //
    590   // Find the SEC Core Entry Point
    591   //
    592   Status = SecPeCoffGetEntryPoint (PeiCorePe32File, (VOID **)&PeiCoreEntryPoint);
    593   if (EFI_ERROR (Status)) {
    594     return ;
    595   }
    596 
    597   //
    598   // Transfer control to the SEC Core
    599   //
    600   PeiSwitchStacks (
    601     (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
    602     SecCoreData,
    603     (VOID *)gPpiList,
    604     TopOfStack
    605     );
    606   //
    607   // If we get here, then the SEC Core returned.  This is an error
    608   //
    609   return ;
    610 }
    611 
    612 
    613 /*++
    614 
    615 Routine Description:
    616   This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
    617   It allows discontinuous memory regions to be supported by the emulator.
    618   It uses gSystemMemory[] and gSystemMemoryCount that were created by
    619   parsing the host environment variable EFI_MEMORY_SIZE.
    620   The size comes from the varaible and the address comes from the call to
    621   UnixOpenFile.
    622 
    623 Arguments:
    624   Index      - Which memory region to use
    625   MemoryBase - Return Base address of memory region
    626   MemorySize - Return size in bytes of the memory region
    627 
    628 Returns:
    629   EFI_SUCCESS - If memory region was mapped
    630   EFI_UNSUPPORTED - If Index is not supported
    631 
    632 **/
    633 EFI_STATUS
    634 SecUnixPeiAutoScan (
    635   IN  UINTN                 Index,
    636   OUT EFI_PHYSICAL_ADDRESS  *MemoryBase,
    637   OUT UINT64                *MemorySize
    638   )
    639 {
    640   void *res;
    641 
    642   if (Index >= gSystemMemoryCount) {
    643     return EFI_UNSUPPORTED;
    644   }
    645 
    646   *MemoryBase = 0;
    647   res = MapMemory (
    648           0, gSystemMemory[Index].Size,
    649           PROT_READ | PROT_WRITE | PROT_EXEC,
    650           MAP_PRIVATE | MAP_ANONYMOUS
    651           );
    652   if (res == MAP_FAILED) {
    653     return EFI_DEVICE_ERROR;
    654   }
    655   *MemorySize = gSystemMemory[Index].Size;
    656   *MemoryBase = (UINTN)res;
    657   gSystemMemory[Index].Memory = *MemoryBase;
    658 
    659   return EFI_SUCCESS;
    660 }
    661 
    662 
    663 /*++
    664 
    665 Routine Description:
    666  Check to see if an address range is in the EFI GCD memory map.
    667 
    668  This is all of GCD for system memory passed to DXE Core. FV
    669  mapping and other device mapped into system memory are not
    670  inlcuded in the check.
    671 
    672 Arguments:
    673   Index      - Which memory region to use
    674   MemoryBase - Return Base address of memory region
    675   MemorySize - Return size in bytes of the memory region
    676 
    677 Returns:
    678   TRUE -  Address is in the EFI GCD memory map
    679   FALSE - Address is NOT in memory map
    680 
    681 **/
    682 BOOLEAN
    683 EfiSystemMemoryRange (
    684   IN  VOID *MemoryAddress
    685   )
    686 {
    687   UINTN                 Index;
    688   EFI_PHYSICAL_ADDRESS  MemoryBase;
    689 
    690   MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
    691   for (Index = 0; Index < gSystemMemoryCount; Index++) {
    692     if ((MemoryBase >= gSystemMemory[Index].Memory) &&
    693         (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)) ) {
    694       return TRUE;
    695     }
    696   }
    697 
    698   return FALSE;
    699 }
    700 
    701 
    702 /*++
    703 
    704 Routine Description:
    705   Since the SEC is the only Unix program in stack it must export
    706   an interface to do POSIX calls.  gUnix is initialized in UnixThunk.c.
    707 
    708 Arguments:
    709   InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
    710   InterfaceBase - Address of the gUnix global
    711 
    712 Returns:
    713   EFI_SUCCESS - Data returned
    714 
    715 **/
    716 VOID *
    717 SecEmuThunkAddress (
    718   VOID
    719   )
    720 {
    721   return &gEmuThunkProtocol;
    722 }
    723 
    724 
    725 
    726 RETURN_STATUS
    727 EFIAPI
    728 SecPeCoffGetEntryPoint (
    729   IN     VOID  *Pe32Data,
    730   IN OUT VOID  **EntryPoint
    731   )
    732 {
    733   EFI_STATUS                    Status;
    734   PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
    735 
    736   ZeroMem (&ImageContext, sizeof (ImageContext));
    737   ImageContext.Handle     = Pe32Data;
    738   ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) SecImageRead;
    739 
    740   Status                  = PeCoffLoaderGetImageInfo (&ImageContext);
    741   if (EFI_ERROR (Status)) {
    742     return Status;
    743   }
    744 
    745   if (ImageContext.ImageAddress != (UINTN)Pe32Data) {
    746     //
    747     // Relocate image to match the address where it resides
    748     //
    749     ImageContext.ImageAddress = (UINTN)Pe32Data;
    750     Status = PeCoffLoaderLoadImage (&ImageContext);
    751     if (EFI_ERROR (Status)) {
    752       return Status;
    753     }
    754 
    755     Status = PeCoffLoaderRelocateImage (&ImageContext);
    756     if (EFI_ERROR (Status)) {
    757       return Status;
    758     }
    759   } else {
    760     //
    761     // Or just return image entry point
    762     //
    763     ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data);
    764     Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint);
    765     if (EFI_ERROR (Status)) {
    766       return Status;
    767     }
    768     ImageContext.EntryPoint = (UINTN)*EntryPoint;
    769   }
    770 
    771   // On Unix a dlopen is done that will change the entry point
    772   SecPeCoffRelocateImageExtraAction (&ImageContext);
    773   *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
    774 
    775   return Status;
    776 }
    777 
    778 
    779 
    780 /*++
    781 
    782 Routine Description:
    783   Return the FD Size and base address. Since the FD is loaded from a
    784   file into host memory only the SEC will know it's address.
    785 
    786 Arguments:
    787   Index  - Which FD, starts at zero.
    788   FdSize - Size of the FD in bytes
    789   FdBase - Start address of the FD. Assume it points to an FV Header
    790   FixUp  - Difference between actual FD address and build address
    791 
    792 Returns:
    793   EFI_SUCCESS     - Return the Base address and size of the FV
    794   EFI_UNSUPPORTED - Index does nto map to an FD in the system
    795 
    796 **/
    797 EFI_STATUS
    798 SecUnixFdAddress (
    799   IN     UINTN                 Index,
    800   IN OUT EFI_PHYSICAL_ADDRESS  *FdBase,
    801   IN OUT UINT64                *FdSize,
    802   IN OUT EFI_PHYSICAL_ADDRESS  *FixUp
    803   )
    804 {
    805   if (Index >= gFdInfoCount) {
    806     return EFI_UNSUPPORTED;
    807   }
    808 
    809   *FdBase = gFdInfo[Index].Address;
    810   *FdSize = gFdInfo[Index].Size;
    811   *FixUp  = 0;
    812 
    813   if (*FdBase == 0 && *FdSize == 0) {
    814     return EFI_UNSUPPORTED;
    815   }
    816 
    817   if (Index == 0) {
    818     //
    819     // FD 0 has XIP code and well known PCD values
    820     // If the memory buffer could not be allocated at the FD build address
    821     // the Fixup is the difference.
    822     //
    823     *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
    824   }
    825 
    826   return EFI_SUCCESS;
    827 }
    828 
    829 
    830 /*++
    831 
    832 Routine Description:
    833   Count the number of separators in String
    834 
    835 Arguments:
    836   String    - String to process
    837   Separator - Item to count
    838 
    839 Returns:
    840   Number of Separator in String
    841 
    842 **/
    843 UINTN
    844 CountSeparatorsInString (
    845   IN  const CHAR16   *String,
    846   IN  CHAR16         Separator
    847   )
    848 {
    849   UINTN Count;
    850 
    851   for (Count = 0; *String != '\0'; String++) {
    852     if (*String == Separator) {
    853       Count++;
    854     }
    855   }
    856 
    857   return Count;
    858 }
    859 
    860 
    861 EFI_STATUS
    862 EFIAPI
    863 SecImageRead (
    864   IN     VOID    *FileHandle,
    865   IN     UINTN   FileOffset,
    866   IN OUT UINTN   *ReadSize,
    867   OUT    VOID    *Buffer
    868   )
    869 /*++
    870 
    871 Routine Description:
    872   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
    873 
    874 Arguments:
    875   FileHandle - The handle to the PE/COFF file
    876   FileOffset - The offset, in bytes, into the file to read
    877   ReadSize   - The number of bytes to read from the file starting at FileOffset
    878   Buffer     - A pointer to the buffer to read the data into.
    879 
    880 Returns:
    881   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
    882 
    883 **/
    884 {
    885   CHAR8 *Destination8;
    886   CHAR8 *Source8;
    887   UINTN Length;
    888 
    889   Destination8  = Buffer;
    890   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
    891   Length        = *ReadSize;
    892   while (Length--) {
    893     *(Destination8++) = *(Source8++);
    894   }
    895 
    896   return EFI_SUCCESS;
    897 }
    898 
    899 
    900 /*++
    901 
    902 Routine Description:
    903   Store the ModHandle in an array indexed by the Pdb File name.
    904   The ModHandle is needed to unload the image.
    905 
    906 Arguments:
    907   ImageContext - Input data returned from PE Laoder Library. Used to find the
    908                  .PDB file name of the PE Image.
    909   ModHandle    - Returned from LoadLibraryEx() and stored for call to
    910                  FreeLibrary().
    911 
    912 Returns:
    913   EFI_SUCCESS - ModHandle was stored.
    914 
    915 **/
    916 EFI_STATUS
    917 AddHandle (
    918   IN  PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext,
    919   IN  VOID                                 *ModHandle
    920   )
    921 {
    922   UINTN                       Index;
    923   IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
    924   UINTN                       PreviousSize;
    925 
    926 
    927   Array = mImageContextModHandleArray;
    928   for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
    929     if (Array->ImageContext == NULL) {
    930       //
    931       // Make a copy of the stirng and store the ModHandle
    932       //
    933       Array->ImageContext = ImageContext;
    934       Array->ModHandle    = ModHandle;
    935       return EFI_SUCCESS;
    936     }
    937   }
    938 
    939   //
    940   // No free space in mImageContextModHandleArray so grow it by
    941   // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
    942   // copy the old values to the new locaiton. But it does
    943   // not zero the new memory area.
    944   //
    945   PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
    946   mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
    947 
    948   mImageContextModHandleArray = ReallocatePool (
    949                                   (mImageContextModHandleArraySize - 1) * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE),
    950                                   mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE),
    951                                   mImageContextModHandleArray
    952                                   );
    953   if (mImageContextModHandleArray == NULL) {
    954     ASSERT (FALSE);
    955     return EFI_OUT_OF_RESOURCES;
    956   }
    957 
    958   memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
    959 
    960   return AddHandle (ImageContext, ModHandle);
    961 }
    962 
    963 
    964 /*++
    965 
    966 Routine Description:
    967   Return the ModHandle and delete the entry in the array.
    968 
    969 Arguments:
    970   ImageContext - Input data returned from PE Laoder Library. Used to find the
    971                  .PDB file name of the PE Image.
    972 
    973 Returns:
    974   ModHandle - ModHandle assoicated with ImageContext is returned
    975   NULL      - No ModHandle associated with ImageContext
    976 
    977 **/
    978 VOID *
    979 RemoveHandle (
    980   IN  PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
    981   )
    982 {
    983   UINTN                        Index;
    984   IMAGE_CONTEXT_TO_MOD_HANDLE  *Array;
    985 
    986   if (ImageContext->PdbPointer == NULL) {
    987     //
    988     // If no PDB pointer there is no ModHandle so return NULL
    989     //
    990     return NULL;
    991   }
    992 
    993   Array = mImageContextModHandleArray;
    994   for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
    995     if (Array->ImageContext == ImageContext) {
    996       //
    997       // If you find a match return it and delete the entry
    998       //
    999       Array->ImageContext = NULL;
   1000       return Array->ModHandle;
   1001     }
   1002   }
   1003 
   1004   return NULL;
   1005 }
   1006 
   1007 
   1008 
   1009 BOOLEAN
   1010 IsPdbFile (
   1011   IN  CHAR8   *PdbFileName
   1012   )
   1013 {
   1014   UINTN Len;
   1015 
   1016   if (PdbFileName == NULL) {
   1017     return FALSE;
   1018   }
   1019 
   1020   Len = strlen (PdbFileName);
   1021   if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
   1022     return FALSE;
   1023   }
   1024 
   1025   if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
   1026       (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
   1027       (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
   1028     return TRUE;
   1029   }
   1030 
   1031   return FALSE;
   1032 }
   1033 
   1034 
   1035 #define MAX_SPRINT_BUFFER_SIZE 0x200
   1036 
   1037 void
   1038 PrintLoadAddress (
   1039   IN PE_COFF_LOADER_IMAGE_CONTEXT          *ImageContext
   1040   )
   1041 {
   1042   if (ImageContext->PdbPointer == NULL) {
   1043     fprintf (stderr,
   1044       "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n",
   1045       (unsigned long)(ImageContext->ImageAddress),
   1046       (unsigned long)ImageContext->EntryPoint
   1047       );
   1048   } else {
   1049     fprintf (stderr,
   1050       "0x%08lx Loading %s with entry point 0x%08lx\n",
   1051       (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
   1052       ImageContext->PdbPointer,
   1053       (unsigned long)ImageContext->EntryPoint
   1054       );
   1055   }
   1056   // Keep output synced up
   1057   fflush (stderr);
   1058 }
   1059 
   1060 
   1061 /**
   1062   Loads the image using dlopen so symbols will be automatically
   1063   loaded by gdb.
   1064 
   1065   @param  ImageContext  The PE/COFF image context
   1066 
   1067   @retval TRUE - The image was successfully loaded
   1068   @retval FALSE - The image was successfully loaded
   1069 
   1070 **/
   1071 BOOLEAN
   1072 DlLoadImage (
   1073   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
   1074   )
   1075 {
   1076 
   1077 #ifdef __APPLE__
   1078 
   1079   return FALSE;
   1080 
   1081 #else
   1082 
   1083   void        *Handle = NULL;
   1084   void        *Entry = NULL;
   1085 
   1086   if (ImageContext->PdbPointer == NULL) {
   1087     return FALSE;
   1088   }
   1089 
   1090   if (!IsPdbFile (ImageContext->PdbPointer)) {
   1091     return FALSE;
   1092   }
   1093 
   1094   fprintf (
   1095      stderr,
   1096      "Loading %s 0x%08lx - entry point 0x%08lx\n",
   1097      ImageContext->PdbPointer,
   1098      (unsigned long)ImageContext->ImageAddress,
   1099      (unsigned long)ImageContext->EntryPoint
   1100      );
   1101 
   1102   Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
   1103   if (Handle != NULL) {
   1104     Entry = dlsym (Handle, "_ModuleEntryPoint");
   1105     AddHandle (ImageContext, Handle);
   1106   } else {
   1107     printf("%s\n", dlerror());
   1108   }
   1109 
   1110   if (Entry != NULL) {
   1111     ImageContext->EntryPoint = (UINTN)Entry;
   1112     printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
   1113     return TRUE;
   1114   } else {
   1115     return FALSE;
   1116   }
   1117 
   1118 #endif
   1119 }
   1120 
   1121 
   1122 VOID
   1123 SecGdbScriptBreak (
   1124   char                *FileName,
   1125   int                 FileNameLength,
   1126   long unsigned int   LoadAddress,
   1127   int                 AddSymbolFlag
   1128   )
   1129 {
   1130   return;
   1131 }
   1132 
   1133 
   1134 /**
   1135   Adds the image to a gdb script so it's symbols can be loaded.
   1136   The AddFirmwareSymbolFile helper macro is used.
   1137 
   1138   @param  ImageContext  The PE/COFF image context
   1139 
   1140 **/
   1141 VOID
   1142 GdbScriptAddImage (
   1143   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
   1144   )
   1145 {
   1146 
   1147   PrintLoadAddress (ImageContext);
   1148 
   1149   if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
   1150     FILE  *GdbTempFile;
   1151     if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) {
   1152       GdbTempFile = fopen (gGdbWorkingFileName, "a");
   1153       if (GdbTempFile != NULL) {
   1154         long unsigned int SymbolsAddr = (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders);
   1155         mScriptSymbolChangesCount++;
   1156         fprintf (
   1157           GdbTempFile,
   1158           "AddFirmwareSymbolFile 0x%x %s 0x%08lx\n",
   1159           mScriptSymbolChangesCount,
   1160           ImageContext->PdbPointer,
   1161           SymbolsAddr
   1162           );
   1163         fclose (GdbTempFile);
   1164         // This is for the lldb breakpoint only
   1165         SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1);
   1166       } else {
   1167         ASSERT (FALSE);
   1168       }
   1169     } else {
   1170       GdbTempFile = fopen (gGdbWorkingFileName, "w");
   1171       if (GdbTempFile != NULL) {
   1172         fprintf (
   1173           GdbTempFile,
   1174           "add-symbol-file %s 0x%08lx\n",
   1175           ImageContext->PdbPointer,
   1176           (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)
   1177           );
   1178         fclose (GdbTempFile);
   1179 
   1180         //
   1181         // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
   1182         // Hey what can you say scripting in gdb is not that great....
   1183         // Also used for the lldb breakpoint script. The lldb breakpoint script does
   1184         // not use the file, it uses the arguments.
   1185         //
   1186         SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1);
   1187       } else {
   1188         ASSERT (FALSE);
   1189       }
   1190     }
   1191   }
   1192 }
   1193 
   1194 
   1195 VOID
   1196 EFIAPI
   1197 SecPeCoffRelocateImageExtraAction (
   1198   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
   1199   )
   1200 {
   1201   if (!DlLoadImage (ImageContext)) {
   1202     GdbScriptAddImage (ImageContext);
   1203   }
   1204 }
   1205 
   1206 
   1207 /**
   1208   Adds the image to a gdb script so it's symbols can be unloaded.
   1209   The RemoveFirmwareSymbolFile helper macro is used.
   1210 
   1211   @param  ImageContext  The PE/COFF image context
   1212 
   1213 **/
   1214 VOID
   1215 GdbScriptRemoveImage (
   1216   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
   1217   )
   1218 {
   1219   FILE  *GdbTempFile;
   1220 
   1221   //
   1222   // Need to skip .PDB files created from VC++
   1223   //
   1224   if (IsPdbFile (ImageContext->PdbPointer)) {
   1225     return;
   1226   }
   1227 
   1228   if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) {
   1229     //
   1230     // Write the file we need for the gdb script
   1231     //
   1232     GdbTempFile = fopen (gGdbWorkingFileName, "a");
   1233     if (GdbTempFile != NULL) {
   1234       mScriptSymbolChangesCount++;
   1235       fprintf (
   1236         GdbTempFile,
   1237         "RemoveFirmwareSymbolFile 0x%x %s\n",
   1238         mScriptSymbolChangesCount,
   1239         ImageContext->PdbPointer
   1240         );
   1241       fclose (GdbTempFile);
   1242       SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0);
   1243     } else {
   1244       ASSERT (FALSE);
   1245     }
   1246   } else {
   1247     GdbTempFile = fopen (gGdbWorkingFileName, "w");
   1248     if (GdbTempFile != NULL) {
   1249       fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
   1250       fclose (GdbTempFile);
   1251 
   1252       //
   1253       // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
   1254       // Hey what can you say scripting in gdb is not that great....
   1255       //
   1256       SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0);
   1257     } else {
   1258       ASSERT (FALSE);
   1259     }
   1260   }
   1261 }
   1262 
   1263 
   1264 VOID
   1265 EFIAPI
   1266 SecPeCoffUnloadImageExtraAction (
   1267   IN PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
   1268   )
   1269 {
   1270   VOID *Handle;
   1271 
   1272   //
   1273   // Check to see if the image symbols were loaded with gdb script, or dlopen
   1274   //
   1275   Handle = RemoveHandle (ImageContext);
   1276   if (Handle != NULL) {
   1277 #ifndef __APPLE__
   1278     dlclose (Handle);
   1279 #endif
   1280     return;
   1281   }
   1282 
   1283   GdbScriptRemoveImage (ImageContext);
   1284 }
   1285 
   1286 
   1287