2 UEFI Event support functions implemented in this file.
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 /// gEfiCurrentTpl - Current Task priority level
23 EFI_TPL gEfiCurrentTpl
= TPL_APPLICATION
;
26 /// gEventQueueLock - Protects the event queues
28 EFI_LOCK gEventQueueLock
= EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL
);
31 /// gEventQueue - A list of event's to notify for each priority level
33 LIST_ENTRY gEventQueue
[TPL_HIGH_LEVEL
+ 1];
36 /// gEventPending - A bitmask of the EventQueues that are pending
38 UINTN gEventPending
= 0;
41 /// gEventSignalQueue - A list of events to signal based on EventGroup type
43 LIST_ENTRY gEventSignalQueue
= INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue
);
46 /// Enumerate the valid types
48 UINT32 mEventTable
[] = {
50 /// 0x80000200 Timer event with a notification function that is
51 /// queue when the event is signaled with SignalEvent()
53 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
55 /// 0x80000000 Timer event without a notification function. It can be
56 /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
60 /// 0x00000100 Generic event with a notification function that
61 /// can be waited on with CheckEvent() or WaitForEvent()
65 /// 0x00000200 Generic event with a notification function that
66 /// is queue when the event is signaled with SignalEvent()
70 /// 0x00000201 ExitBootServicesEvent.
72 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
74 /// 0x60000202 SetVirtualAddressMapEvent.
76 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
79 /// 0x00000000 Generic event without a notification function.
80 /// It can be signaled with SignalEvent() and checked with CheckEvent()
81 /// or WaitForEvent().
85 /// 0x80000100 Timer event with a notification function that can be
86 /// waited on with CheckEvent() or WaitForEvent()
88 EVT_TIMER
| EVT_NOTIFY_WAIT
,
92 /// gIdleLoopEvent - Event which is signalled when the core is idle
94 EFI_EVENT gIdleLoopEvent
= NULL
;
98 Enter critical section by acquiring the lock on gEventQueueLock.
102 CoreAcquireEventLock (
106 CoreAcquireLock (&gEventQueueLock
);
111 Exit critical section by releasing the lock on gEventQueueLock.
115 CoreReleaseEventLock (
119 CoreReleaseLock (&gEventQueueLock
);
125 Initializes "event" support.
127 @retval EFI_SUCCESS Always return success
131 CoreInitializeEventServices (
137 for (Index
=0; Index
<= TPL_HIGH_LEVEL
; Index
++) {
138 InitializeListHead (&gEventQueue
[Index
]);
141 CoreInitializeTimer ();
146 CoreEmptyCallbackFunction
,
158 Dispatches all pending events.
160 @param Priority The task priority level of event notifications
165 CoreDispatchEventNotifies (
172 CoreAcquireEventLock ();
173 ASSERT (gEventQueueLock
.OwnerTpl
== Priority
);
174 Head
= &gEventQueue
[Priority
];
177 // Dispatch all the pending notifications
179 while (!IsListEmpty (Head
)) {
181 Event
= CR (Head
->ForwardLink
, IEVENT
, NotifyLink
, EVENT_SIGNATURE
);
182 RemoveEntryList (&Event
->NotifyLink
);
184 Event
->NotifyLink
.ForwardLink
= NULL
;
187 // Only clear the SIGNAL status if it is a SIGNAL type event.
188 // WAIT type events are only cleared in CheckEvent()
190 if ((Event
->Type
& EVT_NOTIFY_SIGNAL
) != 0) {
191 Event
->SignalCount
= 0;
194 CoreReleaseEventLock ();
199 ASSERT (Event
->NotifyFunction
!= NULL
);
200 Event
->NotifyFunction (Event
, Event
->NotifyContext
);
203 // Check for next pending event
205 CoreAcquireEventLock ();
208 gEventPending
&= ~(UINTN
)(1 << Priority
);
209 CoreReleaseEventLock ();
215 Queues the event's notification function to fire.
217 @param Event The Event to notify
227 // Event database must be locked
229 ASSERT_LOCKED (&gEventQueueLock
);
232 // If the event is queued somewhere, remove it
235 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
236 RemoveEntryList (&Event
->NotifyLink
);
237 Event
->NotifyLink
.ForwardLink
= NULL
;
241 // Queue the event to the pending notification list
244 InsertTailList (&gEventQueue
[Event
->NotifyTpl
], &Event
->NotifyLink
);
245 gEventPending
|= (UINTN
)(1 << Event
->NotifyTpl
);
252 Signals all events in the EventGroup.
254 @param EventGroup The list to signal
258 CoreNotifySignalList (
259 IN EFI_GUID
*EventGroup
266 CoreAcquireEventLock ();
268 Head
= &gEventSignalQueue
;
269 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
270 Event
= CR (Link
, IEVENT
, SignalLink
, EVENT_SIGNATURE
);
271 if (CompareGuid (&Event
->EventGroup
, EventGroup
)) {
272 CoreNotifyEvent (Event
);
276 CoreReleaseEventLock ();
283 @param Type The type of event to create and its mode and
285 @param NotifyTpl The task priority level of event notifications
286 @param NotifyFunction Pointer to the events notification function
287 @param NotifyContext Pointer to the notification functions context;
288 corresponds to parameter "Context" in the
289 notification function
290 @param Event Pointer to the newly created event if the call
291 succeeds; undefined otherwise
293 @retval EFI_SUCCESS The event structure was created
294 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
295 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
302 IN EFI_TPL NotifyTpl
,
303 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
304 IN VOID
*NotifyContext
, OPTIONAL
308 return CoreCreateEventEx (Type
, NotifyTpl
, NotifyFunction
, NotifyContext
, NULL
, Event
);
314 Creates an event in a group.
316 @param Type The type of event to create and its mode and
318 @param NotifyTpl The task priority level of event notifications
319 @param NotifyFunction Pointer to the events notification function
320 @param NotifyContext Pointer to the notification functions context;
321 corresponds to parameter "Context" in the
322 notification function
323 @param EventGroup GUID for EventGroup if NULL act the same as
325 @param Event Pointer to the newly created event if the call
326 succeeds; undefined otherwise
328 @retval EFI_SUCCESS The event structure was created
329 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
330 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
337 IN EFI_TPL NotifyTpl
,
338 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
339 IN CONST VOID
*NotifyContext
, OPTIONAL
340 IN CONST EFI_GUID
*EventGroup
, OPTIONAL
345 // If it's a notify type of event, check for invalid NotifyTpl
347 if ((Type
& (EVT_NOTIFY_WAIT
| EVT_NOTIFY_SIGNAL
)) != 0) {
348 if (NotifyTpl
!= TPL_APPLICATION
&&
349 NotifyTpl
!= TPL_CALLBACK
&&
350 NotifyTpl
!= TPL_NOTIFY
) {
351 return EFI_INVALID_PARAMETER
;
355 return CoreCreateEventInternal (Type
, NotifyTpl
, NotifyFunction
, NotifyContext
, EventGroup
, Event
);
359 Creates a general-purpose event structure
361 @param Type The type of event to create and its mode and
363 @param NotifyTpl The task priority level of event notifications
364 @param NotifyFunction Pointer to the events notification function
365 @param NotifyContext Pointer to the notification functions context;
366 corresponds to parameter "Context" in the
367 notification function
368 @param EventGroup GUID for EventGroup if NULL act the same as
370 @param Event Pointer to the newly created event if the call
371 succeeds; undefined otherwise
373 @retval EFI_SUCCESS The event structure was created
374 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
375 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
380 CoreCreateEventInternal (
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
395 return EFI_INVALID_PARAMETER
;
399 // Check to make sure no reserved flags are set
401 Status
= EFI_INVALID_PARAMETER
;
402 for (Index
= 0; Index
< (sizeof (mEventTable
) / sizeof (UINT32
)); Index
++) {
403 if (Type
== mEventTable
[Index
]) {
404 Status
= EFI_SUCCESS
;
408 if(EFI_ERROR (Status
)) {
409 return EFI_INVALID_PARAMETER
;
413 // Convert Event type for pre-defined Event groups
415 if (EventGroup
!= NULL
) {
417 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
420 if ((Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) || (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
)) {
421 return EFI_INVALID_PARAMETER
;
423 if (CompareGuid (EventGroup
, &gEfiEventExitBootServicesGuid
)) {
424 Type
= EVT_SIGNAL_EXIT_BOOT_SERVICES
;
425 } else if (CompareGuid (EventGroup
, &gEfiEventVirtualAddressChangeGuid
)) {
426 Type
= EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
;
430 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
432 if (Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) {
433 EventGroup
= &gEfiEventExitBootServicesGuid
;
434 } else if (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
) {
435 EventGroup
= &gEfiEventVirtualAddressChangeGuid
;
440 // If it's a notify type of event, check its parameters
442 if ((Type
& (EVT_NOTIFY_WAIT
| EVT_NOTIFY_SIGNAL
)) != 0) {
444 // Check for an invalid NotifyFunction or NotifyTpl
446 if ((NotifyFunction
== NULL
) ||
447 (NotifyTpl
<= TPL_APPLICATION
) ||
448 (NotifyTpl
>= TPL_HIGH_LEVEL
)) {
449 return EFI_INVALID_PARAMETER
;
454 // No notification needed, zero ignored values
457 NotifyFunction
= NULL
;
458 NotifyContext
= NULL
;
462 // Allocate and initialize a new event structure.
464 if ((Type
& EVT_RUNTIME
) != 0) {
465 IEvent
= AllocateRuntimeZeroPool (sizeof (IEVENT
));
467 IEvent
= AllocateZeroPool (sizeof (IEVENT
));
469 if (IEvent
== NULL
) {
470 return EFI_OUT_OF_RESOURCES
;
473 IEvent
->Signature
= EVENT_SIGNATURE
;
476 IEvent
->NotifyTpl
= NotifyTpl
;
477 IEvent
->NotifyFunction
= NotifyFunction
;
478 IEvent
->NotifyContext
= (VOID
*)NotifyContext
;
479 if (EventGroup
!= NULL
) {
480 CopyGuid (&IEvent
->EventGroup
, EventGroup
);
481 IEvent
->ExFlag
|= EVT_EXFLAG_EVENT_GROUP
;
486 if ((Type
& EVT_RUNTIME
) != 0) {
488 // Keep a list of all RT events so we can tell the RT AP.
490 IEvent
->RuntimeData
.Type
= Type
;
491 IEvent
->RuntimeData
.NotifyTpl
= NotifyTpl
;
492 IEvent
->RuntimeData
.NotifyFunction
= NotifyFunction
;
493 IEvent
->RuntimeData
.NotifyContext
= (VOID
*) NotifyContext
;
494 IEvent
->RuntimeData
.Event
= (EFI_EVENT
*) IEvent
;
495 InsertTailList (&gRuntime
->EventHead
, &IEvent
->RuntimeData
.Link
);
498 CoreAcquireEventLock ();
500 if ((Type
& EVT_NOTIFY_SIGNAL
) != 0x00000000) {
502 // The Event's NotifyFunction must be queued whenever the event is signaled
504 InsertHeadList (&gEventSignalQueue
, &IEvent
->SignalLink
);
507 CoreReleaseEventLock ();
519 Signals the event. Queues the event to be notified if needed.
521 @param UserEvent The event to signal .
523 @retval EFI_INVALID_PARAMETER Parameters are not valid.
524 @retval EFI_SUCCESS The event was signaled.
530 IN EFI_EVENT UserEvent
538 return EFI_INVALID_PARAMETER
;
541 if (Event
->Signature
!= EVENT_SIGNATURE
) {
542 return EFI_INVALID_PARAMETER
;
545 CoreAcquireEventLock ();
548 // If the event is not already signalled, do so
551 if (Event
->SignalCount
== 0x00000000) {
552 Event
->SignalCount
++;
555 // If signalling type is a notify function, queue it
557 if ((Event
->Type
& EVT_NOTIFY_SIGNAL
) != 0) {
558 if ((Event
->ExFlag
& EVT_EXFLAG_EVENT_GROUP
) != 0) {
560 // The CreateEventEx() style requires all members of the Event Group
563 CoreReleaseEventLock ();
564 CoreNotifySignalList (&Event
->EventGroup
);
565 CoreAcquireEventLock ();
567 CoreNotifyEvent (Event
);
572 CoreReleaseEventLock ();
579 Check the status of an event.
581 @param UserEvent The event to check
583 @retval EFI_SUCCESS The event is in the signaled state
584 @retval EFI_NOT_READY The event is not in the signaled state
585 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
591 IN EFI_EVENT UserEvent
600 return EFI_INVALID_PARAMETER
;
603 if (Event
->Signature
!= EVENT_SIGNATURE
) {
604 return EFI_INVALID_PARAMETER
;
607 if ((Event
->Type
& EVT_NOTIFY_SIGNAL
) != 0) {
608 return EFI_INVALID_PARAMETER
;
611 Status
= EFI_NOT_READY
;
613 if ((Event
->SignalCount
== 0) && ((Event
->Type
& EVT_NOTIFY_WAIT
) != 0)) {
616 // Queue the wait notify function
618 CoreAcquireEventLock ();
619 if (Event
->SignalCount
== 0) {
620 CoreNotifyEvent (Event
);
622 CoreReleaseEventLock ();
626 // If the even looks signalled, get the lock and clear it
629 if (Event
->SignalCount
!= 0) {
630 CoreAcquireEventLock ();
632 if (Event
->SignalCount
!= 0) {
633 Event
->SignalCount
= 0;
634 Status
= EFI_SUCCESS
;
637 CoreReleaseEventLock ();
646 Stops execution until an event is signaled.
648 @param NumberOfEvents The number of events in the UserEvents array
649 @param UserEvents An array of EFI_EVENT
650 @param UserIndex Pointer to the index of the event which
651 satisfied the wait condition
653 @retval EFI_SUCCESS The event indicated by Index was signaled.
654 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
655 function or Event was not a valid type
656 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
662 IN UINTN NumberOfEvents
,
663 IN EFI_EVENT
*UserEvents
,
671 // Can only WaitForEvent at TPL_APPLICATION
673 if (gEfiCurrentTpl
!= TPL_APPLICATION
) {
674 return EFI_UNSUPPORTED
;
677 if (NumberOfEvents
== 0) {
678 return EFI_INVALID_PARAMETER
;
681 if (UserEvents
== NULL
) {
682 return EFI_INVALID_PARAMETER
;
687 for(Index
= 0; Index
< NumberOfEvents
; Index
++) {
689 Status
= CoreCheckEvent (UserEvents
[Index
]);
692 // provide index of event that caused problem
694 if (Status
!= EFI_NOT_READY
) {
695 if (UserIndex
!= NULL
) {
703 // Signal the Idle event
705 CoreSignalEvent (gIdleLoopEvent
);
711 Closes an event and frees the event structure.
713 @param UserEvent Event to close
715 @retval EFI_INVALID_PARAMETER Parameters are not valid.
716 @retval EFI_SUCCESS The event has been closed
722 IN EFI_EVENT UserEvent
731 return EFI_INVALID_PARAMETER
;
734 if (Event
->Signature
!= EVENT_SIGNATURE
) {
735 return EFI_INVALID_PARAMETER
;
739 // If it's a timer event, make sure it's not pending
741 if ((Event
->Type
& EVT_TIMER
) != 0) {
742 CoreSetTimer (Event
, TimerCancel
, 0);
745 CoreAcquireEventLock ();
748 // If the event is queued somewhere, remove it
751 if (Event
->RuntimeData
.Link
.ForwardLink
!= NULL
) {
752 RemoveEntryList (&Event
->RuntimeData
.Link
);
755 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
756 RemoveEntryList (&Event
->NotifyLink
);
759 if (Event
->SignalLink
.ForwardLink
!= NULL
) {
760 RemoveEntryList (&Event
->SignalLink
);
763 CoreReleaseEventLock ();
766 // If the event is registered on a protocol notify, then remove it from the protocol database
768 if ((Event
->ExFlag
& EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION
) != 0) {
769 CoreUnregisterProtocolNotify (Event
);
773 // To avoid the Event to be signalled wrongly after closed,
774 // clear the Signature of Event before free pool.
776 Event
->Signature
= 0;
777 Status
= CoreFreePool (Event
);
778 ASSERT_EFI_ERROR (Status
);