2 UEFI Event support functions implemented in this file.
4 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
5 All rights reserved. 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 queus
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
,
92 Enter critical section by acquiring the lock on gEventQueueLock.
96 CoreAcquireEventLock (
100 CoreAcquireLock (&gEventQueueLock
);
105 Exit critical section by releasing the lock on gEventQueueLock.
109 CoreReleaseEventLock (
113 CoreReleaseLock (&gEventQueueLock
);
119 Initializes "event" support.
121 @retval EFI_SUCCESS Always return success
125 CoreInitializeEventServices (
131 for (Index
=0; Index
<= TPL_HIGH_LEVEL
; Index
++) {
132 InitializeListHead (&gEventQueue
[Index
]);
135 CoreInitializeTimer ();
143 Dispatches all pending events.
145 @param Priority The task priority level of event notifications
150 CoreDispatchEventNotifies (
157 CoreAcquireEventLock ();
158 ASSERT (gEventQueueLock
.OwnerTpl
== Priority
);
159 Head
= &gEventQueue
[Priority
];
162 // Dispatch all the pending notifications
164 while (!IsListEmpty (Head
)) {
166 Event
= CR (Head
->ForwardLink
, IEVENT
, NotifyLink
, EVENT_SIGNATURE
);
167 RemoveEntryList (&Event
->NotifyLink
);
169 Event
->NotifyLink
.ForwardLink
= NULL
;
172 // Only clear the SIGNAL status if it is a SIGNAL type event.
173 // WAIT type events are only cleared in CheckEvent()
175 if ((Event
->Type
& EVT_NOTIFY_SIGNAL
) != 0) {
176 Event
->SignalCount
= 0;
179 CoreReleaseEventLock ();
184 ASSERT (Event
->NotifyFunction
!= NULL
);
185 Event
->NotifyFunction (Event
, Event
->NotifyContext
);
188 // Check for next pending event
190 CoreAcquireEventLock ();
193 gEventPending
&= ~(1 << Priority
);
194 CoreReleaseEventLock ();
200 Queues the event's notification function to fire.
202 @param Event The Event to notify
212 // Event database must be locked
214 ASSERT_LOCKED (&gEventQueueLock
);
217 // If the event is queued somewhere, remove it
220 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
221 RemoveEntryList (&Event
->NotifyLink
);
222 Event
->NotifyLink
.ForwardLink
= NULL
;
226 // Queue the event to the pending notification list
229 InsertTailList (&gEventQueue
[Event
->NotifyTpl
], &Event
->NotifyLink
);
230 gEventPending
|= (UINTN
)(1 << Event
->NotifyTpl
);
237 Signals all events in the EventGroup.
239 @param EventGroup The list to signal
243 CoreNotifySignalList (
244 IN EFI_GUID
*EventGroup
251 CoreAcquireEventLock ();
253 Head
= &gEventSignalQueue
;
254 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
255 Event
= CR (Link
, IEVENT
, SignalLink
, EVENT_SIGNATURE
);
256 if (CompareGuid (&Event
->EventGroup
, EventGroup
)) {
257 CoreNotifyEvent (Event
);
261 CoreReleaseEventLock ();
266 Creates a general-purpose event structure.
268 @param Type The type of event to create and its mode and
270 @param NotifyTpl The task priority level of event notifications
271 @param NotifyFunction Pointer to the events notification function
272 @param NotifyContext Pointer to the notification functions context;
273 corresponds to parameter "Context" in the
274 notification function
275 @param Event Pointer to the newly created event if the call
276 succeeds; undefined otherwise
278 @retval EFI_SUCCESS The event structure was created
279 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
280 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
287 IN EFI_TPL NotifyTpl
,
288 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
289 IN VOID
*NotifyContext
, OPTIONAL
293 return CoreCreateEventEx (Type
, NotifyTpl
, NotifyFunction
, NotifyContext
, NULL
, Event
);
299 Creates a general-purpose event structure
301 @param Type The type of event to create and its mode and
303 @param NotifyTpl The task priority level of event notifications
304 @param NotifyFunction Pointer to the events notification function
305 @param NotifyContext Pointer to the notification functions context;
306 corresponds to parameter "Context" in the
307 notification function
308 @param EventGroup GUID for EventGroup if NULL act the same as
310 @param Event Pointer to the newly created event if the call
311 succeeds; undefined otherwise
313 @retval EFI_SUCCESS The event structure was created
314 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
315 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
322 IN EFI_TPL NotifyTpl
,
323 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
324 IN CONST VOID
*NotifyContext
, OPTIONAL
325 IN CONST EFI_GUID
*EventGroup
, OPTIONAL
335 return EFI_INVALID_PARAMETER
;
339 // Check to make sure no reserved flags are set
341 Status
= EFI_INVALID_PARAMETER
;
342 for (Index
= 0; Index
< (sizeof (mEventTable
) / sizeof (UINT32
)); Index
++) {
343 if (Type
== mEventTable
[Index
]) {
344 Status
= EFI_SUCCESS
;
348 if(EFI_ERROR (Status
)) {
349 return EFI_INVALID_PARAMETER
;
353 // Convert Event type for pre-defined Event groups
355 if (EventGroup
!= NULL
) {
357 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
360 if ((Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) || (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
)) {
361 return EFI_INVALID_PARAMETER
;
363 if (CompareGuid (EventGroup
, &gEfiEventExitBootServicesGuid
)) {
364 Type
= EVT_SIGNAL_EXIT_BOOT_SERVICES
;
365 } else if (CompareGuid (EventGroup
, &gEfiEventVirtualAddressChangeGuid
)) {
366 Type
= EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
;
370 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
372 if (Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) {
373 EventGroup
= &gEfiEventExitBootServicesGuid
;
374 } else if (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
) {
375 EventGroup
= &gEfiEventVirtualAddressChangeGuid
;
380 // If it's a notify type of event, check its parameters
382 if ((Type
& (EVT_NOTIFY_WAIT
| EVT_NOTIFY_SIGNAL
)) != 0) {
384 // Check for an invalid NotifyFunction or NotifyTpl
386 if ((NotifyFunction
== NULL
) ||
387 (NotifyTpl
<= TPL_APPLICATION
) ||
388 (NotifyTpl
>= TPL_HIGH_LEVEL
)) {
389 return EFI_INVALID_PARAMETER
;
394 // No notification needed, zero ignored values
397 NotifyFunction
= NULL
;
398 NotifyContext
= NULL
;
402 // Allcoate and initialize a new event structure.
404 Status
= CoreAllocatePool (
405 ((Type
& EVT_RUNTIME
) != 0) ? EfiRuntimeServicesData
: EfiBootServicesData
,
409 if (EFI_ERROR (Status
)) {
410 return EFI_OUT_OF_RESOURCES
;
413 ZeroMem (IEvent
, sizeof (IEVENT
));
415 IEvent
->Signature
= EVENT_SIGNATURE
;
418 IEvent
->NotifyTpl
= NotifyTpl
;
419 IEvent
->NotifyFunction
= NotifyFunction
;
420 IEvent
->NotifyContext
= (VOID
*)NotifyContext
;
421 if (EventGroup
!= NULL
) {
422 CopyGuid (&IEvent
->EventGroup
, EventGroup
);
423 IEvent
->ExFlag
= TRUE
;
428 if ((Type
& EVT_RUNTIME
) != 0) {
430 // Keep a list of all RT events so we can tell the RT AP.
432 IEvent
->RuntimeData
.Type
= Type
;
433 IEvent
->RuntimeData
.NotifyTpl
= NotifyTpl
;
434 IEvent
->RuntimeData
.NotifyFunction
= NotifyFunction
;
435 IEvent
->RuntimeData
.NotifyContext
= (VOID
*) NotifyContext
;
436 IEvent
->RuntimeData
.Event
= (EFI_EVENT
*) IEvent
;
437 InsertTailList (&gRuntime
->EventHead
, &IEvent
->RuntimeData
.Link
);
440 CoreAcquireEventLock ();
442 if ((Type
& EVT_NOTIFY_SIGNAL
) != 0x00000000) {
444 // The Event's NotifyFunction must be queued whenever the event is signaled
446 InsertHeadList (&gEventSignalQueue
, &IEvent
->SignalLink
);
449 CoreReleaseEventLock ();
461 Signals the event. Queues the event to be notified if needed.
463 @param UserEvent The event to signal .
465 @retval EFI_INVALID_PARAMETER Parameters are not valid.
466 @retval EFI_SUCCESS The event was signaled.
472 IN EFI_EVENT UserEvent
480 return EFI_INVALID_PARAMETER
;
483 if (Event
->Signature
!= EVENT_SIGNATURE
) {
484 return EFI_INVALID_PARAMETER
;
487 CoreAcquireEventLock ();
490 // If the event is not already signalled, do so
493 if (Event
->SignalCount
== 0x00000000) {
494 Event
->SignalCount
++;
497 // If signalling type is a notify function, queue it
499 if ((Event
->Type
& EVT_NOTIFY_SIGNAL
) != 0) {
502 // The CreateEventEx() style requires all members of the Event Group
505 CoreReleaseEventLock ();
506 CoreNotifySignalList (&Event
->EventGroup
);
507 CoreAcquireEventLock ();
509 CoreNotifyEvent (Event
);
514 CoreReleaseEventLock ();
521 Check the status of an event.
523 @param UserEvent The event to check
525 @retval EFI_SUCCESS The event is in the signaled state
526 @retval EFI_NOT_READY The event is not in the signaled state
527 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
533 IN EFI_EVENT UserEvent
542 return EFI_INVALID_PARAMETER
;
545 if (Event
->Signature
!= EVENT_SIGNATURE
) {
546 return EFI_INVALID_PARAMETER
;
549 if ((Event
->Type
& EVT_NOTIFY_SIGNAL
) != 0) {
550 return EFI_INVALID_PARAMETER
;
553 Status
= EFI_NOT_READY
;
555 if ((Event
->SignalCount
== 0) && ((Event
->Type
& EVT_NOTIFY_WAIT
) != 0)) {
558 // Queue the wait notify function
560 CoreAcquireEventLock ();
561 if (Event
->SignalCount
== 0) {
562 CoreNotifyEvent (Event
);
564 CoreReleaseEventLock ();
568 // If the even looks signalled, get the lock and clear it
571 if (Event
->SignalCount
!= 0) {
572 CoreAcquireEventLock ();
574 if (Event
->SignalCount
!= 0) {
575 Event
->SignalCount
= 0;
576 Status
= EFI_SUCCESS
;
579 CoreReleaseEventLock ();
588 Stops execution until an event is signaled.
590 @param NumberOfEvents The number of events in the UserEvents array
591 @param UserEvents An array of EFI_EVENT
592 @param UserIndex Pointer to the index of the event which
593 satisfied the wait condition
595 @retval EFI_SUCCESS The event indicated by Index was signaled.
596 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
597 function or Event was not a valid type
598 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
604 IN UINTN NumberOfEvents
,
605 IN EFI_EVENT
*UserEvents
,
613 // Can only WaitForEvent at TPL_APPLICATION
615 if (gEfiCurrentTpl
!= TPL_APPLICATION
) {
616 return EFI_UNSUPPORTED
;
621 for(Index
= 0; Index
< NumberOfEvents
; Index
++) {
623 Status
= CoreCheckEvent (UserEvents
[Index
]);
626 // provide index of event that caused problem
628 if (Status
!= EFI_NOT_READY
) {
635 // This was the location of the Idle loop callback in EFI 1.x reference
636 // code. We don't have that concept in this base at this point.
643 Closes an event and frees the event structure.
645 @param UserEvent Event to close
647 @retval EFI_INVALID_PARAMETER Parameters are not valid.
648 @retval EFI_SUCCESS The event has been closed
654 IN EFI_EVENT UserEvent
663 return EFI_INVALID_PARAMETER
;
666 if (Event
->Signature
!= EVENT_SIGNATURE
) {
667 return EFI_INVALID_PARAMETER
;
671 // If it's a timer event, make sure it's not pending
673 if ((Event
->Type
& EVT_TIMER
) != 0) {
674 CoreSetTimer (Event
, TimerCancel
, 0);
677 CoreAcquireEventLock ();
680 // If the event is queued somewhere, remove it
683 if (Event
->RuntimeData
.Link
.ForwardLink
!= NULL
) {
684 RemoveEntryList (&Event
->RuntimeData
.Link
);
687 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
688 RemoveEntryList (&Event
->NotifyLink
);
691 if (Event
->SignalLink
.ForwardLink
!= NULL
) {
692 RemoveEntryList (&Event
->SignalLink
);
695 CoreReleaseEventLock ();
698 // If the event is registered on a protocol notify, then remove it from the protocol database
700 CoreUnregisterProtocolNotify (Event
);
702 Status
= CoreFreePool (Event
);
703 ASSERT_EFI_ERROR (Status
);