#include <Guid/MemoryAllocationHob.h>\r
#include <Guid/EventLegacyBios.h>\r
#include <Guid/EventGroup.h>\r
-\r
+#include <Guid/LoadModuleAtFixedAddress.h>\r
\r
#include <Library/DxeCoreEntryPoint.h>\r
#include <Library/DebugLib.h>\r
#include <Library/TimerLib.h>\r
#include <Library/DxeServicesLib.h>\r
\r
+\r
//\r
// attributes for reserved memory before it is promoted to system memory\r
//\r
extern BOOLEAN gDispatcherRunning;\r
extern EFI_RUNTIME_ARCH_PROTOCOL gRuntimeTemplate;\r
\r
+extern EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable;\r
+extern BOOLEAN gLoadFixedAddressCodeMemoryReady;\r
//\r
// Service Initialization Functions\r
//\r
gEfiDxeServicesTableGuid ## CONSUMES ## GUID\r
gEfiMemoryTypeInformationGuid ## CONSUMES ## GUID\r
gEfiEventDxeDispatchGuid ## CONSUMES ## GUID\r
+ gLoadFixedAddressConfigurationTableGuid ## SOMETIMES_CONSUMES\r
\r
\r
[Protocols]\r
\r
[FeaturePcd.common]\r
gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES\r
+\r
+[FixedPcd.common]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES\r
+\r
+[Pcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES
\ No newline at end of file
};\r
\r
//\r
+// For Loading modules at fixed address feature, the configuration table is to cache the top address below which to load \r
+// Runtime code&boot time code \r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE gLoadModuleAtFixAddressConfigurationTable;\r
+\r
// Main entry point to the DXE Core\r
//\r
\r
//\r
Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation);\r
ASSERT_EFI_ERROR (Status);\r
-\r
+ \r
+ //\r
+ // If Loading modules At fixed address feature is enabled, install Load moduels at fixed address \r
+ // Configuration Table so that user could easily to retrieve the top address to load Dxe and PEI\r
+ // Code and Tseg base to load SMM driver. \r
+ //\r
+ if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
+ Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
//\r
// Report Status Code here for DXE_ENTRY_POINT once it is available\r
//\r
EFI_PHYSICAL_ADDRESS HighAddress;\r
EFI_HOB_RESOURCE_DESCRIPTOR *MaxResourceHob;\r
EFI_HOB_GUID_TYPE *GuidHob;\r
+ UINT32 ReservedCodePageNumber;\r
\r
//\r
// Point at the first HOB. This must be the PHIT HOB.\r
// Cache the PHIT HOB for later use\r
//\r
PhitHob = Hob.HandoffInformationTable;\r
-\r
+ \r
+ if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
+ ReservedCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);\r
+ ReservedCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);\r
+ \r
+ //\r
+ // cache the Top address for loading modules at Fixed Address \r
+ //\r
+ gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop \r
+ + EFI_PAGES_TO_SIZE(ReservedCodePageNumber);\r
+ }\r
//\r
// See if a Memory Type Information HOB is available\r
//\r
NULL, // RuntimeData\r
NULL // LoadedImageDevicePath\r
};\r
-\r
-\r
+//\r
+// The field is define for Loading modules at fixed address feature to tracker the PEI code\r
+// memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page\r
+// available or not. \r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mDxeCodeMemoryRangeUsageBitMap=NULL;\r
\r
/**\r
Add the Image Services to EFI Boot Services Table and install the protocol\r
CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);\r
return EFI_SUCCESS;\r
}\r
+/**\r
+ 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 \r
+ memory range is avaliable, the function will mark the correponding bits to 1 which indicates the memory range is used.\r
+ The function is only invoked when load modules at fixed address feature is enabled. \r
+ \r
+ @param ImageBase The base addres the image will be loaded at.\r
+ @param ImageSize The size of the image\r
+ \r
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available\r
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available\r
+**/\r
+EFI_STATUS\r
+CheckAndMarkFixLoadingMemoryUsageBitMap (\r
+ IN EFI_PHYSICAL_ADDRESS ImageBase,\r
+ IN UINTN ImageSize\r
+ )\r
+{\r
+ UINT32 DxeCodePageNumber;\r
+ UINT64 DxeCodeSize; \r
+ EFI_PHYSICAL_ADDRESS DxeCodeBase;\r
+ UINTN BaseOffsetPageNumber;\r
+ UINTN TopOffsetPageNumber;\r
+ UINTN Index;\r
+ //\r
+ // The DXE code range includes RuntimeCodePage range and Boot time code range.\r
+ // \r
+ DxeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);\r
+ DxeCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);\r
+ DxeCodeSize = EFI_PAGES_TO_SIZE(DxeCodePageNumber);\r
+ DxeCodeBase = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize;\r
+ \r
+ //\r
+ // If the memory usage bit map is not initialized, do it. Every bit in the array \r
+ // indicate the status of the corresponding memory page, available or not\r
+ // \r
+ if (mDxeCodeMemoryRangeUsageBitMap == NULL) {\r
+ mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool(((DxeCodePageNumber/64) + 1)*sizeof(UINT64));\r
+ }\r
+ //\r
+ // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND\r
+ //\r
+ if (!gLoadFixedAddressCodeMemoryReady || mDxeCodeMemoryRangeUsageBitMap == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Test the memory range for loading the image in the DXE code range.\r
+ //\r
+ if (gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize ||\r
+ DxeCodeBase > ImageBase) {\r
+ return EFI_NOT_FOUND; \r
+ } \r
+ //\r
+ // Test if the memory is avalaible or not.\r
+ // \r
+ BaseOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase - DxeCodeBase));\r
+ TopOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - DxeCodeBase));\r
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
+ if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {\r
+ //\r
+ // This page is already used.\r
+ //\r
+ return EFI_NOT_FOUND; \r
+ }\r
+ }\r
+ \r
+ //\r
+ // Being here means the memory range is available. So mark the bits for the memory range\r
+ // \r
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
+ mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));\r
+ }\r
+ return EFI_SUCCESS; \r
+}\r
+/**\r
\r
+ Get the fixed loadding address from image header assigned by build tool. This function only be called\r
+ when Loading module at Fixed address feature enabled.\r
+\r
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
+ image that needs to be examined by this function.\r
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .\r
+ @retval EFI_NOT_FOUND The image has no assigned fixed loadding address.\r
+\r
+**/\r
+EFI_STATUS\r
+GetPeCoffImageFixLoadingAssignedAddress(\r
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
+ )\r
+{\r
+ UINTN SectionHeaderOffset;\r
+ EFI_STATUS Status;\r
+ EFI_IMAGE_SECTION_HEADER SectionHeader;\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
+ UINT16 Index;\r
+ UINTN Size;\r
+ UINT16 NumberOfSections;\r
+ IMAGE_FILE_HANDLE *Handle;\r
+ UINT64 ValueInSectionHeader;\r
+ \r
+\r
+ Status = EFI_NOT_FOUND;\r
+ \r
+ //\r
+ // Get PeHeader pointer\r
+ //\r
+ Handle = (IMAGE_FILE_HANDLE*)ImageContext->Handle;\r
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )Handle->Source + ImageContext->PeCoffHeaderOffset);\r
+ SectionHeaderOffset = (UINTN)(\r
+ ImageContext->PeCoffHeaderOffset +\r
+ sizeof (UINT32) +\r
+ sizeof (EFI_IMAGE_FILE_HEADER) +\r
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
+ );\r
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;\r
+\r
+ //\r
+ // Get base address from the first section header that doesn't point to code section.\r
+ //\r
+ for (Index = 0; Index < NumberOfSections; Index++) {\r
+ //\r
+ // Read section header from file\r
+ //\r
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ Status = ImageContext->ImageRead (\r
+ ImageContext->Handle,\r
+ SectionHeaderOffset,\r
+ &Size,\r
+ &SectionHeader\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ Status = EFI_NOT_FOUND;\r
+ \r
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {\r
+ //\r
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header\r
+ // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an \r
+ // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations \r
+ // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fileds should be set to Zero\r
+ //\r
+ ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);\r
+ if (ValueInSectionHeader != 0) {\r
+ //\r
+ // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext \r
+ // hold the spcified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset\r
+ // relative to top address\r
+ //\r
+ if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) < 0) {\r
+ ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)ImageContext->ImageAddress;\r
+ }\r
+ //\r
+ // Check if the memory range is avaliable.\r
+ //\r
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));\r
+ }\r
+ break; \r
+ }\r
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ }\r
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x. Status = %r \n", ImageContext->ImageAddress, Status));\r
+ return Status;\r
+}\r
/**\r
Loads, relocates, and invokes a PE/COFF image\r
\r
// no modules whose preferred load addresses are below 1MB.\r
//\r
Status = EFI_OUT_OF_RESOURCES;\r
- if (Image->ImageContext.ImageAddress >= 0x100000 || Image->ImageContext.RelocationsStripped) {\r
- Status = CoreAllocatePages (\r
- AllocateAddress,\r
- (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),\r
- Image->NumberOfPages,\r
- &Image->ImageContext.ImageAddress\r
- );\r
- }\r
- if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {\r
- Status = CoreAllocatePages (\r
- AllocateAnyPages,\r
- (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),\r
- Image->NumberOfPages,\r
- &Image->ImageContext.ImageAddress\r
- );\r
+ //\r
+ // If Loading Module At Fixed Address feature is enabled, the module should be loaded to\r
+ // a specified address.\r
+ //\r
+ if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 ) {\r
+ Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext));\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.\r
+ //\r
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));\r
+ \r
+ Status = CoreAllocatePages (\r
+ AllocateAnyPages,\r
+ (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),\r
+ Image->NumberOfPages,\r
+ &Image->ImageContext.ImageAddress\r
+ ); \r
+ } \r
+ } else {\r
+ if (Image->ImageContext.ImageAddress >= 0x100000 || Image->ImageContext.RelocationsStripped) {\r
+ Status = CoreAllocatePages (\r
+ AllocateAddress,\r
+ (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),\r
+ Image->NumberOfPages,\r
+ &Image->ImageContext.ImageAddress\r
+ );\r
+ }\r
+ if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {\r
+ Status = CoreAllocatePages (\r
+ AllocateAnyPages,\r
+ (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),\r
+ Image->NumberOfPages,\r
+ &Image->ImageContext.ImageAddress\r
+ );\r
+ }\r
}\r
if (EFI_ERROR (Status)) {\r
return Status;\r
\r
Image->ImageBasePage = Image->ImageContext.ImageAddress;\r
if (!Image->ImageContext.IsTeImage) {\r
- Image->ImageContext.ImageAddress =\r
- (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &\r
- ~((UINTN)Image->ImageContext.SectionAlignment - 1);\r
+ Image->ImageContext.ImageAddress =\r
+ (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &\r
+ ~((UINTN)Image->ImageContext.SectionAlignment - 1);\r
}\r
\r
//\r
{ EfiPalCode, 0 },\r
{ EfiMaxMemoryType, 0 }\r
};\r
-\r
+//\r
+// Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated\r
+// and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a \r
+// address assigned by DXE core.\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE;\r
\r
/**\r
Enter critical section by gaining lock on gMemoryLock.\r
\r
return;\r
}\r
+/**\r
+ This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD \r
+ PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the \r
+ size of boot time and runtime code.\r
\r
+**/\r
+VOID\r
+CoreLoadingFixedAddressHook (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RuntimeCodePageNumber;\r
+ UINT32 BootTimeCodePageNumber;\r
+ EFI_PHYSICAL_ADDRESS RuntimeCodeBase;\r
+ EFI_PHYSICAL_ADDRESS BootTimeCodeBase;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Make sure these 2 areas are not initialzied.\r
+ //\r
+ if (!gLoadFixedAddressCodeMemoryReady) { \r
+ RuntimeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);\r
+ BootTimeCodePageNumber= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);\r
+ RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));\r
+ BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));\r
+ //\r
+ // Try to allocate runtime memory.\r
+ //\r
+ Status = CoreAllocatePages (\r
+ AllocateAddress,\r
+ EfiRuntimeServicesCode,\r
+ RuntimeCodePageNumber,\r
+ &RuntimeCodeBase\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // Runtime memory allocation failed \r
+ //\r
+ return;\r
+ }\r
+ //\r
+ // Try to allocate boot memory.\r
+ //\r
+ Status = CoreAllocatePages (\r
+ AllocateAddress,\r
+ EfiBootServicesCode,\r
+ BootTimeCodePageNumber,\r
+ &BootTimeCodeBase\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // boot memory allocation failed. Free Runtime code range and will try the allocation again when \r
+ // new memory range is installed.\r
+ //\r
+ CoreFreePages (\r
+ RuntimeCodeBase,\r
+ RuntimeCodePageNumber\r
+ );\r
+ return;\r
+ }\r
+ gLoadFixedAddressCodeMemoryReady = TRUE;\r
+ } \r
+ return;\r
+} \r
\r
/**\r
Called to initialize the memory map and add descriptors to\r
EFI_STATUS Status;\r
UINTN Index;\r
UINTN FreeIndex;\r
-\r
+ \r
if ((Start & EFI_PAGE_MASK) != 0) {\r
return;\r
}\r
if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {\r
return;\r
}\r
-\r
CoreAcquireMemoryLock ();\r
End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
CoreAddRange (Type, Start, End, Attribute);\r
CoreFreeMemoryMapStack ();\r
CoreReleaseMemoryLock ();\r
\r
+ //\r
+ // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type\r
+ //\r
+ if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
+ CoreLoadingFixedAddressHook();\r
+ }\r
+ \r
//\r
// Check to see if the statistics for the different memory types have already been established\r
//\r
return;\r
}\r
\r
+ \r
//\r
// Loop through each memory type in the order specified by the gMemoryTypeInformation[] array\r
//\r
if (Type < 0 || Type > EfiMaxMemoryType) {\r
continue;\r
}\r
-\r
if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
//\r
// Allocate pages for the current memory type from the top of available memory\r
if (Type < 0 || Type > EfiMaxMemoryType) {\r
continue;\r
}\r
-\r
if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
CoreFreePages (\r
mMemoryTypeStatistics[Type].BaseAddress,\r
//\r
return (VOID*) ((UINTN) EntryPoint + (UINTN) PeiCore - (UINTN) _ModuleEntryPoint);\r
}\r
+//\r
+// This is the minimum memory required by DxeCore initialization. When LMFA feature enabled,\r
+// This part of memory still need reserved on the very top of memory so that the DXE Core could \r
+// use these memory for data initialization. This macro should be sync with the same marco\r
+// defined in DXE Core.\r
+//\r
+#define MINIMUM_INITIAL_MEMORY_SIZE 0x10000\r
+/**\r
+ Hook function for Loading Module at Fixed Address feature\r
+ \r
+ This function should only be invoked when Loading Module at Fixed Address(LMFA) feature is enabled. When feature is\r
+ configured as Load Modules at Fix Absolute Address, this function is to validate the top address assigned by user. When \r
+ feature is configured as Load Modules at Fixed Offset, the functino is to find the top address which is TOLM-TSEG in general. \r
+ And also the function will re-install PEI memory. \r
\r
+ @param PrivateData Pointer to the private data passed in from caller\r
+\r
+**/\r
+VOID\r
+PeiLoadFixAddressHook(\r
+ IN PEI_CORE_INSTANCE *PrivateData\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS TopLoadingAddress;\r
+ UINT64 PeiMemorySize;\r
+ UINT64 TotalReservedMemorySize;\r
+ UINT64 MemoryRangeEnd;\r
+ EFI_PHYSICAL_ADDRESS HighAddress; \r
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;\r
+ EFI_HOB_RESOURCE_DESCRIPTOR *NextResourceHob;\r
+ EFI_HOB_RESOURCE_DESCRIPTOR *CurrentResourceHob;\r
+ EFI_PEI_HOB_POINTERS CurrentHob;\r
+ EFI_PEI_HOB_POINTERS Hob;\r
+ EFI_PEI_HOB_POINTERS NextHob;\r
+ EFI_PHYSICAL_ADDRESS MaxMemoryBaseAddress;\r
+ UINT64 MaxMemoryLength;\r
+ //\r
+ // Initialize Local Variables\r
+ //\r
+ CurrentResourceHob = NULL;\r
+ ResourceHob = NULL;\r
+ NextResourceHob = NULL;\r
+ MaxMemoryBaseAddress = 0;\r
+ MaxMemoryLength = 0;\r
+ HighAddress = 0;\r
+ TopLoadingAddress = 0;\r
+ MemoryRangeEnd = 0;\r
+ CurrentHob.Raw = PrivateData->HobList.Raw;\r
+ PeiMemorySize = PrivateData->PhysicalMemoryLength;\r
+ //\r
+ // The top reserved memory include 3 parts: the topest range is for DXE core initialization with the size MINIMUM_INITIAL_MEMORY_SIZE\r
+ // then RuntimeCodePage range and Boot time code range.\r
+ // \r
+ TotalReservedMemorySize = EFI_PAGES_TO_SIZE(PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber)+ PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber))\r
+ + MINIMUM_INITIAL_MEMORY_SIZE; \r
+ \r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressRuntimeCodePageNumber= %x.\n", PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber)));\r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressBootTimeCodePageNumber= %x.\n", PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber)));\r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PcdLoadFixAddressPeiCodePageNumber= %x.\n", PcdGet32(PcdLoadFixAddressPeiCodePageNumber))); \r
+ //\r
+ // PEI memory range lies below the top reserved memory\r
+ // \r
+ TotalReservedMemorySize += PeiMemorySize;\r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Total Reserved Memory Size = %lx.\n", TotalReservedMemorySize));\r
+ //\r
+ // Loop through the system memory typed hob to merge the adjacent memory range \r
+ //\r
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {\r
+ // \r
+ // See if this is a resource descriptor HOB \r
+ //\r
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+ \r
+ ResourceHob = Hob.ResourceDescriptor; \r
+ //\r
+ // If range described in this hob is not system memory or heigher than MAX_ADDRESS, ignored.\r
+ //\r
+ if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY &&\r
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength > MAX_ADDRESS) {\r
+ continue;\r
+ } \r
+ \r
+ for (NextHob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(NextHob); NextHob.Raw = GET_NEXT_HOB(NextHob)) { \r
+ if (NextHob.Raw == Hob.Raw){\r
+ continue;\r
+ } \r
+ //\r
+ // See if this is a resource descriptor HOB\r
+ //\r
+ if (GET_HOB_TYPE (NextHob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+ \r
+ NextResourceHob = NextHob.ResourceDescriptor;\r
+ //\r
+ // test if range described in this NextResourceHob is system memory and have the same attribute.\r
+ // Note: Here is a assumption that system memory should always be healthy even without test.\r
+ // \r
+ if (NextResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&\r
+ (((NextResourceHob->ResourceAttribute^ResourceHob->ResourceAttribute)&(~EFI_RESOURCE_ATTRIBUTE_TESTED)) == 0)){\r
+ \r
+ //\r
+ // See if the memory range described in ResourceHob and NextResourceHob is adjacent\r
+ //\r
+ if ((ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart && \r
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength >= NextResourceHob->PhysicalStart)|| \r
+ (ResourceHob->PhysicalStart >= NextResourceHob->PhysicalStart&&\r
+ ResourceHob->PhysicalStart <= NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) {\r
+ \r
+ MemoryRangeEnd = ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength)>(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength)) ?\r
+ (ResourceHob->PhysicalStart + ResourceHob->ResourceLength):(NextResourceHob->PhysicalStart + NextResourceHob->ResourceLength);\r
+ \r
+ ResourceHob->PhysicalStart = (ResourceHob->PhysicalStart < NextResourceHob->PhysicalStart) ? \r
+ ResourceHob->PhysicalStart : NextResourceHob->PhysicalStart;\r
+ \r
+ \r
+ ResourceHob->ResourceLength = (MemoryRangeEnd - ResourceHob->PhysicalStart);\r
+ \r
+ ResourceHob->ResourceAttribute = ResourceHob->ResourceAttribute & (~EFI_RESOURCE_ATTRIBUTE_TESTED);\r
+ //\r
+ // Delete the NextResourceHob by marking it as unused.\r
+ //\r
+ GET_HOB_TYPE (NextHob) = EFI_HOB_TYPE_UNUSED;\r
+ \r
+ }\r
+ }\r
+ } \r
+ }\r
+ } \r
+ }\r
+ //\r
+ // Try to find and validate the TOP address.\r
+ // \r
+ if ((INT64)FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) > 0 ) {\r
+ //\r
+ // The LMFA feature is enabled as load module at fixed absolute address.\r
+ //\r
+ TopLoadingAddress = (EFI_PHYSICAL_ADDRESS)FixedPcdGet64(PcdLoadModuleAtFixAddressEnable);\r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Loading module at fixed absolute address.\n"));\r
+ //\r
+ // validate the Address. Loop the resource descriptor HOB to make sure the address is in valid memory range\r
+ //\r
+ if ((TopLoadingAddress & EFI_PAGE_MASK) != 0) {\r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address %lx is invalid since top address should be page align. \n", TopLoadingAddress)); \r
+ ASSERT (FALSE); \r
+ }\r
+ //\r
+ // Search for a memory region that is below MAX_ADDRESS and in which TopLoadingAddress lies \r
+ //\r
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {\r
+ //\r
+ // See if this is a resource descriptor HOB\r
+ //\r
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+\r
+ ResourceHob = Hob.ResourceDescriptor;\r
+ //\r
+ // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS\r
+ // \r
+ if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&\r
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {\r
+ //\r
+ // See if Top address specified by user is valid.\r
+ //\r
+ if (ResourceHob->PhysicalStart + TotalReservedMemorySize < TopLoadingAddress && \r
+ (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MINIMUM_INITIAL_MEMORY_SIZE) >= TopLoadingAddress) {\r
+ CurrentResourceHob = ResourceHob; \r
+ CurrentHob = Hob;\r
+ break;\r
+ }\r
+ }\r
+ } \r
+ } \r
+ if (CurrentResourceHob != NULL) {\r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO:Top Address %lx is valid \n", TopLoadingAddress));\r
+ TopLoadingAddress += MINIMUM_INITIAL_MEMORY_SIZE; \r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:Top Address %lx is invalid \n", TopLoadingAddress)); \r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The recommended Top Address for the platform is: \n")); \r
+ //\r
+ // Print the recomended Top address range.\r
+ // \r
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {\r
+ //\r
+ // See if this is a resource descriptor HOB\r
+ //\r
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+ \r
+ ResourceHob = Hob.ResourceDescriptor;\r
+ //\r
+ // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS\r
+ // \r
+ if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&\r
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS) {\r
+ //\r
+ // See if Top address specified by user is valid.\r
+ //\r
+ if (ResourceHob->ResourceLength > TotalReservedMemorySize) {\r
+ DEBUG ((EFI_D_INFO, "(%lx, %lx)\n", \r
+ (ResourceHob->PhysicalStart + TotalReservedMemorySize -MINIMUM_INITIAL_MEMORY_SIZE), \r
+ (ResourceHob->PhysicalStart + ResourceHob->ResourceLength -MINIMUM_INITIAL_MEMORY_SIZE) \r
+ )); \r
+ }\r
+ }\r
+ }\r
+ } \r
+ //\r
+ // Assert here \r
+ //\r
+ ASSERT (FALSE); \r
+ } \r
+ } else {\r
+ //\r
+ // The LMFA feature is enabled as load module at fixed offset relative to TOLM\r
+ // Parse the Hob list to find the topest available memory. Generally it is (TOLM - TSEG)\r
+ //\r
+ //\r
+ // Search for a tested memory region that is below MAX_ADDRESS\r
+ //\r
+ for (Hob.Raw = PrivateData->HobList.Raw; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {\r
+ //\r
+ // See if this is a resource descriptor HOB \r
+ //\r
+ if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+ \r
+ ResourceHob = Hob.ResourceDescriptor; \r
+ //\r
+ // See if this resource descrior HOB describes tested system memory below MAX_ADDRESS\r
+ //\r
+ if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY && \r
+ ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MAX_ADDRESS &&\r
+ ResourceHob->ResourceLength > TotalReservedMemorySize) {\r
+ //\r
+ // See if this is the highest largest system memory region below MaxAddress\r
+ //\r
+ if (ResourceHob->PhysicalStart > HighAddress) {\r
+ CurrentResourceHob = ResourceHob;\r
+ CurrentHob = Hob;\r
+ HighAddress = CurrentResourceHob->PhysicalStart;\r
+ }\r
+ }\r
+ } \r
+ }\r
+ if (CurrentResourceHob == NULL) {\r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR:The System Memory is too small\n")); \r
+ //\r
+ // Assert here \r
+ //\r
+ ASSERT (FALSE); \r
+ } else {\r
+ TopLoadingAddress = CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength ; \r
+ } \r
+ }\r
+ \r
+ if (CurrentResourceHob != NULL) {\r
+ //\r
+ // rebuild hob for PEI memmory and reserved memory\r
+ //\r
+ BuildResourceDescriptorHob (\r
+ EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType,\r
+ (\r
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+ EFI_RESOURCE_ATTRIBUTE_TESTED |\r
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+ ),\r
+ (TopLoadingAddress - TotalReservedMemorySize), // MemoryBegin\r
+ TotalReservedMemorySize // MemoryLength\r
+ );\r
+ //\r
+ // rebuild hob for the remain memory if necessary\r
+ //\r
+ if (CurrentResourceHob->PhysicalStart < TopLoadingAddress - TotalReservedMemorySize) {\r
+ BuildResourceDescriptorHob (\r
+ EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType,\r
+ (\r
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+ ),\r
+ CurrentResourceHob->PhysicalStart, // MemoryBegin\r
+ (TopLoadingAddress - TotalReservedMemorySize - CurrentResourceHob->PhysicalStart) // MemoryLength\r
+ );\r
+ }\r
+ if (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength > TopLoadingAddress ) {\r
+ BuildResourceDescriptorHob (\r
+ EFI_RESOURCE_SYSTEM_MEMORY, \r
+ (\r
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+ ),\r
+ TopLoadingAddress, \r
+ (CurrentResourceHob->PhysicalStart + CurrentResourceHob->ResourceLength - TopLoadingAddress) \r
+ );\r
+ }\r
+ //\r
+ // Delete CurrentHob by marking it as unused since the the memory range described by is rebuilt.\r
+ //\r
+ GET_HOB_TYPE (CurrentHob) = EFI_HOB_TYPE_UNUSED; \r
+ }\r
+\r
+ //\r
+ // Cache the top address for Loading Module at Fixed Address feature\r
+ //\r
+ PrivateData->LoadModuleAtFixAddressTopAddress = TopLoadingAddress - MINIMUM_INITIAL_MEMORY_SIZE;\r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: Top address = %lx\n", PrivateData->LoadModuleAtFixAddressTopAddress)); \r
+ //\r
+ // reinstall the PEI memory relative to TopLoadingAddress\r
+ //\r
+ PrivateData->PhysicalMemoryBegin = TopLoadingAddress - TotalReservedMemorySize;\r
+ PrivateData->FreePhysicalMemoryTop = PrivateData->PhysicalMemoryBegin + PeiMemorySize;\r
+}\r
/**\r
Conduct PEIM dispatch.\r
\r
UINTN OldCheckingTop;\r
UINTN OldCheckingBottom;\r
PEI_CORE_FV_HANDLE *CoreFvHandle;\r
+ VOID *LoadFixPeiCodeBegin;\r
\r
PeiServices = (CONST EFI_PEI_SERVICES **) &Private->PS;\r
PeimEntryPoint = NULL;\r
));\r
DEBUG_CODE_END ();\r
\r
+ if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
+ //\r
+ // Loading Module at Fixed Address is enabled\r
+ //\r
+ PeiLoadFixAddressHook(Private);\r
+ }\r
+ \r
//\r
// Reserve the size of new stack at bottom of physical memory\r
//\r
//\r
PrivateInMem->PeimDispatcherReenter = TRUE;\r
\r
+ if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
+ //\r
+ // if Loading Module at Fixed Address is enabled, This is the first invoke to page \r
+ // allocation for Pei Core segment. This memory segment should be reserved for loading PEIM\r
+ //\r
+ LoadFixPeiCodeBegin = AllocatePages((UINTN)PcdGet32(PcdLoadFixAddressPeiCodePageNumber));\r
+ DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: PeiCodeBegin = %x, PeiCodeTop= %x\n", (UINTN)LoadFixPeiCodeBegin, ((UINTN)LoadFixPeiCodeBegin) + PcdGet32(PcdLoadFixAddressPeiCodePageNumber) * EFI_PAGE_SIZE)); \r
+ //\r
+ // if Loading Module at Fixed Address is enabled, allocate the PEI code memory range usage bit map array.\r
+ // Every bit in the array indicate the status of the corresponding memory page, available or not\r
+ //\r
+ PrivateInMem->PeiCodeMemoryRangeUsageBitMap = AllocateZeroPool (((PcdGet32(PcdLoadFixAddressPeiCodePageNumber)>>6) + 1)*sizeof(UINT64));\r
+ }\r
//\r
// Shadow PEI Core. When permanent memory is avaiable, shadow\r
// PEI Core and PEIMs to get high performance.\r
/** @file\r
Pei Core Load Image Support\r
- \r
-Copyright (c) 2006 - 2010, Intel Corporation \r
-All rights reserved. This program and the accompanying materials \r
-are licensed and made available under the terms and conditions of the BSD License \r
-which accompanies this distribution. The full text of the license may be found at \r
-http://opensource.org/licenses/bsd-license.php \r
- \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
\r
**/\r
\r
\r
return EFI_SUCCESS;\r
}\r
+/**\r
+ 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 \r
+ memory range is avaliable, the function will mark the correponding bits to 1 which indicates the memory range is used.\r
+ The function is only invoked when load modules at fixed address feature is enabled. \r
+ \r
+ @param Private Pointer to the private data passed in from caller\r
+ @param ImageBase The base addres the image will be loaded at.\r
+ @param ImageSize The size of the image\r
+ \r
+ @retval EFI_SUCCESS The memory range the image will be loaded in is available\r
+ @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available\r
+**/\r
+EFI_STATUS\r
+CheckAndMarkFixLoadingMemoryUsageBitMap (\r
+ IN PEI_CORE_INSTANCE *Private,\r
+ IN EFI_PHYSICAL_ADDRESS ImageBase,\r
+ IN UINT32 ImageSize\r
+ )\r
+{\r
+ UINT32 DxeCodePageNumber;\r
+ UINT64 ReservedCodeSize;\r
+ EFI_PHYSICAL_ADDRESS PeiCodeBase;\r
+ UINT32 BaseOffsetPageNumber;\r
+ UINT32 TopOffsetPageNumber;\r
+ UINT32 Index;\r
+ UINT64 *MemoryUsageBitMap;\r
+ \r
+\r
+ //\r
+ // The reserved code range includes RuntimeCodePage range, Boot time code range and PEI code range.\r
+ //\r
+ DxeCodePageNumber = PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);\r
+ DxeCodePageNumber += PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);\r
+ ReservedCodeSize = EFI_PAGES_TO_SIZE(DxeCodePageNumber + PcdGet32(PcdLoadFixAddressPeiCodePageNumber));\r
+ PeiCodeBase = Private->LoadModuleAtFixAddressTopAddress - ReservedCodeSize;\r
+ \r
+ //\r
+ // Test the memory range for loading the image in the PEI code range.\r
+ //\r
+ if ((Private->LoadModuleAtFixAddressTopAddress - EFI_PAGES_TO_SIZE(DxeCodePageNumber)) < (ImageBase + ImageSize) ||\r
+ (PeiCodeBase > ImageBase)) { \r
+ return EFI_NOT_FOUND; \r
+ }\r
+ \r
+ //\r
+ // Test if the memory is avalaible or not.\r
+ //\r
+ MemoryUsageBitMap = Private->PeiCodeMemoryRangeUsageBitMap; \r
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - PeiCodeBase));\r
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - PeiCodeBase));\r
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
+ if ((MemoryUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {\r
+ //\r
+ // This page is already used.\r
+ //\r
+ return EFI_NOT_FOUND; \r
+ }\r
+ }\r
+ \r
+ //\r
+ // Being here means the memory range is available. So mark the bits for the memory range\r
+ // \r
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
+ MemoryUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));\r
+ }\r
+ return EFI_SUCCESS; \r
+}\r
+/**\r
+\r
+ Get the fixed loadding address from image header assigned by build tool. This function only be called\r
+ when Loading module at Fixed address feature enabled.\r
+\r
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
+ image that needs to be examined by this function.\r
+ @param Private Pointer to the private data passed in from caller\r
+\r
+ @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .\r
+ @retval EFI_NOT_FOUND The image has no assigned fixed loadding address.\r
\r
+**/\r
+EFI_STATUS\r
+GetPeCoffImageFixLoadingAssignedAddress(\r
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
+ IN PEI_CORE_INSTANCE *Private\r
+ )\r
+{\r
+ UINTN SectionHeaderOffset;\r
+ EFI_STATUS Status;\r
+ EFI_IMAGE_SECTION_HEADER SectionHeader;\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
+ EFI_PHYSICAL_ADDRESS FixLoaddingAddress;\r
+ UINT16 Index;\r
+ UINTN Size;\r
+ UINT16 NumberOfSections;\r
+ UINT64 ValueInSectionHeader;\r
+ \r
+\r
+ FixLoaddingAddress = 0;\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ //\r
+ // Get PeHeader pointer\r
+ //\r
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);\r
+ if (ImageContext->IsTeImage) {\r
+ //\r
+ // for TE image, the fix loadding address is saved in first section header that doesn't point\r
+ // to code section.\r
+ //\r
+ SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);\r
+ NumberOfSections = ImgHdr->Te.NumberOfSections;\r
+ } else {\r
+ SectionHeaderOffset = (UINTN)(\r
+ ImageContext->PeCoffHeaderOffset +\r
+ sizeof (UINT32) +\r
+ sizeof (EFI_IMAGE_FILE_HEADER) +\r
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
+ );\r
+ NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;\r
+ }\r
+ //\r
+ // Get base address from the first section header that doesn't point to code section.\r
+ //\r
+ for (Index = 0; Index < NumberOfSections; Index++) {\r
+ //\r
+ // Read section header from file\r
+ //\r
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ Status = ImageContext->ImageRead (\r
+ ImageContext->Handle,\r
+ SectionHeaderOffset,\r
+ &Size,\r
+ &SectionHeader\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {\r
+ //\r
+ // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header\r
+ // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is\r
+ // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because\r
+ // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers\r
+ // 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\r
+ // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or\r
+ // else, these 2 fileds should be set to Zero\r
+ //\r
+ ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);\r
+ if (ValueInSectionHeader != 0) {\r
+ //\r
+ // Found first section header that doesn't point to code section.\r
+ //\r
+ if ((INT64)FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) > 0) {\r
+ //\r
+ // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field\r
+ // hold the absolute address of image base runing in memory\r
+ //\r
+ FixLoaddingAddress = ValueInSectionHeader;\r
+ } else {\r
+ //\r
+ // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field\r
+ // hold the offset relative to a platform-specific top address.\r
+ //\r
+ FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);\r
+ }\r
+ //\r
+ // Check if the memory range is avaliable.\r
+ //\r
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoaddingAddress, (UINT32) ImageContext->ImageSize);\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // The assigned address is valid. Return the specified loadding address\r
+ //\r
+ ImageContext->ImageAddress = FixLoaddingAddress;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ }\r
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %lx. Status= %r \n", FixLoaddingAddress, Status));\r
+ return Status;\r
+}\r
/**\r
\r
Loads and relocates a PE/COFF image into memory.\r
// When Image has no reloc section, it can't be relocated into memory.\r
//\r
if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
- DEBUG ((EFI_D_INFO, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));\r
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));\r
}\r
\r
//\r
// Set default base address to current image address.\r
//\r
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;\r
- \r
+\r
//\r
// Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable.\r
//\r
if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
- ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
+ if (FixedPcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
+ Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);\r
+ if (EFI_ERROR (Status)){\r
+ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));\r
+ //\r
+ // The PEIM is not assiged valid address, try to allocate page to load it.\r
+ //\r
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
+ }\r
+ } else {\r
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
+ }\r
ASSERT (ImageContext.ImageAddress != 0);\r
if (ImageContext.ImageAddress == 0) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
- \r
+\r
//\r
// Skip the reserved space for the stripped PeHeader when load TeImage into memory.\r
//\r
if (ImageContext.IsTeImage) {\r
- ImageContext.ImageAddress = ImageContext.ImageAddress + \r
+ ImageContext.ImageAddress = ImageContext.ImageAddress +\r
((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -\r
sizeof (EFI_TE_IMAGE_HEADER);\r
}\r
}\r
\r
/**\r
- Loads a PEIM into memory for subsequent execution. If there are compressed \r
- images or images that need to be relocated into memory for performance reasons, \r
+ Loads a PEIM into memory for subsequent execution. If there are compressed\r
+ images or images that need to be relocated into memory for performance reasons,\r
this service performs that transformation.\r
\r
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
}\r
\r
//\r
- // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst \r
+ // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst\r
// is true, TE will be searched first).\r
//\r
Status = PeiServicesFfsFindSectionData (\r
return Status;\r
}\r
}\r
- \r
+\r
//\r
// If memory is installed, perform the shadow operations\r
//\r
//\r
Pe32Data = (VOID *) ((UINTN) ImageAddress);\r
*EntryPoint = ImageEntryPoint;\r
- \r
+\r
Machine = PeCoffLoaderGetMachineType (Pe32Data);\r
- \r
+\r
if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {\r
if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {\r
return EFI_UNSUPPORTED;\r
if (ImageSizeArg != NULL) {\r
*ImageSizeArg = ImageSize;\r
}\r
- \r
+\r
DEBUG_CODE_BEGIN ();\r
CHAR8 *AsciiString;\r
CHAR8 AsciiBuffer[512];\r
//\r
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));\r
}\r
- \r
+\r
//\r
// Print Module Name by PeImage PDB file name.\r
//\r
AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);\r
- \r
+\r
if (AsciiString != NULL) {\r
for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {\r
if (AsciiString[Index] == '\\') {\r
\r
/**\r
Routine to load image file for subsequent execution by LoadFile Ppi.\r
- If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE \r
+ If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE\r
XIP image format is used.\r
\r
@param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
);\r
if (!EFI_ERROR (PpiStatus)) {\r
Status = LoadFile->LoadFile (\r
- LoadFile, \r
- FileHandle, \r
- &ImageAddress, \r
+ LoadFile,\r
+ FileHandle,\r
+ &ImageAddress,\r
&ImageSize,\r
EntryPoint,\r
AuthenticationState\r
PeiServicesInstallPpi (PrivateData->XipLoadFile);\r
} else {\r
//\r
- // 2nd time we are running from memory so replace the XIP version with the \r
- // new memory version. \r
+ // 2nd time we are running from memory so replace the XIP version with the\r
+ // new memory version.\r
//\r
- PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList); \r
+ PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);\r
}\r
}\r
\r
EFI_PHYSICAL_ADDRESS FreePhysicalMemoryTop;\r
VOID* ShadowedPeiCore;\r
CACHE_SECTION_DATA CacheSection;\r
+ //\r
+ // For Loading modules at fixed address feature to cache the top address below which the \r
+ // Runtime code, boot time code and PEI memory will be placed. Please note that the offset between this field \r
+ // and PS should not be changed since maybe user could get this top address by using the offet to PS. \r
+ //\r
+ EFI_PHYSICAL_ADDRESS LoadModuleAtFixAddressTopAddress;\r
+ //\r
+ // The field is define for Loading modules at fixed address feature to tracker the PEI code\r
+ // memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page\r
+ // available or not. \r
+ //\r
+ UINT64 *PeiCodeMemoryRangeUsageBitMap;\r
} PEI_CORE_INSTANCE;\r
\r
///\r
gEfiTemporaryRamSupportPpiGuid ## CONSUMES\r
\r
[FixedPcd]\r
- gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES\r
- gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeimPerFv ## CONSUMES\r
- gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPpiSupported ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeimPerFv ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPpiSupported ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable ## CONSUMES \r
\r
[Pcd] \r
gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize ## CONSUMES\r
gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst ## CONSUMES\r
gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressPeiCodePageNumber ## SOMETIMES_CONSUMES\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber ## SOMETIMES_CONSUMES \r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber ## SOMETIMES_CONSUMES \r
\r
--- /dev/null
+/** @file\r
+ This file defines:\r
+ A configuration Table Guid for Load module at fixed address. \r
+ This configuration table is to hold the top address below which the Dxe runtime code and \r
+ boot time code will be loaded and Tseg base. When this feature is enabled, Build tools will assigned \r
+ module loading address relative to these 2 address.\r
+ \r
+\r
+Copyright (c) 2010, Intel Corporation. <BR>\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __LOAD_MODULE_AT_FIX_ADDRESS_GUID_H__\r
+#define __LOAD_MODULE_AT_FIX_ADDRESS_GUID_H__\r
+\r
+#define EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE_GUID \\r
+ { 0x2CA88B53,0xD296,0x4080, { 0xA4,0xA5,0xCA,0xD9,0xBA,0xE2,0x4B,0x9} }\r
+\r
+\r
+extern EFI_GUID gLoadFixedAddressConfigurationTableGuid;\r
+\r
+typedef struct {\r
+ EFI_PHYSICAL_ADDRESS DxeCodeTopAddress; ///< The top address below which the Dxe runtime code and below which the Dxe runtime/boot code and PEI code.\r
+ EFI_PHYSICAL_ADDRESS TsegBase; ///< Tseg base. build tool will assigned an offset relative to Tseg base to SMM driver\r
+} EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE;\r
+\r
+#endif\r
# Include/Guid/StatusCodeDataTypeDebug.h\r
gEfiStatusCodeDataTypeDebugGuid = { 0x9A4E9246, 0xD553, 0x11D5, { 0x87, 0xE2, 0x00, 0x06, 0x29, 0x45, 0xC3, 0xB9 }}\r
\r
+ ## A configuration Table Guid for Load module at fixed address \r
+ # Include/Guid/LoadModuleAtFixedAddress.h\r
+ gLoadFixedAddressConfigurationTableGuid = { 0x2CA88B53,0xD296,0x4080, { 0xA4,0xA5,0xCA,0xD9,0xBA,0xE2,0x4B,0x9 } }\r
+\r
[Protocols.common]\r
## Load File protocol provides capability to load and unload EFI image into memory and execute it.\r
# Include/Protocol/LoadPe32Image.h\r
# BIT1 set indicates 8KB alignment\r
gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize|0x1|UINT32|0x10000047\r
\r
+ ## Flag of enabling/disabling the feature of Loading Module at Fixed Address \r
+ # -1: Enable the feature as fixed offset to TOLM\r
+ # 0: Disable the feature.\r
+ # Positive Value: Enable the feature as fixed absolute address, and the value is the top memory address \r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadModuleAtFixAddressEnable|0|UINT64|0x30001015\r
+ \r
## Smbios version\r
gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion|0x0206|UINT16|0x00010055\r
\r
# The default value in DxePhase is 128 KBytes.\r
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1|UINT16|0x00010054\r
\r
+[PcdsPatchableInModule]\r
+ ## Specify memory size with page number for PEI code when \r
+ # the feature of Loading Module at Fixed Address is enabled\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressPeiCodePageNumber|0|UINT32|0x00000029\r
+ \r
+ ## Specify memory size with page number for DXE boot time code when \r
+ # the feature of Loading Module at Fixed Address is enabled\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressBootTimeCodePageNumber|0|UINT32|0x0000002a\r
+ \r
+ ## Specify memory size with page number for DXE runtime code when \r
+ # the feature of Loading Module at Fixed Address is enabled\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressRuntimeCodePageNumber|0|UINT32|0x0000002b\r
+ \r
+ ## Specify memory size with page number for SMM code when \r
+ # the feature of Loading Module at Fixed Address is enabled\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdLoadFixAddressSmmCodePageNumber|0|UINT32|0x0000002c\r
+\r