/** 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; }
/** Get the fixed loadding address from image header assigned by build tool. This function only be called when Loading module at Fixed address feature enabled. @param ImageContext Pointer to the image context structure that describes the PE/COFF image that needs to be examined by this function. @param Private Pointer to the private data passed in from caller @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools . @retval EFI_NOT_FOUND The image has no assigned fixed loadding address. **/ EFI_STATUS GetPeCoffImageFixLoadingAssignedAddress( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, IN PEI_CORE_INSTANCE *Private ) { UINTN SectionHeaderOffset; EFI_STATUS Status; EFI_IMAGE_SECTION_HEADER SectionHeader; EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; EFI_PHYSICAL_ADDRESS FixLoaddingAddress; UINT16 Index; UINTN Size; UINT16 NumberOfSections; UINT64 ValueInSectionHeader; FixLoaddingAddress = 0; Status = EFI_NOT_FOUND; // // Get PeHeader pointer // ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset); if (ImageContext->IsTeImage) { // // for TE image, the fix loadding address is saved in first section header that doesn't point // to code section. // SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER); NumberOfSections = ImgHdr->Te.NumberOfSections; } else { SectionHeaderOffset = (UINTN)( ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader ); NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections; } // // Get base address from the first section header that doesn't point to code section. // for (Index = 0; Index < NumberOfSections; Index++) { // // Read section header from file // Size = sizeof (EFI_IMAGE_SECTION_HEADER); Status = ImageContext->ImageRead ( ImageContext->Handle, SectionHeaderOffset, &Size, &SectionHeader ); if (EFI_ERROR (Status)) { return Status; } Status = EFI_NOT_FOUND; if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { // // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers // hold the image base address when it is shadow to the memory. And there is an assumption that when the feature is enabled, if a // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or // else, these 2 fileds should be set to Zero // ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations); if (ValueInSectionHeader != 0) { // // Found first section header that doesn't point to code section. // if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0) { // // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field // hold the absolute address of image base runing in memory // FixLoaddingAddress = ValueInSectionHeader; } else { // // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field // hold the offset relative to a platform-specific top address. // FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader); } // // Check if the memory range is avaliable. // Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoaddingAddress, (UINT32) ImageContext->ImageSize); if (!EFI_ERROR(Status)) { // // The assigned address is valid. Return the specified loadding address // ImageContext->ImageAddress = FixLoaddingAddress; } } break; } SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); } DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status= %r \n", (VOID *)(UINTN)FixLoaddingAddress, Status)); return Status; }