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.
19 /// gEfiCurrentTpl - Current Task priority level
21 EFI_TPL gEfiCurrentTpl
= TPL_APPLICATION
;
24 /// gEventQueueLock - Protects the event queus
26 EFI_LOCK gEventQueueLock
= EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL
);
29 /// gEventQueue - A list of event's to notify for each priority level
31 LIST_ENTRY gEventQueue
[TPL_HIGH_LEVEL
+ 1];
34 /// gEventPending - A bitmask of the EventQueues that are pending
36 UINTN gEventPending
= 0;
39 /// gEventSignalQueue - A list of events to signal based on EventGroup type
41 LIST_ENTRY gEventSignalQueue
= INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue
);
44 /// Enumerate the valid types
46 UINT32 mEventTable
[] = {
48 /// 0x80000200 Timer event with a notification function that is
49 /// queue when the event is signaled with SignalEvent()
51 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
53 /// 0x80000000 Timer event without a notification function. It can be
54 /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
58 /// 0x00000100 Generic event with a notification function that
59 /// can be waited on with CheckEvent() or WaitForEvent()
63 /// 0x00000200 Generic event with a notification function that
64 /// is queue when the event is signaled with SignalEvent()
68 /// 0x00000201 ExitBootServicesEvent.
70 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
72 /// 0x60000202 SetVirtualAddressMapEvent.
74 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
77 /// 0x00000000 Generic event without a notification function.
78 /// It can be signaled with SignalEvent() and checked with CheckEvent()
79 /// or WaitForEvent().
83 /// 0x80000100 Timer event with a notification function that can be
84 /// waited on with CheckEvent() or WaitForEvent()
86 EVT_TIMER
| EVT_NOTIFY_WAIT
,
91 Enter critical section by acquiring the lock on gEventQueueLock.
95 CoreAcquireEventLock (
99 CoreAcquireLock (&gEventQueueLock
);
104 Exit critical section by releasing the lock on gEventQueueLock.
108 CoreReleaseEventLock (
112 CoreReleaseLock (&gEventQueueLock
);
118 Initializes "event" support.
120 @retval EFI_SUCCESS Always return success
124 CoreInitializeEventServices (
130 for (Index
=0; Index
<= TPL_HIGH_LEVEL
; Index
++) {
131 InitializeListHead (&gEventQueue
[Index
]);
134 CoreInitializeTimer ();
142 Dispatches all pending events.
144 @param Priority The task priority level of event notifications
149 CoreDispatchEventNotifies (
156 CoreAcquireEventLock ();
157 ASSERT (gEventQueueLock
.OwnerTpl
== Priority
);
158 Head
= &gEventQueue
[Priority
];
161 // Dispatch all the pending notifications
163 while (!IsListEmpty (Head
)) {
165 Event
= CR (Head
->ForwardLink
, IEVENT
, NotifyLink
, EVENT_SIGNATURE
);
166 RemoveEntryList (&Event
->NotifyLink
);
168 Event
->NotifyLink
.ForwardLink
= NULL
;
171 // Only clear the SIGNAL status if it is a SIGNAL type event.
172 // WAIT type events are only cleared in CheckEvent()
174 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
175 Event
->SignalCount
= 0;
178 CoreReleaseEventLock ();
183 ASSERT (Event
->NotifyFunction
!= NULL
);
184 Event
->NotifyFunction (Event
, Event
->NotifyContext
);
187 // Check for next pending event
189 CoreAcquireEventLock ();
192 gEventPending
&= ~(1 << Priority
);
193 CoreReleaseEventLock ();
199 Queues the event's notification function to fire.
201 @param Event The Event to notify
211 // Event database must be locked
213 ASSERT_LOCKED (&gEventQueueLock
);
216 // If the event is queued somewhere, remove it
219 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
220 RemoveEntryList (&Event
->NotifyLink
);
221 Event
->NotifyLink
.ForwardLink
= NULL
;
225 // Queue the event to the pending notification list
228 InsertTailList (&gEventQueue
[Event
->NotifyTpl
], &Event
->NotifyLink
);
229 gEventPending
|= (UINTN
)(1 << Event
->NotifyTpl
);
236 Signals all events in the EventGroup.
238 @param EventGroup The list to signal
242 CoreNotifySignalList (
243 IN EFI_GUID
*EventGroup
250 CoreAcquireEventLock ();
252 Head
= &gEventSignalQueue
;
253 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
254 Event
= CR (Link
, IEVENT
, SignalLink
, EVENT_SIGNATURE
);
255 if (CompareGuid (&Event
->EventGroup
, EventGroup
)) {
256 CoreNotifyEvent (Event
);
260 CoreReleaseEventLock ();
265 Creates a general-purpose event structure.
267 @param Type The type of event to create and its mode and
269 @param NotifyTpl The task priority level of event notifications
270 @param NotifyFunction Pointer to the events notification function
271 @param NotifyContext Pointer to the notification functions context;
272 corresponds to parameter "Context" in the
273 notification function
274 @param Event Pointer to the newly created event if the call
275 succeeds; undefined otherwise
277 @retval EFI_SUCCESS The event structure was created
278 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
279 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
286 IN EFI_TPL NotifyTpl
,
287 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
288 IN VOID
*NotifyContext
, OPTIONAL
292 return CoreCreateEventEx (Type
, NotifyTpl
, NotifyFunction
, NotifyContext
, NULL
, Event
);
298 Creates a general-purpose event structure
300 @param Type The type of event to create and its mode and
302 @param NotifyTpl The task priority level of event notifications
303 @param NotifyFunction Pointer to the events notification function
304 @param NotifyContext Pointer to the notification functions context;
305 corresponds to parameter "Context" in the
306 notification function
307 @param EventGroup GUID for EventGroup if NULL act the same as
309 @param Event Pointer to the newly created event if the call
310 succeeds; undefined otherwise
312 @retval EFI_SUCCESS The event structure was created
313 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
314 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
321 IN EFI_TPL NotifyTpl
,
322 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
323 IN CONST VOID
*NotifyContext
, OPTIONAL
324 IN CONST EFI_GUID
*EventGroup
, OPTIONAL
334 return EFI_INVALID_PARAMETER
;
338 // Check to make sure no reserved flags are set
340 Status
= EFI_INVALID_PARAMETER
;
341 for (Index
= 0; Index
< (sizeof (mEventTable
) / sizeof (UINT32
)); Index
++) {
342 if (Type
== mEventTable
[Index
]) {
343 Status
= EFI_SUCCESS
;
347 if(EFI_ERROR (Status
)) {
348 return EFI_INVALID_PARAMETER
;
352 // Convert Event type for pre-defined Event groups
354 if (EventGroup
!= NULL
) {
356 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
359 if ((Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) || (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
)) {
360 return EFI_INVALID_PARAMETER
;
362 if (CompareGuid (EventGroup
, &gEfiEventExitBootServicesGuid
)) {
363 Type
= EVT_SIGNAL_EXIT_BOOT_SERVICES
;
364 } else if (CompareGuid (EventGroup
, &gEfiEventVirtualAddressChangeGuid
)) {
365 Type
= EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
;
369 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
371 if (Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) {
372 EventGroup
= &gEfiEventExitBootServicesGuid
;
373 } else if (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
) {
374 EventGroup
= &gEfiEventVirtualAddressChangeGuid
;
379 // If it's a notify type of event, check its parameters
381 if ((Type
& (EVT_NOTIFY_WAIT
| EVT_NOTIFY_SIGNAL
)) != 0) {
383 // Check for an invalid NotifyFunction or NotifyTpl
385 if ((NotifyFunction
== NULL
) ||
386 (NotifyTpl
<= TPL_APPLICATION
) ||
387 (NotifyTpl
>= TPL_HIGH_LEVEL
)) {
388 return EFI_INVALID_PARAMETER
;
393 // No notification needed, zero ignored values
396 NotifyFunction
= NULL
;
397 NotifyContext
= NULL
;
401 // Allcoate and initialize a new event structure.
403 Status
= CoreAllocatePool (
404 ((Type
& EVT_RUNTIME
) != 0) ? EfiRuntimeServicesData
: EfiBootServicesData
,
408 if (EFI_ERROR (Status
)) {
409 return EFI_OUT_OF_RESOURCES
;
412 ZeroMem (IEvent
, sizeof (IEVENT
));
414 IEvent
->Signature
= EVENT_SIGNATURE
;
417 IEvent
->NotifyTpl
= NotifyTpl
;
418 IEvent
->NotifyFunction
= NotifyFunction
;
419 IEvent
->NotifyContext
= (VOID
*)NotifyContext
;
420 if (EventGroup
!= NULL
) {
421 CopyGuid (&IEvent
->EventGroup
, EventGroup
);
422 IEvent
->ExFlag
= TRUE
;
427 if ((Type
& EVT_RUNTIME
) != 0) {
429 // Keep a list of all RT events so we can tell the RT AP.
431 IEvent
->RuntimeData
.Type
= Type
;
432 IEvent
->RuntimeData
.NotifyTpl
= NotifyTpl
;
433 IEvent
->RuntimeData
.NotifyFunction
= NotifyFunction
;
434 IEvent
->RuntimeData
.NotifyContext
= (VOID
*) NotifyContext
;
435 IEvent
->RuntimeData
.Event
= (EFI_EVENT
*) IEvent
;
436 InsertTailList (&gRuntime
->EventHead
, &IEvent
->RuntimeData
.Link
);
439 CoreAcquireEventLock ();
441 if ((Type
& EVT_NOTIFY_SIGNAL
) != 0x00000000) {
443 // The Event's NotifyFunction must be queued whenever the event is signaled
445 InsertHeadList (&gEventSignalQueue
, &IEvent
->SignalLink
);
448 CoreReleaseEventLock ();
460 Signals the event. Queues the event to be notified if needed.
462 @param UserEvent The event to signal .
464 @retval EFI_INVALID_PARAMETER Parameters are not valid.
465 @retval EFI_SUCCESS The event was signaled.
471 IN EFI_EVENT UserEvent
479 return EFI_INVALID_PARAMETER
;
482 if (Event
->Signature
!= EVENT_SIGNATURE
) {
483 return EFI_INVALID_PARAMETER
;
486 CoreAcquireEventLock ();
489 // If the event is not already signalled, do so
492 if (Event
->SignalCount
== 0x00000000) {
493 Event
->SignalCount
++;
496 // If signalling type is a notify function, queue it
498 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
501 // The CreateEventEx() style requires all members of the Event Group
504 CoreReleaseEventLock ();
505 CoreNotifySignalList (&Event
->EventGroup
);
506 CoreAcquireEventLock ();
508 CoreNotifyEvent (Event
);
513 CoreReleaseEventLock ();
520 Check the status of an event.
522 @param UserEvent The event to check
524 @retval EFI_SUCCESS The event is in the signaled state
525 @retval EFI_NOT_READY The event is not in the signaled state
526 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
532 IN EFI_EVENT UserEvent
541 return EFI_INVALID_PARAMETER
;
544 if (Event
->Signature
!= EVENT_SIGNATURE
) {
545 return EFI_INVALID_PARAMETER
;
548 if ((Event
->Type
& EVT_NOTIFY_SIGNAL
) != 0) {
549 return EFI_INVALID_PARAMETER
;
552 Status
= EFI_NOT_READY
;
554 if (!Event
->SignalCount
&& (Event
->Type
& EVT_NOTIFY_WAIT
)) {
557 // Queue the wait notify function
559 CoreAcquireEventLock ();
560 if (!Event
->SignalCount
) {
561 CoreNotifyEvent (Event
);
563 CoreReleaseEventLock ();
567 // If the even looks signalled, get the lock and clear it
570 if (Event
->SignalCount
) {
571 CoreAcquireEventLock ();
573 if (Event
->SignalCount
) {
574 Event
->SignalCount
= 0;
575 Status
= EFI_SUCCESS
;
578 CoreReleaseEventLock ();
587 Stops execution until an event is signaled.
589 @param NumberOfEvents The number of events in the UserEvents array
590 @param UserEvents An array of EFI_EVENT
591 @param UserIndex Pointer to the index of the event which
592 satisfied the wait condition
594 @retval EFI_SUCCESS The event indicated by Index was signaled.
595 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
596 function or Event was not a valid type
597 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
603 IN UINTN NumberOfEvents
,
604 IN EFI_EVENT
*UserEvents
,
612 // Can only WaitForEvent at TPL_APPLICATION
614 if (gEfiCurrentTpl
!= TPL_APPLICATION
) {
615 return EFI_UNSUPPORTED
;
620 for(Index
= 0; Index
< NumberOfEvents
; Index
++) {
622 Status
= CoreCheckEvent (UserEvents
[Index
]);
625 // provide index of event that caused problem
627 if (Status
!= EFI_NOT_READY
) {
634 // This was the location of the Idle loop callback in EFI 1.x reference
635 // code. We don't have that concept in this base at this point.
642 Closes an event and frees the event structure.
644 @param UserEvent Event to close
646 @retval EFI_INVALID_PARAMETER Parameters are not valid.
647 @retval EFI_SUCCESS The event has been closed
653 IN EFI_EVENT UserEvent
662 return EFI_INVALID_PARAMETER
;
665 if (Event
->Signature
!= EVENT_SIGNATURE
) {
666 return EFI_INVALID_PARAMETER
;
670 // If it's a timer event, make sure it's not pending
672 if ((Event
->Type
& EVT_TIMER
) != 0) {
673 CoreSetTimer (Event
, TimerCancel
, 0);
676 CoreAcquireEventLock ();
679 // If the event is queued somewhere, remove it
682 if (Event
->RuntimeData
.Link
.ForwardLink
!= NULL
) {
683 RemoveEntryList (&Event
->RuntimeData
.Link
);
686 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
687 RemoveEntryList (&Event
->NotifyLink
);
690 if (Event
->SignalLink
.ForwardLink
!= NULL
) {
691 RemoveEntryList (&Event
->SignalLink
);
694 CoreReleaseEventLock ();
697 // If the event is registered on a protocol notify, then remove it from the protocol database
699 CoreUnregisterProtocolNotify (Event
);
701 Status
= CoreFreePool (Event
);
702 ASSERT_EFI_ERROR (Status
);