3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
26 // Enumerate the valid types
28 UINT32 mEventTable
[] = {
30 // 0x80000200 Timer event with a notification function that is
31 // queue when the event is signaled with SignalEvent()
33 EFI_EVENT_TIMER
| EFI_EVENT_NOTIFY_SIGNAL
,
35 // 0x80000000 Timer event without a notification function. It can be
36 // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
40 // 0x00000100 Generic event with a notification function that
41 // can be waited on with CheckEvent() or WaitForEvent()
43 EFI_EVENT_NOTIFY_WAIT
,
45 // 0x00000200 Generic event with a notification function that
46 // is queue when the event is signaled with SignalEvent()
48 EFI_EVENT_NOTIFY_SIGNAL
,
50 // 0x00000201 ExitBootServicesEvent.
52 EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES
,
54 // 0x60000202 SetVirtualAddressMapEvent.
56 EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
58 #if (EFI_SPECIFICATION_VERSION < 0x00020000)
60 // 0x00000203 ReadyToBootEvent.
62 EFI_EVENT_SIGNAL_READY_TO_BOOT
,
64 // 0x00000204 LegacyBootEvent.
66 EFI_EVENT_SIGNAL_LEGACY_BOOT
,
68 // 0x00000603 Signal all ReadyToBootEvents.
70 EFI_EVENT_NOTIFY_SIGNAL_ALL
| EFI_EVENT_SIGNAL_READY_TO_BOOT
,
72 // 0x00000604 Signal all LegacyBootEvents.
74 EFI_EVENT_NOTIFY_SIGNAL_ALL
| EFI_EVENT_SIGNAL_LEGACY_BOOT
,
78 // 0x00000000 Generic event without a notification function.
79 // It can be signaled with SignalEvent() and checked with CheckEvent()
84 // 0x80000100 Timer event with a notification function that can be
85 // waited on with CheckEvent() or WaitForEvent()
87 EFI_EVENT_TIMER
| EFI_EVENT_NOTIFY_WAIT
,
92 CoreAcquireEventLock (
99 Enter critical section by acquiring the lock on gEventQueueLock.
111 CoreAcquireLock (&gEventQueueLock
);
116 CoreReleaseEventLock (
123 Exit critical section by releasing the lock on gEventQueueLock.
135 CoreReleaseLock (&gEventQueueLock
);
140 CoreInitializeEventServices (
147 Initializes "event" support and populates parts of the System and Runtime Table.
155 EFI_SUCCESS - Always return success
161 for (Index
=0; Index
<= EFI_TPL_HIGH_LEVEL
; Index
++) {
162 InitializeListHead (&gEventQueue
[Index
]);
165 CoreInitializeTimer ();
172 CoreShutdownEventServices (
179 Register all runtime events to make sure they are still available after ExitBootService.
187 EFI_SUCCESS - Always return success.
195 // The Runtime AP is required for the core to function!
197 ASSERT (gRuntime
!= NULL
);
199 for (Link
= mRuntimeEventList
.ForwardLink
; Link
!= &mRuntimeEventList
; Link
= Link
->ForwardLink
) {
200 Event
= CR (Link
, IEVENT
, RuntimeLink
, EVENT_SIGNATURE
);
201 gRuntime
->RegisterEvent (
205 Event
->NotifyFunction
,
206 Event
->NotifyContext
,
216 CoreDispatchEventNotifies (
223 Dispatches all pending events.
227 Priority - The task priority level of event notifications to dispatch
238 CoreAcquireEventLock ();
239 ASSERT (gEventQueueLock
.OwnerTpl
== Priority
);
240 Head
= &gEventQueue
[Priority
];
243 // Dispatch all the pending notifications
245 while (!IsListEmpty (Head
)) {
247 Event
= CR (Head
->ForwardLink
, IEVENT
, NotifyLink
, EVENT_SIGNATURE
);
248 RemoveEntryList (&Event
->NotifyLink
);
250 Event
->NotifyLink
.ForwardLink
= NULL
;
253 // Only clear the SIGNAL status if it is a SIGNAL type event.
254 // WAIT type events are only cleared in CheckEvent()
256 if (Event
->Type
& EFI_EVENT_NOTIFY_SIGNAL
) {
257 Event
->SignalCount
= 0;
260 CoreReleaseEventLock ();
265 ASSERT (Event
->NotifyFunction
!= NULL
);
266 Event
->NotifyFunction (Event
, Event
->NotifyContext
);
269 // Check for next pending event
271 CoreAcquireEventLock ();
274 gEventPending
&= ~(1 << Priority
);
275 CoreReleaseEventLock ();
288 Queues the event's notification function to fire
292 Event - The Event to notify
302 // Event database must be locked
304 ASSERT_LOCKED (&gEventQueueLock
);
307 // If the event is queued somewhere, remove it
310 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
311 RemoveEntryList (&Event
->NotifyLink
);
312 Event
->NotifyLink
.ForwardLink
= NULL
;
316 // Queue the event to the pending notification list
319 InsertTailList (&gEventQueue
[Event
->NotifyTpl
], &Event
->NotifyLink
);
320 gEventPending
|= (UINTN
)(1 << Event
->NotifyTpl
);
326 CoreNotifySignalList (
327 IN EFI_GUID
*EventGroup
332 Signals all events in the EventGroup
335 EventGroup - The list to signal
347 CoreAcquireEventLock ();
349 Head
= &gEventSignalQueue
;
350 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
351 Event
= CR (Link
, IEVENT
, SignalLink
, EVENT_SIGNATURE
);
352 if (CompareGuid (&Event
->EventGroup
, EventGroup
)) {
353 CoreNotifyEvent (Event
);
357 CoreReleaseEventLock ();
361 #if (EFI_SPECIFICATION_VERSION < 0x00020000)
366 EventNofitySignalAllNullEvent (
372 // This null event is a size efficent way to enusre that
373 // EFI_EVENT_NOTIFY_SIGNAL_ALL is error checked correctly.
374 // EFI_EVENT_NOTIFY_SIGNAL_ALL is now mapped into
375 // CreateEventEx() and this function is used to make the
376 // old error checking in CreateEvent() for Tiano extensions
391 IN EFI_TPL NotifyTpl
,
392 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
393 IN VOID
*NotifyContext
, OPTIONAL
399 Creates a general-purpose event structure
402 Type - The type of event to create and its mode and attributes
403 NotifyTpl - The task priority level of event notifications
404 NotifyFunction - Pointer to the events notification function
405 NotifyContext - Pointer to the notification functions context; corresponds to
406 parameter "Context" in the notification function
407 Event - Pointer to the newly created event if the call succeeds; undefined otherwise
410 EFI_SUCCESS - The event structure was created
411 EFI_INVALID_PARAMETER - One of the parameters has an invalid value
412 EFI_OUT_OF_RESOURCES - The event could not be allocated
417 EFI_EVENT_NOTIFY Function
;
420 Function
= NotifyFunction
;
422 #if (EFI_SPECIFICATION_VERSION < 0x00020000)
424 // Clear EFI_EVENT_NOFITY_SIGNAL_ALL (Tiano extension) as all events in the
425 // EventGroup now have this property. So we need to filter it out.
427 if (Type
& EFI_EVENT_NOTIFY_SIGNAL_ALL
) {
428 Type
&= ~EFI_EVENT_NOTIFY_SIGNAL_ALL
;
429 Function
= EventNofitySignalAllNullEvent
;
433 // Map the Tiano extensions Events to CreateEventEx form
435 if (Type
== EFI_EVENT_SIGNAL_READY_TO_BOOT
) {
436 GuidPtr
= &gEfiEventReadyToBootGuid
;
437 } else if (Type
== EFI_EVENT_SIGNAL_LEGACY_BOOT
) {
438 GuidPtr
= &gEfiEventLegacyBootGuid
443 // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping
445 if (Type
== EVENT_SIGNAL_EXIT_BOOT_SERVICES
) {
446 GuidPtr
= &gEfiEventExitBootServicesGuid
;
447 } else if (Type
== EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
) {
448 GuidPtr
= &gEfiEventVirtualAddressChangeGuid
;
451 return CoreCreateEventEx (Type
, NotifyTpl
, Function
, NotifyContext
, GuidPtr
, Event
);
459 IN EFI_TPL NotifyTpl
,
460 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
461 IN CONST VOID
*NotifyContext
, OPTIONAL
462 IN CONST EFI_GUID
*EventGroup
, OPTIONAL
468 Creates a general-purpose event structure
471 Type - The type of event to create and its mode and attributes
472 NotifyTpl - The task priority level of event notifications
473 NotifyFunction - Pointer to the events notification function
474 NotifyContext - Pointer to the notification functions context; corresponds to
475 parameter "Context" in the notification function
476 EventGrout - GUID for EventGroup if NULL act the same as gBS->CreateEvent().
477 Event - Pointer to the newly created event if the call succeeds; undefined otherwise
480 EFI_SUCCESS - The event structure was created
481 EFI_INVALID_PARAMETER - One of the parameters has an invalid value
482 EFI_OUT_OF_RESOURCES - The event could not be allocated
491 if ((Event
== NULL
) || (NotifyTpl
== EFI_TPL_APPLICATION
)) {
492 return EFI_INVALID_PARAMETER
;
496 // Check to make sure no reserved flags are set
498 Status
= EFI_INVALID_PARAMETER
;
499 for (Index
= 0; Index
< (sizeof (mEventTable
) / sizeof (UINT32
)); Index
++) {
500 if (Type
== mEventTable
[Index
]) {
501 Status
= EFI_SUCCESS
;
505 if(EFI_ERROR (Status
)) {
506 return EFI_INVALID_PARAMETER
;
510 // If it's a notify type of event, check its parameters
512 if ((Type
& (EFI_EVENT_NOTIFY_WAIT
| EFI_EVENT_NOTIFY_SIGNAL
))) {
514 // Check for an invalid NotifyFunction or NotifyTpl
516 if ((NotifyFunction
== NULL
) ||
517 (NotifyTpl
< EFI_TPL_APPLICATION
) ||
518 (NotifyTpl
>= EFI_TPL_HIGH_LEVEL
)) {
519 return EFI_INVALID_PARAMETER
;
524 // No notification needed, zero ignored values
527 NotifyFunction
= NULL
;
528 NotifyContext
= NULL
;
532 // Allcoate and initialize a new event structure.
534 Status
= CoreAllocatePool (
535 (Type
& EFI_EVENT_RUNTIME
) ? EfiRuntimeServicesData
: EfiBootServicesData
,
539 if (EFI_ERROR (Status
)) {
540 return EFI_OUT_OF_RESOURCES
;
543 SetMem (IEvent
, sizeof (IEVENT
), 0);
545 IEvent
->Signature
= EVENT_SIGNATURE
;
548 IEvent
->NotifyTpl
= NotifyTpl
;
549 IEvent
->NotifyFunction
= NotifyFunction
;
550 IEvent
->NotifyContext
= (VOID
*)NotifyContext
;
551 if (EventGroup
!= NULL
) {
552 CopyGuid (&IEvent
->EventGroup
, EventGroup
);
553 IEvent
->ExFlag
= TRUE
;
558 if (Type
& EFI_EVENT_RUNTIME
) {
560 // Keep a list of all RT events so we can tell the RT AP.
562 InsertTailList (&mRuntimeEventList
, &IEvent
->RuntimeLink
);
565 CoreAcquireEventLock ();
567 if ((Type
& EFI_EVENT_NOTIFY_SIGNAL
) != 0x00000000) {
569 // The Event's NotifyFunction must be queued whenever the event is signaled
571 InsertHeadList (&gEventSignalQueue
, &IEvent
->SignalLink
);
574 CoreReleaseEventLock ();
587 IN EFI_EVENT UserEvent
593 Signals the event. Queues the event to be notified if needed
597 UserEvent - The event to signal
601 EFI_INVALID_PARAMETER - Parameters are not valid.
603 EFI_SUCCESS - The event was signaled.
612 return EFI_INVALID_PARAMETER
;
615 if (Event
->Signature
!= EVENT_SIGNATURE
) {
616 return EFI_INVALID_PARAMETER
;
619 CoreAcquireEventLock ();
622 // If the event is not already signalled, do so
625 if (Event
->SignalCount
== 0x00000000) {
626 Event
->SignalCount
++;
629 // If signalling type is a notify function, queue it
631 if (Event
->Type
& EFI_EVENT_NOTIFY_SIGNAL
) {
634 // The CreateEventEx() style requires all members of the Event Group
637 CoreReleaseEventLock ();
638 CoreNotifySignalList (&Event
->EventGroup
);
639 CoreAcquireEventLock ();
641 CoreNotifyEvent (Event
);
646 CoreReleaseEventLock ();
654 IN EFI_EVENT UserEvent
660 Check the status of an event
664 UserEvent - The event to check
668 EFI_SUCCESS - The event is in the signaled state
669 EFI_NOT_READY - The event is not in the signaled state
670 EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL
681 return EFI_INVALID_PARAMETER
;
684 if (Event
->Signature
!= EVENT_SIGNATURE
) {
685 return EFI_INVALID_PARAMETER
;
688 if (Event
->Type
& EFI_EVENT_NOTIFY_SIGNAL
) {
689 return EFI_INVALID_PARAMETER
;
692 Status
= EFI_NOT_READY
;
694 if (!Event
->SignalCount
&& (Event
->Type
& EFI_EVENT_NOTIFY_WAIT
)) {
697 // Queue the wait notify function
700 CoreAcquireEventLock ();
701 if (!Event
->SignalCount
) {
702 CoreNotifyEvent (Event
);
704 CoreReleaseEventLock ();
708 // If the even looks signalled, get the lock and clear it
711 if (Event
->SignalCount
) {
712 CoreAcquireEventLock ();
714 if (Event
->SignalCount
) {
715 Event
->SignalCount
= 0;
716 Status
= EFI_SUCCESS
;
719 CoreReleaseEventLock ();
730 IN UINTN NumberOfEvents
,
731 IN EFI_EVENT
*UserEvents
,
738 Stops execution until an event is signaled.
742 NumberOfEvents - The number of events in the UserEvents array
743 UserEvents - An array of EFI_EVENT
744 UserIndex - Pointer to the index of the event which satisfied the wait condition
748 EFI_SUCCESS - The event indicated by Index was signaled.
749 EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or
750 Event was not a valid type
751 EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION
760 // Can only WaitForEvent at TPL_APPLICATION
762 if (gEfiCurrentTpl
!= EFI_TPL_APPLICATION
) {
763 return EFI_UNSUPPORTED
;
768 for(Index
= 0; Index
< NumberOfEvents
; Index
++) {
770 Status
= CoreCheckEvent (UserEvents
[Index
]);
773 // provide index of event that caused problem
775 if (Status
!= EFI_NOT_READY
) {
782 // This was the location of the Idle loop callback in EFI 1.x reference
783 // code. We don't have that concept in this base at this point.
792 IN EFI_EVENT UserEvent
798 Closes an event and frees the event structure.
802 UserEvent - Event to close
806 EFI_INVALID_PARAMETER - Parameters are not valid.
808 EFI_SUCCESS - The event has been closed
819 return EFI_INVALID_PARAMETER
;
822 if (Event
->Signature
!= EVENT_SIGNATURE
) {
823 return EFI_INVALID_PARAMETER
;
827 // If it's a timer event, make sure it's not pending
829 if (Event
->Type
& EFI_EVENT_TIMER
) {
830 CoreSetTimer (Event
, TimerCancel
, 0);
833 CoreAcquireEventLock ();
836 // If the event is queued somewhere, remove it
839 if (Event
->RuntimeLink
.ForwardLink
!= NULL
) {
840 RemoveEntryList (&Event
->RuntimeLink
);
843 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
844 RemoveEntryList (&Event
->NotifyLink
);
847 if (Event
->SignalLink
.ForwardLink
!= NULL
) {
848 RemoveEntryList (&Event
->SignalLink
);
851 CoreReleaseEventLock ();
854 // If the event is registered on a protocol notify, then remove it from the protocol database
856 CoreUnregisterProtocolNotify (Event
);
858 Status
= CoreFreePool (Event
);
859 ASSERT_EFI_ERROR (Status
);