2 UEFI Event support functions implemented in this file.
4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 /// gEfiCurrentTpl - Current Task priority level
22 EFI_TPL gEfiCurrentTpl
= TPL_APPLICATION
;
25 /// gEventQueueLock - Protects the event queues
27 EFI_LOCK gEventQueueLock
= EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL
);
30 /// gEventQueue - A list of event's to notify for each priority level
32 LIST_ENTRY gEventQueue
[TPL_HIGH_LEVEL
+ 1];
35 /// gEventPending - A bitmask of the EventQueues that are pending
37 UINTN gEventPending
= 0;
40 /// gEventSignalQueue - A list of events to signal based on EventGroup type
42 LIST_ENTRY gEventSignalQueue
= INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue
);
45 /// Enumerate the valid types
47 UINT32 mEventTable
[] = {
49 /// 0x80000200 Timer event with a notification function that is
50 /// queue when the event is signaled with SignalEvent()
52 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
54 /// 0x80000000 Timer event without a notification function. It can be
55 /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
59 /// 0x00000100 Generic event with a notification function that
60 /// can be waited on with CheckEvent() or WaitForEvent()
64 /// 0x00000200 Generic event with a notification function that
65 /// is queue when the event is signaled with SignalEvent()
69 /// 0x00000201 ExitBootServicesEvent.
71 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
73 /// 0x60000202 SetVirtualAddressMapEvent.
75 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
78 /// 0x00000000 Generic event without a notification function.
79 /// It can be signaled with SignalEvent() and checked with CheckEvent()
80 /// or WaitForEvent().
84 /// 0x80000100 Timer event with a notification function that can be
85 /// waited on with CheckEvent() or WaitForEvent()
87 EVT_TIMER
| EVT_NOTIFY_WAIT
,
91 /// gIdleLoopEvent - Event which is signalled when the core is idle
93 EFI_EVENT gIdleLoopEvent
= NULL
;
97 Enter critical section by acquiring the lock on gEventQueueLock.
101 CoreAcquireEventLock (
105 CoreAcquireLock (&gEventQueueLock
);
110 Exit critical section by releasing the lock on gEventQueueLock.
114 CoreReleaseEventLock (
118 CoreReleaseLock (&gEventQueueLock
);
124 Initializes "event" support.
126 @retval EFI_SUCCESS Always return success
130 CoreInitializeEventServices (
136 for (Index
=0; Index
<= TPL_HIGH_LEVEL
; Index
++) {
137 InitializeListHead (&gEventQueue
[Index
]);
140 CoreInitializeTimer ();
145 CoreEmptyCallbackFunction
,
157 Dispatches all pending events.
159 @param Priority The task priority level of event notifications
164 CoreDispatchEventNotifies (
171 CoreAcquireEventLock ();
172 ASSERT (gEventQueueLock
.OwnerTpl
== Priority
);
173 Head
= &gEventQueue
[Priority
];
176 // Dispatch all the pending notifications
178 while (!IsListEmpty (Head
)) {
180 Event
= CR (Head
->ForwardLink
, IEVENT
, NotifyLink
, EVENT_SIGNATURE
);
181 RemoveEntryList (&Event
->NotifyLink
);
183 Event
->NotifyLink
.ForwardLink
= NULL
;
186 // Only clear the SIGNAL status if it is a SIGNAL type event.
187 // WAIT type events are only cleared in CheckEvent()
189 if ((Event
->Type
& EVT_NOTIFY_SIGNAL
) != 0) {
190 Event
->SignalCount
= 0;
193 CoreReleaseEventLock ();
198 ASSERT (Event
->NotifyFunction
!= NULL
);
199 Event
->NotifyFunction (Event
, Event
->NotifyContext
);
202 // Check for next pending event
204 CoreAcquireEventLock ();
207 gEventPending
&= ~(UINTN
)(1 << Priority
);
208 CoreReleaseEventLock ();
214 Queues the event's notification function to fire.
216 @param Event The Event to notify
226 // Event database must be locked
228 ASSERT_LOCKED (&gEventQueueLock
);
231 // If the event is queued somewhere, remove it
234 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
235 RemoveEntryList (&Event
->NotifyLink
);
236 Event
->NotifyLink
.ForwardLink
= NULL
;
240 // Queue the event to the pending notification list
243 InsertTailList (&gEventQueue
[Event
->NotifyTpl
], &Event
->NotifyLink
);
244 gEventPending
|= (UINTN
)(1 << Event
->NotifyTpl
);
251 Signals all events in the EventGroup.
253 @param EventGroup The list to signal
257 CoreNotifySignalList (
258 IN EFI_GUID
*EventGroup
265 CoreAcquireEventLock ();
267 Head
= &gEventSignalQueue
;
268 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
269 Event
= CR (Link
, IEVENT
, SignalLink
, EVENT_SIGNATURE
);
270 if (CompareGuid (&Event
->EventGroup
, EventGroup
)) {
271 CoreNotifyEvent (Event
);
275 CoreReleaseEventLock ();
282 @param Type The type of event to create and its mode and
284 @param NotifyTpl The task priority level of event notifications
285 @param NotifyFunction Pointer to the events notification function
286 @param NotifyContext Pointer to the notification functions context;
287 corresponds to parameter "Context" in the
288 notification function
289 @param Event Pointer to the newly created event if the call
290 succeeds; undefined otherwise
292 @retval EFI_SUCCESS The event structure was created
293 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
294 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
301 IN EFI_TPL NotifyTpl
,
302 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
303 IN VOID
*NotifyContext
, OPTIONAL
307 return CoreCreateEventEx (Type
, NotifyTpl
, NotifyFunction
, NotifyContext
, NULL
, Event
);
313 Creates an event in a group.
315 @param Type The type of event to create and its mode and
317 @param NotifyTpl The task priority level of event notifications
318 @param NotifyFunction Pointer to the events notification function
319 @param NotifyContext Pointer to the notification functions context;
320 corresponds to parameter "Context" in the
321 notification function
322 @param EventGroup GUID for EventGroup if NULL act the same as
324 @param Event Pointer to the newly created event if the call
325 succeeds; undefined otherwise
327 @retval EFI_SUCCESS The event structure was created
328 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
329 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
336 IN EFI_TPL NotifyTpl
,
337 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
338 IN CONST VOID
*NotifyContext
, OPTIONAL
339 IN CONST EFI_GUID
*EventGroup
, OPTIONAL
344 // If it's a notify type of event, check for invalid NotifyTpl
346 if ((Type
& (EVT_NOTIFY_WAIT
| EVT_NOTIFY_SIGNAL
)) != 0) {
347 if (NotifyTpl
!= TPL_APPLICATION
&&
348 NotifyTpl
!= TPL_CALLBACK
&&
349 NotifyTpl
!= TPL_NOTIFY
) {
350 return EFI_INVALID_PARAMETER
;
354 return CoreCreateEventInternal (Type
, NotifyTpl
, NotifyFunction
, NotifyContext
, EventGroup
, Event
);
358 Creates a general-purpose event structure
360 @param Type The type of event to create and its mode and
362 @param NotifyTpl The task priority level of event notifications
363 @param NotifyFunction Pointer to the events notification function
364 @param NotifyContext Pointer to the notification functions context;
365 corresponds to parameter "Context" in the
366 notification function
367 @param EventGroup GUID for EventGroup if NULL act the same as
369 @param Event Pointer to the newly created event if the call
370 succeeds; undefined otherwise
372 @retval EFI_SUCCESS The event structure was created
373 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
374 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
379 CoreCreateEventInternal (
381 IN EFI_TPL NotifyTpl
,
382 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
383 IN CONST VOID
*NotifyContext
, OPTIONAL
384 IN CONST EFI_GUID
*EventGroup
, OPTIONAL
394 return EFI_INVALID_PARAMETER
;
398 // Check to make sure no reserved flags are set
400 Status
= EFI_INVALID_PARAMETER
;
401 for (Index
= 0; Index
< (sizeof (mEventTable
) / sizeof (UINT32
)); Index
++) {
402 if (Type
== mEventTable
[Index
]) {
403 Status
= EFI_SUCCESS
;
407 if(EFI_ERROR (Status
)) {
408 return EFI_INVALID_PARAMETER
;
412 // Convert Event type for pre-defined Event groups
414 if (EventGroup
!= NULL
) {
416 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
419 if ((Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) || (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
)) {
420 return EFI_INVALID_PARAMETER
;
422 if (CompareGuid (EventGroup
, &gEfiEventExitBootServicesGuid
)) {
423 Type
= EVT_SIGNAL_EXIT_BOOT_SERVICES
;
424 } else if (CompareGuid (EventGroup
, &gEfiEventVirtualAddressChangeGuid
)) {
425 Type
= EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
;
429 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
431 if (Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) {
432 EventGroup
= &gEfiEventExitBootServicesGuid
;
433 } else if (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
) {
434 EventGroup
= &gEfiEventVirtualAddressChangeGuid
;
439 // If it's a notify type of event, check its parameters
441 if ((Type
& (EVT_NOTIFY_WAIT
| EVT_NOTIFY_SIGNAL
)) != 0) {
443 // Check for an invalid NotifyFunction or NotifyTpl
445 if ((NotifyFunction
== NULL
) ||
446 (NotifyTpl
<= TPL_APPLICATION
) ||
447 (NotifyTpl
>= TPL_HIGH_LEVEL
)) {
448 return EFI_INVALID_PARAMETER
;
453 // No notification needed, zero ignored values
456 NotifyFunction
= NULL
;
457 NotifyContext
= NULL
;
461 // Allocate and initialize a new event structure.
463 if ((Type
& EVT_RUNTIME
) != 0) {
464 IEvent
= AllocateRuntimeZeroPool (sizeof (IEVENT
));
466 IEvent
= AllocateZeroPool (sizeof (IEVENT
));
468 if (IEvent
== NULL
) {
469 return EFI_OUT_OF_RESOURCES
;
472 IEvent
->Signature
= EVENT_SIGNATURE
;
475 IEvent
->NotifyTpl
= NotifyTpl
;
476 IEvent
->NotifyFunction
= NotifyFunction
;
477 IEvent
->NotifyContext
= (VOID
*)NotifyContext
;
478 if (EventGroup
!= NULL
) {
479 CopyGuid (&IEvent
->EventGroup
, EventGroup
);
480 IEvent
->ExFlag
= TRUE
;
485 if ((Type
& EVT_RUNTIME
) != 0) {
487 // Keep a list of all RT events so we can tell the RT AP.
489 IEvent
->RuntimeData
.Type
= Type
;
490 IEvent
->RuntimeData
.NotifyTpl
= NotifyTpl
;
491 IEvent
->RuntimeData
.NotifyFunction
= NotifyFunction
;
492 IEvent
->RuntimeData
.NotifyContext
= (VOID
*) NotifyContext
;
493 IEvent
->RuntimeData
.Event
= (EFI_EVENT
*) IEvent
;
494 InsertTailList (&gRuntime
->EventHead
, &IEvent
->RuntimeData
.Link
);
497 CoreAcquireEventLock ();
499 if ((Type
& EVT_NOTIFY_SIGNAL
) != 0x00000000) {
501 // The Event's NotifyFunction must be queued whenever the event is signaled
503 InsertHeadList (&gEventSignalQueue
, &IEvent
->SignalLink
);
506 CoreReleaseEventLock ();
518 Signals the event. Queues the event to be notified if needed.
520 @param UserEvent The event to signal .
522 @retval EFI_INVALID_PARAMETER Parameters are not valid.
523 @retval EFI_SUCCESS The event was signaled.
529 IN EFI_EVENT UserEvent
537 return EFI_INVALID_PARAMETER
;
540 if (Event
->Signature
!= EVENT_SIGNATURE
) {
541 return EFI_INVALID_PARAMETER
;
544 CoreAcquireEventLock ();
547 // If the event is not already signalled, do so
550 if (Event
->SignalCount
== 0x00000000) {
551 Event
->SignalCount
++;
554 // If signalling type is a notify function, queue it
556 if ((Event
->Type
& EVT_NOTIFY_SIGNAL
) != 0) {
559 // The CreateEventEx() style requires all members of the Event Group
562 CoreReleaseEventLock ();
563 CoreNotifySignalList (&Event
->EventGroup
);
564 CoreAcquireEventLock ();
566 CoreNotifyEvent (Event
);
571 CoreReleaseEventLock ();
578 Check the status of an event.
580 @param UserEvent The event to check
582 @retval EFI_SUCCESS The event is in the signaled state
583 @retval EFI_NOT_READY The event is not in the signaled state
584 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
590 IN EFI_EVENT UserEvent
599 return EFI_INVALID_PARAMETER
;
602 if (Event
->Signature
!= EVENT_SIGNATURE
) {
603 return EFI_INVALID_PARAMETER
;
606 if ((Event
->Type
& EVT_NOTIFY_SIGNAL
) != 0) {
607 return EFI_INVALID_PARAMETER
;
610 Status
= EFI_NOT_READY
;
612 if ((Event
->SignalCount
== 0) && ((Event
->Type
& EVT_NOTIFY_WAIT
) != 0)) {
615 // Queue the wait notify function
617 CoreAcquireEventLock ();
618 if (Event
->SignalCount
== 0) {
619 CoreNotifyEvent (Event
);
621 CoreReleaseEventLock ();
625 // If the even looks signalled, get the lock and clear it
628 if (Event
->SignalCount
!= 0) {
629 CoreAcquireEventLock ();
631 if (Event
->SignalCount
!= 0) {
632 Event
->SignalCount
= 0;
633 Status
= EFI_SUCCESS
;
636 CoreReleaseEventLock ();
645 Stops execution until an event is signaled.
647 @param NumberOfEvents The number of events in the UserEvents array
648 @param UserEvents An array of EFI_EVENT
649 @param UserIndex Pointer to the index of the event which
650 satisfied the wait condition
652 @retval EFI_SUCCESS The event indicated by Index was signaled.
653 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
654 function or Event was not a valid type
655 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
661 IN UINTN NumberOfEvents
,
662 IN EFI_EVENT
*UserEvents
,
670 // Can only WaitForEvent at TPL_APPLICATION
672 if (gEfiCurrentTpl
!= TPL_APPLICATION
) {
673 return EFI_UNSUPPORTED
;
676 if (NumberOfEvents
== 0) {
677 return EFI_INVALID_PARAMETER
;
680 if (UserEvents
== NULL
) {
681 return EFI_INVALID_PARAMETER
;
686 for(Index
= 0; Index
< NumberOfEvents
; Index
++) {
688 Status
= CoreCheckEvent (UserEvents
[Index
]);
691 // provide index of event that caused problem
693 if (Status
!= EFI_NOT_READY
) {
694 if (UserIndex
!= NULL
) {
702 // Signal the Idle event
704 CoreSignalEvent (gIdleLoopEvent
);
710 Closes an event and frees the event structure.
712 @param UserEvent Event to close
714 @retval EFI_INVALID_PARAMETER Parameters are not valid.
715 @retval EFI_SUCCESS The event has been closed
721 IN EFI_EVENT UserEvent
730 return EFI_INVALID_PARAMETER
;
733 if (Event
->Signature
!= EVENT_SIGNATURE
) {
734 return EFI_INVALID_PARAMETER
;
738 // If it's a timer event, make sure it's not pending
740 if ((Event
->Type
& EVT_TIMER
) != 0) {
741 CoreSetTimer (Event
, TimerCancel
, 0);
744 CoreAcquireEventLock ();
747 // If the event is queued somewhere, remove it
750 if (Event
->RuntimeData
.Link
.ForwardLink
!= NULL
) {
751 RemoveEntryList (&Event
->RuntimeData
.Link
);
754 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
755 RemoveEntryList (&Event
->NotifyLink
);
758 if (Event
->SignalLink
.ForwardLink
!= NULL
) {
759 RemoveEntryList (&Event
->SignalLink
);
762 CoreReleaseEventLock ();
765 // If the event is registered on a protocol notify, then remove it from the protocol database
767 CoreUnregisterProtocolNotify (Event
);
769 Status
= CoreFreePool (Event
);
770 ASSERT_EFI_ERROR (Status
);