Step to UEFI (260)Section Alignment(0x20) is not 4K

查看 Log 的过程中,发现在 DXE 阶段有错误报出,本文针对这个问题进行了一点研究。

首先,遇到的错误信息如下:

InstallProtocolInterface: BC62157E-3E33-4FEC-9920-2D3B36D750DF 7543E98
ProtectUefiImageCommon - 0x7543B40
  - 0x0000000007105000 - 0x0000000000005E60
InstallProtocolInterface: AA0E8BC1-DABC-46B0-A844-37B8169B2BEA 710A9C0
Loading driver 4B28E4C7-FF36-4E10-93CF-A82159E777C5
InstallProtocolInterface: 5B1B31A1-9562-11D2-8E3F-00A0C969723B 7543140
!!!!!!!!  InsertImageRecord - Section Alignment(0x20) is not 4K  !!!!!!!!
!!!!!!!!  Image - c:\buildbs\stable202108org\Build\OvmfX64\DEBUG_VS2015x86\X64\MdeModulePkg\Universal\ResetSystemRuntimeDxe\ResetSystemRuntimeDxe\DEBUG\ResetSystemRuntimeDxe.pdb  !!!!!!!!
Loading driver at 0x00007AE1000 EntryPoint=0x00007AE14D4 ResetSystemRuntimeDxe.efi
InstallProtocolInterface: BC62157E-3E33-4FEC-9920-2D3B36D750DF 7543418
ProtectUefiImageCommon - 0x7543140
  - 0x0000000007AE1000 - 0x00000000000041A0

接下来定位。输出错误的代码位于 \mdemodulepkg\core\dxe\misc\MemoryAttributesTable.c 中的InsertImageRecord() 函数中:

/**
  Insert image record.

  @param  RuntimeImage    Runtime image information
**/
VOID
InsertImageRecord (
  IN EFI_RUNTIME_IMAGE_ENTRY  *RuntimeImage
  )
……………
  //
  // Get SectionAlignment
  //
  if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    SectionAlignment  = Hdr.Pe32->OptionalHeader.SectionAlignment;
  } else {
    SectionAlignment  = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
  }
  SetMemoryAttributesTableSectionAlignment (SectionAlignment);
  if ((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {
    DEBUG ((DEBUG_WARN, "!!!!!!!!  InsertImageRecord - Section Alignment(0x%x) is not %dK  !!!!!!!!\n",
      SectionAlignment, RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
    PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageAddress);
    if (PdbPointer != NULL) {
      DEBUG ((DEBUG_WARN, "!!!!!!!!  Image - %a  !!!!!!!!\n", PdbPointer));
    }
    goto Finish;
  }
…………

在\MdePkg\Include\X64\ProcessorBind.h 有如下定义:

///
/// Page allocation granularity for x64
///
#define DEFAULT_PAGE_ALLOCATION_GRANULARITY   (0x1000)
#define RUNTIME_PAGE_ALLOCATION_GRANULARITY   (0x1000)

可以看到,SectionAlignment 来自 Hdr.Pe32Plus->OptionalHeader.SectionAlignment,使用 CFF 查看 ResetSystemRuntimeDxe.efi 这个文件,注意下图中的2个位置。上述代码首先检查ImageType(Subsystem) 是否为EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER,如果是再继续检查SectionAlignment是否为4K,如果不是 4K 对齐那么就进行报错。

ImageType的定义在\MdeModulePkg\Universal\ResetSystemRuntimeDxe\ResetSystemRuntimeDxe.inf 文件中:

[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = ResetSystemRuntimeDxe
  MODULE_UNI_FILE                = ResetSystemRuntimeDxe.uni
  FILE_GUID                      = 4B28E4C7-FF36-4e10-93CF-A82159E777C5
  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
  VERSION_STRING                 = 1.0

  ENTRY_POINT                    = InitializeResetSystem

搜索所有 MODULE_TYPE 为 DXE_RUNTIME_DRIVER 的 Module 发现在运行期都有这样的问题。

确定了问题,找到了问题点,接下来就开始分析“为什么出现不满足条件”。

检查\Build\OvmfX64\DEBUG_VS2015x86\X64\MdeModulePkg\Universal\ResetSystemRuntimeDxe\ResetSystemRuntimeDxe\Makefile 文件有下面一行:

DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG
(注意 /ALIGN:32 参数)

尝试修改上面为 /ALIGN:0x1000 修改之后再次编译(需要同样的环境,进入 Debug  目录直接运行 NMAKE,这种方法在之前的实验中有介绍过),生成的EFI如下:

我们需要修改EFI 的生成方式。在\Conf\tools_def.txt 可以看到默认的编译参数:

  DEBUG_VS2015x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG
RELEASE_VS2015x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /MERGE:.rdata=.data
NOOPT_VS2015x86_X64_DLINK_FLAGS    = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

这里我们使用的是DEBUG版,所以需要修改为下面这样(/ALIGN:0x1000)

  DEBUG_VS2015x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:0x1000 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG

修改之后重新编译OVMF,得到的ResetSystemRuntimeDxe.efi 和前面手工修改的结果相同。但是这样修改会导致编译最后一步无法通过:

Generating FVMAIN_COMPACT FV
Generating PEIFV FV
##### ['GenFv', '-a', 'c:\\buildbs\\stable202108org\\Build\\OvmfX64\\DEBUG_VS2015x86\\FV\\Ffs\\PEIFV.inf', '-o', 'c:\\buildbs\\stable202108org\\Build\\OvmfX64\\DEBUG_VS2015x86\\FV\\PEIFV.Fv', '-i', 'c:\\buildbs\\stable202108org\\Build\\OvmfX64\\DEBUG_VS2015x86\\FV\\PEIFV.inf']
Return Value = 2
GenFv: ERROR 3000: Invalid
  PE image Section-Alignment and File-Alignment do not match : c:\buildbs\stable202108org\Build\OvmfX64\DEBUG_VS2015x86\FV\Ffs\52C05B14-0B98-496c-BC3B-04B50211D680PeiCore\52C05B14-0B98-496c-BC3B-04B50211D680.ffs.
GenFv: ERROR 3000: Invalid
  Could not rebase c:\buildbs\stable202108org\Build\OvmfX64\DEBUG_VS2015x86\FV\Ffs\52C05B14-0B98-496c-BC3B-04B50211D680PeiCore\52C05B14-0B98-496c-BC3B-04B50211D680.ffs.

build.py...
 : error 7000: Failed to generate FV
build.py...
 : error 7000: Failed to execute command

看起来是因为 PE头中 SectionAlignment和FileAlignment 不同导致的,在【参考1】介绍了一个设置 FileAlignment 的参数。同样的,将这个参数加入到 tools_def.txt 文件中:

  DEBUG_VS2015x86_X64_DLINK_FLAGS  = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /MAP /ALIGN:0x1000 /FILEALIGN:0x1000 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /LTCG /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DRIVER /DEBUG
(注意  /FILEALIGN:0x1000 )

再次编译可以得到OVMF.FD ,使用QEMU 运行,Log 中就没有这个错误了。

这样的修改虽然能够解决问题,但是我们并不了解 InsertImageRecord() 函数的用途,后面有机会再继续进行分析。

参考:

1.https://blog.csdn.net/bagboy_taobao_com/article/details/7295575/

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注