123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176 |
- /**@file
- WinNt emulator of pre-SEC phase. It's really a Win32 application, but this is
- Ok since all the other modules for NT32 are NOT Win32 applications.
- This program gets NT32 PCD setting and figures out what the memory layout
- will be, how may FD's will be loaded and also what the boot mode is.
- This code produces 128 K of temporary memory for the SEC stack by directly
- allocate memory space with ReadWrite and Execute attribute.
- Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
- (C) Copyright 2016-2020 Hewlett Packard Enterprise Development LP<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "WinHost.h"
- #ifndef SE_TIME_ZONE_NAME
- #define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege")
- #endif
- //
- // The growth size for array of module handle entries
- //
- #define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100
- //
- // Module handle entry structure
- //
- typedef struct {
- CHAR8 *PdbPointer;
- VOID *ModHandle;
- } PDB_NAME_TO_MOD_HANDLE;
- //
- // An Array to hold the module handles
- //
- PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL;
- UINTN mPdbNameModHandleArraySize = 0;
- //
- // Default information about where the FD is located.
- // This array gets filled in with information from PcdWinNtFirmwareVolume
- // The number of array elements is allocated base on parsing
- // PcdWinNtFirmwareVolume and the memory is never freed.
- //
- UINTN gFdInfoCount = 0;
- NT_FD_INFO *gFdInfo;
- //
- // Array that supports separate memory ranges.
- // The memory ranges are set by PcdWinNtMemorySizeForSecMain.
- // The number of array elements is allocated base on parsing
- // PcdWinNtMemorySizeForSecMain value and the memory is never freed.
- //
- UINTN gSystemMemoryCount = 0;
- NT_SYSTEM_MEMORY *gSystemMemory;
- BASE_LIBRARY_JUMP_BUFFER mResetJumpBuffer;
- CHAR8 *mResetTypeStr[] = {
- "EfiResetCold",
- "EfiResetWarm",
- "EfiResetShutdown",
- "EfiResetPlatformSpecific"
- };
- /*++
- Routine Description:
- This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
- It allows discontinuous memory regions to be supported by the emulator.
- It uses gSystemMemory[] and gSystemMemoryCount that were created by
- parsing the host environment variable EFI_MEMORY_SIZE.
- The size comes from the varaible and the address comes from the call to
- UnixOpenFile.
- Arguments:
- Index - Which memory region to use
- MemoryBase - Return Base address of memory region
- MemorySize - Return size in bytes of the memory region
- Returns:
- EFI_SUCCESS - If memory region was mapped
- EFI_UNSUPPORTED - If Index is not supported
- **/
- EFI_STATUS
- WinPeiAutoScan (
- IN UINTN Index,
- OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
- OUT UINT64 *MemorySize
- )
- {
- if (Index >= gSystemMemoryCount) {
- return EFI_UNSUPPORTED;
- }
- *MemoryBase = gSystemMemory[Index].Memory;
- *MemorySize = gSystemMemory[Index].Size;
- return EFI_SUCCESS;
- }
- /*++
- Routine Description:
- Return the FD Size and base address. Since the FD is loaded from a
- file into host memory only the SEC will know 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
- WinFdAddress (
- IN UINTN Index,
- IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
- IN OUT UINT64 *FdSize,
- IN OUT EFI_PHYSICAL_ADDRESS *FixUp
- )
- {
- if (Index >= gFdInfoCount) {
- return EFI_UNSUPPORTED;
- }
- *FdBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gFdInfo[Index].Address;
- *FdSize = (UINT64)gFdInfo[Index].Size;
- *FixUp = 0;
- if ((*FdBase == 0) && (*FdSize == 0)) {
- return EFI_UNSUPPORTED;
- }
- if (Index == 0) {
- //
- // FD 0 has XIP code and well known PCD values
- // If the memory buffer could not be allocated at the FD build address
- // the Fixup is the difference.
- //
- *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
- }
- return EFI_SUCCESS;
- }
- /*++
- Routine Description:
- Since the SEC is the only Unix program in stack it must export
- an interface to do POSIX calls. gUnix is initialized in UnixThunk.c.
- Arguments:
- InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
- InterfaceBase - Address of the gUnix global
- Returns:
- EFI_SUCCESS - Data returned
- **/
- VOID *
- WinThunk (
- VOID
- )
- {
- return &gEmuThunkProtocol;
- }
- EMU_THUNK_PPI mSecEmuThunkPpi = {
- WinPeiAutoScan,
- WinFdAddress,
- WinThunk
- };
- VOID
- SecPrint (
- CHAR8 *Format,
- ...
- )
- {
- va_list Marker;
- UINTN CharCount;
- CHAR8 Buffer[0x1000];
- va_start (Marker, Format);
- _vsnprintf (Buffer, sizeof (Buffer), Format, Marker);
- va_end (Marker);
- CharCount = strlen (Buffer);
- WriteFile (
- GetStdHandle (STD_OUTPUT_HANDLE),
- Buffer,
- (DWORD)CharCount,
- (LPDWORD)&CharCount,
- NULL
- );
- }
- /**
- Resets the entire platform.
- @param[in] ResetType The type of reset to perform.
- @param[in] ResetStatus The status code for the reset.
- @param[in] DataSize The size, in bytes, of ResetData.
- @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
- the data buffer starts with a Null-terminated string, optionally
- followed by additional binary data. The string is a description
- that the caller may use to further indicate the reason for the
- system reset.
- **/
- VOID
- EFIAPI
- WinReset (
- IN EFI_RESET_TYPE ResetType,
- IN EFI_STATUS ResetStatus,
- IN UINTN DataSize,
- IN VOID *ResetData OPTIONAL
- )
- {
- UINTN Index;
- ASSERT (ResetType <= EfiResetPlatformSpecific);
- SecPrint (" Emu ResetSystem is called: ResetType = %s\n", mResetTypeStr[ResetType]);
- if (ResetType == EfiResetShutdown) {
- exit (0);
- } else {
- //
- // Unload all DLLs
- //
- for (Index = 0; Index < mPdbNameModHandleArraySize; Index++) {
- if (mPdbNameModHandleArray[Index].PdbPointer != NULL) {
- SecPrint (" Emu Unload DLL: %s\n", mPdbNameModHandleArray[Index].PdbPointer);
- FreeLibrary (mPdbNameModHandleArray[Index].ModHandle);
- HeapFree (GetProcessHeap (), 0, mPdbNameModHandleArray[Index].PdbPointer);
- mPdbNameModHandleArray[Index].PdbPointer = NULL;
- }
- }
- //
- // Jump back to SetJump with jump code = ResetType + 1
- //
- LongJump (&mResetJumpBuffer, ResetType + 1);
- }
- }
- EFI_PEI_RESET2_PPI mEmuReset2Ppi = {
- WinReset
- };
- /*++
- Routine Description:
- Check to see if an address range is in the EFI GCD memory map.
- This is all of GCD for system memory passed to DXE Core. FV
- mapping and other device mapped into system memory are not
- inlcuded in the check.
- Arguments:
- Index - Which memory region to use
- MemoryBase - Return Base address of memory region
- MemorySize - Return size in bytes of the memory region
- Returns:
- TRUE - Address is in the EFI GCD memory map
- FALSE - Address is NOT in memory map
- **/
- BOOLEAN
- EfiSystemMemoryRange (
- IN VOID *MemoryAddress
- )
- {
- UINTN Index;
- EFI_PHYSICAL_ADDRESS MemoryBase;
- MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
- for (Index = 0; Index < gSystemMemoryCount; Index++) {
- if ((MemoryBase >= gSystemMemory[Index].Memory) &&
- (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)))
- {
- return TRUE;
- }
- }
- return FALSE;
- }
- EFI_STATUS
- WinNtOpenFile (
- IN CHAR16 *FileName OPTIONAL,
- IN UINT32 MapSize,
- IN DWORD CreationDisposition,
- IN OUT VOID **BaseAddress,
- OUT UINTN *Length
- )
- /*++
- Routine Description:
- Opens and memory maps a file using WinNt services. If *BaseAddress is non zero
- the process will try and allocate the memory starting at BaseAddress.
- Arguments:
- FileName - The name of the file to open and map
- MapSize - The amount of the file to map in bytes
- CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
- memory emulation, and exiting files for firmware volume emulation
- BaseAddress - The base address of the mapped file in the user address space.
- If *BaseAddress is 0, the new memory region is used.
- If *BaseAddress is not 0, the request memory region is used for
- the mapping of the file into the process space.
- Length - The size of the mapped region in bytes
- Returns:
- EFI_SUCCESS - The file was opened and mapped.
- EFI_NOT_FOUND - FileName was not found in the current directory
- EFI_DEVICE_ERROR - An error occurred attempting to map the opened file
- --*/
- {
- HANDLE NtFileHandle;
- HANDLE NtMapHandle;
- VOID *VirtualAddress;
- UINTN FileSize;
- //
- // Use Win API to open/create a file
- //
- NtFileHandle = INVALID_HANDLE_VALUE;
- if (FileName != NULL) {
- NtFileHandle = CreateFile (
- FileName,
- GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
- FILE_SHARE_READ,
- NULL,
- CreationDisposition,
- FILE_ATTRIBUTE_NORMAL,
- NULL
- );
- if (NtFileHandle == INVALID_HANDLE_VALUE) {
- return EFI_NOT_FOUND;
- }
- }
- //
- // Map the open file into a memory range
- //
- NtMapHandle = CreateFileMapping (
- NtFileHandle,
- NULL,
- PAGE_EXECUTE_READWRITE,
- 0,
- MapSize,
- NULL
- );
- if (NtMapHandle == NULL) {
- return EFI_DEVICE_ERROR;
- }
- //
- // Get the virtual address (address in the emulator) of the mapped file
- //
- VirtualAddress = MapViewOfFileEx (
- NtMapHandle,
- FILE_MAP_EXECUTE | FILE_MAP_ALL_ACCESS,
- 0,
- 0,
- MapSize,
- *BaseAddress
- );
- if (VirtualAddress == NULL) {
- return EFI_DEVICE_ERROR;
- }
- if (MapSize == 0) {
- //
- // Seek to the end of the file to figure out the true file size.
- //
- FileSize = SetFilePointer (
- NtFileHandle,
- 0,
- NULL,
- FILE_END
- );
- if (FileSize == -1) {
- return EFI_DEVICE_ERROR;
- }
- *Length = FileSize;
- } else {
- *Length = MapSize;
- }
- *BaseAddress = VirtualAddress;
- return EFI_SUCCESS;
- }
- INTN
- EFIAPI
- main (
- IN INT Argc,
- IN CHAR8 **Argv,
- IN CHAR8 **Envp
- )
- /*++
- Routine Description:
- Main entry point to SEC for WinNt. This is a Windows program
- Arguments:
- Argc - Number of command line arguments
- Argv - Array of command line argument strings
- Envp - Array of environment variable strings
- Returns:
- 0 - Normal exit
- 1 - Abnormal exit
- --*/
- {
- EFI_STATUS Status;
- HANDLE Token;
- TOKEN_PRIVILEGES TokenPrivileges;
- VOID *TemporaryRam;
- UINT32 TemporaryRamSize;
- VOID *EmuMagicPage;
- UINTN Index;
- UINTN Index1;
- CHAR16 *FileName;
- CHAR16 *FileNamePtr;
- BOOLEAN Done;
- EFI_PEI_FILE_HANDLE FileHandle;
- VOID *SecFile;
- CHAR16 *MemorySizeStr;
- CHAR16 *FirmwareVolumesStr;
- UINTN ProcessAffinityMask;
- UINTN SystemAffinityMask;
- INT32 LowBit;
- UINTN ResetJumpCode;
- EMU_THUNK_PPI *SecEmuThunkPpi;
- //
- // Enable the privilege so that RTC driver can successfully run SetTime()
- //
- OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &Token);
- if (LookupPrivilegeValue (NULL, SE_TIME_ZONE_NAME, &TokenPrivileges.Privileges[0].Luid)) {
- TokenPrivileges.PrivilegeCount = 1;
- TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- AdjustTokenPrivileges (Token, FALSE, &TokenPrivileges, 0, (PTOKEN_PRIVILEGES)NULL, 0);
- }
- MemorySizeStr = (CHAR16 *)PcdGetPtr (PcdEmuMemorySize);
- FirmwareVolumesStr = (CHAR16 *)PcdGetPtr (PcdEmuFirmwareVolume);
- SecPrint ("\n\rEDK II WIN Host Emulation Environment from http://www.tianocore.org/edk2/\n\r");
- //
- // Determine the first thread available to this process.
- //
- if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {
- LowBit = (INT32)LowBitSet32 ((UINT32)ProcessAffinityMask);
- if (LowBit != -1) {
- //
- // Force the system to bind the process to a single thread to work
- // around odd semaphore type crashes.
- //
- SetProcessAffinityMask (GetCurrentProcess (), (INTN)(BIT0 << LowBit));
- }
- }
- //
- // Make some Windows calls to Set the process to the highest priority in the
- // idle class. We need this to have good performance.
- //
- SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS);
- SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
- SecInitializeThunk ();
- //
- // PPIs pased into PEI_CORE
- //
- SecEmuThunkPpi = AllocateZeroPool (sizeof (EMU_THUNK_PPI) + FixedPcdGet32 (PcdPersistentMemorySize));
- if (SecEmuThunkPpi == NULL) {
- SecPrint ("ERROR : Can not allocate memory for SecEmuThunkPpi. Exiting.\n");
- exit (1);
- }
- CopyMem (SecEmuThunkPpi, &mSecEmuThunkPpi, sizeof (EMU_THUNK_PPI));
- SecEmuThunkPpi->PersistentMemorySize = FixedPcdGet32 (PcdPersistentMemorySize);
- AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, SecEmuThunkPpi);
- AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiPeiReset2PpiGuid, &mEmuReset2Ppi);
- //
- // Emulator Bus Driver Thunks
- //
- AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
- AddThunkProtocol (&mWinNtFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
- AddThunkProtocol (&mWinNtBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);
- AddThunkProtocol (&mWinNtSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);
- //
- // Allocate space for gSystemMemory Array
- //
- gSystemMemoryCount = CountSeparatorsInString (MemorySizeStr, '!') + 1;
- gSystemMemory = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));
- if (gSystemMemory == NULL) {
- SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n\r", MemorySizeStr);
- exit (1);
- }
- //
- // Allocate "physical" memory space for emulator. It will be reported out later throuth MemoryAutoScan()
- //
- for (Index = 0, Done = FALSE; !Done; Index++) {
- ASSERT (Index < gSystemMemoryCount);
- gSystemMemory[Index].Size = ((UINT64)_wtoi (MemorySizeStr)) * ((UINT64)SIZE_1MB);
- gSystemMemory[Index].Memory = (EFI_PHYSICAL_ADDRESS)(UINTN)VirtualAlloc (NULL, (SIZE_T)(gSystemMemory[Index].Size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- if (gSystemMemory[Index].Memory == 0) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Find the next region
- //
- for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++) {
- }
- if (MemorySizeStr[Index1] == 0) {
- Done = TRUE;
- }
- MemorySizeStr = MemorySizeStr + Index1 + 1;
- }
- //
- // Allocate space for gSystemMemory Array
- //
- gFdInfoCount = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;
- gFdInfo = calloc (gFdInfoCount, sizeof (NT_FD_INFO));
- if (gFdInfo == NULL) {
- SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n\r", FirmwareVolumesStr);
- exit (1);
- }
- //
- // Setup Boot Mode.
- //
- SecPrint (" BootMode 0x%02x\n\r", PcdGet32 (PcdEmuBootMode));
- //
- // Allocate 128K memory to emulate temp memory for PEI.
- // on a real platform this would be SRAM, or using the cache as RAM.
- // Set TemporaryRam to zero so WinNtOpenFile will allocate a new mapping
- //
- TemporaryRamSize = TEMPORARY_RAM_SIZE;
- TemporaryRam = VirtualAlloc (NULL, (SIZE_T)(TemporaryRamSize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- if (TemporaryRam == NULL) {
- SecPrint ("ERROR : Can not allocate enough space for SecStack\n\r");
- exit (1);
- }
- //
- // If enabled use the magic page to communicate between modules
- // This replaces the PI PeiServicesTable pointer mechanism that
- // deos not work in the emulator. It also allows the removal of
- // writable globals from SEC, PEI_CORE (libraries), PEIMs
- //
- EmuMagicPage = (VOID *)(UINTN)(FixedPcdGet64 (PcdPeiServicesTablePage) & MAX_UINTN);
- if (EmuMagicPage != NULL) {
- UINT64 Size;
- Status = WinNtOpenFile (
- NULL,
- SIZE_4KB,
- 0,
- &EmuMagicPage,
- &Size
- );
- if (EFI_ERROR (Status)) {
- SecPrint ("ERROR : Could not allocate PeiServicesTablePage @ %p\n\r", EmuMagicPage);
- return EFI_DEVICE_ERROR;
- }
- }
- //
- // Open All the firmware volumes and remember the info in the gFdInfo global
- // Meanwhile, find the SEC Core.
- //
- FileNamePtr = AllocateCopyPool (StrSize (FirmwareVolumesStr), FirmwareVolumesStr);
- if (FileNamePtr == NULL) {
- SecPrint ("ERROR : Can not allocate memory for firmware volume string\n\r");
- exit (1);
- }
- for (Done = FALSE, Index = 0, SecFile = NULL; !Done; Index++) {
- FileName = FileNamePtr;
- for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++) {
- }
- if (FileNamePtr[Index1] == 0) {
- Done = TRUE;
- } else {
- FileNamePtr[Index1] = '\0';
- FileNamePtr = &FileNamePtr[Index1 + 1];
- }
- //
- // Open the FD and remember where it got mapped into our processes address space
- //
- Status = WinNtOpenFile (
- FileName,
- 0,
- OPEN_EXISTING,
- &gFdInfo[Index].Address,
- &gFdInfo[Index].Size
- );
- if (EFI_ERROR (Status)) {
- SecPrint ("ERROR : Can not open Firmware Device File %S (0x%X). Exiting.\n\r", FileName, Status);
- exit (1);
- }
- SecPrint (" FD loaded from %S", FileName);
- if (SecFile == NULL) {
- //
- // Assume the beginning of the FD is an FV and look for the SEC Core.
- // Load the first one we find.
- //
- FileHandle = NULL;
- Status = PeiServicesFfsFindNextFile (
- EFI_FV_FILETYPE_SECURITY_CORE,
- (EFI_PEI_FV_HANDLE)gFdInfo[Index].Address,
- &FileHandle
- );
- if (!EFI_ERROR (Status)) {
- Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
- if (!EFI_ERROR (Status)) {
- SecPrint (" contains SEC Core");
- }
- }
- }
- SecPrint ("\n\r");
- }
- ResetJumpCode = SetJump (&mResetJumpBuffer);
- //
- // Do not clear memory content for warm reset.
- //
- if (ResetJumpCode != EfiResetWarm + 1) {
- SecPrint (" OS Emulator clearing temp RAM and physical RAM (to be discovered later)......\n\r");
- SetMem32 (TemporaryRam, TemporaryRamSize, PcdGet32 (PcdInitValueInTempStack));
- for (Index = 0; Index < gSystemMemoryCount; Index++) {
- SetMem32 ((VOID *)(UINTN)gSystemMemory[Index].Memory, (UINTN)gSystemMemory[Index].Size, PcdGet32 (PcdInitValueInTempStack));
- }
- }
- SecPrint (
- " OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n\r",
- TemporaryRamSize / SIZE_1KB,
- TemporaryRam
- );
- //
- // Hand off to SEC Core
- //
- SecLoadSecCore ((UINTN)TemporaryRam, TemporaryRamSize, gFdInfo[0].Address, gFdInfo[0].Size, SecFile);
- //
- // If we get here, then the SEC Core returned. This is an error as SEC should
- // always hand off to PEI Core and then on to DXE Core.
- //
- SecPrint ("ERROR : SEC returned\n\r");
- exit (1);
- }
- VOID
- SecLoadSecCore (
- IN UINTN TemporaryRam,
- IN UINTN TemporaryRamSize,
- IN VOID *BootFirmwareVolumeBase,
- IN UINTN BootFirmwareVolumeSize,
- IN VOID *SecCorePe32File
- )
- /*++
- Routine Description:
- This is the service to load the SEC Core from the Firmware Volume
- Arguments:
- TemporaryRam - Memory to use for SEC.
- TemporaryRamSize - Size of Memory to use for SEC
- BootFirmwareVolumeBase - Start of the Boot FV
- SecCorePe32File - SEC Core PE32
- Returns:
- Success means control is transferred and thus we should never return
- --*/
- {
- EFI_STATUS Status;
- VOID *TopOfStack;
- VOID *SecCoreEntryPoint;
- EFI_SEC_PEI_HAND_OFF *SecCoreData;
- UINTN SecStackSize;
- //
- // Compute Top Of Memory for Stack and PEI Core Allocations
- //
- SecStackSize = TemporaryRamSize >> 1;
- //
- // |-----------| <---- TemporaryRamBase + TemporaryRamSize
- // | Heap |
- // | |
- // |-----------| <---- StackBase / PeiTemporaryMemoryBase
- // | |
- // | Stack |
- // |-----------| <---- TemporaryRamBase
- //
- TopOfStack = (VOID *)(TemporaryRam + SecStackSize);
- //
- // Reservet space for storing PeiCore's parament in stack.
- //
- TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
- TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
- //
- // Bind this information into the SEC hand-off state
- //
- SecCoreData = (EFI_SEC_PEI_HAND_OFF *)(UINTN)TopOfStack;
- SecCoreData->DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
- SecCoreData->BootFirmwareVolumeBase = BootFirmwareVolumeBase;
- SecCoreData->BootFirmwareVolumeSize = BootFirmwareVolumeSize;
- SecCoreData->TemporaryRamBase = (VOID *)TemporaryRam;
- SecCoreData->TemporaryRamSize = TemporaryRamSize;
- SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
- SecCoreData->StackSize = SecStackSize;
- SecCoreData->PeiTemporaryRamBase = (VOID *)((UINTN)SecCoreData->TemporaryRamBase + SecStackSize);
- SecCoreData->PeiTemporaryRamSize = TemporaryRamSize - SecStackSize;
- //
- // Load the PEI Core from a Firmware Volume
- //
- Status = SecPeCoffGetEntryPoint (
- SecCorePe32File,
- &SecCoreEntryPoint
- );
- if (EFI_ERROR (Status)) {
- return;
- }
- //
- // Transfer control to the SEC Core
- //
- SwitchStack (
- (SWITCH_STACK_ENTRY_POINT)(UINTN)SecCoreEntryPoint,
- SecCoreData,
- GetThunkPpiList (),
- TopOfStack
- );
- //
- // If we get here, then the SEC Core returned. This is an error
- //
- return;
- }
- RETURN_STATUS
- EFIAPI
- SecPeCoffGetEntryPoint (
- IN VOID *Pe32Data,
- IN OUT VOID **EntryPoint
- )
- {
- EFI_STATUS Status;
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
- ZeroMem (&ImageContext, sizeof (ImageContext));
- ImageContext.Handle = Pe32Data;
- ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)SecImageRead;
- Status = PeCoffLoaderGetImageInfo (&ImageContext);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // XIP for SEC and PEI_CORE
- //
- ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
- Status = PeCoffLoaderLoadImage (&ImageContext);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = PeCoffLoaderRelocateImage (&ImageContext);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EFIAPI
- SecImageRead (
- IN VOID *FileHandle,
- IN UINTN FileOffset,
- IN OUT UINTN *ReadSize,
- OUT VOID *Buffer
- )
- /*++
- Routine Description:
- Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
- Arguments:
- FileHandle - The handle to the PE/COFF file
- FileOffset - The offset, in bytes, into the file to read
- ReadSize - The number of bytes to read from the file starting at FileOffset
- Buffer - A pointer to the buffer to read the data into.
- Returns:
- EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
- --*/
- {
- CHAR8 *Destination8;
- CHAR8 *Source8;
- UINTN Length;
- Destination8 = Buffer;
- Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset);
- Length = *ReadSize;
- while (Length--) {
- *(Destination8++) = *(Source8++);
- }
- return EFI_SUCCESS;
- }
- CHAR16 *
- AsciiToUnicode (
- IN CHAR8 *Ascii,
- IN UINTN *StrLen OPTIONAL
- )
- /*++
- Routine Description:
- Convert the passed in Ascii string to Unicode.
- Optionally return the length of the strings.
- Arguments:
- Ascii - Ascii string to convert
- StrLen - Length of string
- Returns:
- Pointer to malloc'ed Unicode version of Ascii
- --*/
- {
- UINTN Index;
- CHAR16 *Unicode;
- //
- // Allocate a buffer for unicode string
- //
- for (Index = 0; Ascii[Index] != '\0'; Index++) {
- }
- Unicode = malloc ((Index + 1) * sizeof (CHAR16));
- if (Unicode == NULL) {
- return NULL;
- }
- for (Index = 0; Ascii[Index] != '\0'; Index++) {
- Unicode[Index] = (CHAR16)Ascii[Index];
- }
- Unicode[Index] = '\0';
- if (StrLen != NULL) {
- *StrLen = Index;
- }
- return Unicode;
- }
- UINTN
- CountSeparatorsInString (
- IN CONST CHAR16 *String,
- IN CHAR16 Separator
- )
- /*++
- Routine Description:
- Count the number of separators in String
- Arguments:
- String - String to process
- Separator - Item to count
- Returns:
- Number of Separator in String
- --*/
- {
- UINTN Count;
- for (Count = 0; *String != '\0'; String++) {
- if (*String == Separator) {
- Count++;
- }
- }
- return Count;
- }
- /**
- Store the ModHandle in an array indexed by the Pdb File name.
- The ModHandle is needed to unload the image.
- @param ImageContext - Input data returned from PE Laoder Library. Used to find the
- .PDB file name of the PE Image.
- @param ModHandle - Returned from LoadLibraryEx() and stored for call to
- FreeLibrary().
- @return return EFI_SUCCESS when ModHandle was stored.
- --*/
- EFI_STATUS
- AddModHandle (
- IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- IN VOID *ModHandle
- )
- {
- UINTN Index;
- PDB_NAME_TO_MOD_HANDLE *Array;
- UINTN PreviousSize;
- PDB_NAME_TO_MOD_HANDLE *TempArray;
- HANDLE Handle;
- UINTN Size;
- //
- // Return EFI_ALREADY_STARTED if this DLL has already been loaded
- //
- Array = mPdbNameModHandleArray;
- for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
- if ((Array->PdbPointer != NULL) && (Array->ModHandle == ModHandle)) {
- return EFI_ALREADY_STARTED;
- }
- }
- Array = mPdbNameModHandleArray;
- for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
- if (Array->PdbPointer == NULL) {
- //
- // Make a copy of the stirng and store the ModHandle
- //
- Handle = GetProcessHeap ();
- Size = AsciiStrLen (ImageContext->PdbPointer) + 1;
- Array->PdbPointer = HeapAlloc (Handle, HEAP_ZERO_MEMORY, Size);
- ASSERT (Array->PdbPointer != NULL);
- AsciiStrCpyS (Array->PdbPointer, Size, ImageContext->PdbPointer);
- Array->ModHandle = ModHandle;
- return EFI_SUCCESS;
- }
- }
- //
- // No free space in mPdbNameModHandleArray so grow it by
- // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires.
- //
- PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);
- mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;
- //
- // re-allocate a new buffer and copy the old values to the new locaiton.
- //
- TempArray = HeapAlloc (
- GetProcessHeap (),
- HEAP_ZERO_MEMORY,
- mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)
- );
- CopyMem ((VOID *)(UINTN)TempArray, (VOID *)(UINTN)mPdbNameModHandleArray, PreviousSize);
- HeapFree (GetProcessHeap (), 0, mPdbNameModHandleArray);
- mPdbNameModHandleArray = TempArray;
- if (mPdbNameModHandleArray == NULL) {
- ASSERT (FALSE);
- return EFI_OUT_OF_RESOURCES;
- }
- return AddModHandle (ImageContext, ModHandle);
- }
- /**
- Return the ModHandle and delete the entry in the array.
- @param ImageContext - Input data returned from PE Laoder Library. Used to find the
- .PDB file name of the PE Image.
- @return
- ModHandle - ModHandle assoicated with ImageContext is returned
- NULL - No ModHandle associated with ImageContext
- **/
- VOID *
- RemoveModHandle (
- IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
- {
- UINTN Index;
- PDB_NAME_TO_MOD_HANDLE *Array;
- if (ImageContext->PdbPointer == NULL) {
- //
- // If no PDB pointer there is no ModHandle so return NULL
- //
- return NULL;
- }
- Array = mPdbNameModHandleArray;
- for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
- if ((Array->PdbPointer != NULL) && (AsciiStrCmp (Array->PdbPointer, ImageContext->PdbPointer) == 0)) {
- //
- // If you find a match return it and delete the entry
- //
- HeapFree (GetProcessHeap (), 0, Array->PdbPointer);
- Array->PdbPointer = NULL;
- return Array->ModHandle;
- }
- }
- return NULL;
- }
- VOID
- EFIAPI
- PeCoffLoaderRelocateImageExtraAction (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
- {
- EFI_STATUS Status;
- VOID *DllEntryPoint;
- CHAR16 *DllFileName;
- HMODULE Library;
- UINTN Index;
- ASSERT (ImageContext != NULL);
- //
- // If we load our own PE COFF images the Windows debugger can not source
- // level debug our code. If a valid PDB pointer exists use it to load
- // the *.dll file as a library using Windows* APIs. This allows
- // source level debug. The image is still loaded and relocated
- // in the Framework memory space like on a real system (by the code above),
- // but the entry point points into the DLL loaded by the code below.
- //
- DllEntryPoint = NULL;
- //
- // Load the DLL if it's not an EBC image.
- //
- if ((ImageContext->PdbPointer != NULL) &&
- (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC))
- {
- //
- // Convert filename from ASCII to Unicode
- //
- DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);
- //
- // Check that we have a valid filename
- //
- if ((Index < 5) || (DllFileName[Index - 4] != '.')) {
- free (DllFileName);
- //
- // Never return an error if PeCoffLoaderRelocateImage() succeeded.
- // The image will run, but we just can't source level debug. If we
- // return an error the image will not run.
- //
- return;
- }
- //
- // Replace .PDB with .DLL on the filename
- //
- DllFileName[Index - 3] = 'D';
- DllFileName[Index - 2] = 'L';
- DllFileName[Index - 1] = 'L';
- //
- // Load the .DLL file into the user process's address space for source
- // level debug
- //
- Library = LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);
- if (Library != NULL) {
- //
- // InitializeDriver is the entry point we put in all our EFI DLL's. The
- // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() suppresses the
- // normal DLL entry point of DllMain, and prevents other modules that are
- // referenced in side the DllFileName from being loaded. There is no error
- // checking as the we can point to the PE32 image loaded by Tiano. This
- // step is only needed for source level debugging
- //
- DllEntryPoint = (VOID *)(UINTN)GetProcAddress (Library, "InitializeDriver");
- }
- if ((Library != NULL) && (DllEntryPoint != NULL)) {
- Status = AddModHandle (ImageContext, Library);
- if (Status == EFI_ALREADY_STARTED) {
- //
- // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.
- //
- ImageContext->PdbPointer = NULL;
- SecPrint ("WARNING: DLL already loaded. No source level debug %S.\n\r", DllFileName);
- } else {
- //
- // This DLL is not already loaded, so source level debugging is supported.
- //
- ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)DllEntryPoint;
- SecPrint ("LoadLibraryEx (\n\r %S,\n\r NULL, DONT_RESOLVE_DLL_REFERENCES)\n\r", DllFileName);
- }
- } else {
- SecPrint ("WARNING: No source level debug %S. \n\r", DllFileName);
- }
- free (DllFileName);
- }
- }
- VOID
- EFIAPI
- PeCoffLoaderUnloadImageExtraAction (
- IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
- {
- VOID *ModHandle;
- ASSERT (ImageContext != NULL);
- ModHandle = RemoveModHandle (ImageContext);
- if (ModHandle != NULL) {
- FreeLibrary (ModHandle);
- SecPrint ("FreeLibrary (\n\r %s)\n\r", ImageContext->PdbPointer);
- } else {
- SecPrint ("WARNING: Unload image without source level debug\n\r");
- }
- }
- VOID
- _ModuleEntryPoint (
- VOID
- )
- {
- }
|