X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FCore%2FPei%2FDispatcher%2FDispatcher.c;h=4c2eac1384e8e29b2578d3659b55beed3573a8c0;hp=ddd149b23e364f4c01270d2ca577e79d39fd7916;hb=HEAD;hpb=4fb720763c32fa4a65c5ee78666553fe458ce212 diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c index ddd149b23e..3552feda8f 100644 --- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c +++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c @@ -1,32 +1,17 @@ /** @file EFI PEI Core dispatch services - -Copyright (c) 2006 - 2010, Intel Corporation -All rights reserved. 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. +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "PeiMain.h" -/// -/// temporary memory is filled with this initial value during SEC phase -/// -#define INIT_CAR_VALUE 0x5AA55AA5 - -typedef struct { - EFI_STATUS_CODE_DATA DataHeader; - EFI_HANDLE Handle; -} PEIM_FILE_HANDLE_EXTENDED_DATA; - /** - Discover all Peims and optional Apriori file in one FV. There is at most one + Discover all PEIMs and optional Apriori file in one FV. There is at most one Apriori file in one FV. @@ -36,523 +21,1320 @@ typedef struct { **/ VOID DiscoverPeimsAndOrderWithApriori ( - IN PEI_CORE_INSTANCE *Private, - IN PEI_CORE_FV_HANDLE *CoreFileHandle + IN PEI_CORE_INSTANCE *Private, + IN PEI_CORE_FV_HANDLE *CoreFileHandle ) { - EFI_STATUS Status; - EFI_PEI_FV_HANDLE FileHandle; - EFI_PEI_FILE_HANDLE AprioriFileHandle; - EFI_GUID *Apriori; - UINTN Index; - UINTN Index2; - UINTN PeimIndex; - UINTN PeimCount; - EFI_GUID *Guid; - EFI_PEI_FV_HANDLE TempFileHandles[FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)]; - EFI_GUID FileGuid[FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)]; - EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; - EFI_FV_FILE_INFO FileInfo; - + 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[0] = NULL; - Guid = NULL; - FileHandle = NULL; + AprioriFileHandle = NULL; + Private->CurrentFvFileHandles = NULL; + Guid = NULL; // - // If the current Fv has been scanned, directly get its cachable record. + // If the current FV has been scanned, directly get its cached records. // - if (Private->Fv[Private->CurrentPeimFvCount].ScanFv) { - CopyMem (Private->CurrentFvFileHandles, Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, sizeof (Private->CurrentFvFileHandles)); + if (CoreFileHandle->ScanFv) { + Private->CurrentFvFileHandles = CoreFileHandle->FvFileHandles; return; } + TempFileHandles = Private->TempFileHandles; + TempFileGuid = Private->TempFileGuid; + // - // Go ahead to scan this Fv, and cache FileHandles within it. + // Go ahead to scan this FV, get PeimCount and cache FileHandles within it to TempFileHandles. // - for (PeimCount = 0; PeimCount < FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv); PeimCount++) { + PeimCount = 0; + FileHandle = NULL; + do { Status = FvPpi->FindFileByType (FvPpi, PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE, CoreFileHandle->FvHandle, &FileHandle); - if (Status != EFI_SUCCESS) { - break; + 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)); - Private->CurrentFvFileHandles[PeimCount] = FileHandle; + DEBUG (( + DEBUG_INFO, + "%a(): Found 0x%x PEI FFS files in the %dth FV\n", + __FUNCTION__, + PeimCount, + Private->CurrentPeimFvCount + )); + + if (PeimCount == 0) { + // + // No PEIM FFS file is found, set ScanFv flag and return. + // + CoreFileHandle->ScanFv = TRUE; + return; } - + // - // Check whether the count of Peims exceeds the max support PEIMs in a FV image - // If more Peims are required in a FV image, PcdPeiCoreMaxPeimPerFv can be set to a larger value in DSC file. + // Record PeimCount, allocate buffer for PeimState and FvFileHandles. // - ASSERT (PeimCount < FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)); + 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) { + 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); + Status = FvPpi->FindSectionByType (FvPpi, EFI_SECTION_RAW, AprioriFileHandle, (VOID **)&Apriori); if (!EFI_ERROR (Status)) { // - // Calculate the number of PEIMs in the A Priori list + // Calculate the number of PEIMs in the Apriori file // Status = FvPpi->GetFileInfo (FvPpi, AprioriFileHandle, &FileInfo); ASSERT_EFI_ERROR (Status); - Private->AprioriCount = FileInfo.BufferSize & 0x00FFFFFF; - Private->AprioriCount -= sizeof (EFI_COMMON_SECTION_HEADER); + 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); - ZeroMem (FileGuid, sizeof (FileGuid)); for (Index = 0; Index < PeimCount; Index++) { // - // Make an array of file name guids that matches the FileHandle array so we can convert + // 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, Private->CurrentFvFileHandles[Index], &FileInfo); - CopyMem (&FileGuid[Index], &FileInfo.FileName, sizeof(EFI_GUID)); + Status = FvPpi->GetFileInfo (FvPpi, TempFileHandles[Index], &FileInfo); + ASSERT_EFI_ERROR (Status); + CopyMem (&TempFileGuid[Index], &FileInfo.FileName, sizeof (EFI_GUID)); } // - // Walk through FileGuid array to find out who is invalid PEIM guid in Apriori file. - // Add avalible PEIMs in Apriori file into TempFileHandles array at first. + // Walk through TempFileGuid array to find out who is invalid PEIM GUID in Apriori file. + // Add available PEIMs in Apriori file into FvFileHandles array. // - Index2 = 0; - for (Index = 0; Index2 < Private->AprioriCount; Index++) { - while (Index2 < Private->AprioriCount) { - Guid = ScanGuid (FileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2++]); - if (Guid != NULL) { - break; - } - } - if (Guid == NULL) { - break; - } - PeimIndex = ((UINTN)Guid - (UINTN)&FileGuid[0])/sizeof (EFI_GUID); - TempFileHandles[Index] = Private->CurrentFvFileHandles[PeimIndex]; + 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. - // - Private->CurrentFvFileHandles[PeimIndex] = NULL; + // + // Since we have copied the file handle we can remove it from this list. + // + TempFileHandles[PeimIndex] = NULL; + } } // - // Update valid Aprioricount + // Update valid AprioriCount // Private->AprioriCount = Index; // // Add in any PEIMs not in the Apriori file // - for (;Index < PeimCount; Index++) { - for (Index2 = 0; Index2 < PeimCount; Index2++) { - if (Private->CurrentFvFileHandles[Index2] != NULL) { - TempFileHandles[Index] = Private->CurrentFvFileHandles[Index2]; - Private->CurrentFvFileHandles[Index2] = NULL; - break; - } + for (Index2 = 0; Index2 < PeimCount; Index2++) { + if (TempFileHandles[Index2] != NULL) { + CoreFileHandle->FvFileHandles[Index++] = TempFileHandles[Index2]; + TempFileHandles[Index2] = NULL; } } - // - //Index the end of array contains re-range Pei moudle. - // - TempFileHandles[Index] = NULL; - // - // Private->CurrentFvFileHandles is currently in PEIM in the FV order. - // We need to update it to start with files in the A Priori list and - // then the remaining files in PEIM order. - // - CopyMem (Private->CurrentFvFileHandles, TempFileHandles, sizeof (Private->CurrentFvFileHandles)); + ASSERT (Index == PeimCount); } + } else { + CopyMem (CoreFileHandle->FvFileHandles, TempFileHandles, sizeof (EFI_PEI_FILE_HANDLE) * PeimCount); } + // - // Cache the current Fv File Handle. So that we don't have to scan the Fv again. - // Instead, we can retrieve the file handles within this Fv from cachable data. + // 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. // - Private->Fv[Private->CurrentPeimFvCount].ScanFv = TRUE; - CopyMem (Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, Private->CurrentFvFileHandles, sizeof (Private->CurrentFvFileHandles)); - + 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 + /** - Shadow PeiCore module from flash to installed memory. - - @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. - @param PrivateInMem PeiCore's private data structure + 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. - @return PeiCore function address after shadowing. + @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 **/ -VOID* -ShadowPeiCore( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN PEI_CORE_INSTANCE *PrivateInMem +BOOLEAN +PeiLoadFixAddressIsMemoryRangeAvailable ( + IN PEI_CORE_INSTANCE *PrivateData, + IN EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob ) { - EFI_PEI_FILE_HANDLE PeiCoreFileHandle; - EFI_PHYSICAL_ADDRESS EntryPoint; - EFI_STATUS Status; - UINT32 AuthenticationState; - - PeiCoreFileHandle = NULL; + EFI_HOB_MEMORY_ALLOCATION *MemoryHob; + BOOLEAN IsAvailable; + EFI_PEI_HOB_POINTERS Hob; - // - // Find the PEI Core in the BFV - // - Status = PrivateInMem->Fv[0].FvPpi->FindFileByType ( - PrivateInMem->Fv[0].FvPpi, - EFI_FV_FILETYPE_PEI_CORE, - PrivateInMem->Fv[0].FvHandle, - &PeiCoreFileHandle - ); - ASSERT_EFI_ERROR (Status); + IsAvailable = TRUE; + if ((PrivateData == NULL) || (ResourceHob == NULL)) { + return FALSE; + } // - // Shadow PEI Core into memory so it will run faster + // test if the memory range describe in the HOB is already allocated. // - Status = PeiLoadImage ( - PeiServices, - *((EFI_PEI_FILE_HANDLE*)&PeiCoreFileHandle), - PEIM_STATE_REGISITER_FOR_SHADOW, - &EntryPoint, - &AuthenticationState - ); - ASSERT_EFI_ERROR (Status); + 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; + } + } + } - // - // Compute the PeiCore's function address after shaowed PeiCore. - // _ModuleEntryPoint is PeiCore main function entry - // - return (VOID*) ((UINTN) EntryPoint + (UINTN) PeiCore - (UINTN) _ModuleEntryPoint); + return IsAvailable; } -// -// 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 + /** 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 functino is to find the top address which is TOLM-TSEG in general. - And also the function will re-install PEI memory. + 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 +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_PHYSICAL_ADDRESS MaxMemoryBaseAddress; - UINT64 MaxMemoryLength; + 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; - MaxMemoryBaseAddress = 0; - MaxMemoryLength = 0; - HighAddress = 0; - TopLoadingAddress = 0; - MemoryRangeEnd = 0; - CurrentHob.Raw = PrivateData->HobList.Raw; - PeiMemorySize = PrivateData->PhysicalMemoryLength; + 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)) ; + // + 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 ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber))); - DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber))); - DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= 0x%x.\n", PcdGet32(PcdLoadFixAddressPeiCodePageNumber))); - DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = 0x%lx.\n", TotalReservedMemorySize)); + + 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 + // 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 + 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; + ResourceHob = Hob.ResourceDescriptor; // - // If range described in this hob is not system memory or heigher than MAX_ADDRESS, ignored. + // 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) { + 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){ + } + + 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)){ - + // + 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); // - // See if the memory range described in ResourceHob and NextResourceHob is adjacent + // Delete the NextResourceHob by marking it as unused. // - 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; - - } - } - } + 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; + EDKII_MIGRATED_FV_INFO MigratedFvInfo; + + ASSERT (Private->PeiMemoryInstalled); + + DEBUG ((DEBUG_VERBOSE, "Beginning evacuation of content in temporary RAM.\n")); + // - // 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 ((EFI_D_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 ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid since top address should be page align. \n", TopLoadingAddress)); - ASSERT (FALSE); + // 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; } - // - // 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)) { + } + + Status = EFI_SUCCESS; + + ConvertPeiCorePpiPointers (Private, &PeiCoreFvHandle); + + 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) + ) + ) + { // - // See if this is a resource descriptor HOB + // Allocate page to save the rebased PEIMs, the PEIMs will get dispatched later. // - if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength), + &FvHeaderAddress + ); + ASSERT_EFI_ERROR (Status); + MigratedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress; - ResourceHob = Hob.ResourceDescriptor; - // - // See if this resource descrior 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) { - CurrentResourceHob = ResourceHob; - CurrentHob = Hob; - break; - } - } - } - } - if (CurrentResourceHob != NULL) { - DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO:Top Address 0x%lx is valid \n", TopLoadingAddress)); - TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE; - } else { - DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address 0x%lx is invalid \n", TopLoadingAddress)); - DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n")); - // - // Print the recomended 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 descrior 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) { - DEBUG ((EFI_D_INFO, "(0x%lx, 0x%lx)\n", - (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE), - (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE) - )); - } - } - } - } // - // Assert here + // Allocate pool to save the raw PEIMs, which is used to keep consistent context across + // multiple boot and PCR0 will keep the same no matter if the address of allocated page is changed. // - ASSERT (FALSE); - } - } 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)) { + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + EFI_SIZE_TO_PAGES ((UINTN)FvHeader->FvLength), + &FvHeaderAddress + ); + ASSERT_EFI_ERROR (Status); + RawDataFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvHeaderAddress; + + DEBUG (( + DEBUG_VERBOSE, + " Migrating FV[%d] from 0x%08X to 0x%08X\n", + FvIndex, + (UINTN)FvHeader, + (UINTN)MigratedFvHeader + )); + // - // See if this is a resource descriptor HOB + // Copy the context to the rebased pages and raw pages, and create hob to save the + // information. The MigratedFvInfo HOB will never be produced when + // PcdMigrateTemporaryRamFirmwareVolumes is FALSE, because the PCD control the + // feature. // - if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { - - ResourceHob = Hob.ResourceDescriptor; - // - // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS - // - if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && - ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS && - ResourceHob->ResourceLength > TotalReservedMemorySize) { - // - // 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 ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n")); + CopyMem (MigratedFvHeader, FvHeader, (UINTN)FvHeader->FvLength); + CopyMem (RawDataFvHeader, MigratedFvHeader, (UINTN)FvHeader->FvLength); + MigratedFvInfo.FvOrgBase = (UINT32)(UINTN)FvHeader; + MigratedFvInfo.FvNewBase = (UINT32)(UINTN)MigratedFvHeader; + MigratedFvInfo.FvDataBase = (UINT32)(UINTN)RawDataFvHeader; + MigratedFvInfo.FvLength = (UINT32)(UINTN)FvHeader->FvLength; + BuildGuidDataHob (&gEdkiiMigratedFvInfoGuid, &MigratedFvInfo, sizeof (MigratedFvInfo)); + // - // Assert here + // Migrate any children for this FV now // - ASSERT (FALSE); - } else { - TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength ; - } - } - - if (CurrentResourceHob != NULL) { - // - // rebuild hob for PEI memmory and reserved memory - // - BuildResourceDescriptorHob ( - EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType, - ( - 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), // MemoryBegin - TotalReservedMemorySize // MemoryLength - ); - // - // rebuild hob for the remain memory if necessary - // - if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) { - BuildResourceDescriptorHob ( - EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType, - ( - 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, // MemoryBegin - (TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart) // MemoryLength - ); - } - 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) - ); + 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); } - // - // Delete CurrentHob by marking it as unused since the 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 ((EFI_D_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; + RemoveFvHobsInTemporaryMemory (Private); + + return Status; } + /** Conduct PEIM dispatch. @@ -568,87 +1350,79 @@ PeiDispatcher ( 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; - PEIM_FILE_HANDLE_EXTENDED_DATA ExtendedData; - EFI_PHYSICAL_ADDRESS NewPermenentMemoryBase; - TEMPORARY_RAM_SUPPORT_PPI *TemporaryRamSupportPpi; - EFI_HOB_HANDOFF_INFO_TABLE *OldHandOffTable; - EFI_HOB_HANDOFF_INFO_TABLE *NewHandOffTable; - INTN StackOffset; - INTN HeapOffset; - PEI_CORE_INSTANCE *PrivateInMem; - UINT64 NewPeiStackSize; - UINT64 OldPeiStackSize; - UINT64 StackGap; - EFI_FV_FILE_INFO FvFileInfo; - UINTN OldCheckingTop; - UINTN OldCheckingBottom; - PEI_CORE_FV_HANDLE *CoreFvHandle; - VOID *LoadFixPeiCodeBegin; - - PeiServices = (CONST EFI_PEI_SERVICES **) &Private->Ps; + 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) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { + 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_REGISITER_FOR_SHADOW to PEIM_STATE_DONE. + // 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 <= SaveCurrentFvCount; Index1++) { - for (Index2 = 0; (Index2 < FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->Fv[Index1].FvFileHandles[Index2] != NULL); Index2++) { - if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISITER_FOR_SHADOW) { - PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2]; - Status = PeiLoadImage ( - (CONST EFI_PEI_SERVICES **) &Private->Ps, - PeimFileHandle, - PEIM_STATE_REGISITER_FOR_SHADOW, - &EntryPoint, - &AuthenticationState - ); + 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_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE + // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE // Private->Fv[Index1].PeimState[Index2]++; - Private->CurrentFileHandle = PeimFileHandle; - Private->CurrentPeimFvCount = Index1; - Private->CurrentPeimCount = Index2; // // Call the PEIM entry point // PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint; - PERF_START (PeimFileHandle, "PEIM", NULL, 0); - PeimEntryPoint(PeimFileHandle, (const EFI_PEI_SERVICES **) &Private->Ps); - PERF_END (PeimFileHandle, "PEIM", NULL, 0); + 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. // - ProcessNotifyList (Private); + ProcessDispatchNotifyList (Private); } } } + Private->CurrentFileHandle = SaveCurrentFileHandle; Private->CurrentPeimFvCount = SaveCurrentFvCount; Private->CurrentPeimCount = SaveCurrentPeimCount; @@ -657,33 +1431,33 @@ PeiDispatcher ( // // 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 + // 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 dipatcher should run only once. + // satisfied, this dispatcher should run only once. // do { // - // In case that reenter PeiCore happens, the last pass record is still available. + // In case that reenter PeiCore happens, the last pass record is still available. // if (!Private->PeimDispatcherReenter) { - Private->PeimNeedingDispatch = FALSE; - Private->PeimDispatchOnThisPass = FALSE; + Private->PeimNeedingDispatch = FALSE; + Private->PeimDispatchOnThisPass = FALSE; } else { - Private->PeimDispatcherReenter = FALSE; + 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) { @@ -696,13 +1470,14 @@ PeiDispatcher ( } // - // Start to dispatch all modules within the current Fv. + // Start to dispatch all modules within the current FV. // for (PeimCount = Private->CurrentPeimCount; - (PeimCount < FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->CurrentFvFileHandles[PeimCount] != NULL); - PeimCount++) { - Private->CurrentPeimCount = PeimCount; - PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount]; + 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)) { @@ -712,10 +1487,23 @@ PeiDispatcher ( ASSERT_EFI_ERROR (Status); if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { // - // For Fv type file, Produce new FV PPI and FV hob + // For FV type file, Produce new FvInfo PPI and FV HOB // - Status = ProcessFvFile (&Private->Fv[FvCount], PeimFileHandle); - AuthenticationState = 0; + 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 @@ -727,276 +1515,101 @@ PeiDispatcher ( &EntryPoint, &AuthenticationState ); - } - - if ((Status == EFI_SUCCESS)) { - // - // The PEIM has its dependencies satisfied, and its entry point - // has been found, so invoke it. - // - PERF_START (PeimFileHandle, "PEIM", NULL, 0); - - ExtendedData.Handle = (EFI_HANDLE)PeimFileHandle; - - REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( - EFI_PROGRESS_CODE, - (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN), - (VOID *)(&ExtendedData), - sizeof (ExtendedData) - ); - - Status = VerifyPeim (Private, CoreFvHandle->FvHandle, PeimFileHandle); - if (Status != EFI_SECURITY_VIOLATION && (AuthenticationState == 0)) { + if (Status == EFI_SUCCESS) { // - // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED + // The PEIM has its dependencies satisfied, and its entry point + // has been found, so invoke it. // - Private->Fv[FvCount].PeimState[PeimCount]++; + PERF_START_IMAGE_BEGIN (PeimFileHandle); - if (FvFileInfo.FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) { + 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); + 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; } - Private->PeimDispatchOnThisPass = 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); } - - REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( - EFI_PROGRESS_CODE, - (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN), - (VOID *)(&ExtendedData), - sizeof (ExtendedData) - ); - PERF_END (PeimFileHandle, "PEIM", NULL, 0); - } - if (Private->SwitchStackSignal) { - // - // Before switch stack from temporary memory to permenent memory, caculate the heap and stack - // usage in temporary memory for debuging. - // - DEBUG_CODE_BEGIN (); - UINT32 *StackPointer; - - for (StackPointer = (UINT32*)SecCoreData->StackBase; - (StackPointer < (UINT32*)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \ - && (*StackPointer == INIT_CAR_VALUE); - StackPointer ++); - - DEBUG ((EFI_D_INFO, "Total temporary memory: %d bytes.\n", (UINT32)SecCoreData->TemporaryRamSize)); - DEBUG ((EFI_D_INFO, " temporary memory stack ever used: %d bytes.\n", - (SecCoreData->StackSize - ((UINTN) StackPointer - (UINTN)SecCoreData->StackBase)) - )); - DEBUG ((EFI_D_INFO, " temporary memory heap used: %d bytes.\n", - ((UINTN) Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom - - (UINTN) Private->HobList.Raw) - )); - DEBUG_CODE_END (); - - if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { - // - // Loading Module at Fixed Address is enabled - // - PeiLoadFixAddressHook(Private); - // - // if Loading Module at Fixed Address is enabled, This is the first invoke to page - // allocation for Pei Code range. This memory range should be reserved for loading PEIMs - // - LoadFixPeiCodeBegin = AllocatePages((UINTN)PcdGet32(PcdLoadFixAddressPeiCodePageNumber)); - DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = 0x%lX, PeiCodeTop= 0x%lX\n", (UINT64)LoadFixPeiCodeBegin, (UINT64)((UINTN)LoadFixPeiCodeBegin + PcdGet32(PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE))); - } - - // - // Reserve the size of new stack at bottom of physical memory - // - OldPeiStackSize = (UINT64) SecCoreData->StackSize; - NewPeiStackSize = (RShiftU64 (Private->PhysicalMemoryLength, 1) + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; - if (PcdGet32(PcdPeiCoreMaxPeiStackSize) > (UINT32) NewPeiStackSize) { - Private->StackSize = NewPeiStackSize; - } else { - Private->StackSize = PcdGet32(PcdPeiCoreMaxPeiStackSize); - } - - // - // In theory, the size of new stack in permenent memory should large than - // 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 permenent memory. - // - DEBUG ((EFI_D_INFO, "Old Stack size %d, New stack size %d\n", (INT32) OldPeiStackSize, (INT32) Private->StackSize)); - ASSERT (Private->StackSize >= OldPeiStackSize); - StackGap = Private->StackSize - OldPeiStackSize; - - // - // Update HandOffHob for new installed permenent memory - // - OldHandOffTable = Private->HobList.HandoffInformationTable; - OldCheckingBottom = (UINTN)(SecCoreData->TemporaryRamBase); - OldCheckingTop = (UINTN)(OldCheckingBottom + SecCoreData->TemporaryRamSize); - - // - // The whole temporary memory will be migrated to physical memory. - // CAUTION: The new base is computed accounding to gap of new stack. - // - NewPermenentMemoryBase = Private->PhysicalMemoryBegin + StackGap; - - // - // Caculate stack offset and heap offset between temporary memory and new permement - // memory seperately. - // - StackOffset = (UINTN) NewPermenentMemoryBase - (UINTN) SecCoreData->StackBase; - HeapOffset = (INTN) ((UINTN) Private->PhysicalMemoryBegin + Private->StackSize - \ - (UINTN) SecCoreData->PeiTemporaryRamBase); - DEBUG ((EFI_D_INFO, "Heap Offset = 0x%lX Stack Offset = 0x%lX\n", (INT64)HeapOffset, (INT64)StackOffset)); - - // - // Caculate new HandOffTable and PrivateData address in permenet memory's stack - // - NewHandOffTable = (EFI_HOB_HANDOFF_INFO_TABLE *)((UINTN)OldHandOffTable + HeapOffset); - PrivateInMem = (PEI_CORE_INSTANCE *)((UINTN) (VOID*) Private + StackOffset); - - // - // TemporaryRamSupportPpi is produced by platform's SEC - // - Status = PeiLocatePpi ( - (CONST EFI_PEI_SERVICES **) PeiServices, - &gEfiTemporaryRamSupportPpiGuid, - 0, - NULL, - (VOID**)&TemporaryRamSupportPpi - ); - - - if (!EFI_ERROR (Status)) { - // - // Temporary Ram support Ppi is provided by platform, it will copy - // temporary memory to permenent memory and do stack switching. - // After invoken temporary Ram support, following code's stack is in - // memory but not in temporary memory. - // - TemporaryRamSupportPpi->TemporaryRamMigration ( - (CONST EFI_PEI_SERVICES **) PeiServices, - (EFI_PHYSICAL_ADDRESS)(UINTN) SecCoreData->TemporaryRamBase, - (EFI_PHYSICAL_ADDRESS)(UINTN) NewPermenentMemoryBase, - SecCoreData->TemporaryRamSize - ); - - } else { - // - // In IA32/x64/Itanium architecture, we need platform provide - // TEMPORAY_RAM_MIGRATION_PPI. - // - ASSERT (FALSE); - } - - - // - // - // Fixup the PeiCore's private data - // - PrivateInMem->Ps = &PrivateInMem->ServiceTableShadow; - PrivateInMem->CpuIo = &PrivateInMem->ServiceTableShadow.CpuIo; - PrivateInMem->HobList.Raw = (VOID*) ((UINTN) PrivateInMem->HobList.Raw + HeapOffset); - PrivateInMem->StackBase = (EFI_PHYSICAL_ADDRESS)(((UINTN)PrivateInMem->PhysicalMemoryBegin + EFI_PAGE_MASK) & ~EFI_PAGE_MASK); - - PeiServices = (CONST EFI_PEI_SERVICES **) &PrivateInMem->Ps; - - // - // Fixup for PeiService's address - // - SetPeiServicesTablePointer(PeiServices); - - // - // Update HandOffHob for new installed permenent memory - // - NewHandOffTable->EfiEndOfHobList = - (EFI_PHYSICAL_ADDRESS)((UINTN) NewHandOffTable->EfiEndOfHobList + HeapOffset); - NewHandOffTable->EfiMemoryTop = PrivateInMem->PhysicalMemoryBegin + - PrivateInMem->PhysicalMemoryLength; - NewHandOffTable->EfiMemoryBottom = PrivateInMem->PhysicalMemoryBegin; - NewHandOffTable->EfiFreeMemoryTop = PrivateInMem->FreePhysicalMemoryTop; - NewHandOffTable->EfiFreeMemoryBottom = NewHandOffTable->EfiEndOfHobList + - sizeof (EFI_HOB_GENERIC_HEADER); - - // - // We need convert the PPI desciptor's pointer - // - ConvertPpiPointers (PrivateInMem, - OldCheckingBottom, - OldCheckingTop, - HeapOffset - ); - - DEBUG ((EFI_D_INFO, "Stack Hob: BaseAddress=0x%lX Length=0x%lX\n", - PrivateInMem->StackBase, - PrivateInMem->StackSize)); - BuildStackHob (PrivateInMem->StackBase, PrivateInMem->StackSize); - - // - // After the whole temporary memory is migrated, then we can allocate page in - // permenent memory. - // - PrivateInMem->PeiMemoryInstalled = TRUE; - - // - // Indicate that PeiCore reenter - // - PrivateInMem->PeimDispatcherReenter = TRUE; - - if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { - // - // if Loading Module at Fixed Address is enabled, allocate the PEI code memory range usage bit map array. - // Every bit in the array indicate the status of the corresponding memory page available or not - // - PrivateInMem->PeiCodeMemoryRangeUsageBitMap = AllocateZeroPool (((PcdGet32(PcdLoadFixAddressPeiCodePageNumber)>>6) + 1)*sizeof(UINT64)); - } - // - // Shadow PEI Core. When permanent memory is avaiable, shadow - // PEI Core and PEIMs to get high performance. - // - PrivateInMem->ShadowedPeiCore = ShadowPeiCore ( - PeiServices, - PrivateInMem - ); - // - // Process the Notify list and dispatch any notifies for - // newly installed PPIs. - // - ProcessNotifyList (PrivateInMem); - - // - // Entry PEI Phase 2 - // - PeiCore (SecCoreData, NULL, PrivateInMem); - - // - // Code should not come here - // - ASSERT_EFI_ERROR(FALSE); - } + PeiCheckAndSwitchStack (SecCoreData, Private); // // Process the Notify list and dispatch any notifies for // newly installed PPIs. // - ProcessNotifyList (Private); + ProcessDispatchNotifyList (Private); - if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISITER_FOR_SHADOW) && \ - (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { + // + // 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 availble we shadow images by default for performance reasons. + // 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); + // 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); + PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **)PeiServices); + // PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0); // - // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE + // PEIM_STATE_REGISTER_FOR_SHADOW move to PEIM_STATE_DONE // Private->Fv[FvCount].PeimState[PeimCount]++; @@ -1004,41 +1617,36 @@ PeiDispatcher ( // Process the Notify list and dispatch any notifies for // newly installed PPIs. // - ProcessNotifyList (Private); + ProcessDispatchNotifyList (Private); } } } } // - // We set to NULL here to optimize the 2nd entry to this routine after - // memory is found. This reprevents rescanning of the FV. We set to - // NULL here so we start at the begining of the next FV - // - Private->CurrentFileHandle = NULL; - Private->CurrentPeimCount = 0; + // Before walking through the next FV, we should set them to NULL/0 to + // start at the beginning of the next FV. // - // Before walking through the next FV,Private->CurrentFvFileHandles[]should set to NULL - // - SetMem (Private->CurrentFvFileHandles, sizeof (Private->CurrentFvFileHandles), 0); + Private->CurrentFileHandle = NULL; + Private->CurrentPeimCount = 0; + Private->CurrentFvFileHandles = NULL; } // - // Before making another pass, we should set Private->CurrentPeimFvCount =0 to go - // through all the FV. + // 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 that did not get + // 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 on this - // pass. If we did not dispatch a PEIM there is no point in trying again + // 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); - } /** @@ -1046,7 +1654,7 @@ PeiDispatcher ( @param PrivateData PeiCore's private data structure @param OldCoreData Old data from SecCore - NULL if being run in non-permament memory mode. + 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. @@ -1056,9 +1664,9 @@ PeiDispatcher ( **/ VOID InitializeDispatcherData ( - IN PEI_CORE_INSTANCE *PrivateData, - IN PEI_CORE_INSTANCE *OldCoreData, - IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData + IN PEI_CORE_INSTANCE *PrivateData, + IN PEI_CORE_INSTANCE *OldCoreData, + IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData ) { if (OldCoreData == NULL) { @@ -1086,18 +1694,27 @@ InitializeDispatcherData ( **/ BOOLEAN DepexSatisfied ( - IN PEI_CORE_INSTANCE *Private, - IN EFI_PEI_FILE_HANDLE FileHandle, - IN UINTN PeimCount + IN PEI_CORE_INSTANCE *Private, + IN EFI_PEI_FILE_HANDLE FileHandle, + IN UINTN PeimCount ) { - EFI_STATUS Status; - VOID *DepexData; + 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 its in the A priori file then we set Depex to TRUE + // If it's in the Apriori file then we set DEPEX to TRUE // + DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n")); return TRUE; } @@ -1105,15 +1722,16 @@ DepexSatisfied ( // Depex section not in the encapsulated section. // Status = PeiServicesFfsFindSectionData ( - EFI_SECTION_PEI_DEPEX, - FileHandle, - (VOID **)&DepexData - ); + 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; } @@ -1124,8 +1742,8 @@ DepexSatisfied ( } /** - This routine enable a PEIM to register itself to shadow when PEI Foundation - discovery permanent memory. + This routine enables a PEIM to register itself for shadow when the PEI Foundation + discovers permanent memory. @param FileHandle File handle of a PEIM. @@ -1137,10 +1755,11 @@ DepexSatisfied ( EFI_STATUS EFIAPI PeiRegisterForShadow ( - IN EFI_PEI_FILE_HANDLE FileHandle + IN EFI_PEI_FILE_HANDLE FileHandle ) { - PEI_CORE_INSTANCE *Private; + PEI_CORE_INSTANCE *Private; + Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); if (Private->CurrentFileHandle != FileHandle) { @@ -1150,17 +1769,14 @@ PeiRegisterForShadow ( return EFI_NOT_FOUND; } - if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISITER_FOR_SHADOW) { + 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_REGISITER_FOR_SHADOW; + Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISTER_FOR_SHADOW; return EFI_SUCCESS; } - - -