summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Core/Pei
diff options
context:
space:
mode:
authorjchen20 <jchen20@6f19259b-4bc3-4df7-8a09-765794883524>2010-02-05 07:54:16 +0000
committerjchen20 <jchen20@6f19259b-4bc3-4df7-8a09-765794883524>2010-02-05 07:54:16 +0000
commit54ea99a798f7d714b59503fcc21ee97878bc6492 (patch)
treedfbab215685cc880a8e46833f2369c24d9e7d28a /MdeModulePkg/Core/Pei
parentf3198cba84f56f85281b87c4e9bf96e77a934f16 (diff)
downloadedk2-platforms-54ea99a798f7d714b59503fcc21ee97878bc6492.tar.xz
Enable the Load Module At fixed Address feature
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9937 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Core/Pei')
-rw-r--r--MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c340
-rw-r--r--MdeModulePkg/Core/Pei/Image/Image.c256
-rw-r--r--MdeModulePkg/Core/Pei/PeiMain.h12
-rw-r--r--MdeModulePkg/Core/Pei/PeiMain.inf10
4 files changed, 585 insertions, 33 deletions
diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
index bdbb00b205..bceae0c62d 100644
--- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
+++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
@@ -233,7 +233,326 @@ ShadowPeiCore(
//
return (VOID*) ((UINTN) EntryPoint + (UINTN) PeiCore - (UINTN) _ModuleEntryPoint);
}
+//
+// 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.
+ @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_PHYSICAL_ADDRESS MaxMemoryBaseAddress;
+ UINT64 MaxMemoryLength;
+ //
+ // 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;
+ //
+ // 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 = EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber)+ PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber))
+ + MINIMUM_INITIAL_MEMORY_SIZE;
+
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= %x.\n", PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber)));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= %x.\n", PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= %x.\n", PcdGet32(PcdLoadFixAddressPeiCodePageNumber)));
+ //
+ // PEI memory range lies below the top reserved memory
+ //
+ TotalReservedMemorySize += PeiMemorySize;
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = %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 heigher 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;
+
+ }
+ }
+ }
+ }
+ }
+ }
+ //
+ // Try to find and validate the TOP address.
+ //
+ if ((INT64)FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) > 0 ) {
+ //
+ // The LMFA feature is enabled as load module at fixed absolute address.
+ //
+ TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)FixedPcdGet64(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 %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 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 %lx is valid \n", TopLoadingAddress));
+ TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE;
+ } else {
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address %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, "(%lx, %lx)\n",
+ (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE),
+ (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE)
+ ));
+ }
+ }
+ }
+ }
+ //
+ // Assert here
+ //
+ 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)) {
+ //
+ // 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 &&
+ 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"));
+ //
+ // Assert here
+ //
+ 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)
+ );
+ }
+ //
+ // 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 = %lx\n", PrivateData->LoadModuleAtFixAddressTopAddress));
+ //
+ // reinstall the PEI memory relative to TopLoadingAddress
+ //
+ PrivateData->PhysicalMemoryBegin = TopLoadingAddress - TotalReservedMemorySize;
+ PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize;
+}
/**
Conduct PEIM dispatch.
@@ -277,6 +596,7 @@ PeiDispatcher (
UINTN OldCheckingTop;
UINTN OldCheckingBottom;
PEI_CORE_FV_HANDLE *CoreFvHandle;
+ VOID *LoadFixPeiCodeBegin;
PeiServices = (CONST EFI_PEI_SERVICES **) &Private->PS;
PeimEntryPoint = NULL;
@@ -476,6 +796,13 @@ PeiDispatcher (
));
DEBUG_CODE_END ();
+ if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ //
+ // Loading Module at Fixed Address is enabled
+ //
+ PeiLoadFixAddressHook(Private);
+ }
+
//
// Reserve the size of new stack at bottom of physical memory
//
@@ -613,6 +940,19 @@ PeiDispatcher (
//
PrivateInMem->PeimDispatcherReenter = TRUE;
+ if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ //
+ // if Loading Module at Fixed Address is enabled, This is the first invoke to page
+ // allocation for Pei Core segment. This memory segment should be reserved for loading PEIM
+ //
+ LoadFixPeiCodeBegin = AllocatePages((UINTN)PcdGet32(PcdLoadFixAddressPeiCodePageNumber));
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = %x, PeiCodeTop= %x\n", (UINTN)LoadFixPeiCodeBegin, ((UINTN)LoadFixPeiCodeBegin) + PcdGet32(PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE));
+ //
+ // 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.
diff --git a/MdeModulePkg/Core/Pei/Image/Image.c b/MdeModulePkg/Core/Pei/Image/Image.c
index 63c8868894..c2683762b7 100644
--- a/MdeModulePkg/Core/Pei/Image/Image.c
+++ b/MdeModulePkg/Core/Pei/Image/Image.c
@@ -1,14 +1,14 @@
/** @file
Pei Core Load Image Support
-
-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 - 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.
**/
@@ -96,7 +96,192 @@ GetImageReadFunction (
return EFI_SUCCESS;
}
+/**
+ To check memory usage bit map arry to figure out if the memory range the image will be loaded in is available or not. If
+ memory range is avaliable, the function will mark the correponding bits to 1 which indicates the memory range is used.
+ The function is only invoked when load modules at fixed address feature is enabled.
+
+ @param Private Pointer to the private data passed in from caller
+ @param ImageBase The base addres the image will be loaded at.
+ @param ImageSize The size of the image
+
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
+**/
+EFI_STATUS
+CheckAndMarkFixLoadingMemoryUsageBitMap (
+ IN PEI_CORE_INSTANCE *Private,
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINT32 ImageSize
+ )
+{
+ UINT32 DxeCodePageNumber;
+ UINT64 ReservedCodeSize;
+ EFI_PHYSICAL_ADDRESS PeiCodeBase;
+ UINT32 BaseOffsetPageNumber;
+ UINT32 TopOffsetPageNumber;
+ UINT32 Index;
+ UINT64 *MemoryUsageBitMap;
+
+
+ //
+ // The reserved code range includes RuntimeCodePage range, Boot time code range and PEI code range.
+ //
+ DxeCodePageNumber = PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
+ DxeCodePageNumber += PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
+ ReservedCodeSize = EFI_PAGES_TO_SIZE(DxeCodePageNumber + PcdGet32(PcdLoadFixAddressPeiCodePageNumber));
+ PeiCodeBase = Private->LoadModuleAtFixAddressTopAddress - ReservedCodeSize;
+
+ //
+ // Test the memory range for loading the image in the PEI code range.
+ //
+ if ((Private->LoadModuleAtFixAddressTopAddress - EFI_PAGES_TO_SIZE(DxeCodePageNumber)) < (ImageBase + ImageSize) ||
+ (PeiCodeBase > ImageBase)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Test if the memory is avalaible or not.
+ //
+ MemoryUsageBitMap = Private->PeiCodeMemoryRangeUsageBitMap;
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - PeiCodeBase));
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - PeiCodeBase));
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ if ((MemoryUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {
+ //
+ // This page is already used.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Being here means the memory range is available. So mark the bits for the memory range
+ //
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
+ MemoryUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));
+ }
+ return EFI_SUCCESS;
+}
+/**
+
+ Get the fixed loadding address from image header assigned by build tool. This function only be called
+ when Loading module at Fixed address feature enabled.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+ @param Private Pointer to the private data passed in from caller
+
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
+ @retval EFI_NOT_FOUND The image has no assigned fixed loadding address.
+**/
+EFI_STATUS
+GetPeCoffImageFixLoadingAssignedAddress(
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN PEI_CORE_INSTANCE *Private
+ )
+{
+ UINTN SectionHeaderOffset;
+ EFI_STATUS Status;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_PHYSICAL_ADDRESS FixLoaddingAddress;
+ UINT16 Index;
+ UINTN Size;
+ UINT16 NumberOfSections;
+ UINT64 ValueInSectionHeader;
+
+
+ FixLoaddingAddress = 0;
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
+ if (ImageContext->IsTeImage) {
+ //
+ // for TE image, the fix loadding address is saved in first section header that doesn't point
+ // to code section.
+ //
+ SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);
+ NumberOfSections = ImgHdr->Te.NumberOfSections;
+ } else {
+ SectionHeaderOffset = (UINTN)(
+ ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
+ );
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
+ }
+ //
+ // Get base address from the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ //
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
+ // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is
+ // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because
+ // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers
+ // hold the image base address when it is shadow to the memory. And there is an assumption that when the feature is enabled, if a
+ // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or
+ // else, these 2 fileds should be set to Zero
+ //
+ ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
+ if (ValueInSectionHeader != 0) {
+ //
+ // Found first section header that doesn't point to code section.
+ //
+ if ((INT64)FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) > 0) {
+ //
+ // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field
+ // hold the absolute address of image base runing in memory
+ //
+ FixLoaddingAddress = ValueInSectionHeader;
+ } else {
+ //
+ // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field
+ // hold the offset relative to a platform-specific top address.
+ //
+ FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);
+ }
+ //
+ // Check if the memory range is avaliable.
+ //
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoaddingAddress, (UINT32) ImageContext->ImageSize);
+ if (!EFI_ERROR(Status)) {
+ //
+ // The assigned address is valid. Return the specified loadding address
+ //
+ ImageContext->ImageAddress = FixLoaddingAddress;
+ }
+ }
+ break;
+ }
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %lx. Status= %r \n", FixLoaddingAddress, Status));
+ return Status;
+}
/**
Loads and relocates a PE/COFF image into memory.
@@ -139,29 +324,40 @@ LoadAndRelocatePeCoffImage (
// When Image has no reloc section, it can't be relocated into memory.
//
if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
- DEBUG ((EFI_D_INFO, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
}
//
// Set default base address to current image address.
//
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
-
+
//
// Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable.
//
if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
- ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
+ if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
+ Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);
+ if (EFI_ERROR (Status)){
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
+ //
+ // The PEIM is not assiged valid address, try to allocate page to load it.
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
+ }
+ } else {
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
+ }
ASSERT (ImageContext.ImageAddress != 0);
if (ImageContext.ImageAddress == 0) {
return EFI_OUT_OF_RESOURCES;
}
-
+
//
// Skip the reserved space for the stripped PeHeader when load TeImage into memory.
//
if (ImageContext.IsTeImage) {
- ImageContext.ImageAddress = ImageContext.ImageAddress +
+ ImageContext.ImageAddress = ImageContext.ImageAddress +
((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -
sizeof (EFI_TE_IMAGE_HEADER);
}
@@ -197,8 +393,8 @@ LoadAndRelocatePeCoffImage (
}
/**
- Loads a PEIM into memory for subsequent execution. If there are compressed
- images or images that need to be relocated into memory for performance reasons,
+ Loads a PEIM into memory for subsequent execution. If there are compressed
+ images or images that need to be relocated into memory for performance reasons,
this service performs that transformation.
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
@@ -245,7 +441,7 @@ PeiLoadImageLoadImage (
}
//
- // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
+ // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
// is true, TE will be searched first).
//
Status = PeiServicesFfsFindSectionData (
@@ -270,7 +466,7 @@ PeiLoadImageLoadImage (
return Status;
}
}
-
+
//
// If memory is installed, perform the shadow operations
//
@@ -293,9 +489,9 @@ PeiLoadImageLoadImage (
//
Pe32Data = (VOID *) ((UINTN) ImageAddress);
*EntryPoint = ImageEntryPoint;
-
+
Machine = PeCoffLoaderGetMachineType (Pe32Data);
-
+
if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
return EFI_UNSUPPORTED;
@@ -309,7 +505,7 @@ PeiLoadImageLoadImage (
if (ImageSizeArg != NULL) {
*ImageSizeArg = ImageSize;
}
-
+
DEBUG_CODE_BEGIN ();
CHAR8 *AsciiString;
CHAR8 AsciiBuffer[512];
@@ -327,12 +523,12 @@ PeiLoadImageLoadImage (
//
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
}
-
+
//
// Print Module Name by PeImage PDB file name.
//
AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
-
+
if (AsciiString != NULL) {
for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {
if (AsciiString[Index] == '\\') {
@@ -454,7 +650,7 @@ RelocationIsStrip (
/**
Routine to load image file for subsequent execution by LoadFile Ppi.
- If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
+ If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
XIP image format is used.
@param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
@@ -500,9 +696,9 @@ PeiLoadImage (
);
if (!EFI_ERROR (PpiStatus)) {
Status = LoadFile->LoadFile (
- LoadFile,
- FileHandle,
- &ImageAddress,
+ LoadFile,
+ FileHandle,
+ &ImageAddress,
&ImageSize,
EntryPoint,
AuthenticationState
@@ -560,10 +756,10 @@ InitializeImageServices (
PeiServicesInstallPpi (PrivateData->XipLoadFile);
} else {
//
- // 2nd time we are running from memory so replace the XIP version with the
- // new memory version.
+ // 2nd time we are running from memory so replace the XIP version with the
+ // new memory version.
//
- PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
+ PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
}
}
diff --git a/MdeModulePkg/Core/Pei/PeiMain.h b/MdeModulePkg/Core/Pei/PeiMain.h
index aa23cc57ed..268aedf454 100644
--- a/MdeModulePkg/Core/Pei/PeiMain.h
+++ b/MdeModulePkg/Core/Pei/PeiMain.h
@@ -177,6 +177,18 @@ typedef struct{
EFI_PHYSICAL_ADDRESS FreePhysicalMemoryTop;
VOID* ShadowedPeiCore;
CACHE_SECTION_DATA CacheSection;
+ //
+ // For Loading modules at fixed address feature to cache the top address below which the
+ // Runtime code, boot time code and PEI memory will be placed. Please note that the offset between this field
+ // and PS should not be changed since maybe user could get this top address by using the offet to PS.
+ //
+ EFI_PHYSICAL_ADDRESS LoadModuleAtFixAddressTopAddress;
+ //
+ // The field is define for Loading modules at fixed address feature to tracker the PEI code
+ // memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page
+ // available or not.
+ //
+ UINT64 *PeiCodeMemoryRangeUsageBitMap;
} PEI_CORE_INSTANCE;
///
diff --git a/MdeModulePkg/Core/Pei/PeiMain.inf b/MdeModulePkg/Core/Pei/PeiMain.inf
index b2747bbd7c..2b8c4ad8b9 100644
--- a/MdeModulePkg/Core/Pei/PeiMain.inf
+++ b/MdeModulePkg/Core/Pei/PeiMain.inf
@@ -85,12 +85,16 @@
gEfiTemporaryRamSupportPpiGuid ## CONSUMES
[FixedPcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeimPerFv ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPpiSupported ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeimPerFv ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPpiSupported ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressPeiCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES