123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269 |
- /*++ @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);
- }
|