From 54ea99a798f7d714b59503fcc21ee97878bc6492 Mon Sep 17 00:00:00 2001 From: jchen20 Date: Fri, 5 Feb 2010 07:54:16 +0000 Subject: [PATCH] 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 --- MdeModulePkg/Core/Dxe/DxeMain.h | 5 +- MdeModulePkg/Core/Dxe/DxeMain.inf | 8 + MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c | 16 +- MdeModulePkg/Core/Dxe/Gcd/Gcd.c | 13 +- MdeModulePkg/Core/Dxe/Image/Image.c | 229 ++++++++++-- MdeModulePkg/Core/Dxe/Mem/Page.c | 83 ++++- MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 340 ++++++++++++++++++ MdeModulePkg/Core/Pei/Image/Image.c | 256 +++++++++++-- MdeModulePkg/Core/Pei/PeiMain.h | 12 + MdeModulePkg/Core/Pei/PeiMain.inf | 10 +- .../Include/Guid/LoadModuleAtFixedAddress.h | 34 ++ MdeModulePkg/MdeModulePkg.dec | 27 ++ 12 files changed, 972 insertions(+), 61 deletions(-) create mode 100644 MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h index 1c496bd8bd..2f7f8b5ea0 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain.h +++ b/MdeModulePkg/Core/Dxe/DxeMain.h @@ -60,7 +60,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include - +#include #include #include @@ -81,6 +81,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include + // // 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 EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate; +extern EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable; +extern BOOLEAN gLoadFixedAddressCodeMemoryReady; // // Service Initialization Functions // diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf index a5b90cf1dd..3a32e1ff31 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain.inf +++ b/MdeModulePkg/Core/Dxe/DxeMain.inf @@ -103,6 +103,7 @@ gEfiDxeServicesTableGuid ## CONSUMES ## GUID gEfiMemoryTypeInformationGuid ## CONSUMES ## GUID gEfiEventDxeDispatchGuid ## CONSUMES ## GUID + gLoadFixedAddressConfigurationTableGuid ## SOMETIMES_CONSUMES [Protocols] @@ -138,3 +139,10 @@ [FeaturePcd.common] gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES + +[FixedPcd.common] + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES \ No newline at end of file diff --git a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c index 52f9437b9e..5d1d6df202 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c +++ b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c @@ -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 // @@ -284,7 +289,16 @@ DxeMain ( // Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation); 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 // diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index 8081fef1b0..2a026c0724 100644 --- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c +++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c @@ -1765,6 +1765,7 @@ CoreInitializeMemoryServices ( EFI_PHYSICAL_ADDRESS HighAddress; EFI_HOB_RESOURCE_DESCRIPTOR *MaxResourceHob; EFI_HOB_GUID_TYPE *GuidHob; + UINT32 ReservedCodePageNumber; // // Point at the first HOB. This must be the PHIT HOB. @@ -1795,7 +1796,17 @@ CoreInitializeMemoryServices ( // Cache the PHIT HOB for later use // 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 // diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c b/MdeModulePkg/Core/Dxe/Image/Image.c index 7e5cea7b76..f516f26f48 100644 --- a/MdeModulePkg/Core/Dxe/Image/Image.c +++ b/MdeModulePkg/Core/Dxe/Image/Image.c @@ -70,8 +70,12 @@ LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = { NULL, // RuntimeData 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 @@ -202,7 +206,170 @@ CoreReadImageFile ( CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize); 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 @@ -308,21 +475,43 @@ CoreLoadPeImage ( // no modules whose preferred load addresses are below 1MB. // Status = EFI_OUT_OF_RESOURCES; - 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 Loading Module At Fixed Address feature is enabled, the module should be loaded to + // a specified address. + // + if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 ) { + Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext)); + + if (EFI_ERROR (Status)) { + // + // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver. + // + DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n")); + + 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)) { return Status; @@ -355,9 +544,9 @@ CoreLoadPeImage ( Image->ImageBasePage = Image->ImageContext.ImageAddress; if (!Image->ImageContext.IsTeImage) { - Image->ImageContext.ImageAddress = - (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) & - ~((UINTN)Image->ImageContext.SectionAlignment - 1); + Image->ImageContext.ImageAddress = + (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) & + ~((UINTN)Image->ImageContext.SectionAlignment - 1); } // diff --git a/MdeModulePkg/Core/Dxe/Mem/Page.c b/MdeModulePkg/Core/Dxe/Mem/Page.c index 4f31b5f57f..2a99507c58 100644 --- a/MdeModulePkg/Core/Dxe/Mem/Page.c +++ b/MdeModulePkg/Core/Dxe/Mem/Page.c @@ -89,7 +89,12 @@ EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = { { EfiPalCode, 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. @@ -419,7 +424,70 @@ PromoteMemoryResource ( 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 @@ -448,7 +516,7 @@ CoreAddMemoryDescriptor ( EFI_STATUS Status; UINTN Index; UINTN FreeIndex; - + if ((Start & EFI_PAGE_MASK) != 0) { return; } @@ -456,13 +524,19 @@ CoreAddMemoryDescriptor ( if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) { return; } - CoreAcquireMemoryLock (); End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1; CoreAddRange (Type, Start, End, Attribute); CoreFreeMemoryMapStack (); 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 // @@ -470,6 +544,7 @@ CoreAddMemoryDescriptor ( return; } + // // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array // @@ -481,7 +556,6 @@ CoreAddMemoryDescriptor ( if (Type < 0 || Type > EfiMaxMemoryType) { continue; } - if (gMemoryTypeInformation[Index].NumberOfPages != 0) { // // Allocate pages for the current memory type from the top of available memory @@ -549,7 +623,6 @@ CoreAddMemoryDescriptor ( if (Type < 0 || Type > EfiMaxMemoryType) { continue; } - if (gMemoryTypeInformation[Index].NumberOfPages != 0) { CoreFreePages ( mMemoryTypeStatistics[Type].BaseAddress, 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 diff --git a/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h b/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h new file mode 100644 index 0000000000..90bb246de9 --- /dev/null +++ b/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h @@ -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.
+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 diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 68805d2f95..d14cf8b56b 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -143,6 +143,10 @@ # Include/Guid/StatusCodeDataTypeDebug.h 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] ## Load File protocol provides capability to load and unload EFI image into memory and execute it. # Include/Protocol/LoadPe32Image.h @@ -343,6 +347,12 @@ # BIT1 set indicates 8KB alignment 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 gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion|0x0206|UINT16|0x00010055 @@ -409,3 +419,20 @@ # The default value in DxePhase is 128 KBytes. 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 +