Step to UEFI (251)Register PPI Notify

St这个系列是根据 QEMU 执行输出的 Log 来研究代码的。这里继续跟踪研究代码,这次研究的对象是下面这条串口输出:

Register PPI Notify: DCD0BE23-9586-40F4-B643-06522CED4EDE

这句话来自 \MdeModulePkg\Core\Pei\Security\Security.c 文件中的InitializeSecurityServices() 函数:

/**
  Initialize the security services.

  @param PeiServices     An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
  @param OldCoreData     Pointer to the old core data.
                         NULL if being run in non-permanent memory mode.

**/
VOID
InitializeSecurityServices (
  IN EFI_PEI_SERVICES  **PeiServices,
  IN PEI_CORE_INSTANCE *OldCoreData
  )
{
  if (OldCoreData == NULL) {
    PeiServicesNotifyPpi (&mNotifyList);
  }
  return;
}

其中 mNotifyList 注册了一个 Ppi Notify 的 Callback 函数:SecurityPpiNotifyCallback()

EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
   EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
   &gEfiPeiSecurity2PpiGuid,
   SecurityPpiNotifyCallback
};

PeiServicesNotifyPpi() 的定义在 \MdePkg\Library\PeiServicesLib\PeiServicesLib.c:

/**
  This service enables PEIMs to register a given service to be invoked when another service is
  installed or reinstalled.

  @param  NotifyList            A pointer to the list of notification interfaces
                                that the caller shall install.

  @retval EFI_SUCCESS           The interface was successfully installed.
  @retval EFI_INVALID_PARAMETER The NotifyList pointer is NULL.
  @retval EFI_INVALID_PARAMETER Any of the PEI notify descriptors in the list do
                                 not have the EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES
                                 bit set in the Flags field.
  @retval EFI_OUT_OF_RESOURCES  There is no additional space in the PPI database.

**/
EFI_STATUS
EFIAPI
PeiServicesNotifyPpi (
  IN CONST EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyList
  )

这个函数的功能是:注册一个 Callback函数,当给定的 Service 安装(install)或者重安装(re-install)时触发这个 callback函数。

经过检查,代码中没有人安装gEfiPeiSecurity2PpiGuid,所以 CallBack 不会发生。接下来找一个有触发 CallBack 函数的作为例子看一下这个如何动作的。

串口输出” Register PPI Notify: 49EDB1C1-BF21-4761-BB12-EB0031AABB397” 和上面的函数类似,这个 GUID定义在  \MdePkg\MdePkg.dec 中:

## Include/Ppi/FirmwareVolumeInfo.h
  gEfiPeiFirmwareVolumeInfoPpiGuid = { 0x49edb1c1, 0xbf21, 0x4761, { 0xbb, 0x12, 0xeb, 0x0, 0x31, 0xaa, 0xbb, 0x39 } }

1. 首先注册Notify,在\MdeModulePkg\Core\Pei\FwVol\FwVol.c 中:

EFI_PEI_NOTIFY_DESCRIPTOR mNotifyOnFvInfoList[] = {
  {
    EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
    &gEfiPeiFirmwareVolumeInfoPpiGuid,
    FirmwareVolumeInfoPpiNotifyCallback
  },
  {
    (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
    &gEfiPeiFirmwareVolumeInfo2PpiGuid,
    FirmwareVolumeInfoPpiNotifyCallback
  }
};

接下来可以在在串口 Log 中找到如下字样:

Install PPI: 49EDB1C1-BF21-4761-BB12-EB0031AABB39
Notify: PPI Guid: 49EDB1C1-BF21-4761-BB12-EB0031AABB39, Peim notify entry point: 82153C

2. “Install PPI: 49EDB1C1-BF21-4761-BB12-EB0031AABB39”来自:

\MdePkg\Library\PeiServicesLib\PeiServicesLib.c 中的InternalPeiServicesInstallFvInfoPpi () 函数,首先给PpiGuid赋值

    //
    // To install FvInfo Ppi.
    //
    FvInfoPpi = AllocateZeroPool (sizeof (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI));
    ASSERT (FvInfoPpi != NULL);
PpiGuid = &gEfiPeiFirmwareVolumeInfoPpiGuid;

接下来PeiServicesInstallPpi (FvInfoPpiDescriptor) 会安装这个 Ppi:

  FvInfoPpiDescriptor->Guid  = PpiGuid;
  FvInfoPpiDescriptor->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
  FvInfoPpiDescriptor->Ppi   = (VOID *) FvInfoPpi;
  Status = PeiServicesInstallPpi (FvInfoPpiDescriptor);

安装过程会出现“Install PPI: 49EDB1C1-BF21-4761-BB12-EB0031AABB39” 的提示。

3. “Notify: PPI Guid: 49EDB1C1-BF21-4761-BB12-EB0031AABB39, Peim notify entry point: 82153C”

因为这里安装了gEfiPeiFirmwareVolumeInfoPpiGuid 所以会执行FirmwareVolumeInfoPpiNotifyCallback() 这个 Callback 函数。在函数中有定义

    DEBUG ((
      EFI_D_INFO,
      "The %dth FV start address is 0x%11p, size is 0x%08x, handle is 0x%p\n",
      (UINT32) CurFvCount,
      (VOID *) FvInfo2Ppi.FvInfo,
      FvInfo2Ppi.FvInfoSize,
      FvHandle
      ));

于是我们在串口上能看到如下 Log :

“The 1th FV start address is 0x00000900000, size is 0x00C00000, handle is 0x900000”

就是说按照我们的预期一样,PeiServicesNotifyPpi 函数是用来注册一个 Callback 函数,当安装给定 GUID  的Service 后,触发这个 Callback 函数。

发表评论

您的电子邮箱地址不会被公开。