- 源代码:EDK2
- 版本:UDK2017
- UEFI源码分析第二篇,异步事件服务
- 第一部分,事件驱动
- 优先级的讨论将在另一篇,即第二部分。
- 定时器类型
EVT_TIMER
将在第三部分
事件
每一个事件都是一个IEvent
类型
/** /Dxe/Event/Event.h **/
45 #define EVENT_SIGNATURE SIGNATURE_32('e','v','n','t')
46 typedef struct {
47 UINTN Signature;
48 UINT32 Type;
49 UINT32 SignalCount;
53 LIST_ENTRY SignalLink;
57 EFI_TPL NotifyTpl;
58 EFI_EVENT_NOTIFY NotifyFunction;
59 VOID *NotifyContext;
60 EFI_GUID EventGroup;
61 LIST_ENTRY NotifyLink;
62 UINT8 ExFlag;
66 EFI_RUNTIME_EVENT_ENTRY RuntimeData;
67 TIMER_EVENT_INFO Timer;
68 } IEVENT;
可以看到有多个链表
SignalLink
NotifyLink
这是提供给不同事件类型所使用。事件有以下几种类型。
/** MdePkg/Include/Uefi/UefiSpec.h **/
384 //
385 // These types can be ORed together as needed - for example,
386 // EVT_TIMER might be Ored with EVT_NOTIFY_WAIT or
387 // EVT_NOTIFY_SIGNAL.
388 //
389 #define EVT_TIMER 0x80000000
390 #define EVT_RUNTIME 0x40000000
391 #define EVT_NOTIFY_WAIT 0x00000100
392 #define EVT_NOTIFY_SIGNAL 0x00000200
393
394 #define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201
395 #define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202
大致有如下特性
- Notify
意味着有NotifyFunction
在事件发生的时候被调用,也就是回调函数
- Wait
意味着可以使用WaitForEvent
来等待事件的发生,其阻塞直到事件被Signal
- Signal
意味着事件可以被唤醒
- Timer
意味着该事件是一个定时器,IEvent
的Timer
域会被填充,其中包含一个Link
来链接所有的定时器
- 这些特性是可以被OR
来组合到一起的,即运算符|
两个类型只在此提一下,不详述
- EVT_SIGNAL_EXIT_BOOT_SERVICES
是在UEFI系统退出(ExitBootServices()
)的时候调用,通常用来回收资源
- EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
在操作系统加载器调用运行时服务RuntimeServices
的虚拟地址服务来进行虚拟地址转换的时候调用。
主要关注两个类型
- EVT_NOTIFY_WAIT
可等待事件
- EVT_NOTIFY_SIGNAL
可唤醒事件
重要的全局变量
gEventSignalQueue
保存所有未被唤醒、类型为EVT_NOTIFY_SIGNAL
的事件gEventQueue
保存已经被唤醒、需要执行回调函数的事件,根据优先级分为多个链表gEventPending
使用位图来保存gEventQueue
是否含有某个优先级的链表mEventTable
包含了所有合法的事件类型
相关接口
创建事件CreateEvent
/** /Dxe/Event/Event.c **/
378 EFI_STATUS
379 EFIAPI
380 CoreCreateEventInternal (
381 IN UINT32 Type,
382 IN EFI_TPL NotifyTpl,
383 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
384 IN CONST VOID *NotifyContext, OPTIONAL
385 IN CONST EFI_GUID *EventGroup, OPTIONAL
386 OUT EFI_EVENT *Event
387 )
388 {
Type
域即事件的类型
NotifyTpl
是回调函数的优先级,在本系列的第二部分会介绍,NorifyFunction
即回调函数本身,NofityContext
即传递给回调函数的参数。
EventGroup
是事件组特性,其使用一个GUID
来标识该事件属于一个事件组,同组内的事件均含有相同的GUID
,不同事件组的GUID
必然不同。
Event
是返回的、创建完成的事件,EFI_EVENT
类型本质上是IEvent*
类型。
1、检查事件的类型
401 Status = EFI_INVALID_PARAMETER;
402 for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
403 if (Type == mEventTable[Index]) {
404 Status = EFI_SUCCESS;
405 break;
406 }
407 }
408 if(EFI_ERROR (Status)) {
409 return EFI_INVALID_PARAMETER;