3 UEFI Event support functions implemented in this file.
5 Copyright (c) 2006 - 2008, Intel Corporation
6 All rights reserved. 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.
20 // Enumerate the valid types
22 UINT32 mEventTable
[] = {
24 // 0x80000200 Timer event with a notification function that is
25 // queue when the event is signaled with SignalEvent()
27 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
29 // 0x80000000 Timer event without a notification function. It can be
30 // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
34 // 0x00000100 Generic event with a notification function that
35 // can be waited on with CheckEvent() or WaitForEvent()
39 // 0x00000200 Generic event with a notification function that
40 // is queue when the event is signaled with SignalEvent()
44 // 0x00000201 ExitBootServicesEvent.
46 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
48 // 0x60000202 SetVirtualAddressMapEvent.
50 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
53 // 0x00000000 Generic event without a notification function.
54 // It can be signaled with SignalEvent() and checked with CheckEvent()
59 // 0x80000100 Timer event with a notification function that can be
60 // waited on with CheckEvent() or WaitForEvent()
62 EVT_TIMER
| EVT_NOTIFY_WAIT
,
67 CoreAcquireEventLock (
74 Enter critical section by acquiring the lock on gEventQueueLock.
86 CoreAcquireLock (&gEventQueueLock
);
91 CoreReleaseEventLock (
98 Exit critical section by releasing the lock on gEventQueueLock.
110 CoreReleaseLock (&gEventQueueLock
);
115 CoreInitializeEventServices (
122 Initializes "event" support and populates parts of the System and Runtime Table.
130 EFI_SUCCESS - Always return success
136 for (Index
=0; Index
<= TPL_HIGH_LEVEL
; Index
++) {
137 InitializeListHead (&gEventQueue
[Index
]);
140 CoreInitializeTimer ();
147 CoreDispatchEventNotifies (
154 Dispatches all pending events.
158 Priority - The task priority level of event notifications to dispatch
169 CoreAcquireEventLock ();
170 ASSERT (gEventQueueLock
.OwnerTpl
== Priority
);
171 Head
= &gEventQueue
[Priority
];
174 // Dispatch all the pending notifications
176 while (!IsListEmpty (Head
)) {
178 Event
= CR (Head
->ForwardLink
, IEVENT
, NotifyLink
, EVENT_SIGNATURE
);
179 RemoveEntryList (&Event
->NotifyLink
);
181 Event
->NotifyLink
.ForwardLink
= NULL
;
184 // Only clear the SIGNAL status if it is a SIGNAL type event.
185 // WAIT type events are only cleared in CheckEvent()
187 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
188 Event
->SignalCount
= 0;
191 CoreReleaseEventLock ();
196 ASSERT (Event
->NotifyFunction
!= NULL
);
197 Event
->NotifyFunction (Event
, Event
->NotifyContext
);
200 // Check for next pending event
202 CoreAcquireEventLock ();
205 gEventPending
&= ~(1 << Priority
);
206 CoreReleaseEventLock ();
219 Queues the event's notification function to fire
223 Event - The Event to notify
233 // Event database must be locked
235 ASSERT_LOCKED (&gEventQueueLock
);
238 // If the event is queued somewhere, remove it
241 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
242 RemoveEntryList (&Event
->NotifyLink
);
243 Event
->NotifyLink
.ForwardLink
= NULL
;
247 // Queue the event to the pending notification list
250 InsertTailList (&gEventQueue
[Event
->NotifyTpl
], &Event
->NotifyLink
);
251 gEventPending
|= (UINTN
)(1 << Event
->NotifyTpl
);
257 CoreNotifySignalList (
258 IN EFI_GUID
*EventGroup
263 Signals all events in the EventGroup
266 EventGroup - The list to signal
278 CoreAcquireEventLock ();
280 Head
= &gEventSignalQueue
;
281 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
282 Event
= CR (Link
, IEVENT
, SignalLink
, EVENT_SIGNATURE
);
283 if (CompareGuid (&Event
->EventGroup
, EventGroup
)) {
284 CoreNotifyEvent (Event
);
288 CoreReleaseEventLock ();
295 IN EFI_TPL NotifyTpl
,
296 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
297 IN VOID
*NotifyContext
, OPTIONAL
303 Creates a general-purpose event structure
306 Type - The type of event to create and its mode and attributes
307 NotifyTpl - The task priority level of event notifications
308 NotifyFunction - Pointer to the events notification function
309 NotifyContext - Pointer to the notification functions context; corresponds to
310 parameter "Context" in the notification function
311 Event - Pointer to the newly created event if the call succeeds; undefined otherwise
314 EFI_SUCCESS - The event structure was created
315 EFI_INVALID_PARAMETER - One of the parameters has an invalid value
316 EFI_OUT_OF_RESOURCES - The event could not be allocated
320 return CoreCreateEventEx (Type
, NotifyTpl
, NotifyFunction
, NotifyContext
, NULL
, Event
);
328 IN EFI_TPL NotifyTpl
,
329 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
330 IN CONST VOID
*NotifyContext
, OPTIONAL
331 IN CONST EFI_GUID
*EventGroup
, OPTIONAL
337 Creates a general-purpose event structure
340 Type - The type of event to create and its mode and attributes
341 NotifyTpl - The task priority level of event notifications
342 NotifyFunction - Pointer to the events notification function
343 NotifyContext - Pointer to the notification functions context; corresponds to
344 parameter "Context" in the notification function
345 EventGroup - GUID for EventGroup if NULL act the same as gBS->CreateEvent().
346 Event - Pointer to the newly created event if the call succeeds; undefined otherwise
349 EFI_SUCCESS - The event structure was created
350 EFI_INVALID_PARAMETER - One of the parameters has an invalid value
351 EFI_OUT_OF_RESOURCES - The event could not be allocated
360 if ((Event
== NULL
) || (NotifyTpl
== TPL_APPLICATION
)) {
361 return EFI_INVALID_PARAMETER
;
365 // Check to make sure no reserved flags are set
367 Status
= EFI_INVALID_PARAMETER
;
368 for (Index
= 0; Index
< (sizeof (mEventTable
) / sizeof (UINT32
)); Index
++) {
369 if (Type
== mEventTable
[Index
]) {
370 Status
= EFI_SUCCESS
;
374 if(EFI_ERROR (Status
)) {
375 return EFI_INVALID_PARAMETER
;
379 // Convert Event type for pre-defined Event groups
381 if (EventGroup
!= NULL
) {
383 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
386 if ((Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) || (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
)) {
387 return EFI_INVALID_PARAMETER
;
389 if (CompareGuid (EventGroup
, &gEfiEventExitBootServicesGuid
)) {
390 Type
= EVT_SIGNAL_EXIT_BOOT_SERVICES
;
391 } else if (CompareGuid (EventGroup
, &gEfiEventVirtualAddressChangeGuid
)) {
392 Type
= EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
;
396 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
398 if (Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) {
399 EventGroup
= &gEfiEventExitBootServicesGuid
;
400 } else if (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
) {
401 EventGroup
= &gEfiEventVirtualAddressChangeGuid
;
406 // If it's a notify type of event, check its parameters
408 if ((Type
& (EVT_NOTIFY_WAIT
| EVT_NOTIFY_SIGNAL
))) {
410 // Check for an invalid NotifyFunction or NotifyTpl
412 if ((NotifyFunction
== NULL
) ||
413 (NotifyTpl
< TPL_APPLICATION
) ||
414 (NotifyTpl
>= TPL_HIGH_LEVEL
)) {
415 return EFI_INVALID_PARAMETER
;
420 // No notification needed, zero ignored values
423 NotifyFunction
= NULL
;
424 NotifyContext
= NULL
;
428 // Allcoate and initialize a new event structure.
430 Status
= CoreAllocatePool (
431 (Type
& EVT_RUNTIME
) ? EfiRuntimeServicesData
: EfiBootServicesData
,
435 if (EFI_ERROR (Status
)) {
436 return EFI_OUT_OF_RESOURCES
;
439 SetMem (IEvent
, sizeof (IEVENT
), 0);
441 IEvent
->Signature
= EVENT_SIGNATURE
;
444 IEvent
->NotifyTpl
= NotifyTpl
;
445 IEvent
->NotifyFunction
= NotifyFunction
;
446 IEvent
->NotifyContext
= (VOID
*)NotifyContext
;
447 if (EventGroup
!= NULL
) {
448 CopyGuid (&IEvent
->EventGroup
, EventGroup
);
449 IEvent
->ExFlag
= TRUE
;
454 if (Type
& EVT_RUNTIME
) {
456 // Keep a list of all RT events so we can tell the RT AP.
458 IEvent
->RuntimeData
.Type
= Type
;
459 IEvent
->RuntimeData
.NotifyTpl
= NotifyTpl
;
460 IEvent
->RuntimeData
.NotifyFunction
= NotifyFunction
;
461 IEvent
->RuntimeData
.NotifyContext
= (VOID
*) NotifyContext
;
462 IEvent
->RuntimeData
.Event
= (EFI_EVENT
*) IEvent
;
463 InsertTailList (&gRuntime
->EventHead
, &IEvent
->RuntimeData
.Link
);
466 CoreAcquireEventLock ();
468 if ((Type
& EVT_NOTIFY_SIGNAL
) != 0x00000000) {
470 // The Event's NotifyFunction must be queued whenever the event is signaled
472 InsertHeadList (&gEventSignalQueue
, &IEvent
->SignalLink
);
475 CoreReleaseEventLock ();
488 IN EFI_EVENT UserEvent
494 Signals the event. Queues the event to be notified if needed
498 UserEvent - The event to signal
502 EFI_INVALID_PARAMETER - Parameters are not valid.
504 EFI_SUCCESS - The event was signaled.
513 return EFI_INVALID_PARAMETER
;
516 if (Event
->Signature
!= EVENT_SIGNATURE
) {
517 return EFI_INVALID_PARAMETER
;
520 CoreAcquireEventLock ();
523 // If the event is not already signalled, do so
526 if (Event
->SignalCount
== 0x00000000) {
527 Event
->SignalCount
++;
530 // If signalling type is a notify function, queue it
532 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
535 // The CreateEventEx() style requires all members of the Event Group
538 CoreReleaseEventLock ();
539 CoreNotifySignalList (&Event
->EventGroup
);
540 CoreAcquireEventLock ();
542 CoreNotifyEvent (Event
);
547 CoreReleaseEventLock ();
555 IN EFI_EVENT UserEvent
561 Check the status of an event
565 UserEvent - The event to check
569 EFI_SUCCESS - The event is in the signaled state
570 EFI_NOT_READY - The event is not in the signaled state
571 EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL
582 return EFI_INVALID_PARAMETER
;
585 if (Event
->Signature
!= EVENT_SIGNATURE
) {
586 return EFI_INVALID_PARAMETER
;
589 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
590 return EFI_INVALID_PARAMETER
;
593 Status
= EFI_NOT_READY
;
595 if (!Event
->SignalCount
&& (Event
->Type
& EVT_NOTIFY_WAIT
)) {
598 // Queue the wait notify function
601 CoreAcquireEventLock ();
602 if (!Event
->SignalCount
) {
603 CoreNotifyEvent (Event
);
605 CoreReleaseEventLock ();
609 // If the even looks signalled, get the lock and clear it
612 if (Event
->SignalCount
) {
613 CoreAcquireEventLock ();
615 if (Event
->SignalCount
) {
616 Event
->SignalCount
= 0;
617 Status
= EFI_SUCCESS
;
620 CoreReleaseEventLock ();
631 IN UINTN NumberOfEvents
,
632 IN EFI_EVENT
*UserEvents
,
639 Stops execution until an event is signaled.
643 NumberOfEvents - The number of events in the UserEvents array
644 UserEvents - An array of EFI_EVENT
645 UserIndex - Pointer to the index of the event which satisfied the wait condition
649 EFI_SUCCESS - The event indicated by Index was signaled.
650 EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or
651 Event was not a valid type
652 EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION
661 // Can only WaitForEvent at TPL_APPLICATION
663 if (gEfiCurrentTpl
!= TPL_APPLICATION
) {
664 return EFI_UNSUPPORTED
;
669 for(Index
= 0; Index
< NumberOfEvents
; Index
++) {
671 Status
= CoreCheckEvent (UserEvents
[Index
]);
674 // provide index of event that caused problem
676 if (Status
!= EFI_NOT_READY
) {
683 // This was the location of the Idle loop callback in EFI 1.x reference
684 // code. We don't have that concept in this base at this point.
693 IN EFI_EVENT UserEvent
699 Closes an event and frees the event structure.
703 UserEvent - Event to close
707 EFI_INVALID_PARAMETER - Parameters are not valid.
709 EFI_SUCCESS - The event has been closed
720 return EFI_INVALID_PARAMETER
;
723 if (Event
->Signature
!= EVENT_SIGNATURE
) {
724 return EFI_INVALID_PARAMETER
;
728 // If it's a timer event, make sure it's not pending
730 if (Event
->Type
& EVT_TIMER
) {
731 CoreSetTimer (Event
, TimerCancel
, 0);
734 CoreAcquireEventLock ();
737 // If the event is queued somewhere, remove it
740 if (Event
->RuntimeData
.Link
.ForwardLink
!= NULL
) {
741 RemoveEntryList (&Event
->RuntimeData
.Link
);
744 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
745 RemoveEntryList (&Event
->NotifyLink
);
748 if (Event
->SignalLink
.ForwardLink
!= NULL
) {
749 RemoveEntryList (&Event
->SignalLink
);
752 CoreReleaseEventLock ();
755 // If the event is registered on a protocol notify, then remove it from the protocol database
757 CoreUnregisterProtocolNotify (Event
);
759 Status
= CoreFreePool (Event
);
760 ASSERT_EFI_ERROR (Status
);