Step to UEFI (241)SecMain 中的 CONSTRUCTOR

在 SecCoreStartupWithStack() 函数中,有下面这一条调用:

ProcessLibraryConstructorList (NULL, NULL);

具体调用的代码在\Build\OvmfX64\DEBUG_VS2015x86\X64\OvmfPkg\Sec\SecMain\DEBUG\AutoGen.c 中:

VOID
EFIAPI
ProcessLibraryConstructorList (
  VOID
  )
{
  RETURN_STATUS  Status;

  Status = PlatformRomDebugLibIoPortConstructor ();
  ASSERT_RETURN_ERROR (Status);

  Status = AcpiTimerLibConstructor ();
  ASSERT_RETURN_ERROR (Status);

  Status = LzmaDecompressLibConstructor ();
  ASSERT_RETURN_ERROR (Status);
}
  1. PlatformRomDebugLibIoPortConstructor() 在 DebugLibDetectRom.c 中,函数是空的直接 return 了事;
  2. AcpiTimerLibConstructor() 在 BaseRomAcpiTimerLib.c 中,可以看到是取得当前一些 IO Base 的信息
/**
  The constructor function enables ACPI IO space.

  If ACPI I/O space not enabled, this function will enable it.
  It will always return RETURN_SUCCESS.

  @retval EFI_SUCCESS   The constructor always returns RETURN_SUCCESS.

**/
RETURN_STATUS
EFIAPI
AcpiTimerLibConstructor (
  VOID
  )
{
  UINT16 HostBridgeDevId;
  UINTN Pmba;
  UINT32 PmbaAndVal;
  UINT32 PmbaOrVal;
  UINTN AcpiCtlReg;
  UINT8 AcpiEnBit;

  //
  // Query Host Bridge DID to determine platform type
  //
  HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
  switch (HostBridgeDevId) {
    case INTEL_82441_DEVICE_ID:
      Pmba       = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
      PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
      PmbaOrVal  = PIIX4_PMBA_VALUE;
      AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
      AcpiEnBit  = PIIX4_PMREGMISC_PMIOSE;
      break;
    case INTEL_Q35_MCH_DEVICE_ID:
      Pmba       = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
      PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
      PmbaOrVal  = ICH9_PMBASE_VALUE;
      AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
      AcpiEnBit  = ICH9_ACPI_CNTL_ACPI_EN;
      break;
    default:
      DEBUG ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
        __FUNCTION__, HostBridgeDevId));
      ASSERT (FALSE);
      return RETURN_UNSUPPORTED;
  }

  //
  // Check to see if the Power Management Base Address is already enabled
  //
  if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
    //
    // If the Power Management Base Address is not programmed,
    // then program it now.
    //
    PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);

    //
    // Enable PMBA I/O port decodes
    //
    PciOr8 (AcpiCtlReg, AcpiEnBit);
  }

  return RETURN_SUCCESS;
}

3.LzmaDecompressLibConstructor 函数定义在\MdeModulePkg\Library\LzmaCustomDecompressLib\GuidedSectionExtraction.c 中:

/**
  Register LzmaDecompress and LzmaDecompressGetInfo handlers with LzmaCustomerDecompressGuid.

  @retval  RETURN_SUCCESS            Register successfully.
  @retval  RETURN_OUT_OF_RESOURCES   No enough memory to store this handler.
**/
EFI_STATUS
EFIAPI
LzmaDecompressLibConstructor (
  VOID
  )
{
  return ExtractGuidedSectionRegisterHandlers (
          &gLzmaCustomDecompressGuid,
          LzmaGuidedSectionGetInfo,
          LzmaGuidedSectionExtraction
          );
}

在 OvmfPkgX64.dsc 中[LibraryClasses.common.SEC] 这个Section可以看到如下三个 Lib:

  1. DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf
  2. TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
  3. <LibraryClasses> NULL|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf

上述的INF 文件中都有定义   CONSTRUCTOR   ,例如: 

CONSTRUCTOR                    = LzmaDecompressLibConstructor

因此,就是说SecMain.inf给出了引用的 LIB,然后在编译过程中如果发现对应的 LIB 有指定CONSTRUCTOR   , 那么就会构造 ProcessLibraryConstructorList() 。这样做的目的是:保证在调用一些LIB之前,已经完成了对应的初始化。类似的还有ProcessLibraryDestructorList(),可以用来完成一些LIB的收尾动作。

接下来的一个问题是:谁做了这个自动生成的动作?

答案是: build.py

在\BaseTools\Source\Python\AutoGen\GenC.py 有下面的函数:

## Create code for library constructor
#
#   @param      Info        The ModuleAutoGen object
#   @param      AutoGenC    The TemplateString object for C code
#   @param      AutoGenH    The TemplateString object for header file
#
def CreateLibraryConstructorCode(Info, AutoGenC, AutoGenH):

在其中加入如下 代码用于验证:

    for Lib in DependentLibraryList:
        if len(Lib.ConstructorList) <= 0:
            continue
        Dict = {'Function':Lib.ConstructorList}
        if Lib.ModuleType in [SUP_MODULE_BASE, SUP_MODULE_SEC]:
            ConstructorPrototypeString.Append("//www.lab-z.com testing");
            ConstructorPrototypeString.Append(gLibraryStructorPrototype[SUP_MODULE_BASE].Replace(Dict))
            ConstructorCallingString.Append(gLibraryStructorCall[SUP_MODULE_BASE].Replace(Dict))

重新编译代码,再次查看\Build\OvmfX64\DEBUG_VS2015x86\X64\OvmfPkg\Sec\SecMain\DEBUG\AutoGen.c可以看到我们测试的注释代码已经写入 AutoGen.c 了:

GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdCpuSmmStackGuard = _PCD_VALUE_PcdCpuSmmStackGuard;
extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdCpuSmmStackGuard;
#define _PCD_GET_MODE_BOOL_PcdCpuSmmStackGuard  _gPcd_FixedAtBuild_PcdCpuSmmStackGuard
//#define _PCD_SET_MODE_BOOL_PcdCpuSmmStackGuard  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD

//www.lab-z.com testing
RETURN_STATUS
EFIAPI
PlatformRomDebugLibIoPortConstructor (
  VOID
  );
//www.lab-z.com testing
RETURN_STATUS
EFIAPI
AcpiTimerLibConstructor (
  VOID
  );
//www.lab-z.com testing
RETURN_STATUS
EFIAPI
LzmaDecompressLibConstructor (
  VOID
  );


VOID
EFIAPI
ProcessLibraryConstructorList (
  VOID
  )
{
  RETURN_STATUS  Status;

  Status = PlatformRomDebugLibIoPortConstructor ();
  ASSERT_RETURN_ERROR (Status);

  Status = AcpiTimerLibConstructor ();
  ASSERT_RETURN_ERROR (Status);

  Status = LzmaDecompressLibConstructor ();
  ASSERT_RETURN_ERROR (Status);

}

上述实验是基于 edk202108, 如果你在其他版本实验,有可能调用的是 build.exe,实验无法成功。

发表评论

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