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
This commit is contained in:
jchen20
2010-02-05 07:54:16 +00:00
parent f3198cba84
commit 54ea99a798
12 changed files with 972 additions and 61 deletions

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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;
///

View File

@@ -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