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 Enter critical section by acquiring the lock on gEventQueueLock.
72 CoreAcquireEventLock (
76 CoreAcquireLock (&gEventQueueLock
);
81 Exit critical section by releasing the lock on gEventQueueLock.
86 CoreReleaseEventLock (
90 CoreReleaseLock (&gEventQueueLock
);
96 Initializes "event" support and populates parts of the System and Runtime Table.
99 @retval EFI_SUCCESS Always return success
103 CoreInitializeEventServices (
109 for (Index
=0; Index
<= TPL_HIGH_LEVEL
; Index
++) {
110 InitializeListHead (&gEventQueue
[Index
]);
113 CoreInitializeTimer ();
121 Dispatches all pending events.
123 @param Priority The task priority level of event notifications
128 CoreDispatchEventNotifies (
135 CoreAcquireEventLock ();
136 ASSERT (gEventQueueLock
.OwnerTpl
== Priority
);
137 Head
= &gEventQueue
[Priority
];
140 // Dispatch all the pending notifications
142 while (!IsListEmpty (Head
)) {
144 Event
= CR (Head
->ForwardLink
, IEVENT
, NotifyLink
, EVENT_SIGNATURE
);
145 RemoveEntryList (&Event
->NotifyLink
);
147 Event
->NotifyLink
.ForwardLink
= NULL
;
150 // Only clear the SIGNAL status if it is a SIGNAL type event.
151 // WAIT type events are only cleared in CheckEvent()
153 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
154 Event
->SignalCount
= 0;
157 CoreReleaseEventLock ();
162 ASSERT (Event
->NotifyFunction
!= NULL
);
163 Event
->NotifyFunction (Event
, Event
->NotifyContext
);
166 // Check for next pending event
168 CoreAcquireEventLock ();
171 gEventPending
&= ~(1 << Priority
);
172 CoreReleaseEventLock ();
178 Queues the event's notification function to fire.
180 @param Event The Event to notify
191 // Event database must be locked
193 ASSERT_LOCKED (&gEventQueueLock
);
196 // If the event is queued somewhere, remove it
199 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
200 RemoveEntryList (&Event
->NotifyLink
);
201 Event
->NotifyLink
.ForwardLink
= NULL
;
205 // Queue the event to the pending notification list
208 InsertTailList (&gEventQueue
[Event
->NotifyTpl
], &Event
->NotifyLink
);
209 gEventPending
|= (UINTN
)(1 << Event
->NotifyTpl
);
216 Signals all events in the EventGroup.
218 @param EventGroup The list to signal
222 CoreNotifySignalList (
223 IN EFI_GUID
*EventGroup
230 CoreAcquireEventLock ();
232 Head
= &gEventSignalQueue
;
233 for (Link
= Head
->ForwardLink
; Link
!= Head
; Link
= Link
->ForwardLink
) {
234 Event
= CR (Link
, IEVENT
, SignalLink
, EVENT_SIGNATURE
);
235 if (CompareGuid (&Event
->EventGroup
, EventGroup
)) {
236 CoreNotifyEvent (Event
);
240 CoreReleaseEventLock ();
245 Creates a general-purpose event structure.
247 @param Type The type of event to create and its mode and
249 @param NotifyTpl The task priority level of event notifications
250 @param NotifyFunction Pointer to the events notification function
251 @param NotifyContext Pointer to the notification functions context;
252 corresponds to parameter "Context" in the
253 notification function
254 @param Event Pointer to the newly created event if the call
255 succeeds; undefined otherwise
257 @retval EFI_SUCCESS The event structure was created
258 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
259 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
266 IN EFI_TPL NotifyTpl
,
267 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
268 IN VOID
*NotifyContext
, OPTIONAL
272 return CoreCreateEventEx (Type
, NotifyTpl
, NotifyFunction
, NotifyContext
, NULL
, Event
);
278 Creates a general-purpose event structure
280 @param Type The type of event to create and its mode and
282 @param NotifyTpl The task priority level of event notifications
283 @param NotifyFunction Pointer to the events notification function
284 @param NotifyContext Pointer to the notification functions context;
285 corresponds to parameter "Context" in the
286 notification function
287 @param EventGroup GUID for EventGroup if NULL act the same as
289 @param Event Pointer to the newly created event if the call
290 succeeds; undefined otherwise
292 @retval EFI_SUCCESS The event structure was created
293 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
294 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
301 IN EFI_TPL NotifyTpl
,
302 IN EFI_EVENT_NOTIFY NotifyFunction
, OPTIONAL
303 IN CONST VOID
*NotifyContext
, OPTIONAL
304 IN CONST EFI_GUID
*EventGroup
, OPTIONAL
313 if ((Event
== NULL
) || (NotifyTpl
== TPL_APPLICATION
)) {
314 return EFI_INVALID_PARAMETER
;
318 // Check to make sure no reserved flags are set
320 Status
= EFI_INVALID_PARAMETER
;
321 for (Index
= 0; Index
< (sizeof (mEventTable
) / sizeof (UINT32
)); Index
++) {
322 if (Type
== mEventTable
[Index
]) {
323 Status
= EFI_SUCCESS
;
327 if(EFI_ERROR (Status
)) {
328 return EFI_INVALID_PARAMETER
;
332 // Convert Event type for pre-defined Event groups
334 if (EventGroup
!= NULL
) {
336 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
339 if ((Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) || (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
)) {
340 return EFI_INVALID_PARAMETER
;
342 if (CompareGuid (EventGroup
, &gEfiEventExitBootServicesGuid
)) {
343 Type
= EVT_SIGNAL_EXIT_BOOT_SERVICES
;
344 } else if (CompareGuid (EventGroup
, &gEfiEventVirtualAddressChangeGuid
)) {
345 Type
= EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
;
349 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
351 if (Type
== EVT_SIGNAL_EXIT_BOOT_SERVICES
) {
352 EventGroup
= &gEfiEventExitBootServicesGuid
;
353 } else if (Type
== EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
) {
354 EventGroup
= &gEfiEventVirtualAddressChangeGuid
;
359 // If it's a notify type of event, check its parameters
361 if ((Type
& (EVT_NOTIFY_WAIT
| EVT_NOTIFY_SIGNAL
)) != 0) {
363 // Check for an invalid NotifyFunction or NotifyTpl
365 if ((NotifyFunction
== NULL
) ||
366 (NotifyTpl
< TPL_APPLICATION
) ||
367 (NotifyTpl
>= TPL_HIGH_LEVEL
)) {
368 return EFI_INVALID_PARAMETER
;
373 // No notification needed, zero ignored values
376 NotifyFunction
= NULL
;
377 NotifyContext
= NULL
;
381 // Allcoate and initialize a new event structure.
383 Status
= CoreAllocatePool (
384 ((Type
& EVT_RUNTIME
) != 0) ? EfiRuntimeServicesData
: EfiBootServicesData
,
388 if (EFI_ERROR (Status
)) {
389 return EFI_OUT_OF_RESOURCES
;
392 SetMem (IEvent
, sizeof (IEVENT
), 0);
394 IEvent
->Signature
= EVENT_SIGNATURE
;
397 IEvent
->NotifyTpl
= NotifyTpl
;
398 IEvent
->NotifyFunction
= NotifyFunction
;
399 IEvent
->NotifyContext
= (VOID
*)NotifyContext
;
400 if (EventGroup
!= NULL
) {
401 CopyGuid (&IEvent
->EventGroup
, EventGroup
);
402 IEvent
->ExFlag
= TRUE
;
407 if ((Type
& EVT_RUNTIME
) != 0) {
409 // Keep a list of all RT events so we can tell the RT AP.
411 IEvent
->RuntimeData
.Type
= Type
;
412 IEvent
->RuntimeData
.NotifyTpl
= NotifyTpl
;
413 IEvent
->RuntimeData
.NotifyFunction
= NotifyFunction
;
414 IEvent
->RuntimeData
.NotifyContext
= (VOID
*) NotifyContext
;
415 IEvent
->RuntimeData
.Event
= (EFI_EVENT
*) IEvent
;
416 InsertTailList (&gRuntime
->EventHead
, &IEvent
->RuntimeData
.Link
);
419 CoreAcquireEventLock ();
421 if ((Type
& EVT_NOTIFY_SIGNAL
) != 0x00000000) {
423 // The Event's NotifyFunction must be queued whenever the event is signaled
425 InsertHeadList (&gEventSignalQueue
, &IEvent
->SignalLink
);
428 CoreReleaseEventLock ();
440 Signals the event. Queues the event to be notified if needed
442 @param UserEvent The event to signal
444 @retval EFI_INVALID_PARAMETER Parameters are not valid.
445 @retval EFI_SUCCESS The event was signaled.
451 IN EFI_EVENT UserEvent
459 return EFI_INVALID_PARAMETER
;
462 if (Event
->Signature
!= EVENT_SIGNATURE
) {
463 return EFI_INVALID_PARAMETER
;
466 CoreAcquireEventLock ();
469 // If the event is not already signalled, do so
472 if (Event
->SignalCount
== 0x00000000) {
473 Event
->SignalCount
++;
476 // If signalling type is a notify function, queue it
478 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
481 // The CreateEventEx() style requires all members of the Event Group
484 CoreReleaseEventLock ();
485 CoreNotifySignalList (&Event
->EventGroup
);
486 CoreAcquireEventLock ();
488 CoreNotifyEvent (Event
);
493 CoreReleaseEventLock ();
500 Check the status of an event.
502 @param UserEvent The event to check
504 @retval EFI_SUCCESS The event is in the signaled state
505 @retval EFI_NOT_READY The event is not in the signaled state
506 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
512 IN EFI_EVENT UserEvent
521 return EFI_INVALID_PARAMETER
;
524 if (Event
->Signature
!= EVENT_SIGNATURE
) {
525 return EFI_INVALID_PARAMETER
;
528 if (Event
->Type
& EVT_NOTIFY_SIGNAL
) {
529 return EFI_INVALID_PARAMETER
;
532 Status
= EFI_NOT_READY
;
534 if (!Event
->SignalCount
&& (Event
->Type
& EVT_NOTIFY_WAIT
)) {
537 // Queue the wait notify function
540 CoreAcquireEventLock ();
541 if (!Event
->SignalCount
) {
542 CoreNotifyEvent (Event
);
544 CoreReleaseEventLock ();
548 // If the even looks signalled, get the lock and clear it
551 if (Event
->SignalCount
) {
552 CoreAcquireEventLock ();
554 if (Event
->SignalCount
) {
555 Event
->SignalCount
= 0;
556 Status
= EFI_SUCCESS
;
559 CoreReleaseEventLock ();
569 Stops execution until an event is signaled.
571 @param NumberOfEvents The number of events in the UserEvents array
572 @param UserEvents An array of EFI_EVENT
573 @param UserIndex Pointer to the index of the event which
574 satisfied the wait condition
576 @retval EFI_SUCCESS The event indicated by Index was signaled.
577 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
578 function or Event was not a valid type
579 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
585 IN UINTN NumberOfEvents
,
586 IN EFI_EVENT
*UserEvents
,
594 // Can only WaitForEvent at TPL_APPLICATION
596 if (gEfiCurrentTpl
!= TPL_APPLICATION
) {
597 return EFI_UNSUPPORTED
;
602 for(Index
= 0; Index
< NumberOfEvents
; Index
++) {
604 Status
= CoreCheckEvent (UserEvents
[Index
]);
607 // provide index of event that caused problem
609 if (Status
!= EFI_NOT_READY
) {
616 // This was the location of the Idle loop callback in EFI 1.x reference
617 // code. We don't have that concept in this base at this point.
625 Closes an event and frees the event structure.
627 @param UserEvent Event to close
629 @retval EFI_INVALID_PARAMETER Parameters are not valid.
630 @retval EFI_SUCCESS The event has been closed
636 IN EFI_EVENT UserEvent
645 return EFI_INVALID_PARAMETER
;
648 if (Event
->Signature
!= EVENT_SIGNATURE
) {
649 return EFI_INVALID_PARAMETER
;
653 // If it's a timer event, make sure it's not pending
655 if (Event
->Type
& EVT_TIMER
) {
656 CoreSetTimer (Event
, TimerCancel
, 0);
659 CoreAcquireEventLock ();
662 // If the event is queued somewhere, remove it
665 if (Event
->RuntimeData
.Link
.ForwardLink
!= NULL
) {
666 RemoveEntryList (&Event
->RuntimeData
.Link
);
669 if (Event
->NotifyLink
.ForwardLink
!= NULL
) {
670 RemoveEntryList (&Event
->NotifyLink
);
673 if (Event
->SignalLink
.ForwardLink
!= NULL
) {
674 RemoveEntryList (&Event
->SignalLink
);
677 CoreReleaseEventLock ();
680 // If the event is registered on a protocol notify, then remove it from the protocol database
682 CoreUnregisterProtocolNotify (Event
);
684 Status
= CoreFreePool (Event
);
685 ASSERT_EFI_ERROR (Status
);