edk2/MdeModulePkg/Core/Dxe/Event/Event.c edk2/MdeModulePkg/Core/Dxe/Event/Tpl.c
1. CoreCreateEvent / CoreCreateEventEx
CoreCreateEvent/CoreCreateEventEx用于创建一个Event,CoreCreateEvent实际上是一个wrapper函数,它内部调用了CoreCreateEventEx,只是EventGroup参数为NULL。
CoreCreateEvent (
IN UINT32 Type, --> Event类型
IN EFI_TPL NotifyTpl, --> 通知优先级
IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, --> Event的回调函数
IN VOID *NotifyContext OPTIONAL, --> 通知上下文
OUT EFI_EVENT *Event --> Event指针
)
{
return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);
}
CoreCreateEventEx这个函数也是一个wrapper函数,仅仅在外层检查了参数合法性后调用CoreCreateEventInternal。
CoreCreateEventEx (
IN UINT32 Type,
IN EFI_TPL NotifyTpl,
IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
IN CONST VOID *NotifyContext OPTIONAL,
IN CONST EFI_GUID *EventGroup OPTIONAL,
OUT EFI_EVENT *Event
)
{
if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
if ((NotifyTpl != TPL_APPLICATION) &&
(NotifyTpl != TPL_CALLBACK) &&
(NotifyTpl != TPL_NOTIFY))
{
return EFI_INVALID_PARAMETER;
}
}
return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);
}
CoreCreateEventInternal里面简单来说就为Event创建一个IEVENT对象,并根据参数将IEVENT的成员一个一个填好。如果EVENT的类型是EVT_NOTIFY_SIGNAL, 则要将该EVENT插入到gEventSignalQueue。
CoreCreateEventInternal (
...
)
{
EFI_STATUS Status;
IEVENT *IEvent;
INTN Index;
...
if (EventGroup != NULL) {
if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {
return EFI_INVALID_PARAMETER;
}
if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {
Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;
} else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {
Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;
}
} else {
if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {
EventGroup = &gEfiEventExitBootServicesGuid;
} else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
EventGroup = &gEfiEventVirtualAddressChangeGuid;
}
}
if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
if ((NotifyFunction == NULL) ||
(NotifyTpl <= TPL_APPLICATION) ||
(NotifyTpl >= TPL_HIGH_LEVEL))
{
return EFI_INVALID_PARAMETER;
}
} else {
NotifyTpl = 0;
NotifyFunction = NULL;
NotifyContext = NULL;
}
if ((Type & EVT_RUNTIME) != 0) {
IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));
} else {
IEvent = AllocateZeroPool (sizeof (IEVENT));
}
IEvent->Signature = EVENT_SIGNATURE;
IEvent->Type = Type;
IEvent->NotifyTpl = NotifyTpl;
IEvent->NotifyFunction = NotifyFunction;
IEvent->NotifyContext = (VOID *)NotifyContext;
if (EventGroup != NULL) {
CopyGuid (&IEvent->EventGroup, EventGroup);
IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;
}
*Event = IEvent;
if ((Type & EVT_RUNTIME) != 0) {
IEvent->RuntimeData.Type = Type;
IEvent->RuntimeData.NotifyTpl = NotifyTpl;
IEvent->RuntimeData.NotifyFunction = NotifyFunction;
IEvent->RuntimeData.NotifyContext = (VOID *)NotifyContext;
IEvent->RuntimeData.Event = (EFI_EVENT *)IEvent;
InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);
}
CoreAcquireEventLock ();
if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {
InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
}
...
}
2. CoreSignalEvent
CoreSignalEvent会向EVENT发送一个信号,然后在这个函数中回去调用在CreateEvent中注册的回调函数NotifyFunction。 虽然字面意思很简单,但实际上这个简单的操作在这个函数里也饶了一圈。
- 它首先会调用CoreNotifySignalList 或者CoreNotifyEvent 把EVENT插入到gEventQueue[Type]链表中
- 然后在CoreReleaseEventLock 的调用中从gEventQueue[Type]拿到pending的EVNET,然后去调用EVNET对应的NotifyFunction
EFI_STATUS
EFIAPI
CoreSignalEvent (
IN EFI_EVENT UserEvent
)
{
IEVENT *Event;
Event = UserEvent;
if (Event == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Event->Signature != EVENT_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
CoreAcquireEventLock ();
if (Event->SignalCount == 0x00000000) {
Event->SignalCount++;
if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {
CoreReleaseEventLock ();
CoreNotifySignalList (&Event->EventGroup);
CoreAcquireEventLock ();
} else {
CoreNotifyEvent (Event);
}
}
}
CoreReleaseEventLock ();
return EFI_SUCCESS;
}
VOID
CoreNotifyEvent (
IN IEVENT *Event
)
{
...
if (Event->NotifyLink.ForwardLink != NULL) {
RemoveEntryList (&Event->NotifyLink);
Event->NotifyLink.ForwardLink = NULL;
}
InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
gEventPending |= (UINTN)(1 << Event->NotifyTpl);
}
CoreReleaseEventLock这个函数在释放gEventQueueLock的同时还会去查看gEventQueue中有没有pending的EVENT,如果有,就调用它们的注册的回调函数。CoreReleaseEventLock的函数调用栈如下,最终会调用到CoreDispatchEventNotifies这个函数中把Event的回调函数调用以下
CoreReleaseEventLock
-->CoreReleaseLock
-->CoreRestoreTpl
-->CoreDispatchEventNotifies
这个函数用于恢复当前任务的Event通知优先级,同时如果有pending的EVENT存在,则调用CoreDispatchEventNotifies处理EVENT。
CoreRestoreTpl (
IN EFI_TPL NewTpl
)
{
EFI_TPL OldTpl;
EFI_TPL PendingTpl;
OldTpl = gEfiCurrentTpl;
while (gEventPending != 0) {
...
CoreDispatchEventNotifies (gEfiCurrentTpl);
}
gEfiCurrentTpl = NewTpl;
...
}
CoreDispatchEventNotifies 这里就是最终从gEventQueue拿出IEVENT,然后调用回调函数Event->NotifyFunction (Event, Event->NotifyContext);
VOID
CoreDispatchEventNotifies (
IN EFI_TPL Priority
)
{
IEVENT *Event;
LIST_ENTRY *Head;
CoreAcquireEventLock ();
Head = &gEventQueue[Priority];
while (!IsListEmpty (Head)) {
Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);
RemoveEntryList (&Event->NotifyLink);
Event->NotifyLink.ForwardLink = NULL;
if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
Event->SignalCount = 0;
}
CoreReleaseEventLock ();
Event->NotifyFunction (Event, Event->NotifyContext);
CoreAcquireEventLock ();
}
gEventPending &= ~(UINTN)(1 << Priority);
CoreReleaseEventLock ();
}
3.CoreWaitForEvent / CoreCheckEvent
CoreWaitForEvent 里面调用了CoreCheckEvent。所以先看CoreCheckEvent。 在CoreCheckEvent中,主要根据Event状态做两种处理。
- Event->SignalCount = 0的情况下调用CoreNotifyEvent 通知Event,并报告给调用者这个Event还没有Ready。
- Event->SignalCount != 0的情况下,就把Event->SignalCount 清0,并报告给调用者这个Event已经被Singal过了。
CoreCheckEvent (
IN EFI_EVENT UserEvent
)
{
IEVENT *Event;
EFI_STATUS Status;
Event = UserEvent;
...
Status = EFI_NOT_READY;
if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {
CoreAcquireEventLock ();
if (Event->SignalCount == 0) {
CoreNotifyEvent (Event);
}
CoreReleaseEventLock ();
}
if (Event->SignalCount != 0) {
CoreAcquireEventLock ();
if (Event->SignalCount != 0) {
Event->SignalCount = 0;
Status = EFI_SUCCESS;
}
CoreReleaseEventLock ();
}
return Status;
}
CoreWaitForEvent 这个函数调用了CoreCheckEvent, 根据CoreCheckEvent的返回值做一些操作。
- 如果CoreCheckEvent返回了EFI_NOT_READY,从上面的分析可以得到就是返回了EFI_SUCCESS,那么就会返回给调用者某个Event已经OK了,可以去处理这个Event了。
- 如果CoreCheckEvent返回了EFI_NOT_READY,那么就会调用CoreSignalEvent (gIdleLoopEvent);发送IDLE的Event,让CPU进入IDLE模式。gIdleLoopEvent这个Event实现在CpuDXE中,在CpuDXE中,IDLE模式的操作其实就是让CPU进入WFI,等待中断到来并等待其他驱动Singal需要的Event,这样就达到了阻塞Wait的效果。
CoreWaitForEvent (
IN UINTN NumberOfEvents,
IN EFI_EVENT *UserEvents,
OUT UINTN *UserIndex
)
{
EFI_STATUS Status;
UINTN Index;
if (gEfiCurrentTpl != TPL_APPLICATION) {
return EFI_UNSUPPORTED;
}
for ( ; ;) {
for (Index = 0; Index < NumberOfEvents; Index++) {
Status = CoreCheckEvent (UserEvents[Index]);
if (Status != EFI_NOT_READY) {
if (UserIndex != NULL) {
*UserIndex = Index;
}
return Status;
}
}
CoreSignalEvent (gIdleLoopEvent);
}
}
|