UEFI学习——事件函数WaitForEvent和CreateEvent/CreateEventEx

       本文参考戴正华《UEFI原理与编程》

1.等待事件的服务WaitForEvent

       启动服务中的WaitForEvent服务的函数原型:

/**等待Event数组内任一事件被触发
  @retval EFI_SUCCESS               下表为*index的事件被触发
  @retval EFI_UNSUPPORTED           当前的TPL不是TPL_APPLICATION
  @retval EFI_INVALID_PARAMETER     下标为*index的事件类型为EVT_NOTIFY_SIGNAL
**/
typedef EFI_STATUS (EFIAPI *EFI_WAIT_FOR_EVENT) (
  IN UINTN NumberOfEvents,          //Event数组内Event的个数
  IN EFI_EVENT *Event,              //Event数组
  OUT UINTN *Index                  //返回处于触发态的事件在数组内的下标
  );

       WaitForEvent是阻塞操作,直到Event数组内任一事件被触发,或任一事件导致错误出现,WaitForEvent才返回。WaitForEvent从前到后依次检查Event数组内的事件,发现有被触发的事件或遇到错误则返回,如果所有事件都没有被触发,则从头开始重新检查。
       当检查到某个事件处于触发态时,*Index赋值为该事件在Event数组中的下标,返回前该事件将重置为非触发态。
当检查到某个事件是EVT_NOTIFY_SIGNAL类型时,*Index赋值为该事件在Event数组中的下标,并返回EFI_INVALID_PARAMETER。
       WaitForEvent必须运行在TPL_APPLICATION级别,否则将返回EFI_UNSUPPORTED。

2.生成事件的服务CreateEvent

       启动服务中的CreateEvent服务的函数原型

//生成一个事件
typedef EFI_STATUS (EFIAPI *EFI_CREATE_EVENT) (
  IN UINT32 Type,                               //事件类型
  IN EFI_TPL NotifyTpl,                         //事件Notification函数的优先级
  IN EFI_EVENT_NOTIFY NotifyFunction,           //事件Notification函数
  IN VOID *NotifyContext,                       //传给事件Notification函数的参数
  OUT EFI_EVENT *Event                          //生成的事件
);

       参数IN UINT32 Type是事件的类型,常用的几种事件类型如表1所示。
                                                                                                         表1

事件类型事件特征
EVT_TIMER定时器事件。普通Timer事件,没有Notification函数。生成事件后需调用SetTimer服务设置时钟属性。事件可以:
①通过SetTimer()设置等待事件 ②到期后通过SignalEvent()触发
③通过WaitForEvent()等待事件被触发④通过CheckEvent()检查状态
EVT_NOTIFY_WAIT普通事件。这个事件有一个Notification函数,当这个事件通过CheckEvent()检查状态或通过WaitForEvent()等待时,这个Notification函数会被放到待执行队列gEventQueue[Event->NotifyTpl]中
EVT_NOTIFY_SIGNAL普通事件。这个事件有一个Notification函数,当这个事件通过SignalEvent()被触发时,这个Notification函数会被放到待执行队列gEventQueue[Event->NotifyTpl]中
0x00000000普通事件。此类事件没有Notification函数。事件可以:
①通过SignalEvent()被触发②通过WaitForEvent()等待事件被触发③通过CheckEvent()检查状态
EVT_TIMER | EVT_NOTIFY_WAIT带Notification函数的定时器事件。此类事件除了具有EVT_TIMER的特性外,还有EVT_NOTIFY_WAIT的特性,即到后期通过SignalEvent()触发。当事件通过CheckEvent()检查状态或通过WaitForEvent()等待时,这个Notification函数回被放到执行队列gEventQueue[Event->NotifyTpl]中
EVT_TIMER | EVT_NOTIFY_SIGNAL带Notification函数的定时器事件。此类事件除了具有EVT_TIMER的特性外,还有EVT_NOTIFY_SIGNAL的特性,即到后期通过SignalEvent()触发。当这个事件通过SignalEvent()被触发时,这个Notification函数会被放到待执行队列gEventQueue[Event->NotifyTpl]中

       CreateEvent的第二个参数为NotifyTPL(即任务优先级),它可以是0~31的一个整数。UEFI预定义了以下4个优先级。

#define TPL_APPLICATION   4
#define TPL_CALLBACK      8
#define TPL_NOTIFY        16
#define TPL_HIGH_LEVEL    31

       优先级别高的任务可以中断级别低的任务,并且从高优先级返回低优先级前会完成所有高于低优先级的任务。表2列出了UEFI预定义的4个任务优先级。
                                                                                                         表2

任务优先级用法函数
TPL_APPLICATION这是预定义的4个级别中最低的一个优先级。应用程序运行(包括Boot Manager和OS Loader)在这个级别。当程序运行在这个级别时,任务队列中没有任何处于就绪状态的事件Notification函数下列函数运行在此级别:
ExitBootServices()、WaitForEvent()、User Manager Protocol/Identify()、Form Browser2 Protocol/SendForm
下列函数运行在此级别或更低级别:
Simple Input Protocol
TPL_CALLBACK比较耗时的操作通常在这个优先级执行,如文件系统、磁盘操作等下列函数运行在此级别或更低级别:
Exit();Serial I/O Protocol、UnloadImage()、Variable Services、NetWork Service Binding、Network Protocol
下列函数运行在低于8的级别:
LoadImage()、StartImage()
TPL_NOTIFY运行在这个级别的程序不允许阻塞,必须尽快执行完毕并且返回。如果需要更多操作,则需要使用Event由内核重新调度。通常,底层的IO操作允许在这个级别,例如UEFI内核中读取键盘状态的代码。大部分Event的Notification函数允许在这个级别下列函数运行在此级别或更低级别:
Protocol Handle Services、Memory Allocation Services、Simple Text Output Protocol、ACPI Table Protocol、User Manager Protocol、User Credential Protocol、User Info Protocol、Authentication Info、Device Path Utilities、Device Path Form Text、EDID Discovered、EDID Active、Graphics Output EDID Override、iSCSI Initiator Name、Tape IO、Deferred Image Load Protocol、HII Protocols、Driver Health
下列函数运行在低于16的级别:
ACPI Table Protocol
TPL_HIGH_LEVEL优先级最高级别。在此级别,中断被禁止。UEFI 内核全局变量的修改需要允许在这个级别下列函数运行在此级别或更低级别:
SignalEvent()、Stall()
下列函数运行在低于31的级别:
CheckEvent()、CloseEvent()、CreateEvent()、SetTimer()、Event Notofication Levels运行在(TPL_APPLICATION,TPL_HIGH_LEVEL)区间的优先级上

       CreateEvent的第三个参数NotifyFunction是EFI_EVENT_NOTIFY类型的函数指针,它的函数原型是:

/**
  Invoke a notification event

  @param[in]  Event                 Event whose notification function is being invoked.
  @param[in]  Context               The pointer to the notification function's context,
                                    which is implementation-dependent.

**/
typedef
VOID
(EFIAPI *EFI_EVENT_NOTIFY)(
  IN  EFI_EVENT                Event,
  IN  VOID                     *Context
  );

       如果事件的类型是EVENT_NOTIFY_WAIT,则EFI_EVENT_NOTIFY函数会在等待此事件的过程中被调用;如果事件的类型是EVT_NOTIFY_SIGNAL,则EFI_EVENT_NOTIFY函数会在事件触发时被调用。既没有EVT_NOTIFY_WAIT属性也没有EVT_NOTIFY_SIGNAL属性的事件,Notification参数将被忽略。
       CreateEvent的第4个参数是NotifyContext,将在Notification函数被调用时作为Notification函数的第2个参数传递给该函数,用于指向这个Notification函数的上下文。

3.CreateEventEx服务

       函数原型(其函数指针):

/**
  Creates an event in a group.

  @param[in]   Type             The type of event to create and its mode and attributes.
  @param[in]   NotifyTpl        The task priority level of event notifications,if needed.
  @param[in]   NotifyFunction   The pointer to the event's notification function, if any.
  @param[in]   NotifyContext    The pointer to the notification function's context; corresponds to parameter
                                Context in the notification function.
  @param[in]   EventGroup       The pointer to the unique identifier of the group to which this event belongs.
                                If this is NULL, then the function behaves as if the parameters were passed
                                to CreateEvent.
  @param[out]  Event            The pointer to the newly created event if the call succeeds; undefined
                                otherwise.

  @retval EFI_SUCCESS           The event structure was created.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
  @retval EFI_OUT_OF_RESOURCES  The event could not be allocated.

**/
typedef
EFI_STATUS
(EFIAPI *EFI_CREATE_EVENT_EX)(
  IN       UINT32                 Type,                       //事件类型
  IN       EFI_TPL                NotifyTpl,                  //事件Notification函数的优先级
  IN       EFI_EVENT_NOTIFY       NotifyFunction OPTIONAL,    //事件Notification函数
  IN CONST VOID                   *NotifyContext OPTIONAL,    //传给事件Notification函数的参数
  IN CONST EFI_GUID               *EventGroup    OPTIONAL,    //事件组
  OUT      EFI_EVENT              *Event                      //生成的事件
  );

       由CreateEventEx生成的事件会加入到EventGroup中,当EventGroup中的任一事件被触发后,组中的所有其他事件都会被触发,进而同组内所有的Notification函数都将被加入到待执行队列。同组内NotifyTpl(优先级)高的Notification函数会先被执行。
如果输入参数EventGroup为NULL,则CreateEventEx退化为CreateEvent。
       关于CreateEventEx的示例代码可以看我的另一篇博客:UEFI学习——使用gRT->GetVariable读取Setup选项值
       在这个博客中对CreateEventEx的使用过程如下图:
                                                 在这里插入图片描述

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值