在 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);
}
- PlatformRomDebugLibIoPortConstructor() 在 DebugLibDetectRom.c 中,函数是空的直接 return 了事;
- 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:
- DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf
- TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
- <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,实验无法成功。