Cstyle的UEFI导读之PEI --- Notify && Callback

    在UEFI当中的PEI阶段我们经常使用一个叫做Notify的工具来进行不同的PEIM模块通信和交换数据(callback函数的入口参数为*PPI指针,可以指向数据,也可以指向PPI描述符),这里来简单介绍下Notify。
在PI SPC定义了PEIM能都调用的系统服务,其中对Notiry是这样定义Notiry的:NotifyPpi() Installs the notification service to be called back upon the  installation or reinstallation of a given interface. 可见当我们install一个PPI或者reinstall一个PPI的时候PEICore就会帮助我们自动的调用我们在之前注册的callback 服务。PPI descriptor有两种分是EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH 和EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,从下图可以看出二者的差别,这种差别会在PEICore当中体现出来。

Cstyle的UEFI导读之PEI --- Notify && Callback_第1张图片


    下面从代码的角度来简要分析下Notiry的实现。

1.PPI描述符,这个将会被install到PPI的数据库当中去。
typedef struct {
      /// This field is a set of flags describing the characteristics of this imported table entry.
      /// All flags are defined as EFI_PEI_PPI_DESCRIPTOR_***, which can also be combined into one.
  UINTN     Flags;
      /// The address of the EFI_GUID that names the interface.
  EFI_GUID  *Guid;
      /// A pointer to the PPI. It contains the information necessary to install a service.
  VOID      *Ppi;
} EFI_PEI_PPI_DESCRIPTOR;

2.Notify描述符,最终也会被注册到PPI数据库当中去,当对应的PPI被install的时候就会被调用。
struct _EFI_PEI_NOTIFY_DESCRIPTOR {
      /// Details if the type of notification are callback or dispatch.
  UINTN                       Flags;
      /// The address of the EFI_GUID that names the interface.
  EFI_GUID                    *Guid;
      /// Address of the notification callback function itself within the PEIM.
  EFI_PEIM_NOTIFY_ENTRY_POINT Notify;
};

3.当某个Notify触发的时候这个服务会被自动调用。
typedef 
EFI_STATUS
(EFIAPI *EFI_PEIM_NOTIFY_ENTRY_POINT)(
  IN EFI_PEI_SERVICES           **PeiServices,
  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
  IN VOID                       *Ppi
  );

4.以下是PPI数据库的实现,基本上就是一个包含了PPI描述符和Notify描述符指针的数组,PPI和和Notify分别处于数组的两端,数组的长度可以在编译阶段通过PCD服务来控制和调整,PCICore会使用PEI_PPI_DATABASE来定义一个实例,用来管理全局的PPI和Notify
typedef union {
  EFI_PEI_PPI_DESCRIPTOR      *Ppi;
  EFI_PEI_NOTIFY_DESCRIPTOR   *Notify;
  VOID                        *Raw;
} PEI_PPI_LIST_POINTERS; //共同体在PpiListPtrs里面可以根据数据类型灵活的调用空指针*Raw。

/// PPI database structure which contains two link: PpiList and NotifyList. PpiList
/// is in head of PpiListPtrs array and notify is in end of PpiListPtrs.
typedef struct {
  /// index of end of PpiList link list.
  INTN                    PpiListEnd;
  /// index of end of notify link list.
  INTN                    NotifyListEnd;
  /// index of the dispatched notify list.
  INTN                    DispatchListEnd;
  /// index of last installed Ppi description in PpiList link list.
  INTN                    LastDispatchedInstall;
  /// index of last dispatched notify in Notify link list.
  INTN                    LastDispatchedNotify;
  /// Ppi database.
  PEI_PPI_LIST_POINTERS   PpiListPtrs[FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)];
} PEI_PPI_DATABASE;

5.来看下PPI服务是如何实现的。

a.从下面可以看到我们在初始的时候,NotifyListEnd,DispatchListEnd ,LastDispatchedNotify都指向PPI数组PpiListPtrs的尾端,而PpiListPtrs的内容则为空。
这里我们 还要注意的一个东西就是他的传入参数,PrivateDate,其实这个就是PEICore的核心数据结构,我们的PPI数据库就存在于这个里面,使用PrivateData->PpiData就能访问到PPI数据库。它开始存在于CAR的栈当中,之后当内存被初始化之后就存在于内存中。

  Initialize PPI services.
  @param PrivateData     Pointer to the PEI Core data.
  @param OldCoreData     Pointer to old PEI Core data. 
                         NULL if being run in non-permament memory mode.
**/
VOID
InitializePpiServices (
  IN PEI_CORE_INSTANCE *PrivateData,
  IN PEI_CORE_INSTANCE *OldCoreData
  )
{
  if (OldCoreData == NULL) {
    PrivateData->PpiData.NotifyListEnd = FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
    PrivateData->PpiData.DispatchListEnd = FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
    PrivateData->PpiData.LastDispatchedNotify = FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
  }
}

b.再看下怎么installPPI就知道PPI数据库是如何添加数据进去的,当然这里的数据就是PPI。
/**
  This function installs an interface in the PEI PPI database by GUID. 
  The purpose of the service is to publish an interface that other parties
  can use to call additional PEIMs.
  @param PeiServices                An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
  @param PpiList                    Pointer to a list of PEI PPI Descriptors.

  @retval EFI_SUCCESS              if all PPIs in PpiList are successfully installed.
  @retval EFI_INVALID_PARAMETER    if PpiList is NULL pointer
                                   if any PPI in PpiList is not valid
  @retval EFI_OUT_OF_RESOURCES     if there is no more memory resource to install PPI
**/
EFI_STATUS
EFIAPI
PeiInstallPpi (
  IN CONST EFI_PEI_SERVICES        **PeiServices,
  IN CONST EFI_PEI_PPI_DESCRIPTOR  *PpiList
  )
{
  PEI_CORE_INSTANCE *PrivateData;
  INTN              Index;
  INTN              LastCallbackInstall;

  if (PpiList == NULL) {     //判断服务的前置条件,是否合法
    return EFI_INVALID_PARAMETER;
  }
  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);   //通过PS指针来获取核心的PEICore数据结构

  Index = PrivateData->PpiData.PpiListEnd;  //获取PPI数据库中最后一个PPI+1【从0~(Index-1)个已经被占用,第Index个是空闲】,注意PPI数据库是一个线性的数组。下标从【0,1,........PcdPeiCoreMaxPpiSupported】
  LastCallbackInstall = Index; //先缓存起来

  // This is loop installs all PPI descriptors in the PpiList.  It is terminated
  // by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
  // EFI_PEI_PPI_DESCRIPTOR in the list.

  for (;;) {
    // Since PpiData is used for NotifyList and PpiList, max resource
    // is reached if the Install reaches the NotifyList
    // PcdPeiCoreMaxPpiSupported can be set to a larger value in DSC to satisfy more PPI requirement.
    //
    if (Index == PrivateData->PpiData.NotifyListEnd + 1) { //查看是否PPI数据库已经满了,如果满了的话就溢出错误,然后返回。
      return  EFI_OUT_OF_RESOURCES;
    }
    // Check if it is a valid PPI.
    // If not, rollback list to exclude all in this list.
    // Try to indicate which item failed.
    //
    if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
      PrivateData->PpiData.PpiListEnd = LastCallbackInstall;   //如果PPI不合法,Flag不对,那么就不改变PpiListEnd,让其任然指向最后的一个PPI占用的位置+1(第一个空闲的位置),报错返回
      DEBUG((EFI_D_ERROR, "ERROR -> InstallPpi: %g %p\n", PpiList->Guid, PpiList->Ppi));
      return  EFI_INVALID_PARAMETER;
    }

    DEBUG((EFI_D_INFO, "Install PPI: %g\n", PpiList->Guid));
    PrivateData->PpiData.PpiListPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR*) PpiList; //把PPI描述符一个一个填入PPI数据库当中,并把指示PPI数据尾的指针PpiListEnd+1,指向下一个空位。
    PrivateData->PpiData.PpiListEnd++;
    //
    // Continue until the end of the PPI List.
    //
    if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
      break;
    }
    PpiList++; //指向下一个PPI
    Index++;指向下一个空位
  }
  // Dispatch any  callback level notifies  for newly installed PPIs. //这里会立即调用callback notifies,具体细节下面详述:
  //
  DispatchNotify (
    PrivateData,
      EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
    LastCallbackInstall,
    PrivateData->PpiData.PpiListEnd,
    PrivateData->PpiData.DispatchListEnd,
    PrivateData->PpiData.NotifyListEnd
    );
  return EFI_SUCCESS;
}

c.除了需要往PPI数据库里面添加数据之外,我们PPI数据库最的作用在于为PEIM和PEICore提供服务,所以我们需要提供获取PPI服务的功能,在这里就是LocatePpi()服务:
/**
  Locate a given named PPI.
  @param PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
  @param Guid               Pointer to GUID of the PPI.
  @param Instance           Instance Number to discover.
  @param PpiDescriptor      Pointer to reference the found descriptor. If not NULL,
                            returns a pointer to the descriptor (includes flags, etc)
  @param Ppi                Pointer to reference the found PPI
  @retval EFI_SUCCESS   if the PPI is in the database
  @retval EFI_NOT_FOUND if the PPI is not in the database
**/
EFI_STATUS
EFIAPI
PeiLocatePpi (
  IN CONST EFI_PEI_SERVICES        **PeiServices,
  IN CONST EFI_GUID                *Guid,
  IN UINTN                         Instance,
  IN OUT EFI_PEI_PPI_DESCRIPTOR    **PpiDescriptor, //指向指针的指针???
  IN OUT VOID                      **Ppi
  )
{
  PEI_CORE_INSTANCE   *PrivateData;
  INTN                Index;
  EFI_GUID            *CheckGuid;
  EFI_PEI_PPI_DESCRIPTOR  *TempPtr;

  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
  //
  // Search the data base for the matching instance of the GUIDed PPI.
  //
  for (Index = 0; Index < PrivateData->PpiData.PpiListEnd; Index++) { //从PPI数据库的顶端开始检索,index=0
    TempPtr = PrivateData->PpiData.PpiListPtrs[Index].Ppi;//获取PPI描述符
    CheckGuid = TempPtr->Guid;//获取代表PPI的唯一标示符—GUID

    // Don't use CompareGuid function here for performance reasons.
    // Instead we compare the GUID as INT32 at a time and branch
    // on the first failed comparison.
    if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&     //比较是否命中
        (((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
        (((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
        (((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3])) {
      if (Instance == 0) {

        if (PpiDescriptor != NULL) {
          *PpiDescriptor = TempPtr;
        }

        if (Ppi != NULL) {
          *Ppi = TempPtr->Ppi;
        }
        return EFI_SUCCESS;
      }
      Instance--; //用来查找满足条件的第instance个PPI,每找到一个就--,直到第Instance个,刚好递减到0.
    }
  }
  return EFI_NOT_FOUND;
}

d.现在说到重点,如何去Notify一个PPI,也就是如何注册一个Notify PPI到PPI数据库里面,这就是NotifyPpi()服务

/**
  This function installs a notification service to be called back when a given 
  interface is installed or reinstalled. The purpose of the service is to publish 
  an interface that other parties can use to call additional PPIs that may materialize later.
  @param PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
  @param NotifyList         Pointer to list of Descriptors to notify upon.
  @retval EFI_SUCCESS           if successful
  @retval EFI_OUT_OF_RESOURCES  if no space in the database
  @retval EFI_INVALID_PARAMETER if not a good decriptor
**/
EFI_STATUS
EFIAPI
PeiNotifyPpi (
  IN CONST EFI_PEI_SERVICES           **PeiServices,
  IN CONST EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyLis t//将要注册的Notify,和installPPI很类似EFI_PEI_PPI_DESCRIPTOR  。
  )
{
  PEI_CORE_INSTANCE                *PrivateData;
  INTN                             Index;
  INTN                             NotifyIndex;
  INTN                             LastCallbackNotify;
  EFI_PEI_NOTIFY_DESCRIPTOR        *NotifyPtr;
  UINTN                            NotifyDispatchCount;


  NotifyDispatchCount = 0;

  if (NotifyList == NULL) { //检查前置条件是否合法
    return EFI_INVALID_PARAMETER;
  }

  PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); //获取PEICore实例

  Index = PrivateData->PpiData.NotifyListEnd; //获取 NotifyListEnd 指针,还记得不?前面有给它赋初值NotifyListEnd ==PcdPeiCoreMaxPpiSupported)-1,也就是从PPI数据库的尾端开始。
  LastCallbackNotify = Index; //先缓存起来

  // This is loop installs all Notify descriptors in the NotifyList.  It is
  // terminated by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
  // EFI_PEI_NOTIFY_DESCRIPTOR in the list.

  for (;;) {
    // Since PpiData is used for NotifyList and InstallList, max resource
    // is reached if the Install reaches the PpiList
    // PcdPeiCoreMaxPpiSupported can be set to a larger value in DSC to satisfy more Notify PPIs requirement.
    if (Index == PrivateData->PpiData.PpiListEnd - 1) { //检查PPI数据库是否溢出。
      return  EFI_OUT_OF_RESOURCES;
    }

    // If some of the PPI data is invalid restore original Notify PPI database value
    if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) { //检查如果Notify 不合法,就不修改PPI数据库中的NotifyListEnd指针。
        PrivateData->PpiData.NotifyListEnd = LastCallbackNotify;
        DEBUG((EFI_D_ERROR, "ERROR -> InstallNotify: %g %p\n", NotifyList->Guid, NotifyList->Notify));
      return  EFI_INVALID_PARAMETER;
    }

    if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) { //否则计数,合法的Notify数目==NotifyDispatchCount 【0~(PpiListEnd - 1)】,注册完所有的Notify后,需要检查是否有Notify已经满足触发条件,我们需要去调用他们注册的服务函数。
      NotifyDispatchCount ++;
    }

    PrivateData->PpiData.PpiListPtrs[Index].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *) NotifyList; //从PPI数据库的尾端开始添加Notify指针。

    PrivateData->PpiData.NotifyListEnd--; //将Notify表的指针(NotifyListEnd)向前移动一个位置,准备插入下一个Notify
    DEBUG((EFI_D_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));
    if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==      //注册完成所有的Notify
        EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
      break;
    }
    // Go the next descriptor. Remember the NotifyList moves down.
    //
    NotifyList++ ;//指向下一个需要注册的Notify
    Index--;  //指向下一个要注册Notify的空位
  }

  // If there is Dispatch Notify PPI installed put them on the bottom
  //
  if (NotifyDispatchCount > 0) {//这一次一共注册了多少个Notify数量(NotifyDispatchCount)
    for (NotifyIndex = LastCallbackNotify; NotifyIndex > PrivateData->PpiData.NotifyListEnd; NotifyIndex--) { //逐减扫描,从这一次注册Notify的NotifyListEnd指针的位置开始(刚进入的时候缓存起来的       ==LastCallbackNotify)到注册完这些Notify之后NotifyListEnd指针的为止,的所有的Notify。
      if ((PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) {
        NotifyPtr = PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify;//取出EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH的Notify

        for (Index = NotifyIndex; Index < PrivateData->PpiData.DispatchListEnd; Index++){ //DispatchListEnd默认值也是从PPI数据库尾端开始,DispatchListEnd ==PcdPeiCoreMaxPpiSupported)-1
          PrivateData->PpiData.PpiListPtrs[Index].Notify = PrivateData->PpiData.PpiListPtrs[Index + 1].Notify ;//使用冒泡法把EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH类型的Notify提到PPI数据 尾端    (数组下标大的)
        }
        PrivateData->PpiData.PpiListPtrs[Index].Notify = NotifyPtr; //DispatchListEnd初始值指向数组的尾端,每次有注册一个EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH类型的Notify
        PrivateData->PpiData.DispatchListEnd-- ;//每次移动一个到次尾端的位置
      }
    }

    LastCallbackNotify -= NotifyDispatchCount; //修改NotifyListEnd 指针缓存,这时候还没有真正的回写,到PPI数据库中去。
  }

  // Dispatch any  callback level notifies  for all previously installed PPIs.  //这里会立即调用callback notifies,具体细节下面详述:
  //
  DispatchNotify (
    PrivateData,
      EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
    0,
    PrivateData->PpiData.PpiListEnd,
    LastCallbackNotify,
    PrivateData->PpiData.NotifyListEnd
    );

  return  EFI_SUCCESS;
}


e.再来看下Notify当中最重要的一个系统调用DispatchNotify()都干了些什么:
/**
 Dispatch notifications.
  @param PrivateData        PeiCore's private data structure
  @param NotifyType         Type of notify to fire.
  @param InstallStartIndex  Install Beginning index.
  @param InstallStopIndex   Install Ending index.
  @param NotifyStartIndex   Notify Beginning index.
  @param NotifyStopIndex    Notify Ending index.
**/
VOID
DispatchNotify (
  IN PEI_CORE_INSTANCE  *PrivateData,
  IN UINTN               NotifyType,
  IN INTN                InstallStartIndex,
  IN INTN                InstallStopIndex,
  IN INTN                NotifyStartIndex,
  IN INTN                NotifyStopIndex
  )
{
  INTN                   Index1;
  INTN                   Index2;
  EFI_GUID                *SearchGuid;
  EFI_GUID                *CheckGuid;
  EFI_PEI_NOTIFY_DESCRIPTOR   *NotifyDescriptor;

  // Remember that Installs moves up and Notifies moves down.

  for (Index1 = NotifyStartIndex; Index1 > NotifyStopIndex; Index1--) {
    NotifyDescriptor = PrivateData->PpiData.PpiListPtrs[Index1].Notify;

    CheckGuid = NotifyDescriptor->Guid;

    for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
      SearchGuid = PrivateData->PpiData.PpiListPtrs[Index2].Ppi->Guid;
      //
      // Don't use CompareGuid function here for performance reasons.
      // Instead we compare the GUID as INT32 at a time and branch
      // on the first failed comparison.
      //
      if ((((INT32 *)SearchGuid)[0] == ((INT32 *)CheckGuid)[0]) &&
          (((INT32 *)SearchGuid)[1] == ((INT32 *)CheckGuid)[1]) &&
          (((INT32 *)SearchGuid)[2] == ((INT32 *)CheckGuid)[2]) &&
          (((INT32 *)SearchGuid)[3] == ((INT32 *)CheckGuid)[3])) {
        DEBUG ((EFI_D_INFO, "Notify: PPI Guid: %g, Peim notify entry point: %p\n",
          SearchGuid,
          NotifyDescriptor->Notify
          ));
        NotifyDescriptor->Notify ( //如果Notify的PPI已经在PPI数据库当中,就去调用Notify描述符的回调函数,它有三个参数分别是:PS,NotifyDescriptor,以及所Notify的PPI(应该可以包含函数指针或者是数据),需要注意的是当Notify被调用之后,并不会从PPI数据库里面删除。
                            (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
                            NotifyDescriptor,
                            (PrivateData->PpiData.PpiListPtrs[Index2].Ppi)->Ppi
                            );
      }
    }
  }
}

f.上面提到的Notify都是Callback类型的,还有一种类型的Notify是Dispatch类型的,它会在每个PEIM被Dispatch完之后去,dispatch那些Dispatch类型的Notify,具体细节如下:
/**
  Process the Notify List at dispatch level.
  @param PrivateData  PeiCore's private data structure.
**/
VOID
ProcessNotifyList (
  IN PEI_CORE_INSTANCE  *PrivateData
  )
{
  INTN                    TempValue;

  while (TRUE) {
    //
    // Check if the PEIM that was just dispatched resulted in any
    // Notifies getting installed.  If so, go process any dispatch
    // level Notifies that match the previouly installed PPIs.
    // Use "while" instead of "if" since DispatchNotify can modify
    // DispatchListEnd (with NotifyPpi) so we have to iterate until the same.
    //
    while (PrivateData->PpiData.LastDispatchedNotify != PrivateData->PpiData.DispatchListEnd) { //此处表示有新dispatch的PEIM注册了新的Dispatch类型的Notify
      TempValue = PrivateData->PpiData.DispatchListEnd;
      DispatchNotify (
        PrivateData,
        EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
        0,
        PrivateData->PpiData.LastDispatchedInstall, //没有新的PPI被install,扫描范围从【0~  LastDispatchedInstall 】
        PrivateData->PpiData.LastDispatchedNotify,
        PrivateData->PpiData.DispatchListEnd// 注册了新的Dispatch类型的Notify,扫描范围从【LastDispatchedNotify~ LastDispatchedNotify】
        );
      PrivateData->PpiData.LastDispatchedNotify = TempValue;
    }
    //
    // Check if the PEIM that was just dispatched resulted in any
    // PPIs getting installed.  If so, go process any dispatch
    // level Notifies that match the installed PPIs.
    // Use "while" instead of "if" since DispatchNotify can modify
    // PpiListEnd (with InstallPpi) so we have to iterate until the same.
    //
    while (PrivateData->PpiData.LastDispatchedInstall != PrivateData->PpiData.PpiListEnd) { //此处表示有新dispatch的PEIM install了新的PPI
      TempValue = PrivateData->PpiData.PpiListEnd;
      DispatchNotify (
        PrivateData,
        EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
        PrivateData->PpiData.LastDispatchedInstall,
        PrivateData->PpiData.PpiListEnd,   //PPI从已经install的PPI范围【 0~PoiListEnd】
        FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-1,
        PrivateData->PpiData.DispatchListEnd// Dispatch类型的Notify的扫描范围【DispatchListEnd~到数据库的尾端】
        );
      PrivateData->PpiData.LastDispatchedInstall = TempValue; //dispatch 完了所有的Dispatch类型的Notify,让判断条件满足,退出while循环(此处默认在调用这个函数之前被dispatch的PEIMinstall    了Dispatch类型的Notify所监测的PPI)
    }

    if (PrivateData->PpiData.LastDispatchedNotify == PrivateData->PpiData.DispatchListEnd) {
      break; //所有的Dispatch类型的Notify都被调用到了,退出循环
    }
  }
  return;
}

6.再看下PPI在PEICore里面是如何运作的。
    Notify主要的作用是在不同的PPI直接传递消息,由于PPI数据库是全局的(存在于PEICore当中),所有的PEIM都能看得到,所以可以在不同的PEIM或者PPI服务之间传递消息,添加一些hook,做一些特别的事情。具体的细节再以后再补充。

转载请注明出处
[email protected]  //  http://blog.csdn.net/CStyle_0x007

你可能感兴趣的:(Cstyle的UEFI导读)