--- /dev/null
+/**@file\r
+ WinNt emulator of pre-SEC phase. It's really a Win32 application, but this is\r
+ Ok since all the other modules for NT32 are NOT Win32 applications.\r
+\r
+ This program gets NT32 PCD setting and figures out what the memory layout\r
+ will be, how may FD's will be loaded and also what the boot mode is.\r
+\r
+ This code produces 128 K of temporary memory for the SEC stack by directly\r
+ allocate memory space with ReadWrite and Execute attribute.\r
+\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include "WinHost.h"\r
+\r
+#ifndef SE_TIME_ZONE_NAME\r
+#define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege")\r
+#endif\r
+\r
+//\r
+// Default information about where the FD is located.\r
+// This array gets filled in with information from PcdWinNtFirmwareVolume\r
+// The number of array elements is allocated base on parsing\r
+// PcdWinNtFirmwareVolume and the memory is never freed.\r
+//\r
+UINTN gFdInfoCount = 0;\r
+NT_FD_INFO *gFdInfo;\r
+\r
+//\r
+// Array that supports seperate memory rantes.\r
+// The memory ranges are set by PcdWinNtMemorySizeForSecMain.\r
+// The number of array elements is allocated base on parsing\r
+// PcdWinNtMemorySizeForSecMain value and the memory is never freed.\r
+//\r
+UINTN gSystemMemoryCount = 0;\r
+NT_SYSTEM_MEMORY *gSystemMemory;\r
+\r
+/*++\r
+\r
+Routine Description:\r
+ This service is called from Index == 0 until it returns EFI_UNSUPPORTED.\r
+ It allows discontinuous memory regions to be supported by the emulator.\r
+ It uses gSystemMemory[] and gSystemMemoryCount that were created by\r
+ parsing the host environment variable EFI_MEMORY_SIZE.\r
+ The size comes from the varaible and the address comes from the call to\r
+ UnixOpenFile.\r
+\r
+Arguments:\r
+ Index - Which memory region to use\r
+ MemoryBase - Return Base address of memory region\r
+ MemorySize - Return size in bytes of the memory region\r
+\r
+Returns:\r
+ EFI_SUCCESS - If memory region was mapped\r
+ EFI_UNSUPPORTED - If Index is not supported\r
+\r
+**/\r
+EFI_STATUS\r
+WinPeiAutoScan (\r
+ IN UINTN Index,\r
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBase,\r
+ OUT UINT64 *MemorySize\r
+ )\r
+{\r
+ if (Index >= gSystemMemoryCount) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Allocate enough memory space for emulator\r
+ //\r
+ gSystemMemory[Index].Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (gSystemMemory[Index].Size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
+ if (gSystemMemory[Index].Memory == 0) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ *MemoryBase = gSystemMemory[Index].Memory;\r
+ *MemorySize = gSystemMemory[Index].Size;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/*++\r
+\r
+Routine Description:\r
+ Return the FD Size and base address. Since the FD is loaded from a\r
+ file into host memory only the SEC will know it's address.\r
+\r
+Arguments:\r
+ Index - Which FD, starts at zero.\r
+ FdSize - Size of the FD in bytes\r
+ FdBase - Start address of the FD. Assume it points to an FV Header\r
+ FixUp - Difference between actual FD address and build address\r
+\r
+Returns:\r
+ EFI_SUCCESS - Return the Base address and size of the FV\r
+ EFI_UNSUPPORTED - Index does nto map to an FD in the system\r
+\r
+**/\r
+EFI_STATUS\r
+WinFdAddress (\r
+ IN UINTN Index,\r
+ IN OUT EFI_PHYSICAL_ADDRESS *FdBase,\r
+ IN OUT UINT64 *FdSize,\r
+ IN OUT EFI_PHYSICAL_ADDRESS *FixUp\r
+ )\r
+{\r
+ if (Index >= gFdInfoCount) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+\r
+ *FdBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gFdInfo[Index].Address;\r
+ *FdSize = (UINT64)gFdInfo[Index].Size;\r
+ *FixUp = 0;\r
+\r
+ if (*FdBase == 0 && *FdSize == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (Index == 0) {\r
+ //\r
+ // FD 0 has XIP code and well known PCD values\r
+ // If the memory buffer could not be allocated at the FD build address\r
+ // the Fixup is the difference.\r
+ //\r
+ *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/*++\r
+\r
+Routine Description:\r
+ Since the SEC is the only Unix program in stack it must export\r
+ an interface to do POSIX calls. gUnix is initialized in UnixThunk.c.\r
+\r
+Arguments:\r
+ InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);\r
+ InterfaceBase - Address of the gUnix global\r
+\r
+Returns:\r
+ EFI_SUCCESS - Data returned\r
+\r
+**/\r
+VOID *\r
+WinThunk (\r
+ VOID\r
+ )\r
+{\r
+ return &gEmuThunkProtocol;\r
+}\r
+\r
+\r
+EMU_THUNK_PPI mSecEmuThunkPpi = {\r
+ WinPeiAutoScan,\r
+ WinFdAddress,\r
+ WinThunk\r
+};\r
+\r
+VOID\r
+SecPrint (\r
+ CHAR8 *Format,\r
+ ...\r
+ )\r
+{\r
+ va_list Marker;\r
+ UINTN CharCount;\r
+ CHAR8 Buffer[0x1000];\r
+\r
+ va_start (Marker, Format);\r
+\r
+ _vsnprintf (Buffer, sizeof (Buffer), Format, Marker);\r
+\r
+ va_end (Marker);\r
+\r
+ CharCount = strlen (Buffer);\r
+ WriteFile (\r
+ GetStdHandle (STD_OUTPUT_HANDLE),\r
+ Buffer,\r
+ (DWORD)CharCount,\r
+ (LPDWORD)&CharCount,\r
+ NULL\r
+ );\r
+}\r
+\r
+/*++\r
+\r
+Routine Description:\r
+ Check to see if an address range is in the EFI GCD memory map.\r
+\r
+ This is all of GCD for system memory passed to DXE Core. FV\r
+ mapping and other device mapped into system memory are not\r
+ inlcuded in the check.\r
+\r
+Arguments:\r
+ Index - Which memory region to use\r
+ MemoryBase - Return Base address of memory region\r
+ MemorySize - Return size in bytes of the memory region\r
+\r
+Returns:\r
+ TRUE - Address is in the EFI GCD memory map\r
+ FALSE - Address is NOT in memory map\r
+\r
+**/\r
+BOOLEAN\r
+EfiSystemMemoryRange (\r
+ IN VOID *MemoryAddress\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_PHYSICAL_ADDRESS MemoryBase;\r
+\r
+ MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;\r
+ for (Index = 0; Index < gSystemMemoryCount; Index++) {\r
+ if ((MemoryBase >= gSystemMemory[Index].Memory) &&\r
+ (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)) ) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+WinNtOpenFile (\r
+ IN CHAR16 *FileName, OPTIONAL\r
+ IN UINT32 MapSize,\r
+ IN DWORD CreationDisposition,\r
+ IN OUT VOID **BaseAddress,\r
+ OUT UINTN *Length\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Opens and memory maps a file using WinNt services. If *BaseAddress is non zero\r
+ the process will try and allocate the memory starting at BaseAddress.\r
+\r
+Arguments:\r
+ FileName - The name of the file to open and map\r
+ MapSize - The amount of the file to map in bytes\r
+ CreationDisposition - The flags to pass to CreateFile(). Use to create new files for\r
+ memory emulation, and exiting files for firmware volume emulation\r
+ BaseAddress - The base address of the mapped file in the user address space.\r
+ If *BaseAddress is 0, the new memory region is used.\r
+ If *BaseAddress is not 0, the request memory region is used for\r
+ the mapping of the file into the process space.\r
+ Length - The size of the mapped region in bytes\r
+\r
+Returns:\r
+ EFI_SUCCESS - The file was opened and mapped.\r
+ EFI_NOT_FOUND - FileName was not found in the current directory\r
+ EFI_DEVICE_ERROR - An error occured attempting to map the opened file\r
+\r
+--*/\r
+{\r
+ HANDLE NtFileHandle;\r
+ HANDLE NtMapHandle;\r
+ VOID *VirtualAddress;\r
+ UINTN FileSize;\r
+\r
+ //\r
+ // Use Win API to open/create a file\r
+ //\r
+ NtFileHandle = INVALID_HANDLE_VALUE;\r
+ if (FileName != NULL) {\r
+ NtFileHandle = CreateFile (\r
+ FileName,\r
+ GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,\r
+ FILE_SHARE_READ,\r
+ NULL,\r
+ CreationDisposition,\r
+ FILE_ATTRIBUTE_NORMAL,\r
+ NULL\r
+ );\r
+ if (NtFileHandle == INVALID_HANDLE_VALUE) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+ //\r
+ // Map the open file into a memory range\r
+ //\r
+ NtMapHandle = CreateFileMapping (\r
+ NtFileHandle,\r
+ NULL,\r
+ PAGE_EXECUTE_READWRITE,\r
+ 0,\r
+ MapSize,\r
+ NULL\r
+ );\r
+ if (NtMapHandle == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Get the virtual address (address in the emulator) of the mapped file\r
+ //\r
+ VirtualAddress = MapViewOfFileEx (\r
+ NtMapHandle,\r
+ FILE_MAP_EXECUTE | FILE_MAP_ALL_ACCESS,\r
+ 0,\r
+ 0,\r
+ MapSize,\r
+ *BaseAddress\r
+ );\r
+ if (VirtualAddress == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (MapSize == 0) {\r
+ //\r
+ // Seek to the end of the file to figure out the true file size.\r
+ //\r
+ FileSize = SetFilePointer (\r
+ NtFileHandle,\r
+ 0,\r
+ NULL,\r
+ FILE_END\r
+ );\r
+ if (FileSize == -1) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ *Length = FileSize;\r
+ } else {\r
+ *Length = MapSize;\r
+ }\r
+\r
+ *BaseAddress = VirtualAddress;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+INTN\r
+EFIAPI\r
+main (\r
+ IN INTN Argc,\r
+ IN CHAR8 **Argv,\r
+ IN CHAR8 **Envp\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Main entry point to SEC for WinNt. This is a Windows program\r
+\r
+Arguments:\r
+ Argc - Number of command line arguments\r
+ Argv - Array of command line argument strings\r
+ Envp - Array of environment variable strings\r
+\r
+Returns:\r
+ 0 - Normal exit\r
+ 1 - Abnormal exit\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ HANDLE Token;\r
+ TOKEN_PRIVILEGES TokenPrivileges;\r
+ VOID *TemporaryRam;\r
+ UINT32 TemporaryRamSize;\r
+ VOID *EmuMagicPage;\r
+ UINTN Index;\r
+ UINTN Index1;\r
+ CHAR16 *FileName;\r
+ CHAR16 *FileNamePtr;\r
+ BOOLEAN Done;\r
+ EFI_PEI_FILE_HANDLE FileHandle;\r
+ VOID *SecFile;\r
+ CHAR16 *MemorySizeStr;\r
+ CHAR16 *FirmwareVolumesStr;\r
+ UINT32 ProcessAffinityMask;\r
+ UINT32 SystemAffinityMask;\r
+ INT32 LowBit;\r
+\r
+ //\r
+ // Enable the privilege so that RTC driver can successfully run SetTime()\r
+ //\r
+ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &Token);\r
+ if (LookupPrivilegeValue(NULL, SE_TIME_ZONE_NAME, &TokenPrivileges.Privileges[0].Luid)) {\r
+ TokenPrivileges.PrivilegeCount = 1;\r
+ TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;\r
+ AdjustTokenPrivileges(Token, FALSE, &TokenPrivileges, 0, (PTOKEN_PRIVILEGES) NULL, 0);\r
+ }\r
+\r
+ MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);\r
+ FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);\r
+\r
+ SecPrint ("\nEDK II WIN Host Emulation Environment from http://www.tianocore.org/edk2/\n");\r
+\r
+ //\r
+ // Determine the first thread available to this process.\r
+ //\r
+ if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {\r
+ LowBit = (INT32)LowBitSet32 (ProcessAffinityMask);\r
+ if (LowBit != -1) {\r
+ //\r
+ // Force the system to bind the process to a single thread to work\r
+ // around odd semaphore type crashes.\r
+ //\r
+ SetProcessAffinityMask (GetCurrentProcess (), (INTN)(BIT0 << LowBit));\r
+ }\r
+ }\r
+\r
+ //\r
+ // Make some Windows calls to Set the process to the highest priority in the\r
+ // idle class. We need this to have good performance.\r
+ //\r
+ SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS);\r
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);\r
+\r
+ SecInitializeThunk ();\r
+ //\r
+ // PPIs pased into PEI_CORE\r
+ //\r
+ AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);\r
+\r
+ //\r
+ // Allocate space for gSystemMemory Array\r
+ //\r
+ gSystemMemoryCount = CountSeparatorsInString (MemorySizeStr, '!') + 1;\r
+ gSystemMemory = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));\r
+ if (gSystemMemory == NULL) {\r
+ SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n", MemorySizeStr);\r
+ exit (1);\r
+ }\r
+\r
+ //\r
+ // Allocate space for gSystemMemory Array\r
+ //\r
+ gFdInfoCount = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;\r
+ gFdInfo = calloc (gFdInfoCount, sizeof (NT_FD_INFO));\r
+ if (gFdInfo == NULL) {\r
+ SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n", FirmwareVolumesStr);\r
+ exit (1);\r
+ }\r
+ //\r
+ // Setup Boot Mode.\r
+ //\r
+ SecPrint (" BootMode 0x%02x\n", PcdGet32 (PcdEmuBootMode));\r
+\r
+ //\r
+ // Allocate 128K memory to emulate temp memory for PEI.\r
+ // on a real platform this would be SRAM, or using the cache as RAM.\r
+ // Set TemporaryRam to zero so WinNtOpenFile will allocate a new mapping\r
+ //\r
+ TemporaryRamSize = TEMPORARY_RAM_SIZE;\r
+ TemporaryRam = VirtualAlloc (NULL, (SIZE_T) (TemporaryRamSize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
+ if (TemporaryRam == NULL) {\r
+ SecPrint ("ERROR : Can not allocate enough space for SecStack\n");\r
+ exit (1);\r
+ }\r
+ SetMemN (TemporaryRam, TemporaryRamSize, PcdGet32 (PcdInitValueInTempStack));\r
+\r
+ SecPrint (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",\r
+ TemporaryRamSize / SIZE_1KB,\r
+ TemporaryRam\r
+ );\r
+\r
+ //\r
+ // If enabled use the magic page to communicate between modules\r
+ // This replaces the PI PeiServicesTable pointer mechanism that\r
+ // deos not work in the emulator. It also allows the removal of\r
+ // writable globals from SEC, PEI_CORE (libraries), PEIMs\r
+ //\r
+ EmuMagicPage = (VOID *)(UINTN)(FixedPcdGet64 (PcdPeiServicesTablePage) & MAX_UINTN);\r
+ if (EmuMagicPage != NULL) {\r
+ UINT64 Size;\r
+ Status = WinNtOpenFile (\r
+ NULL,\r
+ SIZE_4KB,\r
+ 0,\r
+ &EmuMagicPage,\r
+ &Size\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SecPrint ("ERROR : Could not allocate PeiServicesTablePage @ %p\n", EmuMagicPage);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Open All the firmware volumes and remember the info in the gFdInfo global\r
+ // Meanwhile, find the SEC Core.\r
+ //\r
+ FileNamePtr = AllocateCopyPool (StrSize (FirmwareVolumesStr), FirmwareVolumesStr);\r
+ if (FileNamePtr == NULL) {\r
+ SecPrint ("ERROR : Can not allocate memory for firmware volume string\n");\r
+ exit (1);\r
+ }\r
+\r
+ for (Done = FALSE, Index = 0, SecFile = NULL; !Done; Index++) {\r
+ FileName = FileNamePtr;\r
+ for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++)\r
+ ;\r
+ if (FileNamePtr[Index1] == 0) {\r
+ Done = TRUE;\r
+ } else {\r
+ FileNamePtr[Index1] = '\0';\r
+ FileNamePtr = &FileNamePtr[Index1 + 1];\r
+ }\r
+\r
+ //\r
+ // Open the FD and remember where it got mapped into our processes address space\r
+ //\r
+ Status = WinNtOpenFile (\r
+ FileName,\r
+ 0,\r
+ OPEN_EXISTING,\r
+ &gFdInfo[Index].Address,\r
+ &gFdInfo[Index].Size\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SecPrint ("ERROR : Can not open Firmware Device File %S (0x%X). Exiting.\n", FileName, Status);\r
+ exit (1);\r
+ }\r
+\r
+ SecPrint (" FD loaded from %S\n", FileName);\r
+\r
+ if (SecFile == NULL) {\r
+ //\r
+ // Assume the beginning of the FD is an FV and look for the SEC Core.\r
+ // Load the first one we find.\r
+ //\r
+ FileHandle = NULL;\r
+ Status = PeiServicesFfsFindNextFile (\r
+ EFI_FV_FILETYPE_SECURITY_CORE,\r
+ (EFI_PEI_FV_HANDLE)gFdInfo[Index].Address,\r
+ &FileHandle\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);\r
+ if (!EFI_ERROR (Status)) {\r
+ SecPrint (" contains SEC Core");\r
+ }\r
+ }\r
+ }\r
+\r
+ SecPrint ("\n");\r
+ }\r
+ //\r
+ // Calculate memory regions and store the information in the gSystemMemory\r
+ // global for later use. The autosizing code will use this data to\r
+ // map this memory into the SEC process memory space.\r
+ //\r
+ for (Index = 0, Done = FALSE; !Done; Index++) {\r
+ //\r
+ // Save the size of the memory and make a Unicode filename SystemMemory00, ...\r
+ //\r
+ gSystemMemory[Index].Size = _wtoi (MemorySizeStr) * SIZE_1MB;\r
+\r
+ //\r
+ // Find the next region\r
+ //\r
+ for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++)\r
+ ;\r
+ if (MemorySizeStr[Index1] == 0) {\r
+ Done = TRUE;\r
+ }\r
+\r
+ MemorySizeStr = MemorySizeStr + Index1 + 1;\r
+ }\r
+\r
+ SecPrint ("\n");\r
+\r
+ //\r
+ // Hand off to SEC Core\r
+ //\r
+ SecLoadSecCore ((UINTN)TemporaryRam, TemporaryRamSize, gFdInfo[0].Address, gFdInfo[0].Size, SecFile);\r
+\r
+ //\r
+ // If we get here, then the SEC Core returned. This is an error as SEC should\r
+ // always hand off to PEI Core and then on to DXE Core.\r
+ //\r
+ SecPrint ("ERROR : SEC returned\n");\r
+ exit (1);\r
+}\r
+\r
+VOID\r
+SecLoadSecCore (\r
+ IN UINTN TemporaryRam,\r
+ IN UINTN TemporaryRamSize,\r
+ IN VOID *BootFirmwareVolumeBase,\r
+ IN UINTN BootFirmwareVolumeSize,\r
+ IN VOID *SecCorePe32File\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is the service to load the SEC Core from the Firmware Volume\r
+\r
+Arguments:\r
+ TemporaryRam - Memory to use for SEC.\r
+ TemporaryRamSize - Size of Memory to use for SEC\r
+ BootFirmwareVolumeBase - Start of the Boot FV\r
+ SecCorePe32File - SEC Core PE32\r
+\r
+Returns:\r
+ Success means control is transfered and thus we should never return\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *TopOfStack;\r
+ VOID *SecCoreEntryPoint;\r
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;\r
+ UINTN SecStackSize;\r
+\r
+ //\r
+ // Compute Top Of Memory for Stack and PEI Core Allocations\r
+ //\r
+ SecStackSize = TemporaryRamSize >> 1;\r
+\r
+ //\r
+ // |-----------| <---- TemporaryRamBase + TemporaryRamSize\r
+ // | Heap |\r
+ // | |\r
+ // |-----------| <---- StackBase / PeiTemporaryMemoryBase\r
+ // | |\r
+ // | Stack |\r
+ // |-----------| <---- TemporaryRamBase\r
+ //\r
+ TopOfStack = (VOID *)(TemporaryRam + SecStackSize);\r
+\r
+ //\r
+ // Reservet space for storing PeiCore's parament in stack.\r
+ //\r
+ TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);\r
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
+\r
+ //\r
+ // Bind this information into the SEC hand-off state\r
+ //\r
+ SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN)TopOfStack;\r
+ SecCoreData->DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);\r
+ SecCoreData->BootFirmwareVolumeBase = BootFirmwareVolumeBase;\r
+ SecCoreData->BootFirmwareVolumeSize = BootFirmwareVolumeSize;\r
+ SecCoreData->TemporaryRamBase = (VOID*)TemporaryRam;\r
+ SecCoreData->TemporaryRamSize = TemporaryRamSize;\r
+ SecCoreData->StackBase = SecCoreData->TemporaryRamBase;\r
+ SecCoreData->StackSize = SecStackSize;\r
+ SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + SecStackSize);\r
+ SecCoreData->PeiTemporaryRamSize = TemporaryRamSize - SecStackSize;\r
+\r
+ //\r
+ // Load the PEI Core from a Firmware Volume\r
+ //\r
+ Status = SecPeCoffGetEntryPoint (\r
+ SecCorePe32File,\r
+ &SecCoreEntryPoint\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Transfer control to the SEC Core\r
+ //\r
+ SwitchStack (\r
+ (SWITCH_STACK_ENTRY_POINT)SecCoreEntryPoint,\r
+ SecCoreData,\r
+ GetThunkPpiList (),\r
+ TopOfStack\r
+ );\r
+ //\r
+ // If we get here, then the SEC Core returned. This is an error\r
+ //\r
+ return ;\r
+}\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+SecPeCoffGetEntryPoint (\r
+ IN VOID *Pe32Data,\r
+ IN OUT VOID **EntryPoint\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+\r
+ ZeroMem (&ImageContext, sizeof (ImageContext));\r
+ ImageContext.Handle = Pe32Data;\r
+\r
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;\r
+\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribute.\r
+ // Extra space is for alignment\r
+ //\r
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
+ if (ImageContext.ImageAddress == 0) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Align buffer on section boundary\r
+ //\r
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
+ ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);\r
+\r
+ Status = PeCoffLoaderLoadImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SecImageRead (\r
+ IN VOID *FileHandle,\r
+ IN UINTN FileOffset,\r
+ IN OUT UINTN *ReadSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
+\r
+Arguments:\r
+ FileHandle - The handle to the PE/COFF file\r
+ FileOffset - The offset, in bytes, into the file to read\r
+ ReadSize - The number of bytes to read from the file starting at FileOffset\r
+ Buffer - A pointer to the buffer to read the data into.\r
+\r
+Returns:\r
+ EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
+\r
+--*/\r
+{\r
+ CHAR8 *Destination8;\r
+ CHAR8 *Source8;\r
+ UINTN Length;\r
+\r
+ Destination8 = Buffer;\r
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
+ Length = *ReadSize;\r
+ while (Length--) {\r
+ *(Destination8++) = *(Source8++);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+CHAR16 *\r
+AsciiToUnicode (\r
+ IN CHAR8 *Ascii,\r
+ IN UINTN *StrLen OPTIONAL\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Convert the passed in Ascii string to Unicode.\r
+ Optionally return the length of the strings.\r
+\r
+Arguments:\r
+ Ascii - Ascii string to convert\r
+ StrLen - Length of string\r
+\r
+Returns:\r
+ Pointer to malloc'ed Unicode version of Ascii\r
+\r
+--*/\r
+{\r
+ UINTN Index;\r
+ CHAR16 *Unicode;\r
+\r
+ //\r
+ // Allocate a buffer for unicode string\r
+ //\r
+ for (Index = 0; Ascii[Index] != '\0'; Index++)\r
+ ;\r
+ Unicode = malloc ((Index + 1) * sizeof (CHAR16));\r
+ if (Unicode == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ for (Index = 0; Ascii[Index] != '\0'; Index++) {\r
+ Unicode[Index] = (CHAR16) Ascii[Index];\r
+ }\r
+\r
+ Unicode[Index] = '\0';\r
+\r
+ if (StrLen != NULL) {\r
+ *StrLen = Index;\r
+ }\r
+\r
+ return Unicode;\r
+}\r
+\r
+UINTN\r
+CountSeparatorsInString (\r
+ IN CONST CHAR16 *String,\r
+ IN CHAR16 Separator\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Count the number of separators in String\r
+\r
+Arguments:\r
+ String - String to process\r
+ Separator - Item to count\r
+\r
+Returns:\r
+ Number of Separator in String\r
+\r
+--*/\r
+{\r
+ UINTN Count;\r
+\r
+ for (Count = 0; *String != '\0'; String++) {\r
+ if (*String == Separator) {\r
+ Count++;\r
+ }\r
+ }\r
+\r
+ return Count;\r
+}\r
+\r
+\r
+VOID\r
+EFIAPI\r
+PeCoffLoaderRelocateImageExtraAction (\r
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+ )\r
+{\r
+ VOID *DllEntryPoint;\r
+ CHAR16 *DllFileName;\r
+ HMODULE Library;\r
+ UINTN Index;\r
+\r
+ ASSERT (ImageContext != NULL);\r
+ //\r
+ // If we load our own PE COFF images the Windows debugger can not source\r
+ // level debug our code. If a valid PDB pointer exists usw it to load\r
+ // the *.dll file as a library using Windows* APIs. This allows\r
+ // source level debug. The image is still loaded and relocated\r
+ // in the Framework memory space like on a real system (by the code above),\r
+ // but the entry point points into the DLL loaded by the code bellow.\r
+ //\r
+\r
+ DllEntryPoint = NULL;\r
+\r
+ //\r
+ // Load the DLL if it's not an EBC image.\r
+ //\r
+ if ((ImageContext->PdbPointer != NULL) &&\r
+ (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {\r
+ //\r
+ // Convert filename from ASCII to Unicode\r
+ //\r
+ DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);\r
+\r
+ //\r
+ // Check that we have a valid filename\r
+ //\r
+ if (Index < 5 || DllFileName[Index - 4] != '.') {\r
+ free (DllFileName);\r
+\r
+ //\r
+ // Never return an error if PeCoffLoaderRelocateImage() succeeded.\r
+ // The image will run, but we just can't source level debug. If we\r
+ // return an error the image will not run.\r
+ //\r
+ return;\r
+ }\r
+ //\r
+ // Replace .PDB with .DLL on the filename\r
+ //\r
+ DllFileName[Index - 3] = 'D';\r
+ DllFileName[Index - 2] = 'L';\r
+ DllFileName[Index - 1] = 'L';\r
+\r
+ //\r
+ // Load the .DLL file into the user process's address space for source\r
+ // level debug\r
+ //\r
+ Library = LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);\r
+ if (Library != NULL) {\r
+ //\r
+ // InitializeDriver is the entry point we put in all our EFI DLL's. The\r
+ // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() suppresses the\r
+ // normal DLL entry point of DllMain, and prevents other modules that are\r
+ // referenced in side the DllFileName from being loaded. There is no error\r
+ // checking as the we can point to the PE32 image loaded by Tiano. This\r
+ // step is only needed for source level debugging\r
+ //\r
+ DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver");\r
+\r
+ }\r
+\r
+ if ((Library != NULL) && (DllEntryPoint != NULL)) {\r
+ ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
+ SecPrint ("LoadLibraryEx (%S,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName);\r
+ } else {\r
+ SecPrint ("WARNING: No source level debug %S. \n", DllFileName);\r
+ }\r
+\r
+ free (DllFileName);\r
+ }\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+PeCoffLoaderUnloadImageExtraAction (\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+)\r
+{\r
+ ASSERT (ImageContext != NULL);\r
+}\r
+\r
+\r
+VOID\r
+_ModuleEntryPoint (\r
+ VOID\r
+ )\r
+{\r
+}\r
--- /dev/null
+/*++ @file\r
+\r
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <stdlib.h>\r
+\r
+/**\r
+ Allocates a buffer of type EfiBootServicesData.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a\r
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is\r
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ @param AllocationSize The number of bytes to allocate.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocatePool (\r
+ IN UINTN AllocationSize\r
+ )\r
+{\r
+ return (VOID*) malloc (AllocationSize);\r
+}\r
+\r
+\r
+/**\r
+ Allocates and zeros a buffer of type EfiBootServicesData.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the\r
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a\r
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the\r
+ request, then NULL is returned.\r
+\r
+ @param AllocationSize The number of bytes to allocate and zero.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateZeroPool (\r
+ IN UINTN AllocationSize\r
+ )\r
+{\r
+ VOID *Buffer;\r
+\r
+ Buffer = AllocatePool (AllocationSize);\r
+ if (Buffer == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ ZeroMem (Buffer, AllocationSize);\r
+\r
+ return Buffer;\r
+}\r
+\r
+\r
+/**\r
+ Reallocates a buffer of type EfiBootServicesData.\r
+\r
+ Allocates and zeros the number bytes specified by NewSize from memory of type\r
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and\r
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and\r
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.\r
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not\r
+ enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize\r
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().\r
+\r
+ @param OldSize The size, in bytes, of OldBuffer.\r
+ @param NewSize The size, in bytes, of the buffer to reallocate.\r
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional\r
+ parameter that may be NULL.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+ReallocatePool (\r
+ IN UINTN OldSize,\r
+ IN UINTN NewSize,\r
+ IN VOID *OldBuffer OPTIONAL\r
+ )\r
+{\r
+ VOID *NewBuffer;\r
+\r
+ NewBuffer = AllocatePool (NewSize);\r
+ if (NewBuffer == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ if (OldBuffer != NULL) {\r
+ if (OldSize > 0) {\r
+ CopyMem (NewBuffer, OldBuffer, OldSize);\r
+ }\r
+\r
+ FreePool (OldBuffer);\r
+ }\r
+\r
+ return NewBuffer;\r
+}\r
+\r
+/**\r
+ Copies a buffer to an allocated buffer of type EfiBootServicesData.\r
+\r
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies\r
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the\r
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there\r
+ is not enough memory remaining to satisfy the request, then NULL is returned.\r
+\r
+ If Buffer is NULL, then ASSERT().\r
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().\r
+\r
+ @param AllocationSize The number of bytes to allocate and zero.\r
+ @param Buffer The buffer to copy to the allocated buffer.\r
+\r
+ @return A pointer to the allocated buffer or NULL if allocation fails.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+AllocateCopyPool (\r
+ IN UINTN AllocationSize,\r
+ IN CONST VOID *Buffer\r
+ )\r
+{\r
+ VOID *Memory;\r
+\r
+ Memory = AllocatePool (AllocationSize);\r
+ if (Memory != NULL) {\r
+ Memory = CopyMem (Memory, Buffer, AllocationSize);\r
+ }\r
+ return Memory;\r
+}\r
+\r
+\r
+/**\r
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the\r
+ Memory Allocation Library.\r
+\r
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the\r
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool\r
+ resources, then this function will perform no actions.\r
+\r
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,\r
+ then ASSERT().\r
+\r
+ @param Buffer Pointer to the buffer to free.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FreePool (\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ free ((void *) Buffer);\r
+}\r
+\r