3 Copyright (c) 2006 - 2007, 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 EVT_TIMER
| EVT_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()
45 // 0x00000200 Generic event with a notification function that
46 // is queue when the event is signaled with SignalEvent()
50 // 0x00000201 ExitBootServicesEvent.
52 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
54 // 0x60000202 SetVirtualAddressMapEvent.
56 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
59 // 0x00000000 Generic event without a notification function.
60 // It can be signaled with SignalEvent() and checked with CheckEvent()
65 // 0x80000100 Timer event with a notification function that can be
66 // waited on with CheckEvent() or WaitForEvent()
68 EVT_TIMER
| EVT_NOTIFY_WAIT
,
73 CoreAcquireEventLock (
80 Enter critical section by acquiring the lock on gEventQueueLock.
92 CoreAcquireLock (&gEventQueueLock
);
97 CoreReleaseEventLock (
104 Exit critical section by releasing the lock on gEventQueueLock.
116 CoreReleaseLock (&gEventQueueLock
);
121 CoreInitializeEventServices (
128 Initializes "event" support and populates parts of the System and Runtime Table.
136 EFI_SUCCESS - Always return success
142 for (Index
=0; Index
<= TPL_HIGH_LEVEL
; Index
++) {
143 InitializeListHead (&gEventQueue
[Index
]);
146 CoreInitializeTimer ();
153 CoreDispatchEventNotifies (
160 Dispatches all pending events.
164 Priority - The task priority level of event notifications to dispatch
175 CoreAcquireEventLock ();
176 ASSERT (gEventQueueLock
.OwnerTpl
== Priority
);
177 Head
= &gEventQueue
[Priority
];
180 // Dispatch all the pending notifications
182 while (!IsListEmpty (Head
)) {
184 Event
= CR (Head
->ForwardLink
, IEVENT
, NotifyLink
, EVENT_SIGNATURE
);
185 RemoveEntryList (&Event
->NotifyLink
);
187 Event
->NotifyLink
.ForwardLink
= NULL
;
190 // Only clear the SIGNAL status if it is a SIGNAL type event.
191 // WAIT type events are only cleared in CheckEvent()
193 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
194 Event
->SignalCount
= 0;
197 CoreReleaseEventLock ();
202 ASSERT (Event
->NotifyFunction
!= NULL
);
203 Event
->NotifyFunction (Event
, Event
->NotifyContext
);
206 // Check for next pending event
208 CoreAcquireEventLock ();
211 gEventPending
&= ~(1 << Priority
);
212 CoreReleaseEventLock ();
225 Queues the event's notification function to fire
229 Event - The Event to notify
239 // Event database must be locked
241 ASSERT_LOCKED (&gEventQueueLock
);
244 // If the event is queued somewhere, remove it
247 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
248 RemoveEntryList (&Event
->NotifyLink
);
249 Event
->NotifyLink
.ForwardLink
= NULL
;
253 // Queue the event to the pending notification list
256 InsertTailList (&gEventQueue
[Event
->NotifyTpl
], &Event
->NotifyLink
);
257 gEventPending
|= (UINTN
)(1 << Event
->NotifyTpl
);
263 CoreNotifySignalList (
264 IN EFI_GUID
*EventGroup
269 Signals all events in the EventGroup
272 EventGroup - The list to signal
284 CoreAcquireEventLock ();
286 Head
= &gEventSignalQueue
;
287 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
288 Event
= CR (Link
, IEVENT
, SignalLink
, EVENT_SIGNATURE
);
289 if (CompareGuid (&Event
->EventGroup
, EventGroup
)) {
290 CoreNotifyEvent (Event
);
294 CoreReleaseEventLock ();
301 IN EFI_TPL NotifyTpl
,
302 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
303 IN VOID
*NotifyContext
, OPTIONAL
309 Creates a general-purpose event structure
312 Type - The type of event to create and its mode and attributes
313 NotifyTpl - The task priority level of event notifications
314 NotifyFunction - Pointer to the events notification function
315 NotifyContext - Pointer to the notification functions context; corresponds to
316 parameter "Context" in the notification function
317 Event - Pointer to the newly created event if the call succeeds; undefined otherwise
320 EFI_SUCCESS - The event structure was created
321 EFI_INVALID_PARAMETER - One of the parameters has an invalid value
322 EFI_OUT_OF_RESOURCES - The event could not be allocated
326 return CoreCreateEventEx (Type
, NotifyTpl
, NotifyFunction
, NotifyContext
, NULL
, Event
);
334 IN EFI_TPL NotifyTpl
,
335 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
336 IN CONST VOID
*NotifyContext
, OPTIONAL
337 IN CONST EFI_GUID
*EventGroup
, OPTIONAL
343 Creates a general-purpose event structure
346 Type - The type of event to create and its mode and attributes
347 NotifyTpl - The task priority level of event notifications
348 NotifyFunction - Pointer to the events notification function
349 NotifyContext - Pointer to the notification functions context; corresponds to
350 parameter "Context" in the notification function
351 EventGroup - GUID for EventGroup if NULL act the same as gBS->CreateEvent().
352 Event - Pointer to the newly created event if the call succeeds; undefined otherwise
355 EFI_SUCCESS - The event structure was created
356 EFI_INVALID_PARAMETER - One of the parameters has an invalid value
357 EFI_OUT_OF_RESOURCES - The event could not be allocated
366 if ((Event
== NULL
) || (NotifyTpl
== TPL_APPLICATION
)) {
367 return EFI_INVALID_PARAMETER
;
371 // Check to make sure no reserved flags are set
373 Status
= EFI_INVALID_PARAMETER
;
374 for (Index
= 0; Index
< (sizeof (mEventTable
) / sizeof (UINT32
)); Index
++) {
375 if (Type
== mEventTable
[Index
]) {
376 Status
= EFI_SUCCESS
;
380 if(EFI_ERROR (Status
)) {
381 return EFI_INVALID_PARAMETER
;
385 // Convert Event type for pre-defined Event groups
387 if (EventGroup
!= NULL
) {
389 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
392 if ((Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) || (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
)) {
393 return EFI_INVALID_PARAMETER
;
395 if (CompareGuid (EventGroup
, &gEfiEventExitBootServicesGuid
)) {
396 Type
= EVT_SIGNAL_EXIT_BOOT_SERVICES
;
397 } else if (CompareGuid (EventGroup
, &gEfiEventVirtualAddressChangeGuid
)) {
398 Type
= EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
;
402 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
404 if (Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) {
405 EventGroup
= &gEfiEventExitBootServicesGuid
;
406 } else if (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
) {
407 EventGroup
= &gEfiEventVirtualAddressChangeGuid
;
412 // If it's a notify type of event, check its parameters
414 if ((Type
& (EVT_NOTIFY_WAIT
| EVT_NOTIFY_SIGNAL
))) {
416 // Check for an invalid NotifyFunction or NotifyTpl
418 if ((NotifyFunction
== NULL
) ||
419 (NotifyTpl
< TPL_APPLICATION
) ||
420 (NotifyTpl
>= TPL_HIGH_LEVEL
)) {
421 return EFI_INVALID_PARAMETER
;
426 // No notification needed, zero ignored values
429 NotifyFunction
= NULL
;
430 NotifyContext
= NULL
;
434 // Allcoate and initialize a new event structure.
436 Status
= CoreAllocatePool (
437 (Type
& EVT_RUNTIME
) ? EfiRuntimeServicesData
: EfiBootServicesData
,
441 if (EFI_ERROR (Status
)) {
442 return EFI_OUT_OF_RESOURCES
;
445 SetMem (IEvent
, sizeof (IEVENT
), 0);
447 IEvent
->Signature
= EVENT_SIGNATURE
;
450 IEvent
->NotifyTpl
= NotifyTpl
;
451 IEvent
->NotifyFunction
= NotifyFunction
;
452 IEvent
->NotifyContext
= (VOID
*)NotifyContext
;
453 if (EventGroup
!= NULL
) {
454 CopyGuid (&IEvent
->EventGroup
, EventGroup
);
455 IEvent
->ExFlag
= TRUE
;
460 if (Type
& EVT_RUNTIME
) {
462 // Keep a list of all RT events so we can tell the RT AP.
464 IEvent
->RuntimeData
.Type
= Type
;
465 IEvent
->RuntimeData
.NotifyTpl
= NotifyTpl
;
466 IEvent
->RuntimeData
.NotifyFunction
= NotifyFunction
;
467 IEvent
->RuntimeData
.NotifyContext
= (VOID
*) NotifyContext
;
468 IEvent
->RuntimeData
.Event
= (EFI_EVENT
*) IEvent
;
469 InsertTailList (&gRuntime
->EventHead
, &IEvent
->RuntimeData
.Link
);
472 CoreAcquireEventLock ();
474 if ((Type
& EVT_NOTIFY_SIGNAL
) != 0x00000000) {
476 // The Event's NotifyFunction must be queued whenever the event is signaled
478 InsertHeadList (&gEventSignalQueue
, &IEvent
->SignalLink
);
481 CoreReleaseEventLock ();
494 IN EFI_EVENT UserEvent
500 Signals the event. Queues the event to be notified if needed
504 UserEvent - The event to signal
508 EFI_INVALID_PARAMETER - Parameters are not valid.
510 EFI_SUCCESS - The event was signaled.
519 return EFI_INVALID_PARAMETER
;
522 if (Event
->Signature
!= EVENT_SIGNATURE
) {
523 return EFI_INVALID_PARAMETER
;
526 CoreAcquireEventLock ();
529 // If the event is not already signalled, do so
532 if (Event
->SignalCount
== 0x00000000) {
533 Event
->SignalCount
++;
536 // If signalling type is a notify function, queue it
538 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
541 // The CreateEventEx() style requires all members of the Event Group
544 CoreReleaseEventLock ();
545 CoreNotifySignalList (&Event
->EventGroup
);
546 CoreAcquireEventLock ();
548 CoreNotifyEvent (Event
);
553 CoreReleaseEventLock ();
561 IN EFI_EVENT UserEvent
567 Check the status of an event
571 UserEvent - The event to check
575 EFI_SUCCESS - The event is in the signaled state
576 EFI_NOT_READY - The event is not in the signaled state
577 EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL
588 return EFI_INVALID_PARAMETER
;
591 if (Event
->Signature
!= EVENT_SIGNATURE
) {
592 return EFI_INVALID_PARAMETER
;
595 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
596 return EFI_INVALID_PARAMETER
;
599 Status
= EFI_NOT_READY
;
601 if (!Event
->SignalCount
&& (Event
->Type
& EVT_NOTIFY_WAIT
)) {
604 // Queue the wait notify function
607 CoreAcquireEventLock ();
608 if (!Event
->SignalCount
) {
609 CoreNotifyEvent (Event
);
611 CoreReleaseEventLock ();
615 // If the even looks signalled, get the lock and clear it
618 if (Event
->SignalCount
) {
619 CoreAcquireEventLock ();
621 if (Event
->SignalCount
) {
622 Event
->SignalCount
= 0;
623 Status
= EFI_SUCCESS
;
626 CoreReleaseEventLock ();
637 IN UINTN NumberOfEvents
,
638 IN EFI_EVENT
*UserEvents
,
645 Stops execution until an event is signaled.
649 NumberOfEvents - The number of events in the UserEvents array
650 UserEvents - An array of EFI_EVENT
651 UserIndex - Pointer to the index of the event which satisfied the wait condition
655 EFI_SUCCESS - The event indicated by Index was signaled.
656 EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or
657 Event was not a valid type
658 EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION
667 // Can only WaitForEvent at TPL_APPLICATION
669 if (gEfiCurrentTpl
!= TPL_APPLICATION
) {
670 return EFI_UNSUPPORTED
;
675 for(Index
= 0; Index
< NumberOfEvents
; Index
++) {
677 Status
= CoreCheckEvent (UserEvents
[Index
]);
680 // provide index of event that caused problem
682 if (Status
!= EFI_NOT_READY
) {
689 // This was the location of the Idle loop callback in EFI 1.x reference
690 // code. We don't have that concept in this base at this point.
699 IN EFI_EVENT UserEvent
705 Closes an event and frees the event structure.
709 UserEvent - Event to close
713 EFI_INVALID_PARAMETER - Parameters are not valid.
715 EFI_SUCCESS - The event has been closed
726 return EFI_INVALID_PARAMETER
;
729 if (Event
->Signature
!= EVENT_SIGNATURE
) {
730 return EFI_INVALID_PARAMETER
;
734 // If it's a timer event, make sure it's not pending
736 if (Event
->Type
& EVT_TIMER
) {
737 CoreSetTimer (Event
, TimerCancel
, 0);
740 CoreAcquireEventLock ();
743 // If the event is queued somewhere, remove it
746 if (Event
->RuntimeData
.Link
.ForwardLink
!= NULL
) {
747 RemoveEntryList (&Event
->RuntimeData
.Link
);
750 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
751 RemoveEntryList (&Event
->NotifyLink
);
754 if (Event
->SignalLink
.ForwardLink
!= NULL
) {
755 RemoveEntryList (&Event
->SignalLink
);
758 CoreReleaseEventLock ();
761 // If the event is registered on a protocol notify, then remove it from the protocol database
763 CoreUnregisterProtocolNotify (Event
);
765 Status
= CoreFreePool (Event
);
766 ASSERT_EFI_ERROR (Status
);