+//\r
+// The global variable is defined for Loading modules at fixed address feature to track the SMM code\r
+// memory range usage. It is a bit mapped array in which every bit indicates the corresponding\r
+// memory page available or not. \r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mSmmCodeMemoryRangeUsageBitMap=NULL;\r
+\r
+/**\r
+ 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\r
+ memory range is available, the function will mark the corresponding 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 address 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 SmmCodePageNumber;\r
+ UINT64 SmmCodeSize; \r
+ EFI_PHYSICAL_ADDRESS SmmCodeBase;\r
+ UINTN BaseOffsetPageNumber;\r
+ UINTN TopOffsetPageNumber;\r
+ UINTN Index;\r
+ //\r
+ // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber\r
+ //\r
+ SmmCodePageNumber = PcdGet32(PcdLoadFixAddressSmmCodePageNumber);\r
+ SmmCodeSize = EFI_PAGES_TO_SIZE (SmmCodePageNumber);\r
+ SmmCodeBase = gLoadModuleAtFixAddressSmramBase;\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 (mSmmCodeMemoryRangeUsageBitMap == NULL) {\r
+ mSmmCodeMemoryRangeUsageBitMap = AllocateZeroPool(((SmmCodePageNumber / 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 (mSmmCodeMemoryRangeUsageBitMap == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // see if the memory range for loading the image is in the SMM code range.\r
+ //\r
+ if (SmmCodeBase + SmmCodeSize < ImageBase + ImageSize || SmmCodeBase > ImageBase) {\r
+ return EFI_NOT_FOUND; \r
+ } \r
+ //\r
+ // Test if the memory is avalaible or not.\r
+ // \r
+ BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - SmmCodeBase));\r
+ TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - SmmCodeBase));\r
+ for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
+ if ((mSmmCodeMemoryRangeUsageBitMap[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
+ mSmmCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));\r
+ }\r
+ return EFI_SUCCESS; \r
+}\r
+/**\r
+ Get the fixed loading 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 loading 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
+ EFI_PHYSICAL_ADDRESS FixLoadingAddress;\r
+ UINT16 Index;\r
+ UINTN Size;\r
+ UINT16 NumberOfSections;\r
+ UINT64 ValueInSectionHeader;\r
+\r
+ FixLoadingAddress = 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
+ SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +\r
+ sizeof (UINT32) +\r
+ sizeof (EFI_IMAGE_FILE_HEADER) +\r
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;\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.So there is an assumption that when the feature is enabled,\r
+ // if a module with a loading address assigned by tools, the PointerToRelocations & PointerToLineNumbers fields\r
+ // should not be Zero, or else, these 2 fields 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 in which build tool saves the\r
+ // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields\r
+ //\r
+ FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressSmramBase + (INT64)ValueInSectionHeader);\r
+ //\r
+ // Check if the memory range is available.\r
+ //\r
+ Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // The assigned address is valid. Return the specified loading address\r
+ //\r
+ ImageContext->ImageAddress = FixLoadingAddress;\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 %x, Status = %r\n", FixLoadingAddress, Status));\r
+ return Status;\r
+}\r