From: jchen20 Date: Wed, 3 Mar 2010 05:45:50 +0000 (+0000) Subject: Enable "Load Module At fixed Address" feature in SMM Core X-Git-Tag: edk2-stable201903~16170 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=3c447c2760b3438a6d5ff0a7f2dbd580526452e5;p=mirror_edk2.git Enable "Load Module At fixed Address" feature in SMM Core git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10166 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c index 9e1a778900..9625eabd91 100644 --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c @@ -122,6 +122,176 @@ FV_FILEPATH_DEVICE_PATH mFvDevicePath; // EFI_SECURITY_ARCH_PROTOCOL *mSecurity = NULL; +// +// The global variable is defined for Loading modules at fixed address feature to track the SMM 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 *mSmmCodeMemoryRangeUsageBitMap=NULL; + +/** + To check memory usage bit map array to figure out if the memory range in which the image will be loaded 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 SmmCodePageNumber; + UINT64 SmmCodeSize; + EFI_PHYSICAL_ADDRESS SmmCodeBase; + UINTN BaseOffsetPageNumber; + UINTN TopOffsetPageNumber; + UINTN Index; + // + // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber + // + SmmCodePageNumber = PcdGet32(PcdLoadFixAddressSmmCodePageNumber); + SmmCodeSize = EFI_PAGES_TO_SIZE (SmmCodePageNumber); + SmmCodeBase = gLoadModuleAtFixAddressSmramBase; + + // + // 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 (mSmmCodeMemoryRangeUsageBitMap == NULL) { + mSmmCodeMemoryRangeUsageBitMap = AllocateZeroPool(((SmmCodePageNumber / 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 (mSmmCodeMemoryRangeUsageBitMap == NULL) { + return EFI_NOT_FOUND; + } + // + // see if the memory range for loading the image is in the SMM code range. + // + if (SmmCodeBase + SmmCodeSize < ImageBase + ImageSize || SmmCodeBase > ImageBase) { + return EFI_NOT_FOUND; + } + // + // Test if the memory is avalaible or not. + // + BaseOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase - SmmCodeBase)); + TopOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - SmmCodeBase)); + for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) { + if ((mSmmCodeMemoryRangeUsageBitMap[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 ++) { + mSmmCodeMemoryRangeUsageBitMap[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; + 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); + 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.So there is an assumption that when the feature is enabled, + // if a module with a loading address assigned by tools, the 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 in which uild tool saves the + // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields + // + FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressSmramBase + (INT64)ValueInSectionHeader); + // + // Check if the memory range is avaliable. + // + Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoaddingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment)); + 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 %x, Status = %r\n", FixLoaddingAddress, Status)); + return Status; +} /** Loads an EFI image into SMRAM. @@ -258,24 +428,63 @@ SmmLoadImage ( } return Status; } - - PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment); - DstBuffer = (UINTN)(-1); - - Status = SmmAllocatePages ( - AllocateMaxAddress, - EfiRuntimeServicesCode, - PageCount, - &DstBuffer - ); - if (EFI_ERROR (Status)) { - if (Buffer != NULL) { - Status = gBS->FreePool (Buffer); + // + // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE + // to hold the Smm driver code + // + if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { + // + // Get the fixed loading address assigned by Build tool + // + Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); + if (!EFI_ERROR (Status)) { + // + // Since the memory range to load Smm core alreay been cut out, so no need to allocate and free this range + // following statements is to bypass SmmFreePages + // + PageCount = 0; + DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase; + } else { + DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); + // + // allocate the memory to load the SMM driver + // + PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment); + DstBuffer = (UINTN)(-1); + + Status = SmmAllocatePages ( + AllocateMaxAddress, + EfiRuntimeServicesCode, + PageCount, + &DstBuffer + ); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + Status = gBS->FreePool (Buffer); + } + return Status; + } + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } - return Status; + } else { + PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment); + DstBuffer = (UINTN)(-1); + + Status = SmmAllocatePages ( + AllocateMaxAddress, + EfiRuntimeServicesCode, + PageCount, + &DstBuffer + ); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + Status = gBS->FreePool (Buffer); + } + return Status; + } + + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } - - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; // // Align buffer on section boundry // diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h index 2926f90d35..1cbae1ca5a 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h @@ -41,7 +41,8 @@ #include #include #include -#include +#include +#include #include "PiSmmCorePrivateData.h" @@ -178,6 +179,7 @@ typedef struct { extern SMM_CORE_PRIVATE_DATA *gSmmCorePrivate; extern EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst; extern LIST_ENTRY gHandleList; +extern EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase; /** Called to initialize the memory service. diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf index 5f38065c0c..63296bc99e 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf @@ -39,6 +39,7 @@ [Packages] MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec [LibraryClasses] UefiDriverEntryPoint @@ -52,6 +53,7 @@ UefiLib UefiBootServicesTableLib MemoryAllocationLib + PcdLib [Protocols] gEfiDxeSmmReadyToLockProtocolGuid # PROTOCOL ALWAYS_CONSUMED @@ -62,6 +64,10 @@ gEfiLoadedImageProtocolGuid # PROTOCOL SOMETIMES_PRODUCED gEfiDevicePathProtocolGuid # PROTOCOL SOMETIMES_CONSUMED +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber # SIMETIMES_CONSUMED + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable # ALWAYS_CONSUMED + [Guids] gAprioriGuid # ALWAYS_CONSUMED gEfiEventDxeDispatchGuid # ALWAYS_CONSUMED diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c index 1029a07779..ff7eff73bf 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #include "PiSmmCorePrivateData.h" @@ -703,7 +705,101 @@ GetSectionInAnyFv ( return NULL; } +/** + 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; + EFI_PHYSICAL_ADDRESS FixLoaddingAddress; + UINT16 Index; + UINTN Size; + UINT16 NumberOfSections; + EFI_PHYSICAL_ADDRESS SmramBase; + UINT64 SmmCodeSize; + UINT64 ValueInSectionHeader; + // + // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber + // + SmmCodeSize = EFI_PAGES_TO_SIZE (PcdGet32(PcdLoadFixAddressSmmCodePageNumber)); + + FixLoaddingAddress = 0; + Status = EFI_NOT_FOUND; + SmramBase = mCurrentSmramRange->CpuStart; + // + // Get PeHeader pointer + // + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + 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 saves the offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields in the + // first section header that doesn't point to code section in 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) { + // + // Found first section header that doesn't point to code section in which uild tool saves the + // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields + // + FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase + (INT64)ValueInSectionHeader); + + if (SmramBase + SmmCodeSize > FixLoaddingAddress && SmramBase <= FixLoaddingAddress) { + // + // The assigned address is valid. Return the specified loadding address + // + ImageContext->ImageAddress = FixLoaddingAddress; + Status = EFI_SUCCESS; + } + } + 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", FixLoaddingAddress, Status)); + return Status; +} /** Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM. @@ -749,23 +845,58 @@ ExecuteSmmCoreFromSmram ( if (EFI_ERROR (Status)) { return Status; } - // - // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR - // specified by SmramRange + // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to + // the address assigned by build tool. // - PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment); + if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { + // + // Get the fixed loading address assigned by Build tool + // + Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); + if (!EFI_ERROR (Status)) { + // + // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range + // + PageCount = 0; + } else { + DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n")); + // + // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR + // specified by SmramRange + // + PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment); - ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); - ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); + ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); + ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); - SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount); - DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize; + SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount); + DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize; - // - // Align buffer on section boundry - // - ImageContext.ImageAddress = DestinationBuffer; + // + // Align buffer on section boundry + // + ImageContext.ImageAddress = DestinationBuffer; + } + } else { + // + // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR + // specified by SmramRange + // + PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment); + + ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); + ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); + + SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount); + DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize; + + // + // Align buffer on section boundry + // + ImageContext.ImageAddress = DestinationBuffer; + } + ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); @@ -847,6 +978,8 @@ SmmIplEntry ( EFI_SMM_RESERVED_SMRAM_REGION *SmramResRegion; UINT64 MaxSize; VOID *Registration; + UINT64 SmmCodeSize; + EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable; // // Fill in the image handle of the SMM IPL so the SMM Core can use this as the @@ -954,7 +1087,34 @@ SmmIplEntry ( if (EFI_ERROR (Status)) { DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n")); } - + // + // if Loading module at Fixed Address feature is enabled, save the SMRAM base to Load + // Modules At Fixed Address Configuration Table. + // + if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { + // + // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber + // + SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT); + // + // The SMRAM available memory is assumed to be larger than SmmCodeSize + // + ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize); + // + // Retrieve Load modules At fixed address configuration table and save the SMRAM base. + // + Status = EfiGetSystemConfigurationTable ( + &gLoadFixedAddressConfigurationTableGuid, + (VOID **) &LMFAConfigurationTable + ); + if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) { + LMFAConfigurationTable->SmramBase = mCurrentSmramRange->CpuStart; + } + // + // Print the SMRAM base + // + DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: TSEG BASE is %x. \n", LMFAConfigurationTable->SmramBase)); + } // // Load SMM Core into SMRAM and execute it from SMRAM // diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf index 1c4c2af454..d6c33dab30 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf @@ -33,6 +33,7 @@ [Packages] MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec [LibraryClasses] UefiDriverEntryPoint @@ -62,6 +63,12 @@ gEfiEventReadyToBootGuid # ALWAYS_CONSUMED gEfiEventLegacyBootGuid # ALWAYS_CONSUMED gEfiEventVirtualAddressChangeGuid # ALWAYS_CONSUMED - + gLoadFixedAddressConfigurationTableGuid # SIMETIMES_CONSUMED + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber # SIMETIMES_CONSUMED + gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable # ALWAYS_CONSUMED + + [Depex] gEfiSmmAccess2ProtocolGuid AND gEfiSmmControl2ProtocolGuid AND gEfiCpuArchProtocolGuid diff --git a/MdeModulePkg/Core/PiSmmCore/Pool.c b/MdeModulePkg/Core/PiSmmCore/Pool.c index d7f80f4f8c..10a85c47ab 100644 --- a/MdeModulePkg/Core/PiSmmCore/Pool.c +++ b/MdeModulePkg/Core/PiSmmCore/Pool.c @@ -42,6 +42,11 @@ typedef struct { } FREE_POOL_HEADER; LIST_ENTRY mSmmPoolLists[MAX_POOL_INDEX]; +// +// To cache the SMRAM base since when Loading modules At fixed address feature is enabled, +// all module is assigned an offset relative the SMRAM base in build time. +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0; /** Called to initialize the memory service. @@ -56,7 +61,10 @@ SmmInitializeMemoryServices ( IN EFI_SMRAM_DESCRIPTOR *SmramRanges ) { - UINTN Index; + UINTN Index; + UINT64 SmmCodeSize; + UINTN CurrentSmramRangesIndex; + UINT64 MaxSize; // // Initialize Pool list @@ -64,7 +72,38 @@ SmmInitializeMemoryServices ( for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) { InitializeListHead (&mSmmPoolLists[--Index]); } - + CurrentSmramRangesIndex = 0; + // + // If Loadding Module At fixed Address feature is enabled, cache the SMRAM base here + // + if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { + // + // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber + // + SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT); + + // + // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size + // + for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) { + if (SmramRanges[Index].CpuStart >= BASE_1MB) { + if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize) <= BASE_4GB) { + if (SmramRanges[Index].PhysicalSize >= MaxSize) { + MaxSize = SmramRanges[Index].PhysicalSize; + CurrentSmramRangesIndex = Index; + } + } + } + } + gLoadModuleAtFixAddressSmramBase = SmramRanges[CurrentSmramRangesIndex].CpuStart; + + // + // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code + // A notable thing is that SMM core is already loaded into this range. + // + SmramRanges[CurrentSmramRangesIndex].CpuStart = SmramRanges[CurrentSmramRangesIndex].CpuStart + SmmCodeSize; + SmramRanges[CurrentSmramRangesIndex].PhysicalSize = SmramRanges[CurrentSmramRangesIndex].PhysicalSize - SmmCodeSize; + } // // Initialize free SMRAM regions // @@ -76,6 +115,7 @@ SmmInitializeMemoryServices ( SmramRanges[Index].RegionState ); } + } /** diff --git a/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h b/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h index 070430db9c..a04e0b224d 100644 --- a/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h +++ b/MdeModulePkg/Include/Guid/LoadModuleAtFixedAddress.h @@ -28,7 +28,7 @@ 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_PHYSICAL_ADDRESS SmramBase; ///< SMM RAME base. build tool will assigned an offset relative to SMRAM base for SMM driver } EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE; #endif