mirror of https://github.com/acidanthera/audk.git
1137 lines
33 KiB
C
1137 lines
33 KiB
C
/**@file
|
|
|
|
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
|
|
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
|
|
SecMain.c
|
|
|
|
Abstract:
|
|
WinNt emulator of 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.
|
|
|
|
The SEC registers a set of services with the SEC core. gPrivateDispatchTable
|
|
is a list of PPI's produced by the SEC that are availble for usage in PEI.
|
|
|
|
This code produces 128 K of temporary memory for the PEI stack by directly
|
|
allocate memory space with ReadWrite and Execute attribute.
|
|
|
|
**/
|
|
|
|
#include "SecMain.h"
|
|
|
|
#ifndef SE_TIME_ZONE_NAME
|
|
#define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege")
|
|
#endif
|
|
|
|
NT_PEI_LOAD_FILE_PPI mSecNtLoadFilePpi = { SecWinNtPeiLoadFile };
|
|
|
|
PEI_NT_AUTOSCAN_PPI mSecNtAutoScanPpi = { SecWinNtPeiAutoScan };
|
|
|
|
PEI_NT_THUNK_PPI mSecWinNtThunkPpi = { SecWinNtWinNtThunkAddress };
|
|
|
|
EFI_PEI_PROGRESS_CODE_PPI mSecStatusCodePpi = { SecPeiReportStatusCode };
|
|
|
|
NT_FWH_PPI mSecFwhInformationPpi = { SecWinNtFdAddress };
|
|
|
|
EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mSecTemporaryRamSupportPpi = {SecTemporaryRamSupport};
|
|
|
|
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
|
|
{
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI,
|
|
&gNtPeiLoadFilePpiGuid,
|
|
&mSecNtLoadFilePpi
|
|
},
|
|
{
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI,
|
|
&gPeiNtAutoScanPpiGuid,
|
|
&mSecNtAutoScanPpi
|
|
},
|
|
{
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI,
|
|
&gPeiNtThunkPpiGuid,
|
|
&mSecWinNtThunkPpi
|
|
},
|
|
{
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI,
|
|
&gEfiPeiStatusCodePpiGuid,
|
|
&mSecStatusCodePpi
|
|
},
|
|
{
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI,
|
|
&gEfiTemporaryRamSupportPpiGuid,
|
|
&mSecTemporaryRamSupportPpi
|
|
},
|
|
{
|
|
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
|
|
&gNtFwhPpiGuid,
|
|
&mSecFwhInformationPpi
|
|
}
|
|
};
|
|
|
|
|
|
//
|
|
// 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 seperate memory rantes.
|
|
// 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;
|
|
|
|
VOID
|
|
EFIAPI
|
|
SecSwitchStack (
|
|
UINT32 TemporaryMemoryBase,
|
|
UINT32 PermenentMemoryBase
|
|
);
|
|
EFI_STATUS
|
|
SecNt32PeCoffRelocateImage (
|
|
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
|
|
);
|
|
|
|
VOID
|
|
EFIAPI
|
|
PeiSwitchStacks (
|
|
IN SWITCH_STACK_ENTRY_POINT EntryPoint,
|
|
IN VOID *Context1, OPTIONAL
|
|
IN VOID *Context2, OPTIONAL
|
|
IN VOID *Context3, OPTIONAL
|
|
IN VOID *NewStack
|
|
);
|
|
|
|
VOID
|
|
SecPrint (
|
|
CHAR8 *Format,
|
|
...
|
|
)
|
|
{
|
|
va_list Marker;
|
|
UINTN CharCount;
|
|
CHAR8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE];
|
|
|
|
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
|
|
);
|
|
}
|
|
|
|
INTN
|
|
EFIAPI
|
|
main (
|
|
IN INTN 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 environmemt variable strings
|
|
|
|
Returns:
|
|
0 - Normal exit
|
|
1 - Abnormal exit
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
HANDLE Token;
|
|
TOKEN_PRIVILEGES TokenPrivileges;
|
|
EFI_PHYSICAL_ADDRESS InitialStackMemory;
|
|
UINT64 InitialStackMemorySize;
|
|
UINTN Index;
|
|
UINTN Index1;
|
|
UINTN Index2;
|
|
CHAR16 *FileName;
|
|
CHAR16 *FileNamePtr;
|
|
BOOLEAN Done;
|
|
VOID *PeiCoreFile;
|
|
CHAR16 *MemorySizeStr;
|
|
CHAR16 *FirmwareVolumesStr;
|
|
UINTN *StackPointer;
|
|
UINT32 ProcessAffinityMask;
|
|
UINT32 SystemAffinityMask;
|
|
INT32 LowBit;
|
|
|
|
|
|
//
|
|
// 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 (PcdWinNtMemorySizeForSecMain);
|
|
FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdWinNtFirmwareVolume);
|
|
|
|
SecPrint ("\nEDK II SEC Main NT Emulation Environment from www.TianoCore.org\n");
|
|
|
|
//
|
|
// Determine the first thread available to this process.
|
|
//
|
|
if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {
|
|
LowBit = (INT32)LowBitSet32 (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);
|
|
|
|
//
|
|
// Allocate space for gSystemMemory Array
|
|
//
|
|
gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;
|
|
gSystemMemory = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));
|
|
if (gSystemMemory == NULL) {
|
|
SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n", MemorySizeStr);
|
|
exit (1);
|
|
}
|
|
//
|
|
// Allocate space for gSystemMemory Array
|
|
//
|
|
gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
|
|
gFdInfo = calloc (gFdInfoCount, sizeof (NT_FD_INFO));
|
|
if (gFdInfo == NULL) {
|
|
SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n", FirmwareVolumesStr);
|
|
exit (1);
|
|
}
|
|
//
|
|
// Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION)
|
|
//
|
|
SecPrint (" BootMode 0x%02x\n", PcdGet32 (PcdWinNtBootMode));
|
|
|
|
//
|
|
// Allocate 128K memory to emulate temp memory for PEI.
|
|
// on a real platform this would be SRAM, or using the cache as RAM.
|
|
// Set InitialStackMemory to zero so WinNtOpenFile will allocate a new mapping
|
|
//
|
|
InitialStackMemorySize = STACK_SIZE;
|
|
InitialStackMemory = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (InitialStackMemorySize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
if (InitialStackMemory == 0) {
|
|
SecPrint ("ERROR : Can not allocate enough space for SecStack\n");
|
|
exit (1);
|
|
}
|
|
|
|
for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
|
|
StackPointer < (UINTN*) ((UINTN)InitialStackMemory + (SIZE_T) InitialStackMemorySize);
|
|
StackPointer ++) {
|
|
*StackPointer = 0x5AA55AA5;
|
|
}
|
|
|
|
SecPrint (" SEC passing in %d bytes of temp RAM to PEI\n", InitialStackMemorySize);
|
|
|
|
//
|
|
// Open All the firmware volumes and remember the info in the gFdInfo global
|
|
//
|
|
FileNamePtr = (CHAR16 *)malloc (StrLen ((CHAR16 *)FirmwareVolumesStr) * sizeof(CHAR16));
|
|
if (FileNamePtr == NULL) {
|
|
SecPrint ("ERROR : Can not allocate memory for firmware volume string\n");
|
|
exit (1);
|
|
}
|
|
|
|
StrCpy (FileNamePtr, (CHAR16*)FirmwareVolumesStr);
|
|
|
|
for (Done = FALSE, Index = 0, PeiCoreFile = 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 remmeber 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", FileName, Status);
|
|
exit (1);
|
|
}
|
|
|
|
SecPrint (" FD loaded from");
|
|
//
|
|
// printf can't print filenames directly as the \ gets interperted as an
|
|
// escape character.
|
|
//
|
|
for (Index2 = 0; FileName[Index2] != '\0'; Index2++) {
|
|
SecPrint ("%c", FileName[Index2]);
|
|
}
|
|
|
|
if (PeiCoreFile == NULL) {
|
|
//
|
|
// Assume the beginning of the FD is an FV and look for the PEI Core.
|
|
// Load the first one we find.
|
|
//
|
|
Status = SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) gFdInfo[Index].Address, &PeiCoreFile);
|
|
if (!EFI_ERROR (Status)) {
|
|
SecPrint (" contains SEC Core");
|
|
}
|
|
}
|
|
|
|
SecPrint ("\n");
|
|
}
|
|
//
|
|
// Calculate memory regions and store the information in the gSystemMemory
|
|
// global for later use. The autosizing code will use this data to
|
|
// map this memory into the SEC process memory space.
|
|
//
|
|
for (Index = 0, Done = FALSE; !Done; Index++) {
|
|
//
|
|
// Save the size of the memory and make a Unicode filename SystemMemory00, ...
|
|
//
|
|
gSystemMemory[Index].Size = _wtoi (MemorySizeStr) * 0x100000;
|
|
|
|
//
|
|
// Find the next region
|
|
//
|
|
for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++)
|
|
;
|
|
if (MemorySizeStr[Index1] == 0) {
|
|
Done = TRUE;
|
|
}
|
|
|
|
MemorySizeStr = MemorySizeStr + Index1 + 1;
|
|
}
|
|
|
|
SecPrint ("\n");
|
|
|
|
//
|
|
// Hand off to PEI Core
|
|
//
|
|
SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, PeiCoreFile);
|
|
|
|
//
|
|
// If we get here, then the PEI Core returned. This is an error as PEI should
|
|
// always hand off to DXE.
|
|
//
|
|
SecPrint ("ERROR : PEI Core returned\n");
|
|
exit (1);
|
|
}
|
|
|
|
EFI_STATUS
|
|
WinNtOpenFile (
|
|
IN CHAR16 *FileName,
|
|
IN UINT32 MapSize,
|
|
IN DWORD CreationDisposition,
|
|
IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
|
|
OUT UINT64 *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 passed in as NULL the a new memory region is used.
|
|
If passed in as non NULL the request memory region is used for
|
|
the mapping of the file into the process space.
|
|
Length - The size of the mapped region in bytes
|
|
|
|
Returns:
|
|
EFI_SUCCESS - The file was opened and mapped.
|
|
EFI_NOT_FOUND - FileName was not found in the current directory
|
|
EFI_DEVICE_ERROR - An error occured attempting to map the opened file
|
|
|
|
--*/
|
|
{
|
|
HANDLE NtFileHandle;
|
|
HANDLE NtMapHandle;
|
|
VOID *VirtualAddress;
|
|
UINTN FileSize;
|
|
|
|
//
|
|
// Use Win API to open/create a file
|
|
//
|
|
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,
|
|
(LPVOID) (UINTN) *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 = (UINT64) FileSize;
|
|
} else {
|
|
*Length = (UINT64) MapSize;
|
|
}
|
|
|
|
*BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAddress;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
#define BYTES_PER_RECORD 512
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SecPeiReportStatusCode (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN EFI_STATUS_CODE_TYPE CodeType,
|
|
IN EFI_STATUS_CODE_VALUE Value,
|
|
IN UINT32 Instance,
|
|
IN CONST EFI_GUID *CallerId,
|
|
IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine produces the ReportStatusCode PEI service. It's passed
|
|
up to the PEI Core via a PPI. T
|
|
|
|
This code currently uses the NT clib printf. This does not work the same way
|
|
as the EFI Print (), as %t, %g, %s as Unicode are not supported.
|
|
|
|
Arguments:
|
|
(see EFI_PEI_REPORT_STATUS_CODE)
|
|
|
|
Returns:
|
|
EFI_SUCCESS - Always return success
|
|
|
|
--*/
|
|
// TODO: PeiServices - add argument and description to function comment
|
|
// TODO: CodeType - add argument and description to function comment
|
|
// TODO: Value - add argument and description to function comment
|
|
// TODO: Instance - add argument and description to function comment
|
|
// TODO: CallerId - add argument and description to function comment
|
|
// TODO: Data - add argument and description to function comment
|
|
{
|
|
CHAR8 *Format;
|
|
BASE_LIST Marker;
|
|
CHAR8 PrintBuffer[BYTES_PER_RECORD * 2];
|
|
CHAR8 *Filename;
|
|
CHAR8 *Description;
|
|
UINT32 LineNumber;
|
|
UINT32 ErrorLevel;
|
|
|
|
|
|
if (Data == NULL) {
|
|
} else if (ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
|
|
//
|
|
// Processes ASSERT ()
|
|
//
|
|
SecPrint ("ASSERT %s(%d): %s\n", Filename, (int)LineNumber, Description);
|
|
|
|
} else if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
|
|
//
|
|
// Process DEBUG () macro
|
|
//
|
|
AsciiBSPrint (PrintBuffer, BYTES_PER_RECORD, Format, Marker);
|
|
SecPrint (PrintBuffer);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
#if defined (MDE_CPU_IA32)
|
|
/**
|
|
Transfers control to a function starting with a new stack.
|
|
|
|
Transfers control to the function specified by EntryPoint using the new stack
|
|
specified by NewStack and passing in the parameters specified by Context1 and
|
|
Context2. Context1 and Context2 are optional and may be NULL. The function
|
|
EntryPoint must never return.
|
|
|
|
If EntryPoint is NULL, then ASSERT().
|
|
If NewStack is NULL, then ASSERT().
|
|
|
|
@param EntryPoint A pointer to function to call with the new stack.
|
|
@param Context1 A pointer to the context to pass into the EntryPoint
|
|
function.
|
|
@param Context2 A pointer to the context to pass into the EntryPoint
|
|
function.
|
|
@param NewStack A pointer to the new stack to use for the EntryPoint
|
|
function.
|
|
@param NewBsp A pointer to the new BSP for the EntryPoint on IPF. It's
|
|
Reserved on other architectures.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
PeiSwitchStacks (
|
|
IN SWITCH_STACK_ENTRY_POINT EntryPoint,
|
|
IN VOID *Context1, OPTIONAL
|
|
IN VOID *Context2, OPTIONAL
|
|
IN VOID *Context3, OPTIONAL
|
|
IN VOID *NewStack
|
|
)
|
|
{
|
|
BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
|
|
|
|
ASSERT (EntryPoint != NULL);
|
|
ASSERT (NewStack != NULL);
|
|
|
|
//
|
|
// Stack should be aligned with CPU_STACK_ALIGNMENT
|
|
//
|
|
ASSERT (((UINTN)NewStack & (CPU_STACK_ALIGNMENT - 1)) == 0);
|
|
|
|
JumpBuffer.Eip = (UINTN)EntryPoint;
|
|
JumpBuffer.Esp = (UINTN)NewStack - sizeof (VOID*);
|
|
JumpBuffer.Esp -= sizeof (Context1) + sizeof (Context2) + sizeof(Context3);
|
|
((VOID**)JumpBuffer.Esp)[1] = Context1;
|
|
((VOID**)JumpBuffer.Esp)[2] = Context2;
|
|
((VOID**)JumpBuffer.Esp)[3] = Context3;
|
|
|
|
LongJump (&JumpBuffer, (UINTN)-1);
|
|
|
|
|
|
//
|
|
// InternalSwitchStack () will never return
|
|
//
|
|
ASSERT (FALSE);
|
|
}
|
|
#endif
|
|
|
|
VOID
|
|
SecLoadFromCore (
|
|
IN UINTN LargestRegion,
|
|
IN UINTN LargestRegionSize,
|
|
IN UINTN BootFirmwareVolumeBase,
|
|
IN VOID *PeiCorePe32File
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is the service to load the PEI Core from the Firmware Volume
|
|
|
|
Arguments:
|
|
LargestRegion - Memory to use for PEI.
|
|
LargestRegionSize - Size of Memory to use for PEI
|
|
BootFirmwareVolumeBase - Start of the Boot FV
|
|
PeiCorePe32File - PEI Core PE32
|
|
|
|
Returns:
|
|
Success means control is transfered and thus we should never return
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *TopOfStack;
|
|
UINT64 PeiCoreSize;
|
|
EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
|
|
EFI_PHYSICAL_ADDRESS PeiImageAddress;
|
|
EFI_SEC_PEI_HAND_OFF *SecCoreData;
|
|
UINTN PeiStackSize;
|
|
|
|
//
|
|
// Compute Top Of Memory for Stack and PEI Core Allocations
|
|
//
|
|
PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
|
|
|
|
//
|
|
// |-----------| <---- TemporaryRamBase + TemporaryRamSize
|
|
// | Heap |
|
|
// | |
|
|
// |-----------| <---- StackBase / PeiTemporaryMemoryBase
|
|
// | |
|
|
// | Stack |
|
|
// |-----------| <---- TemporaryRamBase
|
|
//
|
|
TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
|
|
|
|
//
|
|
// Reservet space for storing PeiCore's parament in stack.
|
|
//
|
|
TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
|
|
TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
|
|
|
|
//
|
|
// Bind this information into the SEC hand-off state
|
|
//
|
|
SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
|
|
SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
|
|
SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
|
|
SecCoreData->BootFirmwareVolumeSize = PcdGet32(PcdWinNtFirmwareFdSize);
|
|
SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
|
|
SecCoreData->TemporaryRamSize = STACK_SIZE;
|
|
SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
|
|
SecCoreData->StackSize = PeiStackSize;
|
|
SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
|
|
SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
|
|
|
|
//
|
|
// Load the PEI Core from a Firmware Volume
|
|
//
|
|
Status = SecWinNtPeiLoadFile (
|
|
PeiCorePe32File,
|
|
&PeiImageAddress,
|
|
&PeiCoreSize,
|
|
&PeiCoreEntryPoint
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Transfer control to the PEI Core
|
|
//
|
|
PeiSwitchStacks (
|
|
(SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
|
|
SecCoreData,
|
|
(VOID *) (UINTN) ((EFI_PEI_PPI_DESCRIPTOR *) &gPrivateDispatchTable),
|
|
NULL,
|
|
TopOfStack
|
|
);
|
|
//
|
|
// If we get here, then the PEI Core returned. This is an error
|
|
//
|
|
return ;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SecWinNtPeiAutoScan (
|
|
IN UINTN Index,
|
|
OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
|
|
OUT UINT64 *MemorySize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
|
|
It allows discontiguous memory regions to be supported by the emulator.
|
|
It uses gSystemMemory[] and gSystemMemoryCount that were created by
|
|
parsing PcdWinNtMemorySizeForSecMain value.
|
|
The size comes from the Pcd value and the address comes from the memory space
|
|
with ReadWrite and Execute attributes allocated by VirtualAlloc() API.
|
|
|
|
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
|
|
|
|
--*/
|
|
{
|
|
if (Index >= gSystemMemoryCount) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Allocate enough memory space for emulator
|
|
//
|
|
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;
|
|
}
|
|
|
|
*MemoryBase = gSystemMemory[Index].Memory;
|
|
*MemorySize = gSystemMemory[Index].Size;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VOID *
|
|
EFIAPI
|
|
SecWinNtWinNtThunkAddress (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Since the SEC is the only Windows program in stack it must export
|
|
an interface to do Win API calls. That's what the WinNtThunk address
|
|
is for. gWinNt is initailized in WinNtThunk.c.
|
|
|
|
Arguments:
|
|
InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
|
|
InterfaceBase - Address of the gWinNt global
|
|
|
|
Returns:
|
|
EFI_SUCCESS - Data returned
|
|
|
|
--*/
|
|
{
|
|
return gWinNt;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SecWinNtPeiLoadFile (
|
|
IN VOID *Pe32Data,
|
|
IN EFI_PHYSICAL_ADDRESS *ImageAddress,
|
|
IN UINT64 *ImageSize,
|
|
IN EFI_PHYSICAL_ADDRESS *EntryPoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Loads and relocates a PE/COFF image into memory.
|
|
|
|
Arguments:
|
|
Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
|
|
ImageAddress - The base address of the relocated PE/COFF image
|
|
ImageSize - The size of the relocated PE/COFF image
|
|
EntryPoint - The entry point of the relocated PE/COFF image
|
|
|
|
Returns:
|
|
EFI_SUCCESS - The file was loaded and relocated
|
|
EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
//
|
|
// Allocate space in NT (not emulator) memory with ReadWrite and Execute attribue.
|
|
// Extra space is for alignment
|
|
//
|
|
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
if (ImageContext.ImageAddress == 0) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
//
|
|
// Align buffer on section boundry
|
|
//
|
|
ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
|
|
ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
|
|
|
|
Status = PeCoffLoaderLoadImage (&ImageContext);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = SecNt32PeCoffRelocateImage (&ImageContext);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// BugBug: Flush Instruction Cache Here when CPU Lib is ready
|
|
//
|
|
|
|
*ImageAddress = ImageContext.ImageAddress;
|
|
*ImageSize = ImageContext.ImageSize;
|
|
*EntryPoint = ImageContext.EntryPoint;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SecWinNtFdAddress (
|
|
IN UINTN Index,
|
|
IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
|
|
IN OUT UINT64 *FdSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Return the FD Size and base address. Since the FD is loaded from a
|
|
file into Windows memory only the SEC will know it's 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
|
|
|
|
Returns:
|
|
EFI_SUCCESS - Return the Base address and size of the FV
|
|
EFI_UNSUPPORTED - Index does nto map to an FD in the system
|
|
|
|
--*/
|
|
{
|
|
if (Index >= gFdInfoCount) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
*FdBase = gFdInfo[Index].Address;
|
|
*FdSize = gFdInfo[Index].Size;
|
|
|
|
if (*FdBase == 0 && *FdSize == 0) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
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
|
|
CountSeperatorsInString (
|
|
IN CONST CHAR16 *String,
|
|
IN CHAR16 Seperator
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Count the number of seperators in String
|
|
|
|
Arguments:
|
|
String - String to process
|
|
Seperator - Item to count
|
|
|
|
Returns:
|
|
Number of Seperator in String
|
|
|
|
--*/
|
|
{
|
|
UINTN Count;
|
|
|
|
for (Count = 0; *String != '\0'; String++) {
|
|
if (*String == Seperator) {
|
|
Count++;
|
|
}
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
SecNt32PeCoffRelocateImage (
|
|
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *DllEntryPoint;
|
|
CHAR16 *DllFileName;
|
|
HMODULE Library;
|
|
UINTN Index;
|
|
|
|
|
|
Status = PeCoffLoaderRelocateImage (ImageContext);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// We could not relocated the image in memory properly
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// If we load our own PE COFF images the Windows debugger can not source
|
|
// level debug our code. If a valid PDB pointer exists usw it to load
|
|
// the *.dll file as a library using Windows* APIs. This allows
|
|
// source level debug. The image is still loaded and reloaced
|
|
// 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 bellow.
|
|
//
|
|
|
|
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 EFI_SUCCESS;
|
|
}
|
|
//
|
|
// 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() supresses 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 debuging
|
|
//
|
|
DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver");
|
|
|
|
}
|
|
|
|
if ((Library != NULL) && (DllEntryPoint != NULL)) {
|
|
ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;
|
|
SecPrint ("LoadLibraryEx (%S,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName);
|
|
} else {
|
|
SecPrint ("WARNING: No source level debug %S. \n", DllFileName);
|
|
}
|
|
|
|
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 EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
_ModuleEntryPoint (
|
|
VOID
|
|
)
|
|
{
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SecTemporaryRamSupport (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
|
|
IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
|
|
IN UINTN CopySize
|
|
)
|
|
{
|
|
//
|
|
// Migrate the whole temporary memory to permenent memory.
|
|
//
|
|
CopyMem (
|
|
(VOID*)(UINTN)PermanentMemoryBase,
|
|
(VOID*)(UINTN)TemporaryMemoryBase,
|
|
CopySize
|
|
);
|
|
|
|
//
|
|
// SecSwitchStack function must be invoked after the memory migration
|
|
// immediatly, also we need fixup the stack change caused by new call into
|
|
// permenent memory.
|
|
//
|
|
SecSwitchStack (
|
|
(UINT32) TemporaryMemoryBase,
|
|
(UINT32) PermanentMemoryBase
|
|
);
|
|
|
|
//
|
|
// We need *not* fix the return address because currently,
|
|
// The PeiCore is excuted in flash.
|
|
//
|
|
|
|
//
|
|
// Simulate to invalid temporary memory, terminate temporary memory
|
|
//
|
|
//ZeroMem ((VOID*)(UINTN)TemporaryMemoryBase, CopySize);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|