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

@ -60,7 +60,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Guid/MemoryAllocationHob.h> #include <Guid/MemoryAllocationHob.h>
#include <Guid/EventLegacyBios.h> #include <Guid/EventLegacyBios.h>
#include <Guid/EventGroup.h> #include <Guid/EventGroup.h>
#include <Guid/LoadModuleAtFixedAddress.h>
#include <Library/DxeCoreEntryPoint.h> #include <Library/DxeCoreEntryPoint.h>
#include <Library/DebugLib.h> #include <Library/DebugLib.h>
@ -81,6 +81,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/TimerLib.h> #include <Library/TimerLib.h>
#include <Library/DxeServicesLib.h> #include <Library/DxeServicesLib.h>
// //
// attributes for reserved memory before it is promoted to system memory // attributes for reserved memory before it is promoted to system memory
// //
@ -204,6 +205,8 @@ extern EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMem
extern BOOLEAN gDispatcherRunning; extern BOOLEAN gDispatcherRunning;
extern EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate; extern EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate;
extern EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable;
extern BOOLEAN gLoadFixedAddressCodeMemoryReady;
// //
// Service Initialization Functions // Service Initialization Functions
// //

View File

@ -103,6 +103,7 @@
gEfiDxeServicesTableGuid ## CONSUMES ## GUID gEfiDxeServicesTableGuid ## CONSUMES ## GUID
gEfiMemoryTypeInformationGuid ## CONSUMES ## GUID gEfiMemoryTypeInformationGuid ## CONSUMES ## GUID
gEfiEventDxeDispatchGuid ## CONSUMES ## GUID gEfiEventDxeDispatchGuid ## CONSUMES ## GUID
gLoadFixedAddressConfigurationTableGuid ## SOMETIMES_CONSUMES
[Protocols] [Protocols]
@ -138,3 +139,10 @@
[FeaturePcd.common] [FeaturePcd.common]
gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES
[FixedPcd.common]
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES

View File

@ -210,6 +210,11 @@ EFI_DECOMPRESS_PROTOCOL gEfiDecompress = {
}; };
// //
// For Loading modules at fixed address feature, the configuration table is to cache the top address below which to load
// Runtime code&boot time code
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable;
// Main entry point to the DXE Core // Main entry point to the DXE Core
// //
@ -284,7 +289,16 @@ DxeMain (
// //
Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation); Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation);
ASSERT_EFI_ERROR (Status); ASSERT_EFI_ERROR (Status);
//
// If Loading modules At fixed address feature is enabled, install Load moduels at fixed address
// Configuration Table so that user could easily to retrieve the top address to load Dxe and PEI
// Code and Tseg base to load SMM driver.
//
if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable);
ASSERT_EFI_ERROR (Status);
}
// //
// Report Status Code here for DXE_ENTRY_POINT once it is available // Report Status Code here for DXE_ENTRY_POINT once it is available
// //

View File

@ -1765,6 +1765,7 @@ CoreInitializeMemoryServices (
EFI_PHYSICAL_ADDRESS HighAddress; EFI_PHYSICAL_ADDRESS HighAddress;
EFI_HOB_RESOURCE_DESCRIPTOR *MaxResourceHob; EFI_HOB_RESOURCE_DESCRIPTOR *MaxResourceHob;
EFI_HOB_GUID_TYPE *GuidHob; EFI_HOB_GUID_TYPE *GuidHob;
UINT32 ReservedCodePageNumber;
// //
// Point at the first HOB. This must be the PHIT HOB. // Point at the first HOB. This must be the PHIT HOB.
@ -1795,7 +1796,17 @@ CoreInitializeMemoryServices (
// Cache the PHIT HOB for later use // Cache the PHIT HOB for later use
// //
PhitHob = Hob.HandoffInformationTable; PhitHob = Hob.HandoffInformationTable;
if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
ReservedCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
ReservedCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
//
// cache the Top address for loading modules at Fixed Address
//
gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop
+ EFI_PAGES_TO_SIZE(ReservedCodePageNumber);
}
// //
// See if a Memory Type Information HOB is available // See if a Memory Type Information HOB is available
// //

View File

@ -70,8 +70,12 @@ LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = {
NULL, // RuntimeData NULL, // RuntimeData
NULL // LoadedImageDevicePath NULL // LoadedImageDevicePath
}; };
//
// 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.
//
GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mDxeCodeMemoryRangeUsageBitMap=NULL;
/** /**
Add the Image Services to EFI Boot Services Table and install the protocol Add the Image Services to EFI Boot Services Table and install the protocol
@ -202,7 +206,170 @@ CoreReadImageFile (
CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize); CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);
return EFI_SUCCESS; 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 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 EFI_PHYSICAL_ADDRESS ImageBase,
IN UINTN ImageSize
)
{
UINT32 DxeCodePageNumber;
UINT64 DxeCodeSize;
EFI_PHYSICAL_ADDRESS DxeCodeBase;
UINTN BaseOffsetPageNumber;
UINTN TopOffsetPageNumber;
UINTN Index;
//
// The DXE code range includes RuntimeCodePage range and Boot time code range.
//
DxeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
DxeCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
DxeCodeSize = EFI_PAGES_TO_SIZE(DxeCodePageNumber);
DxeCodeBase = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize;
//
// If the memory usage bit map is not initialized, do it. Every bit in the array
// indicate the status of the corresponding memory page, available or not
//
if (mDxeCodeMemoryRangeUsageBitMap == NULL) {
mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool(((DxeCodePageNumber/64) + 1)*sizeof(UINT64));
}
//
// If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
//
if (!gLoadFixedAddressCodeMemoryReady || mDxeCodeMemoryRangeUsageBitMap == NULL) {
return EFI_NOT_FOUND;
}
//
// Test the memory range for loading the image in the DXE code range.
//
if (gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize ||
DxeCodeBase > ImageBase) {
return EFI_NOT_FOUND;
}
//
// Test if the memory is avalaible or not.
//
BaseOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase - DxeCodeBase));
TopOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - DxeCodeBase));
for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
if ((mDxeCodeMemoryRangeUsageBitMap[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 ++) {
mDxeCodeMemoryRangeUsageBitMap[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.
@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
)
{
UINTN SectionHeaderOffset;
EFI_STATUS Status;
EFI_IMAGE_SECTION_HEADER SectionHeader;
EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
UINT16 Index;
UINTN Size;
UINT16 NumberOfSections;
IMAGE_FILE_HANDLE *Handle;
UINT64 ValueInSectionHeader;
Status = EFI_NOT_FOUND;
//
// Get PeHeader pointer
//
Handle = (IMAGE_FILE_HANDLE*)ImageContext->Handle;
ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )Handle->Source + ImageContext->PeCoffHeaderOffset);
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. 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) {
//
// When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext
// hold the spcified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset
// relative to top address
//
if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) < 0) {
ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)ImageContext->ImageAddress;
}
//
// Check if the memory range is avaliable.
//
Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
}
break;
}
SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
}
DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x. Status = %r \n", ImageContext->ImageAddress, Status));
return Status;
}
/** /**
Loads, relocates, and invokes a PE/COFF image Loads, relocates, and invokes a PE/COFF image
@ -308,21 +475,43 @@ CoreLoadPeImage (
// no modules whose preferred load addresses are below 1MB. // no modules whose preferred load addresses are below 1MB.
// //
Status = EFI_OUT_OF_RESOURCES; Status = EFI_OUT_OF_RESOURCES;
if (Image->ImageContext.ImageAddress >= 0x100000 || Image->ImageContext.RelocationsStripped) { //
Status = CoreAllocatePages ( // If Loading Module At Fixed Address feature is enabled, the module should be loaded to
AllocateAddress, // a specified address.
(EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType), //
Image->NumberOfPages, if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 ) {
&Image->ImageContext.ImageAddress Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext));
);
} if (EFI_ERROR (Status)) {
if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) { //
Status = CoreAllocatePages ( // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.
AllocateAnyPages, //
(EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType), DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));
Image->NumberOfPages,
&Image->ImageContext.ImageAddress Status = CoreAllocatePages (
); AllocateAnyPages,
(EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
Image->NumberOfPages,
&Image->ImageContext.ImageAddress
);
}
} else {
if (Image->ImageContext.ImageAddress >= 0x100000 || Image->ImageContext.RelocationsStripped) {
Status = CoreAllocatePages (
AllocateAddress,
(EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
Image->NumberOfPages,
&Image->ImageContext.ImageAddress
);
}
if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {
Status = CoreAllocatePages (
AllocateAnyPages,
(EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
Image->NumberOfPages,
&Image->ImageContext.ImageAddress
);
}
} }
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return Status; return Status;
@ -355,9 +544,9 @@ CoreLoadPeImage (
Image->ImageBasePage = Image->ImageContext.ImageAddress; Image->ImageBasePage = Image->ImageContext.ImageAddress;
if (!Image->ImageContext.IsTeImage) { if (!Image->ImageContext.IsTeImage) {
Image->ImageContext.ImageAddress = Image->ImageContext.ImageAddress =
(Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) & (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &
~((UINTN)Image->ImageContext.SectionAlignment - 1); ~((UINTN)Image->ImageContext.SectionAlignment - 1);
} }
// //

View File

@ -89,7 +89,12 @@ EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
{ EfiPalCode, 0 }, { EfiPalCode, 0 },
{ EfiMaxMemoryType, 0 } { EfiMaxMemoryType, 0 }
}; };
//
// Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
// and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a
// address assigned by DXE core.
//
GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE;
/** /**
Enter critical section by gaining lock on gMemoryLock. Enter critical section by gaining lock on gMemoryLock.
@ -419,7 +424,70 @@ PromoteMemoryResource (
return; return;
} }
/**
This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD
PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the
size of boot time and runtime code.
**/
VOID
CoreLoadingFixedAddressHook (
VOID
)
{
UINT32 RuntimeCodePageNumber;
UINT32 BootTimeCodePageNumber;
EFI_PHYSICAL_ADDRESS RuntimeCodeBase;
EFI_PHYSICAL_ADDRESS BootTimeCodeBase;
EFI_STATUS Status;
//
// Make sure these 2 areas are not initialzied.
//
if (!gLoadFixedAddressCodeMemoryReady) {
RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));
BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));
//
// Try to allocate runtime memory.
//
Status = CoreAllocatePages (
AllocateAddress,
EfiRuntimeServicesCode,
RuntimeCodePageNumber,
&RuntimeCodeBase
);
if (EFI_ERROR(Status)) {
//
// Runtime memory allocation failed
//
return;
}
//
// Try to allocate boot memory.
//
Status = CoreAllocatePages (
AllocateAddress,
EfiBootServicesCode,
BootTimeCodePageNumber,
&BootTimeCodeBase
);
if (EFI_ERROR(Status)) {
//
// boot memory allocation failed. Free Runtime code range and will try the allocation again when
// new memory range is installed.
//
CoreFreePages (
RuntimeCodeBase,
RuntimeCodePageNumber
);
return;
}
gLoadFixedAddressCodeMemoryReady = TRUE;
}
return;
}
/** /**
Called to initialize the memory map and add descriptors to Called to initialize the memory map and add descriptors to
@ -448,7 +516,7 @@ CoreAddMemoryDescriptor (
EFI_STATUS Status; EFI_STATUS Status;
UINTN Index; UINTN Index;
UINTN FreeIndex; UINTN FreeIndex;
if ((Start & EFI_PAGE_MASK) != 0) { if ((Start & EFI_PAGE_MASK) != 0) {
return; return;
} }
@ -456,13 +524,19 @@ CoreAddMemoryDescriptor (
if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) { if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {
return; return;
} }
CoreAcquireMemoryLock (); CoreAcquireMemoryLock ();
End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1; End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
CoreAddRange (Type, Start, End, Attribute); CoreAddRange (Type, Start, End, Attribute);
CoreFreeMemoryMapStack (); CoreFreeMemoryMapStack ();
CoreReleaseMemoryLock (); CoreReleaseMemoryLock ();
//
// If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type
//
if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
CoreLoadingFixedAddressHook();
}
// //
// Check to see if the statistics for the different memory types have already been established // Check to see if the statistics for the different memory types have already been established
// //
@ -470,6 +544,7 @@ CoreAddMemoryDescriptor (
return; return;
} }
// //
// Loop through each memory type in the order specified by the gMemoryTypeInformation[] array // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
// //
@ -481,7 +556,6 @@ CoreAddMemoryDescriptor (
if (Type < 0 || Type > EfiMaxMemoryType) { if (Type < 0 || Type > EfiMaxMemoryType) {
continue; continue;
} }
if (gMemoryTypeInformation[Index].NumberOfPages != 0) { if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
// //
// Allocate pages for the current memory type from the top of available memory // Allocate pages for the current memory type from the top of available memory
@ -549,7 +623,6 @@ CoreAddMemoryDescriptor (
if (Type < 0 || Type > EfiMaxMemoryType) { if (Type < 0 || Type > EfiMaxMemoryType) {
continue; continue;
} }
if (gMemoryTypeInformation[Index].NumberOfPages != 0) { if (gMemoryTypeInformation[Index].NumberOfPages != 0) {
CoreFreePages ( CoreFreePages (
mMemoryTypeStatistics[Type].BaseAddress, mMemoryTypeStatistics[Type].BaseAddress,

View File

@ -233,7 +233,326 @@ ShadowPeiCore(
// //
return (VOID*) ((UINTN) EntryPoint + (UINTN) PeiCore - (UINTN) _ModuleEntryPoint); 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. Conduct PEIM dispatch.
@ -277,6 +596,7 @@ PeiDispatcher (
UINTN OldCheckingTop; UINTN OldCheckingTop;
UINTN OldCheckingBottom; UINTN OldCheckingBottom;
PEI_CORE_FV_HANDLE *CoreFvHandle; PEI_CORE_FV_HANDLE *CoreFvHandle;
VOID *LoadFixPeiCodeBegin;
PeiServices = (CONST EFI_PEI_SERVICES **) &Private->PS; PeiServices = (CONST EFI_PEI_SERVICES **) &Private->PS;
PeimEntryPoint = NULL; PeimEntryPoint = NULL;
@ -476,6 +796,13 @@ PeiDispatcher (
)); ));
DEBUG_CODE_END (); 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 // Reserve the size of new stack at bottom of physical memory
// //
@ -613,6 +940,19 @@ PeiDispatcher (
// //
PrivateInMem->PeimDispatcherReenter = TRUE; 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 // Shadow PEI Core. When permanent memory is avaiable, shadow
// PEI Core and PEIMs to get high performance. // PEI Core and PEIMs to get high performance.

View File

@ -1,14 +1,14 @@
/** @file /** @file
Pei Core Load Image Support Pei Core Load Image Support
Copyright (c) 2006 - 2010, Intel Corporation Copyright (c) 2006 - 2010, Intel Corporation
All rights reserved. This program and the accompanying materials All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/ **/
@ -96,7 +96,192 @@ GetImageReadFunction (
return EFI_SUCCESS; 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. 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. // 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)) { 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. // Set default base address to current image address.
// //
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; 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. // 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)) { 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); ASSERT (ImageContext.ImageAddress != 0);
if (ImageContext.ImageAddress == 0) { if (ImageContext.ImageAddress == 0) {
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
} }
// //
// Skip the reserved space for the stripped PeHeader when load TeImage into memory. // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
// //
if (ImageContext.IsTeImage) { if (ImageContext.IsTeImage) {
ImageContext.ImageAddress = ImageContext.ImageAddress + ImageContext.ImageAddress = ImageContext.ImageAddress +
((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -
sizeof (EFI_TE_IMAGE_HEADER); sizeof (EFI_TE_IMAGE_HEADER);
} }
@ -197,8 +393,8 @@ LoadAndRelocatePeCoffImage (
} }
/** /**
Loads a PEIM into memory for subsequent execution. If there are compressed 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, images or images that need to be relocated into memory for performance reasons,
this service performs that transformation. this service performs that transformation.
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @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). // is true, TE will be searched first).
// //
Status = PeiServicesFfsFindSectionData ( Status = PeiServicesFfsFindSectionData (
@ -270,7 +466,7 @@ PeiLoadImageLoadImage (
return Status; return Status;
} }
} }
// //
// If memory is installed, perform the shadow operations // If memory is installed, perform the shadow operations
// //
@ -293,9 +489,9 @@ PeiLoadImageLoadImage (
// //
Pe32Data = (VOID *) ((UINTN) ImageAddress); Pe32Data = (VOID *) ((UINTN) ImageAddress);
*EntryPoint = ImageEntryPoint; *EntryPoint = ImageEntryPoint;
Machine = PeCoffLoaderGetMachineType (Pe32Data); Machine = PeCoffLoaderGetMachineType (Pe32Data);
if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) { if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) { if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
@ -309,7 +505,7 @@ PeiLoadImageLoadImage (
if (ImageSizeArg != NULL) { if (ImageSizeArg != NULL) {
*ImageSizeArg = ImageSize; *ImageSizeArg = ImageSize;
} }
DEBUG_CODE_BEGIN (); DEBUG_CODE_BEGIN ();
CHAR8 *AsciiString; CHAR8 *AsciiString;
CHAR8 AsciiBuffer[512]; 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))); 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. // Print Module Name by PeImage PDB file name.
// //
AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data); AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
if (AsciiString != NULL) { if (AsciiString != NULL) {
for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) { for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {
if (AsciiString[Index] == '\\') { if (AsciiString[Index] == '\\') {
@ -454,7 +650,7 @@ RelocationIsStrip (
/** /**
Routine to load image file for subsequent execution by LoadFile Ppi. 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. XIP image format is used.
@param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @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)) { if (!EFI_ERROR (PpiStatus)) {
Status = LoadFile->LoadFile ( Status = LoadFile->LoadFile (
LoadFile, LoadFile,
FileHandle, FileHandle,
&ImageAddress, &ImageAddress,
&ImageSize, &ImageSize,
EntryPoint, EntryPoint,
AuthenticationState AuthenticationState
@ -560,10 +756,10 @@ InitializeImageServices (
PeiServicesInstallPpi (PrivateData->XipLoadFile); PeiServicesInstallPpi (PrivateData->XipLoadFile);
} else { } else {
// //
// 2nd time we are running from memory so replace the XIP version with the // 2nd time we are running from memory so replace the XIP version with the
// new memory version. // new memory version.
// //
PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList); PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
} }
} }

View File

@ -177,6 +177,18 @@ typedef struct{
EFI_PHYSICAL_ADDRESS FreePhysicalMemoryTop; EFI_PHYSICAL_ADDRESS FreePhysicalMemoryTop;
VOID* ShadowedPeiCore; VOID* ShadowedPeiCore;
CACHE_SECTION_DATA CacheSection; 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; } PEI_CORE_INSTANCE;
/// ///

View File

@ -85,12 +85,16 @@
gEfiTemporaryRamSupportPpiGuid ## CONSUMES gEfiTemporaryRamSupportPpiGuid ## CONSUMES
[FixedPcd] [FixedPcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeimPerFv ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeimPerFv ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPpiSupported ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPpiSupported ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES
[Pcd] [Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressPeiCodePageNumber ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES

View File

@ -0,0 +1,34 @@
/** @file
This file defines:
A configuration Table Guid for Load module at fixed address.
This configuration table is to hold the top address below which the Dxe runtime code and
boot time code will be loaded and Tseg base. When this feature is enabled, Build tools will assigned
module loading address relative to these 2 address.
Copyright (c) 2010, Intel Corporation. <BR>
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.
**/
#ifndef __LOAD_MODULE_AT_FIX_ADDRESS_GUID_H__
#define __LOAD_MODULE_AT_FIX_ADDRESS_GUID_H__
#define EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE_GUID \
{ 0x2CA88B53,0xD296,0x4080, { 0xA4,0xA5,0xCA,0xD9,0xBA,0xE2,0x4B,0x9} }
extern EFI_GUID gLoadFixedAddressConfigurationTableGuid;
typedef struct {
EFI_PHYSICAL_ADDRESS DxeCodeTopAddress; ///< The top address below which the Dxe runtime code and below which the Dxe runtime/boot code and PEI code.
EFI_PHYSICAL_ADDRESS TsegBase; ///< Tseg base. build tool will assigned an offset relative to Tseg base to SMM driver
} EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE;
#endif

View File

@ -143,6 +143,10 @@
# Include/Guid/StatusCodeDataTypeDebug.h # Include/Guid/StatusCodeDataTypeDebug.h
gEfiStatusCodeDataTypeDebugGuid = { 0x9A4E9246, 0xD553, 0x11D5, { 0x87, 0xE2, 0x00, 0x06, 0x29, 0x45, 0xC3, 0xB9 }} gEfiStatusCodeDataTypeDebugGuid = { 0x9A4E9246, 0xD553, 0x11D5, { 0x87, 0xE2, 0x00, 0x06, 0x29, 0x45, 0xC3, 0xB9 }}
## A configuration Table Guid for Load module at fixed address
# Include/Guid/LoadModuleAtFixedAddress.h
gLoadFixedAddressConfigurationTableGuid = { 0x2CA88B53,0xD296,0x4080, { 0xA4,0xA5,0xCA,0xD9,0xBA,0xE2,0x4B,0x9 } }
[Protocols.common] [Protocols.common]
## Load File protocol provides capability to load and unload EFI image into memory and execute it. ## Load File protocol provides capability to load and unload EFI image into memory and execute it.
# Include/Protocol/LoadPe32Image.h # Include/Protocol/LoadPe32Image.h
@ -343,6 +347,12 @@
# BIT1 set indicates 8KB alignment # BIT1 set indicates 8KB alignment
gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize|0x1|UINT32|0x10000047 gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize|0x1|UINT32|0x10000047
## Flag of enabling/disabling the feature of Loading Module at Fixed Address
# -1: Enable the feature as fixed offset to TOLM
# 0: Disable the feature.
# Positive Value: Enable the feature as fixed absolute address, and the value is the top memory address
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable|0|UINT64|0x30001015
## Smbios version ## Smbios version
gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion|0x0206|UINT16|0x00010055 gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion|0x0206|UINT16|0x00010055
@ -409,3 +419,20 @@
# The default value in DxePhase is 128 KBytes. # The default value in DxePhase is 128 KBytes.
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1|UINT16|0x00010054 gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1|UINT16|0x00010054
[PcdsPatchableInModule]
## Specify memory size with page number for PEI code when
# the feature of Loading Module at Fixed Address is enabled
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressPeiCodePageNumber|0|UINT32|0x00000029
## Specify memory size with page number for DXE boot time code when
# the feature of Loading Module at Fixed Address is enabled
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber|0|UINT32|0x0000002a
## Specify memory size with page number for DXE runtime code when
# the feature of Loading Module at Fixed Address is enabled
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber|0|UINT32|0x0000002b
## Specify memory size with page number for SMM code when
# the feature of Loading Module at Fixed Address is enabled
gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber|0|UINT32|0x0000002c