From 54ea99a798f7d714b59503fcc21ee97878bc6492 Mon Sep 17 00:00:00 2001 From: jchen20 Date: Fri, 5 Feb 2010 07:54:16 +0000 Subject: 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 +++++++++++- 6 files changed, 326 insertions(+), 28 deletions(-) (limited to 'MdeModulePkg/Core/Dxe') 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, -- cgit v1.2.3