/** @file | |
EFI PEI Core dispatch services | |
Copyright (c) 2006 - 2024, Intel Corporation. All rights reserved.<BR> | |
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "PeiMain.h" | |
/** | |
Discover all PEIMs and optional Apriori file in one FV. There is at most one | |
Apriori file in one FV. | |
@param Private Pointer to the private data passed in from caller | |
@param CoreFileHandle The instance of PEI_CORE_FV_HANDLE. | |
**/ | |
VOID | |
DiscoverPeimsAndOrderWithApriori ( | |
IN PEI_CORE_INSTANCE *Private, | |
IN PEI_CORE_FV_HANDLE *CoreFileHandle | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_PEI_FILE_HANDLE FileHandle; | |
EFI_PEI_FILE_HANDLE AprioriFileHandle; | |
EFI_GUID *Apriori; | |
UINTN Index; | |
UINTN Index2; | |
UINTN PeimIndex; | |
UINTN PeimCount; | |
EFI_GUID *Guid; | |
EFI_PEI_FILE_HANDLE *TempFileHandles; | |
EFI_GUID *TempFileGuid; | |
EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; | |
EFI_FV_FILE_INFO FileInfo; | |
FvPpi = CoreFileHandle->FvPpi; | |
// | |
// Walk the FV and find all the PEIMs and the Apriori file. | |
// | |
AprioriFileHandle = NULL; | |
Private->CurrentFvFileHandles = NULL; | |
Guid = NULL; | |
// | |
// If the current FV has been scanned, directly get its cached records. | |
// | |
if (CoreFileHandle->ScanFv) { | |
Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles; | |
return; | |
} | |
TempFileHandles = Private->TempFileHandles; | |
TempFileGuid = Private->TempFileGuid; | |
// | |
// Go ahead to scan this FV, get PeimCount and cache FileHandles within it to TempFileHandles. | |
// | |
PeimCount = 0; | |
FileHandle = NULL; | |
do { | |
Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle); | |
if (!EFI_ERROR (Status)) { | |
if (PeimCount >= Private->TempPeimCount) { | |
// | |
// Run out of room, grow the buffer. | |
// | |
TempFileHandles = AllocatePool ( | |
sizeof (EFI_PEI_FILE_HANDLE) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP) | |
); | |
ASSERT (TempFileHandles != NULL); | |
CopyMem ( | |
TempFileHandles, | |
Private->TempFileHandles, | |
sizeof (EFI_PEI_FILE_HANDLE) * Private->TempPeimCount | |
); | |
Private->TempFileHandles = TempFileHandles; | |
TempFileGuid = AllocatePool ( | |
sizeof (EFI_GUID) * (Private->TempPeimCount + TEMP_FILE_GROWTH_STEP) | |
); | |
ASSERT (TempFileGuid != NULL); | |
CopyMem ( | |
TempFileGuid, | |
Private->TempFileGuid, | |
sizeof (EFI_GUID) * Private->TempPeimCount | |
); | |
Private->TempFileGuid = TempFileGuid; | |
Private->TempPeimCount = Private->TempPeimCount + TEMP_FILE_GROWTH_STEP; | |
} | |
TempFileHandles[PeimCount++] = FileHandle; | |
} | |
} while (!EFI_ERROR (Status)); | |
DEBUG (( | |
DEBUG_INFO, | |
"%a(): Found 0x%x PEI FFS files in the %dth FV\n", | |
__func__, | |
PeimCount, | |
Private->CurrentPeimFvCount | |
)); | |
if (PeimCount == 0) { | |
// | |
// No PEIM FFS file is found, set ScanFv flag and return. | |
// | |
CoreFileHandle->ScanFv = TRUE; | |
return; | |
} | |
// | |
// Record PeimCount, allocate buffer for PeimState and FvFileHandles. | |
// | |
CoreFileHandle->PeimCount = PeimCount; | |
CoreFileHandle->PeimState = AllocateZeroPool (sizeof (UINT8) * PeimCount); | |
ASSERT (CoreFileHandle->PeimState != NULL); | |
CoreFileHandle->FvFileHandles = AllocateZeroPool (sizeof (EFI_PEI_FILE_HANDLE) * PeimCount); | |
ASSERT (CoreFileHandle->FvFileHandles != NULL); | |
// | |
// Get Apriori File handle | |
// | |
Private->AprioriCount = 0; | |
Status = FvPpi->FindFileByName (FvPpi, &gPeiAprioriFileNameGuid, &CoreFileHandle->FvHandle, &AprioriFileHandle); | |
if (!EFI_ERROR (Status) && (AprioriFileHandle != NULL)) { | |
// | |
// Read the Apriori file | |
// | |
Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **)&Apriori); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Calculate the number of PEIMs in the Apriori file | |
// | |
Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo); | |
ASSERT_EFI_ERROR (Status); | |
Private->AprioriCount = FileInfo.BufferSize; | |
if (IS_SECTION2 (FileInfo.Buffer)) { | |
Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER2); | |
} else { | |
Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER); | |
} | |
Private->AprioriCount /= sizeof (EFI_GUID); | |
for (Index = 0; Index < PeimCount; Index++) { | |
// | |
// Make an array of file name GUIDs that matches the FileHandle array so we can convert | |
// quickly from file name to file handle | |
// | |
Status = FvPpi->GetFileInfo (FvPpi, TempFileHandles[Index], &FileInfo); | |
ASSERT_EFI_ERROR (Status); | |
CopyMem (&TempFileGuid[Index], &FileInfo.FileName, sizeof (EFI_GUID)); | |
} | |
// | |
// Walk through TempFileGuid array to find out who is invalid PEIM GUID in Apriori file. | |
// Add available PEIMs in Apriori file into FvFileHandles array. | |
// | |
Index = 0; | |
for (Index2 = 0; Index2 < Private->AprioriCount; Index2++) { | |
Guid = ScanGuid (TempFileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2]); | |
if (Guid != NULL) { | |
PeimIndex = ((UINTN)Guid - (UINTN)&TempFileGuid[0])/sizeof (EFI_GUID); | |
CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[PeimIndex]; | |
// | |
// Since we have copied the file handle we can remove it from this list. | |
// | |
TempFileHandles[PeimIndex] = NULL; | |
} | |
} | |
// | |
// Update valid AprioriCount | |
// | |
Private->AprioriCount = Index; | |
// | |
// Add in any PEIMs not in the Apriori file | |
// | |
for (Index2 = 0; Index2 < PeimCount; Index2++) { | |
if (TempFileHandles[Index2] != NULL) { | |
CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[Index2]; | |
TempFileHandles[Index2] = NULL; | |
} | |
} | |
ASSERT (Index == PeimCount); | |
} | |
} else { | |
CopyMem (CoreFileHandle->FvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PeimCount); | |
} | |
// | |
// The current FV File Handles have been cached. So that we don't have to scan the FV again. | |
// Instead, we can retrieve the file handles within this FV from cached records. | |
// | |
CoreFileHandle->ScanFv = TRUE; | |
Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles; | |
} | |
// | |
// This is the minimum memory required by DxeCore initialization. When LMFA feature enabled, | |
// This part of memory still need reserved on the very top of memory so that the DXE Core could | |
// use these memory for data initialization. This macro should be sync with the same marco | |
// defined in DXE Core. | |
// | |
#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000 | |
/** | |
This function is to test if the memory range described in resource HOB is available or not. | |
This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. Some platform may allocate the | |
memory before PeiLoadFixAddressHook in invoked. so this function is to test if the memory range described by the input resource HOB is | |
available or not. | |
@param PrivateData Pointer to the private data passed in from caller | |
@param ResourceHob Pointer to a resource HOB which described the memory range described by the input resource HOB | |
**/ | |
BOOLEAN | |
PeiLoadFixAddressIsMemoryRangeAvailable ( | |
IN PEI_CORE_INSTANCE *PrivateData, | |
IN EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob | |
) | |
{ | |
EFI_HOB_MEMORY_ALLOCATION *MemoryHob; | |
BOOLEAN IsAvailable; | |
EFI_PEI_HOB_POINTERS Hob; | |
IsAvailable = TRUE; | |
if ((PrivateData == NULL) || (ResourceHob == NULL)) { | |
return FALSE; | |
} | |
// | |
// test if the memory range describe in the HOB is already allocated. | |
// | |
for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { | |
// | |
// See if this is a memory allocation HOB | |
// | |
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) { | |
MemoryHob = Hob.MemoryAllocation; | |
if ((MemoryHob->AllocDescriptor.MemoryBaseAddress == ResourceHob->PhysicalStart) && | |
(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength == ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) | |
{ | |
IsAvailable = FALSE; | |
break; | |
} | |
} | |
} | |
return IsAvailable; | |
} | |
/** | |
Hook function for Loading Module at Fixed Address feature | |
This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. When feature is | |
configured as Load Modules at Fix Absolute Address, this function is to validate the top address assigned by user. When | |
feature is configured as Load Modules at Fixed Offset, the function is to find the top address which is TOLM-TSEG in general. | |
And also the function will re-install PEI memory. | |
@param PrivateData Pointer to the private data passed in from caller | |
**/ | |
VOID | |
PeiLoadFixAddressHook ( | |
IN PEI_CORE_INSTANCE *PrivateData | |
) | |
{ | |
EFI_PHYSICAL_ADDRESS TopLoadingAddress; | |
UINT64 PeiMemorySize; | |
UINT64 TotalReservedMemorySize; | |
UINT64 MemoryRangeEnd; | |
EFI_PHYSICAL_ADDRESS HighAddress; | |
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; | |
EFI_HOB_RESOURCE_DESCRIPTOR *NextResourceHob; | |
EFI_HOB_RESOURCE_DESCRIPTOR *CurrentResourceHob; | |
EFI_PEI_HOB_POINTERS CurrentHob; | |
EFI_PEI_HOB_POINTERS Hob; | |
EFI_PEI_HOB_POINTERS NextHob; | |
EFI_HOB_MEMORY_ALLOCATION *MemoryHob; | |
// | |
// Initialize Local Variables | |
// | |
CurrentResourceHob = NULL; | |
ResourceHob = NULL; | |
NextResourceHob = NULL; | |
HighAddress = 0; | |
TopLoadingAddress = 0; | |
MemoryRangeEnd = 0; | |
CurrentHob.Raw = PrivateData->HobList.Raw; | |
PeiMemorySize = PrivateData->PhysicalMemoryLength; | |
// | |
// The top reserved memory include 3 parts: the topest range is for DXE core initialization with the size MINIMUM_INITIAL_MEMORY_SIZE | |
// then RuntimeCodePage range and Boot time code range. | |
// | |
TotalReservedMemorySize = MINIMUM_INITIAL_MEMORY_SIZE + EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber)); | |
TotalReservedMemorySize += EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber)); | |
// | |
// PEI memory range lies below the top reserved memory | |
// | |
TotalReservedMemorySize += PeiMemorySize; | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber))); | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber))); | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32 (PcdLoadFixAddressPeiCodePageNumber))); | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize)); | |
// | |
// Loop through the system memory typed HOB to merge the adjacent memory range | |
// | |
for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { | |
// | |
// See if this is a resource descriptor HOB | |
// | |
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { | |
ResourceHob = Hob.ResourceDescriptor; | |
// | |
// If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored. | |
// | |
if ((ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) || | |
(ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS)) | |
{ | |
continue; | |
} | |
for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (NextHob); NextHob.Raw = GET_NEXT_HOB (NextHob)) { | |
if (NextHob.Raw == Hob.Raw) { | |
continue; | |
} | |
// | |
// See if this is a resource descriptor HOB | |
// | |
if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { | |
NextResourceHob = NextHob.ResourceDescriptor; | |
// | |
// test if range described in this NextResourceHob is system memory and have the same attribute. | |
// Note: Here is a assumption that system memory should always be healthy even without test. | |
// | |
if ((NextResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) && | |
(((NextResourceHob->ResourceAttribute^ResourceHob->ResourceAttribute)&(~EFI_RESOURCE_ATTRIBUTE_TESTED)) == 0)) | |
{ | |
// | |
// See if the memory range described in ResourceHob and NextResourceHob is adjacent | |
// | |
if (((ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart) && | |
(ResourceHob->PhysicalStart + ResourceHob->ResourceLength >= NextResourceHob->PhysicalStart)) || | |
((ResourceHob->PhysicalStart >= NextResourceHob->PhysicalStart) && | |
(ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength))) | |
{ | |
MemoryRangeEnd = ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) ? | |
(ResourceHob->PhysicalStart + ResourceHob->ResourceLength) : (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength); | |
ResourceHob->PhysicalStart = (ResourceHob->PhysicalStart < NextResourceHob->PhysicalStart) ? | |
ResourceHob->PhysicalStart : NextResourceHob->PhysicalStart; | |
ResourceHob->ResourceLength = (MemoryRangeEnd - ResourceHob->PhysicalStart); | |
ResourceHob->ResourceAttribute = ResourceHob->ResourceAttribute & (~EFI_RESOURCE_ATTRIBUTE_TESTED); | |
// | |
// Delete the NextResourceHob by marking it as unused. | |
// | |
GET_HOB_TYPE (NextHob) = EFI_HOB_TYPE_UNUSED; | |
} | |
} | |
} | |
} | |
} | |
} | |
// | |
// Some platform is already allocated pages before the HOB re-org. Here to build dedicated resource HOB to describe | |
// the allocated memory range | |
// | |
for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { | |
// | |
// See if this is a memory allocation HOB | |
// | |
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) { | |
MemoryHob = Hob.MemoryAllocation; | |
for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (NextHob); NextHob.Raw = GET_NEXT_HOB (NextHob)) { | |
// | |
// See if this is a resource descriptor HOB | |
// | |
if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { | |
NextResourceHob = NextHob.ResourceDescriptor; | |
// | |
// If range described in this HOB is not system memory or higher than MAX_ADDRESS, ignored. | |
// | |
if ((NextResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) || (NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength > MAX_ADDRESS)) { | |
continue; | |
} | |
// | |
// If the range describe in memory allocation HOB belongs to the memory range described by the resource HOB | |
// | |
if ((MemoryHob->AllocDescriptor.MemoryBaseAddress >= NextResourceHob->PhysicalStart) && | |
(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) | |
{ | |
// | |
// Build separate resource HOB for this allocated range | |
// | |
if (MemoryHob->AllocDescriptor.MemoryBaseAddress > NextResourceHob->PhysicalStart) { | |
BuildResourceDescriptorHob ( | |
EFI_RESOURCE_SYSTEM_MEMORY, | |
NextResourceHob->ResourceAttribute, | |
NextResourceHob->PhysicalStart, | |
(MemoryHob->AllocDescriptor.MemoryBaseAddress - NextResourceHob->PhysicalStart) | |
); | |
} | |
if (MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength < NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength) { | |
BuildResourceDescriptorHob ( | |
EFI_RESOURCE_SYSTEM_MEMORY, | |
NextResourceHob->ResourceAttribute, | |
MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength, | |
(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength -(MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength)) | |
); | |
} | |
NextResourceHob->PhysicalStart = MemoryHob->AllocDescriptor.MemoryBaseAddress; | |
NextResourceHob->ResourceLength = MemoryHob->AllocDescriptor.MemoryLength; | |
break; | |
} | |
} | |
} | |
} | |
} | |
// | |
// Try to find and validate the TOP address. | |
// | |
if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) > 0 ) { | |
// | |
// The LMFA feature is enabled as load module at fixed absolute address. | |
// | |
TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdLoadModuleAtFixAddressEnable); | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Loading module at fixed absolute address.\n")); | |
// | |
// validate the Address. Loop the resource descriptor HOB to make sure the address is in valid memory range | |
// | |
if ((TopLoadingAddress & EFI_PAGE_MASK) != 0) { | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid since top address should be page align. \n", TopLoadingAddress)); | |
ASSERT (FALSE); | |
} | |
// | |
// Search for a memory region that is below MAX_ADDRESS and in which TopLoadingAddress lies | |
// | |
for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { | |
// | |
// See if this is a resource descriptor HOB | |
// | |
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { | |
ResourceHob = Hob.ResourceDescriptor; | |
// | |
// See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS | |
// | |
if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) && | |
(ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS)) | |
{ | |
// | |
// See if Top address specified by user is valid. | |
// | |
if ((ResourceHob->PhysicalStart + TotalReservedMemorySize < TopLoadingAddress) && | |
((ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MINIMUM_INITIAL_MEMORY_SIZE) >= TopLoadingAddress) && | |
PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob)) | |
{ | |
CurrentResourceHob = ResourceHob; | |
CurrentHob = Hob; | |
break; | |
} | |
} | |
} | |
} | |
if (CurrentResourceHob != NULL) { | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n", TopLoadingAddress)); | |
TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE; | |
} else { | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n", TopLoadingAddress)); | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n")); | |
// | |
// Print the recommended Top address range. | |
// | |
for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { | |
// | |
// See if this is a resource descriptor HOB | |
// | |
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { | |
ResourceHob = Hob.ResourceDescriptor; | |
// | |
// See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS | |
// | |
if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) && | |
(ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS)) | |
{ | |
// | |
// See if Top address specified by user is valid. | |
// | |
if ((ResourceHob->ResourceLength > TotalReservedMemorySize) && PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob)) { | |
DEBUG (( | |
DEBUG_INFO, | |
"(0x%lx, 0x%lx)\n", | |
(ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE), | |
(ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE) | |
)); | |
} | |
} | |
} | |
} | |
// | |
// Assert here | |
// | |
ASSERT (FALSE); | |
return; | |
} | |
} else { | |
// | |
// The LMFA feature is enabled as load module at fixed offset relative to TOLM | |
// Parse the Hob list to find the topest available memory. Generally it is (TOLM - TSEG) | |
// | |
// | |
// Search for a tested memory region that is below MAX_ADDRESS | |
// | |
for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { | |
// | |
// See if this is a resource descriptor HOB | |
// | |
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { | |
ResourceHob = Hob.ResourceDescriptor; | |
// | |
// See if this resource descriptor HOB describes tested system memory below MAX_ADDRESS | |
// | |
if ((ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) && | |
(ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) && | |
(ResourceHob->ResourceLength > TotalReservedMemorySize) && PeiLoadFixAddressIsMemoryRangeAvailable (PrivateData, ResourceHob)) | |
{ | |
// | |
// See if this is the highest largest system memory region below MaxAddress | |
// | |
if (ResourceHob->PhysicalStart > HighAddress) { | |
CurrentResourceHob = ResourceHob; | |
CurrentHob = Hob; | |
HighAddress = CurrentResourceHob->PhysicalStart; | |
} | |
} | |
} | |
} | |
if (CurrentResourceHob == NULL) { | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n")); | |
// | |
// Assert here | |
// | |
ASSERT (FALSE); | |
return; | |
} else { | |
TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength; | |
} | |
} | |
if (CurrentResourceHob != NULL) { | |
// | |
// rebuild resource HOB for PEI memory and reserved memory | |
// | |
BuildResourceDescriptorHob ( | |
EFI_RESOURCE_SYSTEM_MEMORY, | |
( | |
EFI_RESOURCE_ATTRIBUTE_PRESENT | | |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | | |
EFI_RESOURCE_ATTRIBUTE_TESTED | | |
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | |
), | |
(TopLoadingAddress - TotalReservedMemorySize), | |
TotalReservedMemorySize | |
); | |
// | |
// rebuild resource for the remain memory if necessary | |
// | |
if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) { | |
BuildResourceDescriptorHob ( | |
EFI_RESOURCE_SYSTEM_MEMORY, | |
( | |
EFI_RESOURCE_ATTRIBUTE_PRESENT | | |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | | |
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | |
), | |
CurrentResourceHob->PhysicalStart, | |
(TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart) | |
); | |
} | |
if (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength > TopLoadingAddress ) { | |
BuildResourceDescriptorHob ( | |
EFI_RESOURCE_SYSTEM_MEMORY, | |
( | |
EFI_RESOURCE_ATTRIBUTE_PRESENT | | |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | | |
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | |
), | |
TopLoadingAddress, | |
(CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength - TopLoadingAddress) | |
); | |
} | |
// | |
// Delete CurrentHob by marking it as unused since the memory range described by is rebuilt. | |
// | |
GET_HOB_TYPE (CurrentHob) = EFI_HOB_TYPE_UNUSED; | |
} | |
// | |
// Cache the top address for Loading Module at Fixed Address feature | |
// | |
PrivateData->LoadModuleAtFixAddressTopAddress = TopLoadingAddress - MINIMUM_INITIAL_MEMORY_SIZE; | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: Top address = 0x%lx\n", PrivateData->LoadModuleAtFixAddressTopAddress)); | |
// | |
// reinstall the PEI memory relative to TopLoadingAddress | |
// | |
PrivateData->PhysicalMemoryBegin = TopLoadingAddress - TotalReservedMemorySize; | |
PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize; | |
} | |
/** | |
This routine is invoked in switch stack as PeiCore Entry. | |
@param SecCoreData Points to a data structure containing information about the PEI core's operating | |
environment, such as the size and location of temporary RAM, the stack location and | |
the BFV location. | |
@param Private Pointer to old core data that is used to initialize the | |
core's data areas. | |
**/ | |
VOID | |
EFIAPI | |
PeiCoreEntry ( | |
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData, | |
IN PEI_CORE_INSTANCE *Private | |
) | |
{ | |
// | |
// Entry PEI Phase 2 | |
// | |
PeiCore (SecCoreData, NULL, Private); | |
} | |
/** | |
Check SwitchStackSignal and switch stack if SwitchStackSignal is TRUE. | |
@param[in] SecCoreData Points to a data structure containing information about the PEI core's operating | |
environment, such as the size and location of temporary RAM, the stack location and | |
the BFV location. | |
@param[in] Private Pointer to the private data passed in from caller. | |
**/ | |
VOID | |
PeiCheckAndSwitchStack ( | |
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData, | |
IN PEI_CORE_INSTANCE *Private | |
) | |
{ | |
VOID *LoadFixPeiCodeBegin; | |
EFI_STATUS Status; | |
CONST EFI_PEI_SERVICES **PeiServices; | |
UINT64 NewStackSize; | |
EFI_PHYSICAL_ADDRESS TopOfOldStack; | |
EFI_PHYSICAL_ADDRESS TopOfNewStack; | |
UINTN StackOffset; | |
BOOLEAN StackOffsetPositive; | |
EFI_PHYSICAL_ADDRESS TemporaryRamBase; | |
UINTN TemporaryRamSize; | |
UINTN TemporaryStackSize; | |
VOID *TemporaryStackBase; | |
UINTN PeiTemporaryRamSize; | |
VOID *PeiTemporaryRamBase; | |
EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI *TemporaryRamSupportPpi; | |
EFI_PHYSICAL_ADDRESS BaseOfNewHeap; | |
EFI_PHYSICAL_ADDRESS HoleMemBase; | |
UINTN HoleMemSize; | |
UINTN HeapTemporaryRamSize; | |
EFI_PHYSICAL_ADDRESS TempBase1; | |
UINTN TempSize1; | |
EFI_PHYSICAL_ADDRESS TempBase2; | |
UINTN TempSize2; | |
UINTN Index; | |
PeiServices = (CONST EFI_PEI_SERVICES **)&Private->Ps; | |
if (Private->SwitchStackSignal) { | |
// | |
// Before switch stack from temporary memory to permanent memory, calculate the heap and stack | |
// usage in temporary memory for debugging. | |
// | |
DEBUG_CODE_BEGIN (); | |
UINT32 *StackPointer; | |
EFI_PEI_HOB_POINTERS Hob; | |
for ( StackPointer = (UINT32 *)SecCoreData->StackBase; | |
(StackPointer < (UINT32 *)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \ | |
&& (*StackPointer == PcdGet32 (PcdInitValueInTempStack)); | |
StackPointer++) | |
{ | |
} | |
DEBUG ((DEBUG_INFO, "Temp Stack : BaseAddress=0x%p Length=0x%X\n", SecCoreData->StackBase, (UINT32)SecCoreData->StackSize)); | |
DEBUG ((DEBUG_INFO, "Temp Heap : BaseAddress=0x%p Length=0x%X\n", SecCoreData->PeiTemporaryRamBase, (UINT32)SecCoreData->PeiTemporaryRamSize)); | |
DEBUG ((DEBUG_INFO, "Total temporary memory: %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize)); | |
DEBUG (( | |
DEBUG_INFO, | |
" temporary memory stack ever used: %d bytes.\n", | |
(UINT32)(SecCoreData->StackSize - ((UINTN)StackPointer - (UINTN)SecCoreData->StackBase)) | |
)); | |
DEBUG (( | |
DEBUG_INFO, | |
" temporary memory heap used for HobList: %d bytes.\n", | |
(UINT32)((UINTN)Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - (UINTN)Private->HobList.Raw) | |
)); | |
DEBUG (( | |
DEBUG_INFO, | |
" temporary memory heap occupied by memory pages: %d bytes.\n", | |
(UINT32)(UINTN)(Private->HobList.HandoffInformationTable->EfiMemoryTop - Private->HobList.HandoffInformationTable->EfiFreeMemoryTop) | |
)); | |
for (Hob.Raw = Private->HobList.Raw; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { | |
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) { | |
DEBUG (( | |
DEBUG_INFO, | |
"Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \ | |
Hob.MemoryAllocation->AllocDescriptor.MemoryType, \ | |
Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \ | |
Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1 | |
)); | |
} | |
} | |
DEBUG_CODE_END (); | |
if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { | |
// | |
// Loading Module at Fixed Address is enabled | |
// | |
PeiLoadFixAddressHook (Private); | |
// | |
// If Loading Module at Fixed Address is enabled, Allocating memory range for Pei code range. | |
// | |
LoadFixPeiCodeBegin = AllocatePages ((UINTN)PcdGet32 (PcdLoadFixAddressPeiCodePageNumber)); | |
DEBUG ((DEBUG_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)(UINTN)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32 (PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE))); | |
} | |
// | |
// Reserve the size of new stack at bottom of physical memory | |
// | |
// The size of new stack in permanent memory must be the same size | |
// or larger than the size of old stack in temporary memory. | |
// But if new stack is smaller than the size of old stack, we also reserve | |
// the size of old stack at bottom of permanent memory. | |
// | |
NewStackSize = RShiftU64 (Private->PhysicalMemoryLength, 1); | |
NewStackSize = ALIGN_VALUE (NewStackSize, EFI_PAGE_SIZE); | |
NewStackSize = MIN (PcdGet32 (PcdPeiCoreMaxPeiStackSize), NewStackSize); | |
DEBUG ((DEBUG_INFO, "Old Stack size %d, New stack size %d\n", (UINT32)SecCoreData->StackSize, (UINT32)NewStackSize)); | |
ASSERT (NewStackSize >= SecCoreData->StackSize); | |
// | |
// Calculate stack offset and heap offset between temporary memory and new permanent | |
// memory separately. | |
// | |
TopOfOldStack = (UINTN)SecCoreData->StackBase + SecCoreData->StackSize; | |
TopOfNewStack = Private->PhysicalMemoryBegin + NewStackSize; | |
if (TopOfNewStack >= TopOfOldStack) { | |
StackOffsetPositive = TRUE; | |
StackOffset = (UINTN)(TopOfNewStack - TopOfOldStack); | |
} else { | |
StackOffsetPositive = FALSE; | |
StackOffset = (UINTN)(TopOfOldStack - TopOfNewStack); | |
} | |
Private->StackOffsetPositive = StackOffsetPositive; | |
Private->StackOffset = StackOffset; | |
// | |
// Build Stack HOB that describes the permanent memory stack | |
// | |
DEBUG ((DEBUG_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", TopOfNewStack - NewStackSize, NewStackSize)); | |
BuildStackHob (TopOfNewStack - NewStackSize, NewStackSize); | |
// | |
// Cache information from SecCoreData into locals before SecCoreData is converted to a permanent memory address | |
// | |
TemporaryRamBase = (EFI_PHYSICAL_ADDRESS)(UINTN)SecCoreData->TemporaryRamBase; | |
TemporaryRamSize = SecCoreData->TemporaryRamSize; | |
TemporaryStackSize = SecCoreData->StackSize; | |
TemporaryStackBase = SecCoreData->StackBase; | |
PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize; | |
PeiTemporaryRamBase = SecCoreData->PeiTemporaryRamBase; | |
// | |
// TemporaryRamSupportPpi is produced by platform's SEC | |
// | |
Status = PeiServicesLocatePpi ( | |
&gEfiTemporaryRamSupportPpiGuid, | |
0, | |
NULL, | |
(VOID **)&TemporaryRamSupportPpi | |
); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Heap Offset | |
// | |
BaseOfNewHeap = TopOfNewStack; | |
if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) { | |
Private->HeapOffsetPositive = TRUE; | |
Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase); | |
} else { | |
Private->HeapOffsetPositive = FALSE; | |
Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap); | |
} | |
DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset)); | |
// | |
// Calculate new HandOffTable and PrivateData address in permanent memory's stack | |
// | |
if (StackOffsetPositive) { | |
SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset); | |
Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset); | |
} else { | |
SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset); | |
Private = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset); | |
} | |
// | |
// Temporary Ram Support PPI is provided by platform, it will copy | |
// temporary memory to permanent memory and do stack switching. | |
// After invoking Temporary Ram Support PPI, the following code's | |
// stack is in permanent memory. | |
// | |
TemporaryRamSupportPpi->TemporaryRamMigration ( | |
PeiServices, | |
TemporaryRamBase, | |
(EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize), | |
TemporaryRamSize | |
); | |
// | |
// Migrate memory pages allocated in pre-memory phase. | |
// It could not be called before calling TemporaryRamSupportPpi->TemporaryRamMigration() | |
// as the migrated memory pages may be overridden by TemporaryRamSupportPpi->TemporaryRamMigration(). | |
// | |
MigrateMemoryPages (Private, TRUE); | |
// | |
// Entry PEI Phase 2 | |
// | |
PeiCore (SecCoreData, NULL, Private); | |
} else { | |
// | |
// Migrate memory pages allocated in pre-memory phase. | |
// | |
MigrateMemoryPages (Private, FALSE); | |
// | |
// Migrate the PEI Services Table pointer from temporary RAM to permanent RAM. | |
// | |
MigratePeiServicesTablePointer (); | |
// | |
// Heap Offset | |
// | |
BaseOfNewHeap = TopOfNewStack; | |
HoleMemBase = TopOfNewStack; | |
HoleMemSize = TemporaryRamSize - PeiTemporaryRamSize - TemporaryStackSize; | |
if (HoleMemSize != 0) { | |
// | |
// Make sure HOB List start address is 8 byte alignment. | |
// | |
BaseOfNewHeap = ALIGN_VALUE (BaseOfNewHeap + HoleMemSize, 8); | |
} | |
if (BaseOfNewHeap >= (UINTN)SecCoreData->PeiTemporaryRamBase) { | |
Private->HeapOffsetPositive = TRUE; | |
Private->HeapOffset = (UINTN)(BaseOfNewHeap - (UINTN)SecCoreData->PeiTemporaryRamBase); | |
} else { | |
Private->HeapOffsetPositive = FALSE; | |
Private->HeapOffset = (UINTN)((UINTN)SecCoreData->PeiTemporaryRamBase - BaseOfNewHeap); | |
} | |
DEBUG ((DEBUG_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (UINT64)Private->HeapOffset, (UINT64)Private->StackOffset)); | |
// | |
// Migrate Heap | |
// | |
HeapTemporaryRamSize = (UINTN)(Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - Private->HobList.HandoffInformationTable->EfiMemoryBottom); | |
ASSERT (BaseOfNewHeap + HeapTemporaryRamSize <= Private->FreePhysicalMemoryTop); | |
CopyMem ((UINT8 *)(UINTN)BaseOfNewHeap, PeiTemporaryRamBase, HeapTemporaryRamSize); | |
// | |
// Migrate Stack | |
// | |
CopyMem ((UINT8 *)(UINTN)(TopOfNewStack - TemporaryStackSize), TemporaryStackBase, TemporaryStackSize); | |
// | |
// Copy Hole Range Data | |
// | |
if (HoleMemSize != 0) { | |
// | |
// Prepare Hole | |
// | |
if (PeiTemporaryRamBase < TemporaryStackBase) { | |
TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase; | |
TempSize1 = PeiTemporaryRamSize; | |
TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase; | |
TempSize2 = TemporaryStackSize; | |
} else { | |
TempBase1 = (EFI_PHYSICAL_ADDRESS)(UINTN)TemporaryStackBase; | |
TempSize1 = TemporaryStackSize; | |
TempBase2 = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiTemporaryRamBase; | |
TempSize2 = PeiTemporaryRamSize; | |
} | |
if (TemporaryRamBase < TempBase1) { | |
Private->HoleData[0].Base = TemporaryRamBase; | |
Private->HoleData[0].Size = (UINTN)(TempBase1 - TemporaryRamBase); | |
} | |
if (TempBase1 + TempSize1 < TempBase2) { | |
Private->HoleData[1].Base = TempBase1 + TempSize1; | |
Private->HoleData[1].Size = (UINTN)(TempBase2 - TempBase1 - TempSize1); | |
} | |
if (TempBase2 + TempSize2 < TemporaryRamBase + TemporaryRamSize) { | |
Private->HoleData[2].Base = TempBase2 + TempSize2; | |
Private->HoleData[2].Size = (UINTN)(TemporaryRamBase + TemporaryRamSize - TempBase2 - TempSize2); | |
} | |
// | |
// Copy Hole Range data. | |
// | |
for (Index = 0; Index < HOLE_MAX_NUMBER; Index++) { | |
if (Private->HoleData[Index].Size > 0) { | |
if (HoleMemBase > Private->HoleData[Index].Base) { | |
Private->HoleData[Index].OffsetPositive = TRUE; | |
Private->HoleData[Index].Offset = (UINTN)(HoleMemBase - Private->HoleData[Index].Base); | |
} else { | |
Private->HoleData[Index].OffsetPositive = FALSE; | |
Private->HoleData[Index].Offset = (UINTN)(Private->HoleData[Index].Base - HoleMemBase); | |
} | |
CopyMem ((VOID *)(UINTN)HoleMemBase, (VOID *)(UINTN)Private->HoleData[Index].Base, Private->HoleData[Index].Size); | |
HoleMemBase = HoleMemBase + Private->HoleData[Index].Size; | |
} | |
} | |
} | |
// | |
// Switch new stack | |
// | |
SwitchStack ( | |
(SWITCH_STACK_ENTRY_POINT)(UINTN)PeiCoreEntry, | |
(VOID *)SecCoreData, | |
(VOID *)Private, | |
(VOID *)(UINTN)TopOfNewStack | |
); | |
} | |
// | |
// Code should not come here | |
// | |
ASSERT (FALSE); | |
} | |
} | |
/** | |
Migrate a PEIM from temporary RAM to permanent memory. | |
@param PeimFileHandle Pointer to the FFS file header of the image. | |
@param MigratedFileHandle Pointer to the FFS file header of the migrated image. | |
@retval EFI_SUCCESS Successfully migrated the PEIM to permanent memory. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MigratePeim ( | |
IN EFI_PEI_FILE_HANDLE FileHandle, | |
IN EFI_PEI_FILE_HANDLE MigratedFileHandle | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_FFS_FILE_HEADER *FileHeader; | |
VOID *Pe32Data; | |
VOID *ImageAddress; | |
CHAR8 *AsciiString; | |
UINTN Index; | |
Status = EFI_SUCCESS; | |
FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle; | |
ASSERT (!IS_FFS_FILE2 (FileHeader)); | |
ImageAddress = NULL; | |
PeiGetPe32Data (MigratedFileHandle, &ImageAddress); | |
if (ImageAddress != NULL) { | |
DEBUG_CODE_BEGIN (); | |
AsciiString = PeCoffLoaderGetPdbPointer (ImageAddress); | |
for (Index = 0; AsciiString[Index] != 0; Index++) { | |
if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) { | |
AsciiString = AsciiString + Index + 1; | |
Index = 0; | |
} else if (AsciiString[Index] == '.') { | |
AsciiString[Index] = 0; | |
} | |
} | |
DEBUG ((DEBUG_VERBOSE, "%a", AsciiString)); | |
DEBUG_CODE_END (); | |
Pe32Data = (VOID *)((UINTN)ImageAddress - (UINTN)MigratedFileHandle + (UINTN)FileHandle); | |
Status = LoadAndRelocatePeCoffImageInPlace (Pe32Data, ImageAddress); | |
ASSERT_EFI_ERROR (Status); | |
} | |
return Status; | |
} | |
/** | |
Migrate Status Code Callback function pointers inside an FV from temporary memory to permanent memory. | |
@param OrgFvHandle Address of FV handle in temporary memory. | |
@param FvHandle Address of FV handle in permanent memory. | |
@param FvSize Size of the FV. | |
**/ | |
VOID | |
ConvertStatusCodeCallbacks ( | |
IN UINTN OrgFvHandle, | |
IN UINTN FvHandle, | |
IN UINTN FvSize | |
) | |
{ | |
EFI_PEI_HOB_POINTERS Hob; | |
UINTN *NumberOfEntries; | |
UINTN *CallbackEntry; | |
UINTN Index; | |
Hob.Raw = GetFirstGuidHob (&gStatusCodeCallbackGuid); | |
while (Hob.Raw != NULL) { | |
NumberOfEntries = GET_GUID_HOB_DATA (Hob); | |
CallbackEntry = NumberOfEntries + 1; | |
for (Index = 0; Index < *NumberOfEntries; Index++) { | |
if (((VOID *)CallbackEntry[Index]) != NULL) { | |
if ((CallbackEntry[Index] >= OrgFvHandle) && (CallbackEntry[Index] < (OrgFvHandle + FvSize))) { | |
DEBUG (( | |
DEBUG_INFO, | |
"Migrating CallbackEntry[%Lu] from 0x%0*Lx to ", | |
(UINT64)Index, | |
(sizeof CallbackEntry[Index]) * 2, | |
(UINT64)CallbackEntry[Index] | |
)); | |
if (OrgFvHandle > FvHandle) { | |
CallbackEntry[Index] = CallbackEntry[Index] - (OrgFvHandle - FvHandle); | |
} else { | |
CallbackEntry[Index] = CallbackEntry[Index] + (FvHandle - OrgFvHandle); | |
} | |
DEBUG (( | |
DEBUG_INFO, | |
"0x%0*Lx\n", | |
(sizeof CallbackEntry[Index]) * 2, | |
(UINT64)CallbackEntry[Index] | |
)); | |
} | |
} | |
} | |
Hob.Raw = GET_NEXT_HOB (Hob); | |
Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw); | |
} | |
} | |
/** | |
Migrates PEIMs in the given firmware volume. | |
@param Private Pointer to the PeiCore's private data structure. | |
@param FvIndex The firmware volume index to migrate. | |
@param OrgFvHandle The handle to the firmware volume in temporary memory. | |
@param FvHandle The handle to the firmware volume in permanent memory. | |
@retval EFI_SUCCESS The PEIMs in the FV were migrated successfully | |
@retval EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MigratePeimsInFv ( | |
IN PEI_CORE_INSTANCE *Private, | |
IN UINTN FvIndex, | |
IN UINTN OrgFvHandle, | |
IN UINTN FvHandle | |
) | |
{ | |
EFI_STATUS Status; | |
volatile UINTN FileIndex; | |
EFI_PEI_FILE_HANDLE MigratedFileHandle; | |
EFI_PEI_FILE_HANDLE FileHandle; | |
if ((Private == NULL) || (FvIndex >= Private->FvCount)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (Private->Fv[FvIndex].ScanFv) { | |
for (FileIndex = 0; FileIndex < Private->Fv[FvIndex].PeimCount; FileIndex++) { | |
if (Private->Fv[FvIndex].FvFileHandles[FileIndex] != NULL) { | |
FileHandle = Private->Fv[FvIndex].FvFileHandles[FileIndex]; | |
MigratedFileHandle = (EFI_PEI_FILE_HANDLE)((UINTN)FileHandle - OrgFvHandle + FvHandle); | |
DEBUG ((DEBUG_VERBOSE, " Migrating FileHandle %2d ", FileIndex)); | |
Status = MigratePeim (FileHandle, MigratedFileHandle); | |
DEBUG ((DEBUG_VERBOSE, "\n")); | |
ASSERT_EFI_ERROR (Status); | |
if (!EFI_ERROR (Status)) { | |
Private->Fv[FvIndex].FvFileHandles[FileIndex] = MigratedFileHandle; | |
if (FvIndex == Private->CurrentPeimFvCount) { | |
Private->CurrentFvFileHandles[FileIndex] = MigratedFileHandle; | |
} | |
} | |
} | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Migrate FVs out of temporary RAM before the cache is flushed. | |
@param Private PeiCore's private data structure | |
@param SecCoreData Points to a data structure containing information about the PEI core's operating | |
environment, such as the size and location of temporary RAM, the stack location and | |
the BFV location. | |
@retval EFI_SUCCESS Successfully migrated installed FVs from temporary RAM to permanent memory. | |
@retval EFI_OUT_OF_RESOURCES Insufficient memory exists to allocate needed pages. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
EvacuateTempRam ( | |
IN PEI_CORE_INSTANCE *Private, | |
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData | |
) | |
{ | |
EFI_STATUS Status; | |
volatile UINTN FvIndex; | |
volatile UINTN FvChildIndex; | |
UINTN ChildFvOffset; | |
EFI_PHYSICAL_ADDRESS FvHeaderAddress; | |
EFI_FIRMWARE_VOLUME_HEADER *FvHeader; | |
EFI_FIRMWARE_VOLUME_HEADER *ChildFvHeader; | |
EFI_FIRMWARE_VOLUME_HEADER *MigratedFvHeader; | |
EFI_FIRMWARE_VOLUME_HEADER *RawDataFvHeader; | |
EFI_FIRMWARE_VOLUME_HEADER *MigratedChildFvHeader; | |
PEI_CORE_FV_HANDLE PeiCoreFvHandle; | |
EFI_PEI_CORE_FV_LOCATION_PPI *PeiCoreFvLocationPpi; | |
EFI_PEI_HOB_POINTERS Hob; | |
EDKII_MIGRATION_INFO *MigrationInfo; | |
TO_MIGRATE_FV_INFO *ToMigrateFvInfo; | |
UINT32 FvMigrationFlags; | |
EDKII_MIGRATED_FV_INFO MigratedFvInfo; | |
UINTN Index; | |
ASSERT (Private->PeiMemoryInstalled); | |
DEBUG ((DEBUG_VERBOSE, "Beginning evacuation of content in temporary RAM.\n")); | |
// | |
// Migrate PPI Pointers of PEI_CORE from temporary memory to newly loaded PEI_CORE in permanent memory. | |
// | |
Status = PeiLocatePpi ((CONST EFI_PEI_SERVICES **)&Private->Ps, &gEfiPeiCoreFvLocationPpiGuid, 0, NULL, (VOID **)&PeiCoreFvLocationPpi); | |
if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) { | |
PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)PeiCoreFvLocationPpi->PeiCoreFvLocation; | |
} else { | |
PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE)SecCoreData->BootFirmwareVolumeBase; | |
} | |
for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) { | |
if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) { | |
CopyMem (&PeiCoreFvHandle, &Private->Fv[FvIndex], sizeof (PEI_CORE_FV_HANDLE)); | |
break; | |
} | |
} | |
Status = EFI_SUCCESS; | |
ConvertPeiCorePpiPointers (Private, &PeiCoreFvHandle); | |
Hob.Raw = GetFirstGuidHob (&gEdkiiMigrationInfoGuid); | |
if (Hob.Raw != NULL) { | |
MigrationInfo = GET_GUID_HOB_DATA (Hob); | |
} else { | |
MigrationInfo = NULL; | |
} | |
for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) { | |
FvHeader = Private->Fv[FvIndex].FvHeader; | |
ASSERT (FvHeader != NULL); | |
ASSERT (FvIndex < Private->FvCount); | |
DEBUG ((DEBUG_VERBOSE, "FV[%02d] at 0x%x.\n", FvIndex, (UINTN)FvHeader)); | |
if ( | |
!( | |
((EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader >= Private->PhysicalMemoryBegin) && | |
(((EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader + (FvHeader->FvLength - 1)) < Private->FreePhysicalMemoryTop) | |
) | |
) | |
{ | |
if ((MigrationInfo == NULL) || (MigrationInfo->MigrateAll == TRUE)) { | |
// | |
// Migrate all FVs and copy raw data | |
// | |
FvMigrationFlags = FLAGS_FV_RAW_DATA_COPY; | |
} else { | |
for (Index = 0; Index < MigrationInfo->ToMigrateFvCount; Index++) { | |
ToMigrateFvInfo = ((TO_MIGRATE_FV_INFO *)(MigrationInfo + 1)) + Index; | |
if (ToMigrateFvInfo->FvOrgBaseOnTempRam == (UINT32)(UINTN)FvHeader) { | |
// | |
// This FV is to migrate | |
// | |
FvMigrationFlags = ToMigrateFvInfo->FvMigrationFlags; | |
break; | |
} | |
} | |
if (Index == MigrationInfo->ToMigrateFvCount) { | |
// | |
// This FV is not expected to migrate | |
// | |
continue; | |
} | |
} | |
// | |
// Allocate pages to save the rebased PEIMs, the PEIMs will get dispatched later. | |
// | |
Status = PeiServicesAllocatePages ( | |
EfiBootServicesCode, | |
EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength), | |
&FvHeaderAddress | |
); | |
ASSERT_EFI_ERROR (Status); | |
MigratedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress; | |
CopyMem (MigratedFvHeader, FvHeader, (UINTN)FvHeader->FvLength); | |
DEBUG (( | |
DEBUG_VERBOSE, | |
" Migrating FV[%d] from 0x%08X to 0x%08X\n", | |
FvIndex, | |
(UINTN)FvHeader, | |
(UINTN)MigratedFvHeader | |
)); | |
// | |
// Create hob to save MigratedFvInfo, this hob will only be produced when | |
// Migration feature PCD PcdMigrateTemporaryRamFirmwareVolumes is set to TRUE. | |
// | |
MigratedFvInfo.FvOrgBase = (UINT32)(UINTN)FvHeader; | |
MigratedFvInfo.FvNewBase = (UINT32)(UINTN)MigratedFvHeader; | |
MigratedFvInfo.FvDataBase = 0; | |
MigratedFvInfo.FvLength = (UINT32)(UINTN)FvHeader->FvLength; | |
// | |
// When FLAGS_FV_RAW_DATA_COPY bit is set, copy the context to the raw pages and | |
// reset raw data base address in MigratedFvInfo hob. | |
// | |
if ((FvMigrationFlags & FLAGS_FV_RAW_DATA_COPY) == FLAGS_FV_RAW_DATA_COPY) { | |
// | |
// Allocate pages to save the raw PEIMs | |
// | |
Status = PeiServicesAllocatePages ( | |
EfiBootServicesCode, | |
EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength), | |
&FvHeaderAddress | |
); | |
ASSERT_EFI_ERROR (Status); | |
RawDataFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress; | |
CopyMem (RawDataFvHeader, FvHeader, (UINTN)FvHeader->FvLength); | |
MigratedFvInfo.FvDataBase = (UINT32)(UINTN)RawDataFvHeader; | |
} | |
BuildGuidDataHob (&gEdkiiMigratedFvInfoGuid, &MigratedFvInfo, sizeof (MigratedFvInfo)); | |
// | |
// Migrate any children for this FV now | |
// | |
for (FvChildIndex = FvIndex; FvChildIndex < Private->FvCount; FvChildIndex++) { | |
ChildFvHeader = Private->Fv[FvChildIndex].FvHeader; | |
if ( | |
((UINTN)ChildFvHeader > (UINTN)FvHeader) && | |
(((UINTN)ChildFvHeader + ChildFvHeader->FvLength) < ((UINTN)FvHeader) + FvHeader->FvLength) | |
) | |
{ | |
DEBUG ((DEBUG_VERBOSE, " Child FV[%02d] is being migrated.\n", FvChildIndex)); | |
ChildFvOffset = (UINTN)ChildFvHeader - (UINTN)FvHeader; | |
DEBUG ((DEBUG_VERBOSE, " Child FV offset = 0x%x.\n", ChildFvOffset)); | |
MigratedChildFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)MigratedFvHeader + ChildFvOffset); | |
Private->Fv[FvChildIndex].FvHeader = MigratedChildFvHeader; | |
Private->Fv[FvChildIndex].FvHandle = (EFI_PEI_FV_HANDLE)MigratedChildFvHeader; | |
DEBUG ((DEBUG_VERBOSE, " Child migrated FV header at 0x%x.\n", (UINTN)MigratedChildFvHeader)); | |
Status = MigratePeimsInFv (Private, FvChildIndex, (UINTN)ChildFvHeader, (UINTN)MigratedChildFvHeader); | |
ASSERT_EFI_ERROR (Status); | |
ConvertPpiPointersFv ( | |
Private, | |
(UINTN)ChildFvHeader, | |
(UINTN)MigratedChildFvHeader, | |
(UINTN)ChildFvHeader->FvLength - 1 | |
); | |
ConvertStatusCodeCallbacks ( | |
(UINTN)ChildFvHeader, | |
(UINTN)MigratedChildFvHeader, | |
(UINTN)ChildFvHeader->FvLength - 1 | |
); | |
ConvertFvHob (Private, (UINTN)ChildFvHeader, (UINTN)MigratedChildFvHeader); | |
} | |
} | |
Private->Fv[FvIndex].FvHeader = MigratedFvHeader; | |
Private->Fv[FvIndex].FvHandle = (EFI_PEI_FV_HANDLE)MigratedFvHeader; | |
Status = MigratePeimsInFv (Private, FvIndex, (UINTN)FvHeader, (UINTN)MigratedFvHeader); | |
ASSERT_EFI_ERROR (Status); | |
ConvertPpiPointersFv ( | |
Private, | |
(UINTN)FvHeader, | |
(UINTN)MigratedFvHeader, | |
(UINTN)FvHeader->FvLength - 1 | |
); | |
ConvertStatusCodeCallbacks ( | |
(UINTN)FvHeader, | |
(UINTN)MigratedFvHeader, | |
(UINTN)FvHeader->FvLength - 1 | |
); | |
ConvertFvHob (Private, (UINTN)FvHeader, (UINTN)MigratedFvHeader); | |
} | |
} | |
return Status; | |
} | |
/** | |
Conduct PEIM dispatch. | |
@param SecCoreData Points to a data structure containing information about the PEI core's operating | |
environment, such as the size and location of temporary RAM, the stack location and | |
the BFV location. | |
@param Private Pointer to the private data passed in from caller | |
**/ | |
VOID | |
PeiDispatcher ( | |
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData, | |
IN PEI_CORE_INSTANCE *Private | |
) | |
{ | |
EFI_STATUS Status; | |
UINT32 Index1; | |
UINT32 Index2; | |
CONST EFI_PEI_SERVICES **PeiServices; | |
EFI_PEI_FILE_HANDLE PeimFileHandle; | |
UINTN FvCount; | |
UINTN PeimCount; | |
UINT32 AuthenticationState; | |
EFI_PHYSICAL_ADDRESS EntryPoint; | |
EFI_PEIM_ENTRY_POINT2 PeimEntryPoint; | |
UINTN SaveCurrentPeimCount; | |
UINTN SaveCurrentFvCount; | |
EFI_PEI_FILE_HANDLE SaveCurrentFileHandle; | |
EFI_FV_FILE_INFO FvFileInfo; | |
PEI_CORE_FV_HANDLE *CoreFvHandle; | |
PeiServices = (CONST EFI_PEI_SERVICES **)&Private->Ps; | |
PeimEntryPoint = NULL; | |
PeimFileHandle = NULL; | |
EntryPoint = 0; | |
if ((Private->PeiMemoryInstalled) && | |
(PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) || | |
(Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) || | |
PcdGetBool (PcdShadowPeimOnS3Boot)) | |
) | |
{ | |
// | |
// Once real memory is available, shadow the RegisterForShadow modules. And meanwhile | |
// update the modules' status from PEIM_STATE_REGISTER_FOR_SHADOW to PEIM_STATE_DONE. | |
// | |
SaveCurrentPeimCount = Private->CurrentPeimCount; | |
SaveCurrentFvCount = Private->CurrentPeimFvCount; | |
SaveCurrentFileHandle = Private->CurrentFileHandle; | |
for (Index1 = 0; Index1 < Private->FvCount; Index1++) { | |
for (Index2 = 0; Index2 < Private->Fv[Index1].PeimCount; Index2++) { | |
if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISTER_FOR_SHADOW) { | |
PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2]; | |
Private->CurrentFileHandle = PeimFileHandle; | |
Private->CurrentPeimFvCount = Index1; | |
Private->CurrentPeimCount = Index2; | |
Status = PeiLoadImage ( | |
(CONST EFI_PEI_SERVICES **)&Private->Ps, | |
PeimFileHandle, | |
PEIM_STATE_REGISTER_FOR_SHADOW, | |
&EntryPoint, | |
&AuthenticationState | |
); | |
if (Status == EFI_SUCCESS) { | |
// | |
// PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE | |
// | |
Private->Fv[Index1].PeimState[Index2]++; | |
// | |
// Call the PEIM entry point | |
// | |
PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint; | |
PERF_START_IMAGE_BEGIN (PeimFileHandle); | |
PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)&Private->Ps); | |
PERF_START_IMAGE_END (PeimFileHandle); | |
} | |
// | |
// Process the Notify list and dispatch any notifies for | |
// newly installed PPIs. | |
// | |
ProcessDispatchNotifyList (Private); | |
} | |
} | |
} | |
Private->CurrentFileHandle = SaveCurrentFileHandle; | |
Private->CurrentPeimFvCount = SaveCurrentFvCount; | |
Private->CurrentPeimCount = SaveCurrentPeimCount; | |
} | |
// | |
// This is the main dispatch loop. It will search known FVs for PEIMs and | |
// attempt to dispatch them. If any PEIM gets dispatched through a single | |
// pass of the dispatcher, it will start over from the BFV again to see | |
// if any new PEIMs dependencies got satisfied. With a well ordered | |
// FV where PEIMs are found in the order their dependencies are also | |
// satisfied, this dispatcher should run only once. | |
// | |
do { | |
// | |
// In case that reenter PeiCore happens, the last pass record is still available. | |
// | |
if (!Private->PeimDispatcherReenter) { | |
Private->PeimNeedingDispatch = FALSE; | |
Private->PeimDispatchOnThisPass = FALSE; | |
} else { | |
Private->PeimDispatcherReenter = FALSE; | |
} | |
for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) { | |
CoreFvHandle = FindNextCoreFvHandle (Private, FvCount); | |
ASSERT (CoreFvHandle != NULL); | |
// | |
// If the FV has corresponding EFI_PEI_FIRMWARE_VOLUME_PPI instance, then dispatch it. | |
// | |
if (CoreFvHandle->FvPpi == NULL) { | |
continue; | |
} | |
Private->CurrentPeimFvCount = FvCount; | |
if (Private->CurrentPeimCount == 0) { | |
// | |
// When going through each FV, at first, search Apriori file to | |
// reorder all PEIMs to ensure the PEIMs in Apriori file to get | |
// dispatch at first. | |
// | |
DiscoverPeimsAndOrderWithApriori (Private, CoreFvHandle); | |
} | |
// | |
// Start to dispatch all modules within the current FV. | |
// | |
for (PeimCount = Private->CurrentPeimCount; | |
PeimCount < Private->Fv[FvCount].PeimCount; | |
PeimCount++) | |
{ | |
Private->CurrentPeimCount = PeimCount; | |
PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount]; | |
if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) { | |
if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) { | |
Private->PeimNeedingDispatch = TRUE; | |
} else { | |
Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeimFileHandle, &FvFileInfo); | |
ASSERT_EFI_ERROR (Status); | |
if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { | |
// | |
// For FV type file, Produce new FvInfo PPI and FV HOB | |
// | |
Status = ProcessFvFile (Private, &Private->Fv[FvCount], PeimFileHandle); | |
if (Status == EFI_SUCCESS) { | |
// | |
// PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED | |
// | |
Private->Fv[FvCount].PeimState[PeimCount]++; | |
Private->PeimDispatchOnThisPass = TRUE; | |
} else { | |
// | |
// The related GuidedSectionExtraction/Decompress PPI for the | |
// encapsulated FV image section may be installed in the rest | |
// of this do-while loop, so need to make another pass. | |
// | |
Private->PeimNeedingDispatch = TRUE; | |
} | |
} else { | |
// | |
// For PEIM driver, Load its entry point | |
// | |
Status = PeiLoadImage ( | |
PeiServices, | |
PeimFileHandle, | |
PEIM_STATE_NOT_DISPATCHED, | |
&EntryPoint, | |
&AuthenticationState | |
); | |
if (Status == EFI_SUCCESS) { | |
// | |
// The PEIM has its dependencies satisfied, and its entry point | |
// has been found, so invoke it. | |
// | |
PERF_START_IMAGE_BEGIN (PeimFileHandle); | |
REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( | |
EFI_PROGRESS_CODE, | |
(EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN), | |
(VOID *)(&PeimFileHandle), | |
sizeof (PeimFileHandle) | |
); | |
Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle, AuthenticationState); | |
if (Status != EFI_SECURITY_VIOLATION) { | |
// | |
// PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED | |
// | |
Private->Fv[FvCount].PeimState[PeimCount]++; | |
// | |
// Call the PEIM entry point for PEIM driver | |
// | |
PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint; | |
PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices); | |
Private->PeimDispatchOnThisPass = TRUE; | |
} else { | |
// | |
// The related GuidedSectionExtraction PPI for the | |
// signed PEIM image section may be installed in the rest | |
// of this do-while loop, so need to make another pass. | |
// | |
Private->PeimNeedingDispatch = TRUE; | |
} | |
REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( | |
EFI_PROGRESS_CODE, | |
(EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END), | |
(VOID *)(&PeimFileHandle), | |
sizeof (PeimFileHandle) | |
); | |
PERF_START_IMAGE_END (PeimFileHandle); | |
} | |
} | |
PeiCheckAndSwitchStack (SecCoreData, Private); | |
// | |
// Process the Notify list and dispatch any notifies for | |
// newly installed PPIs. | |
// | |
ProcessDispatchNotifyList (Private); | |
// | |
// Recheck SwitchStackSignal after ProcessDispatchNotifyList() | |
// in case PeiInstallPeiMemory() is done in a callback with | |
// EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH. | |
// | |
PeiCheckAndSwitchStack (SecCoreData, Private); | |
if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) && \ | |
(PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) || | |
(Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) || | |
PcdGetBool (PcdShadowPeimOnS3Boot)) | |
) | |
{ | |
// | |
// If memory is available we shadow images by default for performance reasons. | |
// We call the entry point a 2nd time so the module knows it's shadowed. | |
// | |
// PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0); | |
if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) && | |
!PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) | |
{ | |
// | |
// Load PEIM into Memory for Register for shadow PEIM. | |
// | |
Status = PeiLoadImage ( | |
PeiServices, | |
PeimFileHandle, | |
PEIM_STATE_REGISTER_FOR_SHADOW, | |
&EntryPoint, | |
&AuthenticationState | |
); | |
if (Status == EFI_SUCCESS) { | |
PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint; | |
} | |
} | |
ASSERT (PeimEntryPoint != NULL); | |
PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices); | |
// PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0); | |
// | |
// PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE | |
// | |
Private->Fv[FvCount].PeimState[PeimCount]++; | |
// | |
// Process the Notify list and dispatch any notifies for | |
// newly installed PPIs. | |
// | |
ProcessDispatchNotifyList (Private); | |
} | |
} | |
} | |
} | |
// | |
// Before walking through the next FV, we should set them to NULL/0 to | |
// start at the beginning of the next FV. | |
// | |
Private->CurrentFileHandle = NULL; | |
Private->CurrentPeimCount = 0; | |
Private->CurrentFvFileHandles = NULL; | |
Private->AprioriCount = 0; | |
} | |
// | |
// Before making another pass, we should set it to 0 to | |
// go through all the FVs. | |
// | |
Private->CurrentPeimFvCount = 0; | |
// | |
// PeimNeedingDispatch being TRUE means we found a PEIM/FV that did not get | |
// dispatched. So we need to make another pass | |
// | |
// PeimDispatchOnThisPass being TRUE means we dispatched a PEIM/FV on this | |
// pass. If we did not dispatch a PEIM/FV there is no point in trying again | |
// as it will fail the next time too (nothing has changed). | |
// | |
} while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass); | |
} | |
/** | |
Initialize the Dispatcher's data members | |
@param PrivateData PeiCore's private data structure | |
@param OldCoreData Old data from SecCore | |
NULL if being run in non-permanent memory mode. | |
@param SecCoreData Points to a data structure containing information about the PEI core's operating | |
environment, such as the size and location of temporary RAM, the stack location and | |
the BFV location. | |
@return None. | |
**/ | |
VOID | |
InitializeDispatcherData ( | |
IN PEI_CORE_INSTANCE *PrivateData, | |
IN PEI_CORE_INSTANCE *OldCoreData, | |
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData | |
) | |
{ | |
if (OldCoreData == NULL) { | |
PrivateData->PeimDispatcherReenter = FALSE; | |
PeiInitializeFv (PrivateData, SecCoreData); | |
} else { | |
PeiReinitializeFv (PrivateData); | |
} | |
return; | |
} | |
/** | |
This routine parses the Dependency Expression, if available, and | |
decides if the module can be executed. | |
@param Private PeiCore's private data structure | |
@param FileHandle PEIM's file handle | |
@param PeimCount Peim count in all dispatched PEIMs. | |
@retval TRUE Can be dispatched | |
@retval FALSE Cannot be dispatched | |
**/ | |
BOOLEAN | |
DepexSatisfied ( | |
IN PEI_CORE_INSTANCE *Private, | |
IN EFI_PEI_FILE_HANDLE FileHandle, | |
IN UINTN PeimCount | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *DepexData; | |
EFI_FV_FILE_INFO FileInfo; | |
Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(Unknown)\n")); | |
} else { | |
DEBUG ((DEBUG_DISPATCH, "Evaluate PEI DEPEX for FFS(%g)\n", &FileInfo.FileName)); | |
} | |
if (PeimCount < Private->AprioriCount) { | |
// | |
// If it's in the Apriori file then we set DEPEX to TRUE | |
// | |
DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n")); | |
return TRUE; | |
} | |
// | |
// Depex section not in the encapsulated section. | |
// | |
Status = PeiServicesFfsFindSectionData ( | |
EFI_SECTION_PEI_DEPEX, | |
FileHandle, | |
(VOID **)&DepexData | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// If there is no DEPEX, assume the module can be executed | |
// | |
DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (No DEPEX)\n")); | |
return TRUE; | |
} | |
// | |
// Evaluate a given DEPEX | |
// | |
return PeimDispatchReadiness (&Private->Ps, DepexData); | |
} | |
/** | |
This routine enables a PEIM to register itself for shadow when the PEI Foundation | |
discovers permanent memory. | |
@param FileHandle File handle of a PEIM. | |
@retval EFI_NOT_FOUND The file handle doesn't point to PEIM itself. | |
@retval EFI_ALREADY_STARTED Indicate that the PEIM has been registered itself. | |
@retval EFI_SUCCESS Successfully to register itself. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
PeiRegisterForShadow ( | |
IN EFI_PEI_FILE_HANDLE FileHandle | |
) | |
{ | |
PEI_CORE_INSTANCE *Private; | |
Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); | |
if (Private->CurrentFileHandle != FileHandle) { | |
// | |
// The FileHandle must be for the current PEIM | |
// | |
return EFI_NOT_FOUND; | |
} | |
if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISTER_FOR_SHADOW) { | |
// | |
// If the PEIM has already entered the PEIM_STATE_REGISTER_FOR_SHADOW or PEIM_STATE_DONE then it's already been started | |
// | |
return EFI_ALREADY_STARTED; | |
} | |
Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISTER_FOR_SHADOW; | |
return EFI_SUCCESS; | |
} |