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 // Enumerate the valid types
21 UINT32 mEventTable
[] = {
23 // 0x80000200 Timer event with a notification function that is
24 // queue when the event is signaled with SignalEvent()
26 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
28 // 0x80000000 Timer event without a notification function. It can be
29 // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
33 // 0x00000100 Generic event with a notification function that
34 // can be waited on with CheckEvent() or WaitForEvent()
38 // 0x00000200 Generic event with a notification function that
39 // is queue when the event is signaled with SignalEvent()
43 // 0x00000201 ExitBootServicesEvent.
45 EVT_SIGNAL_EXIT_BOOT_SERVICES
,
47 // 0x60000202 SetVirtualAddressMapEvent.
49 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
,
52 // 0x00000000 Generic event without a notification function.
53 // It can be signaled with SignalEvent() and checked with CheckEvent()
58 // 0x80000100 Timer event with a notification function that can be
59 // waited on with CheckEvent() or WaitForEvent()
61 EVT_TIMER
| EVT_NOTIFY_WAIT
,
66 Enter critical section by acquiring the lock on gEventQueueLock.
70 CoreAcquireEventLock (
74 CoreAcquireLock (&gEventQueueLock
);
79 Exit critical section by releasing the lock on gEventQueueLock.
83 CoreReleaseEventLock (
87 CoreReleaseLock (&gEventQueueLock
);
93 Initializes "event" support and populates parts of the System and Runtime Table.
96 @retval EFI_SUCCESS Always return success
100 CoreInitializeEventServices (
106 for (Index
=0; Index
<= TPL_HIGH_LEVEL
; Index
++) {
107 InitializeListHead (&gEventQueue
[Index
]);
110 CoreInitializeTimer ();
118 Dispatches all pending events.
120 @param Priority The task priority level of event notifications
125 CoreDispatchEventNotifies (
132 CoreAcquireEventLock ();
133 ASSERT (gEventQueueLock
.OwnerTpl
== Priority
);
134 Head
= &gEventQueue
[Priority
];
137 // Dispatch all the pending notifications
139 while (!IsListEmpty (Head
)) {
141 Event
= CR (Head
->ForwardLink
, IEVENT
, NotifyLink
, EVENT_SIGNATURE
);
142 RemoveEntryList (&Event
->NotifyLink
);
144 Event
->NotifyLink
.ForwardLink
= NULL
;
147 // Only clear the SIGNAL status if it is a SIGNAL type event.
148 // WAIT type events are only cleared in CheckEvent()
150 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
151 Event
->SignalCount
= 0;
154 CoreReleaseEventLock ();
159 ASSERT (Event
->NotifyFunction
!= NULL
);
160 Event
->NotifyFunction (Event
, Event
->NotifyContext
);
163 // Check for next pending event
165 CoreAcquireEventLock ();
168 gEventPending
&= ~(1 << Priority
);
169 CoreReleaseEventLock ();
175 Queues the event's notification function to fire.
177 @param Event The Event to notify
187 // Event database must be locked
189 ASSERT_LOCKED (&gEventQueueLock
);
192 // If the event is queued somewhere, remove it
195 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
196 RemoveEntryList (&Event
->NotifyLink
);
197 Event
->NotifyLink
.ForwardLink
= NULL
;
201 // Queue the event to the pending notification list
204 InsertTailList (&gEventQueue
[Event
->NotifyTpl
], &Event
->NotifyLink
);
205 gEventPending
|= (UINTN
)(1 << Event
->NotifyTpl
);
212 Signals all events in the EventGroup.
214 @param EventGroup The list to signal
218 CoreNotifySignalList (
219 IN EFI_GUID
*EventGroup
226 CoreAcquireEventLock ();
228 Head
= &gEventSignalQueue
;
229 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
230 Event
= CR (Link
, IEVENT
, SignalLink
, EVENT_SIGNATURE
);
231 if (CompareGuid (&Event
->EventGroup
, EventGroup
)) {
232 CoreNotifyEvent (Event
);
236 CoreReleaseEventLock ();
241 Creates a general-purpose event structure.
243 @param Type The type of event to create and its mode and
245 @param NotifyTpl The task priority level of event notifications
246 @param NotifyFunction Pointer to the events notification function
247 @param NotifyContext Pointer to the notification functions context;
248 corresponds to parameter "Context" in the
249 notification function
250 @param Event Pointer to the newly created event if the call
251 succeeds; undefined otherwise
253 @retval EFI_SUCCESS The event structure was created
254 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
255 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
262 IN EFI_TPL NotifyTpl
,
263 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
264 IN VOID
*NotifyContext
, OPTIONAL
268 return CoreCreateEventEx (Type
, NotifyTpl
, NotifyFunction
, NotifyContext
, NULL
, Event
);
274 Creates a general-purpose event structure
276 @param Type The type of event to create and its mode and
278 @param NotifyTpl The task priority level of event notifications
279 @param NotifyFunction Pointer to the events notification function
280 @param NotifyContext Pointer to the notification functions context;
281 corresponds to parameter "Context" in the
282 notification function
283 @param EventGroup GUID for EventGroup if NULL act the same as
285 @param Event Pointer to the newly created event if the call
286 succeeds; undefined otherwise
288 @retval EFI_SUCCESS The event structure was created
289 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
290 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
297 IN EFI_TPL NotifyTpl
,
298 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
299 IN CONST VOID
*NotifyContext
, OPTIONAL
300 IN CONST EFI_GUID
*EventGroup
, OPTIONAL
309 if ((Event
== NULL
) || (NotifyTpl
== TPL_APPLICATION
)) {
310 return EFI_INVALID_PARAMETER
;
314 // Check to make sure no reserved flags are set
316 Status
= EFI_INVALID_PARAMETER
;
317 for (Index
= 0; Index
< (sizeof (mEventTable
) / sizeof (UINT32
)); Index
++) {
318 if (Type
== mEventTable
[Index
]) {
319 Status
= EFI_SUCCESS
;
323 if(EFI_ERROR (Status
)) {
324 return EFI_INVALID_PARAMETER
;
328 // Convert Event type for pre-defined Event groups
330 if (EventGroup
!= NULL
) {
332 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
335 if ((Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) || (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
)) {
336 return EFI_INVALID_PARAMETER
;
338 if (CompareGuid (EventGroup
, &gEfiEventExitBootServicesGuid
)) {
339 Type
= EVT_SIGNAL_EXIT_BOOT_SERVICES
;
340 } else if (CompareGuid (EventGroup
, &gEfiEventVirtualAddressChangeGuid
)) {
341 Type
= EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
;
345 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
347 if (Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) {
348 EventGroup
= &gEfiEventExitBootServicesGuid
;
349 } else if (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
) {
350 EventGroup
= &gEfiEventVirtualAddressChangeGuid
;
355 // If it's a notify type of event, check its parameters
357 if ((Type
& (EVT_NOTIFY_WAIT
| EVT_NOTIFY_SIGNAL
)) != 0) {
359 // Check for an invalid NotifyFunction or NotifyTpl
361 if ((NotifyFunction
== NULL
) ||
362 (NotifyTpl
< TPL_APPLICATION
) ||
363 (NotifyTpl
>= TPL_HIGH_LEVEL
)) {
364 return EFI_INVALID_PARAMETER
;
369 // No notification needed, zero ignored values
372 NotifyFunction
= NULL
;
373 NotifyContext
= NULL
;
377 // Allcoate and initialize a new event structure.
379 Status
= CoreAllocatePool (
380 ((Type
& EVT_RUNTIME
) != 0) ? EfiRuntimeServicesData
: EfiBootServicesData
,
384 if (EFI_ERROR (Status
)) {
385 return EFI_OUT_OF_RESOURCES
;
388 SetMem (IEvent
, sizeof (IEVENT
), 0);
390 IEvent
->Signature
= EVENT_SIGNATURE
;
393 IEvent
->NotifyTpl
= NotifyTpl
;
394 IEvent
->NotifyFunction
= NotifyFunction
;
395 IEvent
->NotifyContext
= (VOID
*)NotifyContext
;
396 if (EventGroup
!= NULL
) {
397 CopyGuid (&IEvent
->EventGroup
, EventGroup
);
398 IEvent
->ExFlag
= TRUE
;
403 if ((Type
& EVT_RUNTIME
) != 0) {
405 // Keep a list of all RT events so we can tell the RT AP.
407 IEvent
->RuntimeData
.Type
= Type
;
408 IEvent
->RuntimeData
.NotifyTpl
= NotifyTpl
;
409 IEvent
->RuntimeData
.NotifyFunction
= NotifyFunction
;
410 IEvent
->RuntimeData
.NotifyContext
= (VOID
*) NotifyContext
;
411 IEvent
->RuntimeData
.Event
= (EFI_EVENT
*) IEvent
;
412 InsertTailList (&gRuntime
->EventHead
, &IEvent
->RuntimeData
.Link
);
415 CoreAcquireEventLock ();
417 if ((Type
& EVT_NOTIFY_SIGNAL
) != 0x00000000) {
419 // The Event's NotifyFunction must be queued whenever the event is signaled
421 InsertHeadList (&gEventSignalQueue
, &IEvent
->SignalLink
);
424 CoreReleaseEventLock ();
436 Signals the event. Queues the event to be notified if needed
438 @param UserEvent The event to signal
440 @retval EFI_INVALID_PARAMETER Parameters are not valid.
441 @retval EFI_SUCCESS The event was signaled.
447 IN EFI_EVENT UserEvent
455 return EFI_INVALID_PARAMETER
;
458 if (Event
->Signature
!= EVENT_SIGNATURE
) {
459 return EFI_INVALID_PARAMETER
;
462 CoreAcquireEventLock ();
465 // If the event is not already signalled, do so
468 if (Event
->SignalCount
== 0x00000000) {
469 Event
->SignalCount
++;
472 // If signalling type is a notify function, queue it
474 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
477 // The CreateEventEx() style requires all members of the Event Group
480 CoreReleaseEventLock ();
481 CoreNotifySignalList (&Event
->EventGroup
);
482 CoreAcquireEventLock ();
484 CoreNotifyEvent (Event
);
489 CoreReleaseEventLock ();
496 Check the status of an event.
498 @param UserEvent The event to check
500 @retval EFI_SUCCESS The event is in the signaled state
501 @retval EFI_NOT_READY The event is not in the signaled state
502 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
508 IN EFI_EVENT UserEvent
517 return EFI_INVALID_PARAMETER
;
520 if (Event
->Signature
!= EVENT_SIGNATURE
) {
521 return EFI_INVALID_PARAMETER
;
524 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
525 return EFI_INVALID_PARAMETER
;
528 Status
= EFI_NOT_READY
;
530 if (!Event
->SignalCount
&& (Event
->Type
& EVT_NOTIFY_WAIT
)) {
533 // Queue the wait notify function
536 CoreAcquireEventLock ();
537 if (!Event
->SignalCount
) {
538 CoreNotifyEvent (Event
);
540 CoreReleaseEventLock ();
544 // If the even looks signalled, get the lock and clear it
547 if (Event
->SignalCount
) {
548 CoreAcquireEventLock ();
550 if (Event
->SignalCount
) {
551 Event
->SignalCount
= 0;
552 Status
= EFI_SUCCESS
;
555 CoreReleaseEventLock ();
565 Stops execution until an event is signaled.
567 @param NumberOfEvents The number of events in the UserEvents array
568 @param UserEvents An array of EFI_EVENT
569 @param UserIndex Pointer to the index of the event which
570 satisfied the wait condition
572 @retval EFI_SUCCESS The event indicated by Index was signaled.
573 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
574 function or Event was not a valid type
575 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
581 IN UINTN NumberOfEvents
,
582 IN EFI_EVENT
*UserEvents
,
590 // Can only WaitForEvent at TPL_APPLICATION
592 if (gEfiCurrentTpl
!= TPL_APPLICATION
) {
593 return EFI_UNSUPPORTED
;
598 for(Index
= 0; Index
< NumberOfEvents
; Index
++) {
600 Status
= CoreCheckEvent (UserEvents
[Index
]);
603 // provide index of event that caused problem
605 if (Status
!= EFI_NOT_READY
) {
612 // This was the location of the Idle loop callback in EFI 1.x reference
613 // code. We don't have that concept in this base at this point.
621 Closes an event and frees the event structure.
623 @param UserEvent Event to close
625 @retval EFI_INVALID_PARAMETER Parameters are not valid.
626 @retval EFI_SUCCESS The event has been closed
632 IN EFI_EVENT UserEvent
641 return EFI_INVALID_PARAMETER
;
644 if (Event
->Signature
!= EVENT_SIGNATURE
) {
645 return EFI_INVALID_PARAMETER
;
649 // If it's a timer event, make sure it's not pending
651 if (Event
->Type
& EVT_TIMER
) {
652 CoreSetTimer (Event
, TimerCancel
, 0);
655 CoreAcquireEventLock ();
658 // If the event is queued somewhere, remove it
661 if (Event
->RuntimeData
.Link
.ForwardLink
!= NULL
) {
662 RemoveEntryList (&Event
->RuntimeData
.Link
);
665 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
666 RemoveEntryList (&Event
->NotifyLink
);
669 if (Event
->SignalLink
.ForwardLink
!= NULL
) {
670 RemoveEntryList (&Event
->SignalLink
);
673 CoreReleaseEventLock ();
676 // If the event is registered on a protocol notify, then remove it from the protocol database
678 CoreUnregisterProtocolNotify (Event
);
680 Status
= CoreFreePool (Event
);
681 ASSERT_EFI_ERROR (Status
);