Comments for CoreInitializeMemoryServices should be updated
[edk2.git] / MdeModulePkg / Core / Dxe / Event / Event.c
bloba01225f248d76fa02af11ea4203ba29fc9ae5e3c
1 /** @file
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.
13 **/
16 #include "DxeMain.h"
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().
31 EVT_TIMER,
33 // 0x00000100 Generic event with a notification function that
34 // can be waited on with CheckEvent() or WaitForEvent()
36 EVT_NOTIFY_WAIT,
38 // 0x00000200 Generic event with a notification function that
39 // is queue when the event is signaled with SignalEvent()
41 EVT_NOTIFY_SIGNAL,
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()
54 // or WaitForEvent().
56 0x00000000,
58 // 0x80000100 Timer event with a notification function that can be
59 // waited on with CheckEvent() or WaitForEvent()
61 EVT_TIMER | EVT_NOTIFY_WAIT,
65 /**
66 Enter critical section by acquiring the lock on gEventQueueLock.
68 **/
69 VOID
70 CoreAcquireEventLock (
71 VOID
74 CoreAcquireLock (&gEventQueueLock);
78 /**
79 Exit critical section by releasing the lock on gEventQueueLock.
81 **/
82 VOID
83 CoreReleaseEventLock (
84 VOID
87 CoreReleaseLock (&gEventQueueLock);
92 /**
93 Initializes "event" support.
95 @retval EFI_SUCCESS Always return success
97 **/
98 EFI_STATUS
99 CoreInitializeEventServices (
100 VOID
103 UINTN Index;
105 for (Index=0; Index <= TPL_HIGH_LEVEL; Index++) {
106 InitializeListHead (&gEventQueue[Index]);
109 CoreInitializeTimer ();
111 return EFI_SUCCESS;
117 Dispatches all pending events.
119 @param Priority The task priority level of event notifications
120 to dispatch
123 VOID
124 CoreDispatchEventNotifies (
125 IN EFI_TPL Priority
128 IEVENT *Event;
129 LIST_ENTRY *Head;
131 CoreAcquireEventLock ();
132 ASSERT (gEventQueueLock.OwnerTpl == Priority);
133 Head = &gEventQueue[Priority];
136 // Dispatch all the pending notifications
138 while (!IsListEmpty (Head)) {
140 Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);
141 RemoveEntryList (&Event->NotifyLink);
143 Event->NotifyLink.ForwardLink = NULL;
146 // Only clear the SIGNAL status if it is a SIGNAL type event.
147 // WAIT type events are only cleared in CheckEvent()
149 if (Event->Type & EVT_NOTIFY_SIGNAL) {
150 Event->SignalCount = 0;
153 CoreReleaseEventLock ();
156 // Notify this event
158 ASSERT (Event->NotifyFunction != NULL);
159 Event->NotifyFunction (Event, Event->NotifyContext);
162 // Check for next pending event
164 CoreAcquireEventLock ();
167 gEventPending &= ~(1 << Priority);
168 CoreReleaseEventLock ();
174 Queues the event's notification function to fire.
176 @param Event The Event to notify
179 VOID
180 CoreNotifyEvent (
181 IN IEVENT *Event
186 // Event database must be locked
188 ASSERT_LOCKED (&gEventQueueLock);
191 // If the event is queued somewhere, remove it
194 if (Event->NotifyLink.ForwardLink != NULL) {
195 RemoveEntryList (&Event->NotifyLink);
196 Event->NotifyLink.ForwardLink = NULL;
200 // Queue the event to the pending notification list
203 InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
204 gEventPending |= (UINTN)(1 << Event->NotifyTpl);
211 Signals all events in the EventGroup.
213 @param EventGroup The list to signal
216 VOID
217 CoreNotifySignalList (
218 IN EFI_GUID *EventGroup
221 LIST_ENTRY *Link;
222 LIST_ENTRY *Head;
223 IEVENT *Event;
225 CoreAcquireEventLock ();
227 Head = &gEventSignalQueue;
228 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
229 Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);
230 if (CompareGuid (&Event->EventGroup, EventGroup)) {
231 CoreNotifyEvent (Event);
235 CoreReleaseEventLock ();
240 Creates a general-purpose event structure.
242 @param Type The type of event to create and its mode and
243 attributes
244 @param NotifyTpl The task priority level of event notifications
245 @param NotifyFunction Pointer to the events notification function
246 @param NotifyContext Pointer to the notification functions context;
247 corresponds to parameter "Context" in the
248 notification function
249 @param Event Pointer to the newly created event if the call
250 succeeds; undefined otherwise
252 @retval EFI_SUCCESS The event structure was created
253 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
254 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
257 EFI_STATUS
258 EFIAPI
259 CoreCreateEvent (
260 IN UINT32 Type,
261 IN EFI_TPL NotifyTpl,
262 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
263 IN VOID *NotifyContext, OPTIONAL
264 OUT EFI_EVENT *Event
267 return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);
273 Creates a general-purpose event structure
275 @param Type The type of event to create and its mode and
276 attributes
277 @param NotifyTpl The task priority level of event notifications
278 @param NotifyFunction Pointer to the events notification function
279 @param NotifyContext Pointer to the notification functions context;
280 corresponds to parameter "Context" in the
281 notification function
282 @param EventGroup GUID for EventGroup if NULL act the same as
283 gBS->CreateEvent().
284 @param Event Pointer to the newly created event if the call
285 succeeds; undefined otherwise
287 @retval EFI_SUCCESS The event structure was created
288 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
289 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
292 EFI_STATUS
293 EFIAPI
294 CoreCreateEventEx (
295 IN UINT32 Type,
296 IN EFI_TPL NotifyTpl,
297 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
298 IN CONST VOID *NotifyContext, OPTIONAL
299 IN CONST EFI_GUID *EventGroup, OPTIONAL
300 OUT EFI_EVENT *Event
303 EFI_STATUS Status;
304 IEVENT *IEvent;
305 INTN Index;
308 if (Event == NULL) {
309 return EFI_INVALID_PARAMETER;
313 // Check to make sure no reserved flags are set
315 Status = EFI_INVALID_PARAMETER;
316 for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
317 if (Type == mEventTable[Index]) {
318 Status = EFI_SUCCESS;
319 break;
322 if(EFI_ERROR (Status)) {
323 return EFI_INVALID_PARAMETER;
327 // Convert Event type for pre-defined Event groups
329 if (EventGroup != NULL) {
331 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
332 // are not valid
334 if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {
335 return EFI_INVALID_PARAMETER;
337 if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {
338 Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;
339 } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {
340 Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;
342 } else {
344 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
346 if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {
347 EventGroup = &gEfiEventExitBootServicesGuid;
348 } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
349 EventGroup = &gEfiEventVirtualAddressChangeGuid;
354 // If it's a notify type of event, check its parameters
356 if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
358 // Check for an invalid NotifyFunction or NotifyTpl
360 if ((NotifyFunction == NULL) ||
361 (NotifyTpl <= TPL_APPLICATION) ||
362 (NotifyTpl >= TPL_HIGH_LEVEL)) {
363 return EFI_INVALID_PARAMETER;
366 } else {
368 // No notification needed, zero ignored values
370 NotifyTpl = 0;
371 NotifyFunction = NULL;
372 NotifyContext = NULL;
376 // Allcoate and initialize a new event structure.
378 Status = CoreAllocatePool (
379 ((Type & EVT_RUNTIME) != 0) ? EfiRuntimeServicesData: EfiBootServicesData,
380 sizeof (IEVENT),
381 (VOID **)&IEvent
383 if (EFI_ERROR (Status)) {
384 return EFI_OUT_OF_RESOURCES;
387 ZeroMem (IEvent, sizeof (IEVENT));
389 IEvent->Signature = EVENT_SIGNATURE;
390 IEvent->Type = Type;
392 IEvent->NotifyTpl = NotifyTpl;
393 IEvent->NotifyFunction = NotifyFunction;
394 IEvent->NotifyContext = (VOID *)NotifyContext;
395 if (EventGroup != NULL) {
396 CopyGuid (&IEvent->EventGroup, EventGroup);
397 IEvent->ExFlag = TRUE;
400 *Event = IEvent;
402 if ((Type & EVT_RUNTIME) != 0) {
404 // Keep a list of all RT events so we can tell the RT AP.
406 IEvent->RuntimeData.Type = Type;
407 IEvent->RuntimeData.NotifyTpl = NotifyTpl;
408 IEvent->RuntimeData.NotifyFunction = NotifyFunction;
409 IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;
410 IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;
411 InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);
414 CoreAcquireEventLock ();
416 if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {
418 // The Event's NotifyFunction must be queued whenever the event is signaled
420 InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
423 CoreReleaseEventLock ();
426 // Done
428 return EFI_SUCCESS;
435 Signals the event. Queues the event to be notified if needed.
437 @param UserEvent The event to signal .
439 @retval EFI_INVALID_PARAMETER Parameters are not valid.
440 @retval EFI_SUCCESS The event was signaled.
443 EFI_STATUS
444 EFIAPI
445 CoreSignalEvent (
446 IN EFI_EVENT UserEvent
449 IEVENT *Event;
451 Event = UserEvent;
453 if (Event == NULL) {
454 return EFI_INVALID_PARAMETER;
457 if (Event->Signature != EVENT_SIGNATURE) {
458 return EFI_INVALID_PARAMETER;
461 CoreAcquireEventLock ();
464 // If the event is not already signalled, do so
467 if (Event->SignalCount == 0x00000000) {
468 Event->SignalCount++;
471 // If signalling type is a notify function, queue it
473 if (Event->Type & EVT_NOTIFY_SIGNAL) {
474 if (Event->ExFlag) {
476 // The CreateEventEx() style requires all members of the Event Group
477 // to be signaled.
479 CoreReleaseEventLock ();
480 CoreNotifySignalList (&Event->EventGroup);
481 CoreAcquireEventLock ();
482 } else {
483 CoreNotifyEvent (Event);
488 CoreReleaseEventLock ();
489 return EFI_SUCCESS;
495 Check the status of an event.
497 @param UserEvent The event to check
499 @retval EFI_SUCCESS The event is in the signaled state
500 @retval EFI_NOT_READY The event is not in the signaled state
501 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
504 EFI_STATUS
505 EFIAPI
506 CoreCheckEvent (
507 IN EFI_EVENT UserEvent
510 IEVENT *Event;
511 EFI_STATUS Status;
513 Event = UserEvent;
515 if (Event == NULL) {
516 return EFI_INVALID_PARAMETER;
519 if (Event->Signature != EVENT_SIGNATURE) {
520 return EFI_INVALID_PARAMETER;
523 if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
524 return EFI_INVALID_PARAMETER;
527 Status = EFI_NOT_READY;
529 if (!Event->SignalCount && (Event->Type & EVT_NOTIFY_WAIT)) {
532 // Queue the wait notify function
534 CoreAcquireEventLock ();
535 if (!Event->SignalCount) {
536 CoreNotifyEvent (Event);
538 CoreReleaseEventLock ();
542 // If the even looks signalled, get the lock and clear it
545 if (Event->SignalCount) {
546 CoreAcquireEventLock ();
548 if (Event->SignalCount) {
549 Event->SignalCount = 0;
550 Status = EFI_SUCCESS;
553 CoreReleaseEventLock ();
556 return Status;
562 Stops execution until an event is signaled.
564 @param NumberOfEvents The number of events in the UserEvents array
565 @param UserEvents An array of EFI_EVENT
566 @param UserIndex Pointer to the index of the event which
567 satisfied the wait condition
569 @retval EFI_SUCCESS The event indicated by Index was signaled.
570 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
571 function or Event was not a valid type
572 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
575 EFI_STATUS
576 EFIAPI
577 CoreWaitForEvent (
578 IN UINTN NumberOfEvents,
579 IN EFI_EVENT *UserEvents,
580 OUT UINTN *UserIndex
583 EFI_STATUS Status;
584 UINTN Index;
587 // Can only WaitForEvent at TPL_APPLICATION
589 if (gEfiCurrentTpl != TPL_APPLICATION) {
590 return EFI_UNSUPPORTED;
593 for(;;) {
595 for(Index = 0; Index < NumberOfEvents; Index++) {
597 Status = CoreCheckEvent (UserEvents[Index]);
600 // provide index of event that caused problem
602 if (Status != EFI_NOT_READY) {
603 *UserIndex = Index;
604 return Status;
609 // This was the location of the Idle loop callback in EFI 1.x reference
610 // code. We don't have that concept in this base at this point.
617 Closes an event and frees the event structure.
619 @param UserEvent Event to close
621 @retval EFI_INVALID_PARAMETER Parameters are not valid.
622 @retval EFI_SUCCESS The event has been closed
625 EFI_STATUS
626 EFIAPI
627 CoreCloseEvent (
628 IN EFI_EVENT UserEvent
631 EFI_STATUS Status;
632 IEVENT *Event;
634 Event = UserEvent;
636 if (Event == NULL) {
637 return EFI_INVALID_PARAMETER;
640 if (Event->Signature != EVENT_SIGNATURE) {
641 return EFI_INVALID_PARAMETER;
645 // If it's a timer event, make sure it's not pending
647 if ((Event->Type & EVT_TIMER) != 0) {
648 CoreSetTimer (Event, TimerCancel, 0);
651 CoreAcquireEventLock ();
654 // If the event is queued somewhere, remove it
657 if (Event->RuntimeData.Link.ForwardLink != NULL) {
658 RemoveEntryList (&Event->RuntimeData.Link);
661 if (Event->NotifyLink.ForwardLink != NULL) {
662 RemoveEntryList (&Event->NotifyLink);
665 if (Event->SignalLink.ForwardLink != NULL) {
666 RemoveEntryList (&Event->SignalLink);
669 CoreReleaseEventLock ();
672 // If the event is registered on a protocol notify, then remove it from the protocol database
674 CoreUnregisterProtocolNotify (Event);
676 Status = CoreFreePool (Event);
677 ASSERT_EFI_ERROR (Status);
679 return Status;