+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. 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
+Module Name:\r
+\r
+ SecMain.c\r
+\r
+Abstract:\r
+ WinNt emulator of 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 processes Windows environment variables and figures out\r
+ what the memory layout will be, how may FD's will be loaded and also\r
+ what the boot mode is.\r
+\r
+ The SEC registers a set of services with the SEC core. gPrivateDispatchTable\r
+ is a list of PPI's produced by the SEC that are availble for usage in PEI.\r
+\r
+ This code produces 128 K of temporary memory for the PEI stack by opening a\r
+ Windows file and mapping it directly to memory addresses.\r
+\r
+ The system.cmd script is used to set windows environment variables that drive\r
+ the configuration opitons of the SEC.\r
+\r
+--*/\r
+\r
+#include "SecMain.h"\r
+#pragma warning(disable : 4996)\r
+\r
+//\r
+// Globals\r
+//\r
+EFI_PEI_PE_COFF_LOADER_PROTOCOL_INSTANCE mPeiEfiPeiPeCoffLoaderInstance = {\r
+ {\r
+ SecNt32PeCoffGetImageInfo,\r
+ SecNt32PeCoffLoadImage,\r
+ SecNt32PeCoffRelocateImage,\r
+ SecNt32PeCoffUnloadimage\r
+ },\r
+ NULL\r
+};\r
+\r
+\r
+\r
+EFI_PEI_PE_COFF_LOADER_PROTOCOL *gPeiEfiPeiPeCoffLoader = &mPeiEfiPeiPeCoffLoaderInstance.PeCoff;\r
+\r
+NT_PEI_LOAD_FILE_PPI mSecNtLoadFilePpi = { SecWinNtPeiLoadFile };\r
+\r
+PEI_NT_AUTOSCAN_PPI mSecNtAutoScanPpi = { SecWinNtPeiAutoScan };\r
+\r
+PEI_NT_THUNK_PPI mSecWinNtThunkPpi = { SecWinNtWinNtThunkAddress };\r
+\r
+EFI_PEI_PROGRESS_CODE_PPI mSecStatusCodePpi = { SecPeiReportStatusCode };\r
+\r
+NT_FWH_PPI mSecFwhInformationPpi = { SecWinNtFdAddress };\r
+\r
+\r
+EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {\r
+ {\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+ &gEfiPeiPeCoffLoaderGuid,\r
+ NULL\r
+ },\r
+ {\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+ &gNtPeiLoadFilePpiGuid,\r
+ &mSecNtLoadFilePpi\r
+ },\r
+ {\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+ &gPeiNtAutoScanPpiGuid,\r
+ &mSecNtAutoScanPpi\r
+ },\r
+ {\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+ &gPeiNtThunkPpiGuid,\r
+ &mSecWinNtThunkPpi\r
+ },\r
+ {\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+ &gEfiPeiStatusCodePpiGuid,\r
+ &mSecStatusCodePpi\r
+ },\r
+ {\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+ &gNtFwhPpiGuid,\r
+ &mSecFwhInformationPpi\r
+ }\r
+};\r
+\r
+\r
+//\r
+// Default information about where the FD is located.\r
+// This array gets filled in with information from EFI_FIRMWARE_VOLUMES\r
+// EFI_FIRMWARE_VOLUMES is a Windows environment variable set by system.cmd.\r
+// The number of array elements is allocated base on parsing\r
+// EFI_FIRMWARE_VOLUMES 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 in system.cmd via the EFI_MEMORY_SIZE variable.\r
+// The number of array elements is allocated base on parsing\r
+// EFI_MEMORY_SIZE and the memory is never freed.\r
+//\r
+UINTN gSystemMemoryCount = 0;\r
+NT_SYSTEM_MEMORY *gSystemMemory;\r
+\r
+\r
+UINTN mPdbNameModHandleArraySize = 0;\r
+PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL;\r
+\r
+\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 environmemt variable strings\r
+\r
+Returns:\r
+ 0 - Normal exit\r
+ 1 - Abnormal exit\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS InitialStackMemory;\r
+ UINT64 InitialStackMemorySize;\r
+ UINTN Index;\r
+ UINTN Index1;\r
+ UINTN Index2;\r
+ UINTN PeiIndex;\r
+ CHAR16 *FileName;\r
+ CHAR16 *FileNamePtr;\r
+ BOOLEAN Done;\r
+ VOID *PeiCoreFile;\r
+ CHAR16 *MemorySizeStr;\r
+ CHAR16 *FirmwareVolumesStr;\r
+\r
+ MemorySizeStr = (CHAR16 *)L"64!64";\r
+ FirmwareVolumesStr = (CHAR16 *)L"..\\Fv\\Fv_Recovery.fd";\r
+\r
+ printf ("\nEDK SEC Main NT Emulation Environment from www.TianoCore.org\n");\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
+ //\r
+ // Allocate space for gSystemMemory Array\r
+ //\r
+ gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;\r
+ gSystemMemory = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));\r
+ if (gSystemMemory == NULL) {\r
+ printf ("ERROR : Can not allocate memory for %s. Exiting.\n", MemorySizeStr);\r
+ exit (1);\r
+ }\r
+ //\r
+ // Allocate space for gSystemMemory Array\r
+ //\r
+ gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;\r
+ gFdInfo = calloc (gFdInfoCount, sizeof (NT_FD_INFO));\r
+ if (gFdInfo == NULL) {\r
+ printf ("ERROR : Can not allocate memory for %s. Exiting.\n", FirmwareVolumesStr);\r
+ exit (1);\r
+ }\r
+ //\r
+ // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION)\r
+ //\r
+ printf (" BootMode 0x%02x\n", FixedPcdGet32 (PcdWinNtBootMode));\r
+\r
+ //\r
+ // Open up a 128K file to emulate temp memory for PEI.\r
+ // on a real platform this would be SRAM, or using the cache as RAM.\r
+ // Set InitialStackMemory to zero so WinNtOpenFile will allocate a new mapping\r
+ //\r
+ InitialStackMemory = 0;\r
+ InitialStackMemorySize = 0x20000;\r
+ Status = WinNtOpenFile (\r
+ L"SecStack",\r
+ (UINT32) InitialStackMemorySize,\r
+ OPEN_ALWAYS,\r
+ &InitialStackMemory,\r
+ &InitialStackMemorySize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ printf ("ERROR : Can not open SecStack Exiting\n");\r
+ exit (1);\r
+ }\r
+\r
+ printf (" SEC passing in %d bytes of temp RAM to PEI\n", InitialStackMemorySize);\r
+\r
+ //\r
+ // Open All the firmware volumes and remember the info in the gFdInfo global\r
+ //\r
+ FileNamePtr = (CHAR16 *)malloc (StrLen ((CHAR16 *)FirmwareVolumesStr) * sizeof(CHAR16));\r
+ if (FileNamePtr == NULL) {\r
+ printf ("ERROR : Can not allocate memory for firmware volume string\n");\r
+ exit (1);\r
+ }\r
+\r
+ StrCpy (FileNamePtr, (CHAR16*)FirmwareVolumesStr);\r
+\r
+ for (Done = FALSE, Index = 0, PeiIndex = 0, PeiCoreFile = 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 remmeber 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
+ printf ("ERROR : Can not open Firmware Device File %S (%r). Exiting.\n", FileName, Status);\r
+ exit (1);\r
+ }\r
+\r
+ printf (" FD loaded from");\r
+ //\r
+ // printf can't print filenames directly as the \ gets interperted as an\r
+ // escape character.\r
+ //\r
+ for (Index2 = 0; FileName[Index2] != '\0'; Index2++) {\r
+ printf ("%c", FileName[Index2]);\r
+ }\r
+\r
+ if (PeiCoreFile == NULL) {\r
+ //\r
+ // Assume the beginning of the FD is an FV and look for the PEI Core.\r
+ // Load the first one we find.\r
+ //\r
+ Status = SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) gFdInfo[Index].Address, &PeiCoreFile);\r
+ if (!EFI_ERROR (Status)) {\r
+ PeiIndex = Index;\r
+ printf (" contains SEC Core");\r
+ }\r
+ }\r
+\r
+ printf ("\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) * 0x100000;\r
+ _snwprintf (gSystemMemory[Index].FileName, NT_SYSTEM_MEMORY_FILENAME_SIZE, L"SystemMemory%02d", Index);\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
+ printf ("\n");\r
+\r
+ //\r
+ // Hand off to PEI Core\r
+ //\r
+ SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, PeiCoreFile);\r
+\r
+ //\r
+ // If we get here, then the PEI Core returned. This is an error as PEI should\r
+ // always hand off to DXE.\r
+ //\r
+ printf ("ERROR : PEI Core returned\n");\r
+ exit (1);\r
+}\r
+\r
+EFI_STATUS\r
+WinNtOpenFile (\r
+ IN CHAR16 *FileName,\r
+ IN UINT32 MapSize,\r
+ IN DWORD CreationDisposition,\r
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,\r
+ OUT UINT64 *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 passed in as NULL the a new memory region is used.\r
+ If passed in as non NULL 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 = CreateFile (\r
+ FileName,\r
+ GENERIC_READ | GENERIC_WRITE,\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
+ // Map the open file into a memory range\r
+ //\r
+ NtMapHandle = CreateFileMapping (\r
+ NtFileHandle,\r
+ NULL,\r
+ PAGE_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_ALL_ACCESS,\r
+ 0,\r
+ 0,\r
+ MapSize,\r
+ (LPVOID) (UINTN) *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 = (UINT64) FileSize;\r
+ } else {\r
+ *Length = (UINT64) MapSize;\r
+ }\r
+\r
+ *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAddress;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+#define BYTES_PER_RECORD 512\r
+\r
+/**\r
+ Extracts ASSERT() information from a status code structure.\r
+\r
+ Converts the status code specified by CodeType, Value, and Data to the ASSERT()\r
+ arguments specified by Filename, Description, and LineNumber. If CodeType is \r
+ an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and \r
+ Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract \r
+ Filename, Description, and LineNumber from the optional data area of the \r
+ status code buffer specified by Data. The optional data area of Data contains \r
+ a Null-terminated ASCII string for the FileName, followed by a Null-terminated \r
+ ASCII string for the Description, followed by a 32-bit LineNumber. If the \r
+ ASSERT() information could be extracted from Data, then return TRUE. \r
+ Otherwise, FALSE is returned. \r
+\r
+ If Data is NULL, then ASSERT().\r
+ If Filename is NULL, then ASSERT().\r
+ If Description is NULL, then ASSERT().\r
+ If LineNumber is NULL, then ASSERT().\r
+\r
+ @param CodeType The type of status code being converted.\r
+ @param Value The status code value being converted.\r
+ @param Data Pointer to status code data buffer. \r
+ @param Filename Pointer to the source file name that generated the ASSERT().\r
+ @param Description Pointer to the description of the ASSERT().\r
+ @param LineNumber Pointer to source line number that generated the ASSERT().\r
+\r
+ @retval TRUE The status code specified by CodeType, Value, and Data was \r
+ converted ASSERT() arguments specified by Filename, Description, \r
+ and LineNumber.\r
+ @retval FALSE The status code specified by CodeType, Value, and Data could \r
+ not be converted to ASSERT() arguments.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+ReportStatusCodeExtractAssertInfo (\r
+ IN EFI_STATUS_CODE_TYPE CodeType,\r
+ IN EFI_STATUS_CODE_VALUE Value, \r
+ IN CONST EFI_STATUS_CODE_DATA *Data, \r
+ OUT CHAR8 **Filename,\r
+ OUT CHAR8 **Description,\r
+ OUT UINT32 *LineNumber\r
+ )\r
+{\r
+ EFI_DEBUG_ASSERT_DATA *AssertData;\r
+\r
+ ASSERT (Data != NULL);\r
+ ASSERT (Filename != NULL);\r
+ ASSERT (Description != NULL);\r
+ ASSERT (LineNumber != NULL);\r
+\r
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) && \r
+ ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) &&\r
+ ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {\r
+ AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);\r
+ *Filename = (CHAR8 *)(AssertData + 1);\r
+ *Description = *Filename + AsciiStrLen (*Filename) + 1;\r
+ *LineNumber = AssertData->LineNumber;\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SecPeiReportStatusCode (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_STATUS_CODE_TYPE CodeType,\r
+ IN EFI_STATUS_CODE_VALUE Value,\r
+ IN UINT32 Instance,\r
+ IN EFI_GUID * CallerId,\r
+ IN EFI_STATUS_CODE_DATA * Data OPTIONAL\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine produces the ReportStatusCode PEI service. It's passed\r
+ up to the PEI Core via a PPI. T\r
+\r
+ This code currently uses the NT clib printf. This does not work the same way\r
+ as the EFI Print (), as %t, %g, %s as Unicode are not supported.\r
+\r
+Arguments:\r
+ (see EFI_PEI_REPORT_STATUS_CODE)\r
+\r
+Returns:\r
+ EFI_SUCCESS - Always return success\r
+\r
+--*/\r
+// TODO: PeiServices - add argument and description to function comment\r
+// TODO: CodeType - add argument and description to function comment\r
+// TODO: Value - add argument and description to function comment\r
+// TODO: Instance - add argument and description to function comment\r
+// TODO: CallerId - add argument and description to function comment\r
+// TODO: Data - add argument and description to function comment\r
+{\r
+ CHAR8 *Format;\r
+ EFI_DEBUG_INFO *DebugInfo;\r
+ VA_LIST Marker;\r
+ CHAR8 PrintBuffer[BYTES_PER_RECORD * 2];\r
+ CHAR8 *Filename;\r
+ CHAR8 *Description;\r
+ UINT32 LineNumber;\r
+\r
+ if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {\r
+ //\r
+ // This supports DEBUG () marcos\r
+ // Data format\r
+ // EFI_STATUS_CODE_DATA\r
+ // EFI_DEBUG_INFO\r
+ //\r
+ // The first 12 * UINT64 bytes of the string are really an\r
+ // arguement stack to support varargs on the Format string.\r
+ //\r
+ if (Data != NULL) {\r
+ DebugInfo = (EFI_DEBUG_INFO *) (Data + 1);\r
+ Marker = (VA_LIST) (DebugInfo + 1);\r
+ Format = (CHAR8 *) (((UINT64 *) Marker) + 12);\r
+\r
+ AsciiVSPrint (PrintBuffer, BYTES_PER_RECORD, Format, Marker);\r
+ printf (PrintBuffer);\r
+ } else {\r
+ printf ("DEBUG <null>\n");\r
+ }\r
+ }\r
+\r
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) &&\r
+ ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED)\r
+ ) {\r
+ if (Data != NULL && ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {\r
+ //\r
+ // Support ASSERT () macro\r
+ //\r
+ printf ("ASSERT %s(%d): %s\n", Filename, LineNumber, Description);\r
+ } else {\r
+ printf ("ASSERT <null>\n");\r
+ }\r
+ CpuBreakpoint ();\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+VOID\r
+SecLoadFromCore (\r
+ IN UINTN LargestRegion,\r
+ IN UINTN LargestRegionSize,\r
+ IN UINTN BootFirmwareVolumeBase,\r
+ IN VOID *PeiCorePe32File\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This is the service to load the PEI Core from the Firmware Volume\r
+\r
+Arguments:\r
+ LargestRegion - Memory to use for PEI.\r
+ LargestRegionSize - Size of Memory to use for PEI\r
+ BootFirmwareVolumeBase - Start of the Boot FV\r
+ PeiCorePe32File - PEI 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
+ EFI_PHYSICAL_ADDRESS TopOfMemory;\r
+ VOID *TopOfStack;\r
+ UINT64 PeiCoreSize;\r
+ EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;\r
+ EFI_PHYSICAL_ADDRESS PeiImageAddress;\r
+ EFI_PEI_STARTUP_DESCRIPTOR *PeiStartup;\r
+\r
+ //\r
+ // Compute Top Of Memory for Stack and PEI Core Allocations\r
+ //\r
+ TopOfMemory = LargestRegion + LargestRegionSize;\r
+\r
+ //\r
+ // Allocate 128KB for the Stack\r
+ //\r
+ TopOfStack = (VOID *)((UINTN)TopOfMemory - sizeof (EFI_PEI_STARTUP_DESCRIPTOR) - CPU_STACK_ALIGNMENT);\r
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
+ TopOfMemory = TopOfMemory - STACK_SIZE;\r
+\r
+ //\r
+ // Patch value in dispatch table values\r
+ //\r
+ gPrivateDispatchTable[0].Ppi = gPeiEfiPeiPeCoffLoader;\r
+\r
+ //\r
+ // Bind this information into the SEC hand-off state\r
+ //\r
+ PeiStartup = (EFI_PEI_STARTUP_DESCRIPTOR *) (UINTN) TopOfStack;\r
+ PeiStartup->DispatchTable = (EFI_PEI_PPI_DESCRIPTOR *) &gPrivateDispatchTable;\r
+ PeiStartup->SizeOfCacheAsRam = STACK_SIZE;\r
+ PeiStartup->BootFirmwareVolume = BootFirmwareVolumeBase;\r
+\r
+ //\r
+ // Load the PEI Core from a Firmware Volume\r
+ //\r
+ Status = SecWinNtPeiLoadFile (\r
+ PeiCorePe32File,\r
+ &PeiImageAddress,\r
+ &PeiCoreSize,\r
+ &PeiCoreEntryPoint\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+ //\r
+ // Transfer control to the PEI Core\r
+ //\r
+ SwitchStack (\r
+ (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,\r
+ PeiStartup,\r
+ NULL,\r
+ TopOfStack\r
+ );\r
+ //\r
+ // If we get here, then the PEI Core returned. This is an error\r
+ //\r
+ return ;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SecWinNtPeiAutoScan (\r
+ IN UINTN Index,\r
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBase,\r
+ OUT UINT64 *MemorySize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This service is called from Index == 0 until it returns EFI_UNSUPPORTED.\r
+ It allows discontiguous memory regions to be supported by the emulator.\r
+ It uses gSystemMemory[] and gSystemMemoryCount that were created by\r
+ parsing the Windows environment variable EFI_MEMORY_SIZE.\r
+ The size comes from the varaible and the address comes from the call to\r
+ WinNtOpenFile.\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
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (Index >= gSystemMemoryCount) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ *MemoryBase = 0;\r
+ Status = WinNtOpenFile (\r
+ gSystemMemory[Index].FileName,\r
+ (UINT32) gSystemMemory[Index].Size,\r
+ OPEN_ALWAYS,\r
+ MemoryBase,\r
+ MemorySize\r
+ );\r
+\r
+ gSystemMemory[Index].Memory = *MemoryBase;\r
+\r
+ return Status;\r
+}\r
+\r
+VOID *\r
+EFIAPI\r
+SecWinNtWinNtThunkAddress (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Since the SEC is the only Windows program in stack it must export\r
+ an interface to do Win API calls. That's what the WinNtThunk address\r
+ is for. gWinNt is initailized in WinNtThunk.c.\r
+\r
+Arguments:\r
+ InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);\r
+ InterfaceBase - Address of the gWinNt global\r
+\r
+Returns:\r
+ EFI_SUCCESS - Data returned\r
+\r
+--*/\r
+{\r
+ return gWinNt;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SecWinNtPeiLoadFile (\r
+ IN VOID *Pe32Data,\r
+ IN EFI_PHYSICAL_ADDRESS *ImageAddress,\r
+ IN UINT64 *ImageSize,\r
+ IN EFI_PHYSICAL_ADDRESS *EntryPoint\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Loads and relocates a PE/COFF image into memory.\r
+\r
+Arguments:\r
+ Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated\r
+ ImageAddress - The base address of the relocated PE/COFF image\r
+ ImageSize - The size of the relocated PE/COFF image\r
+ EntryPoint - The entry point of the relocated PE/COFF image\r
+\r
+Returns:\r
+ EFI_SUCCESS - The file was loaded and relocated\r
+ EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file\r
+\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 = gPeiEfiPeiPeCoffLoader->GetImageInfo (gPeiEfiPeiPeCoffLoader, &ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Allocate space in NT (not emulator) memory. Extra space is for alignment\r
+ //\r
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) malloc ((UINTN) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)));\r
+ if (ImageContext.ImageAddress == 0) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Align buffer on section boundry\r
+ //\r
+ ImageContext.ImageAddress += ImageContext.SectionAlignment;\r
+ ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
+\r
+ Status = gPeiEfiPeiPeCoffLoader->LoadImage (gPeiEfiPeiPeCoffLoader, &ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gPeiEfiPeiPeCoffLoader->RelocateImage (gPeiEfiPeiPeCoffLoader, &ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // BugBug: Flush Instruction Cache Here when CPU Lib is ready\r
+ //\r
+\r
+ *ImageAddress = ImageContext.ImageAddress;\r
+ *ImageSize = ImageContext.ImageSize;\r
+ *EntryPoint = ImageContext.EntryPoint;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SecWinNtFdAddress (\r
+ IN UINTN Index,\r
+ IN OUT EFI_PHYSICAL_ADDRESS *FdBase,\r
+ IN OUT UINT64 *FdSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Return the FD Size and base address. Since the FD is loaded from a\r
+ file into Windows 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
+\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
+{\r
+ if (Index >= gFdInfoCount) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ *FdBase = gFdInfo[Index].Address;\r
+ *FdSize = gFdInfo[Index].Size;\r
+\r
+ if (*FdBase == 0 && *FdSize == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\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
+CountSeperatorsInString (\r
+ IN const CHAR16 *String,\r
+ IN CHAR16 Seperator\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Count the number of seperators in String\r
+\r
+Arguments:\r
+ String - String to process\r
+ Seperator - Item to count\r
+\r
+Returns:\r
+ Number of Seperator in String\r
+\r
+--*/\r
+{\r
+ UINTN Count;\r
+\r
+ for (Count = 0; *String != '\0'; String++) {\r
+ if (*String == Seperator) {\r
+ Count++;\r
+ }\r
+ }\r
+\r
+ return Count;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+AddModHandle (\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
+ IN VOID *ModHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Store the ModHandle in an array indexed by the Pdb File name.\r
+ The ModHandle is needed to unload the image. \r
+\r
+Arguments:\r
+ ImageContext - Input data returned from PE Laoder Library. Used to find the \r
+ .PDB file name of the PE Image.\r
+ ModHandle - Returned from LoadLibraryEx() and stored for call to \r
+ FreeLibrary().\r
+\r
+Returns:\r
+ EFI_SUCCESS - ModHandle was stored. \r
+\r
+--*/\r
+{\r
+ UINTN Index;\r
+ PDB_NAME_TO_MOD_HANDLE *Array;\r
+ UINTN PreviousSize;\r
+\r
+\r
+ Array = mPdbNameModHandleArray;\r
+ for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
+ if (Array->PdbPointer == NULL) {\r
+ //\r
+ // Make a copy of the stirng and store the ModHandle\r
+ //\r
+ Array->PdbPointer = malloc (strlen (ImageContext->PdbPointer) + 1);\r
+ ASSERT (Array->PdbPointer != NULL);\r
+\r
+ strcpy (Array->PdbPointer, ImageContext->PdbPointer);\r
+ Array->ModHandle = ModHandle;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // No free space in mPdbNameModHandleArray so grow it by \r
+ // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires. realloc will\r
+ // copy the old values to the new locaiton. But it does\r
+ // not zero the new memory area.\r
+ //\r
+ PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);\r
+ mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;\r
+\r
+ mPdbNameModHandleArray = realloc (mPdbNameModHandleArray, mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE));\r
+ if (mPdbNameModHandleArray == NULL) {\r
+ ASSERT (FALSE);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ \r
+ memset (mPdbNameModHandleArray + PreviousSize, 0, MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (PDB_NAME_TO_MOD_HANDLE));\r
+ \r
+ return AddModHandle (ImageContext, ModHandle);\r
+}\r
+\r
+\r
+VOID *\r
+RemoveModeHandle (\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Return the ModHandle and delete the entry in the array.\r
+\r
+Arguments:\r
+ ImageContext - Input data returned from PE Laoder Library. Used to find the \r
+ .PDB file name of the PE Image.\r
+\r
+Returns:\r
+ ModHandle - ModHandle assoicated with ImageContext is returned\r
+ NULL - No ModHandle associated with ImageContext\r
+\r
+--*/\r
+{\r
+ UINTN Index;\r
+ PDB_NAME_TO_MOD_HANDLE *Array;\r
+\r
+ if (ImageContext->PdbPointer == NULL) {\r
+ //\r
+ // If no PDB pointer there is no ModHandle so return NULL\r
+ //\r
+ return NULL;\r
+ }\r
+\r
+ Array = mPdbNameModHandleArray;\r
+ for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
+ if ((Array->PdbPointer != NULL) && (strcmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) {\r
+ //\r
+ // If you find a match return it and delete the entry\r
+ //\r
+ free (Array->PdbPointer);\r
+ Array->PdbPointer = NULL;\r
+ return Array->ModHandle;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SecNt32PeCoffGetImageInfo (\r
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = PeCoffLoaderGetImageInfo (ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ switch (ImageContext->ImageType) {\r
+\r
+ case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
+ ImageContext->ImageCodeMemoryType = EfiLoaderCode;\r
+ ImageContext->ImageDataMemoryType = EfiLoaderData;\r
+ break;\r
+\r
+ case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
+ ImageContext->ImageCodeMemoryType = EfiBootServicesCode;\r
+ ImageContext->ImageDataMemoryType = EfiBootServicesData;\r
+ break;\r
+\r
+ case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
+ case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:\r
+ ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode;\r
+ ImageContext->ImageDataMemoryType = EfiRuntimeServicesData;\r
+ break;\r
+\r
+ default:\r
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SecNt32PeCoffLoadImage (\r
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = PeCoffLoaderLoadImage (ImageContext);\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SecNt32PeCoffRelocateImage (\r
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *DllEntryPoint;\r
+ CHAR16 *DllFileName;\r
+ HMODULE Library;\r
+ UINTN Index;\r
+\r
+\r
+ Status = PeCoffLoaderRelocateImage (ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // We could not relocated the image in memory properly\r
+ //\r
+ return Status;\r
+ }\r
+\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 reloaced\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 EFI_SUCCESS;\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() supresses 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 debuging\r
+ //\r
+ DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver");\r
+\r
+ }\r
+\r
+ if ((Library != NULL) && (DllEntryPoint != NULL)) {\r
+ AddModHandle (ImageContext, Library);\r
+ ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
+ wprintf (L"LoadLibraryEx (%s,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName);\r
+ } else {\r
+ wprintf (L"WARNING: No source level debug %s. \n", DllFileName);\r
+ }\r
+\r
+ free (DllFileName);\r
+ }\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 EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SecNt32PeCoffUnloadimage (\r
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+ )\r
+{\r
+ VOID *ModHandle;\r
+\r
+ ModHandle = RemoveModeHandle (ImageContext);\r
+ if (ModHandle != NULL) {\r
+ FreeLibrary (ModHandle);\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+_ModuleEntryPoint (\r
+ VOID\r
+ )\r
+{\r
+}\r
+\r
+#pragma warning(default : 4996)\r