]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Event/Event.c
MdeModulePkg DxeCore: Fix issue to print GUID value %g without pointer
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Event / Event.c
1 /** @file
2 UEFI Event support functions implemented in this file.
3
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 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
10
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.
13
14 **/
15
16
17 #include "DxeMain.h"
18 #include "Event.h"
19
20 ///
21 /// gEfiCurrentTpl - Current Task priority level
22 ///
23 EFI_TPL gEfiCurrentTpl = TPL_APPLICATION;
24
25 ///
26 /// gEventQueueLock - Protects the event queues
27 ///
28 EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
29
30 ///
31 /// gEventQueue - A list of event's to notify for each priority level
32 ///
33 LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1];
34
35 ///
36 /// gEventPending - A bitmask of the EventQueues that are pending
37 ///
38 UINTN gEventPending = 0;
39
40 ///
41 /// gEventSignalQueue - A list of events to signal based on EventGroup type
42 ///
43 LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue);
44
45 ///
46 /// Enumerate the valid types
47 ///
48 UINT32 mEventTable[] = {
49 ///
50 /// 0x80000200 Timer event with a notification function that is
51 /// queue when the event is signaled with SignalEvent()
52 ///
53 EVT_TIMER | EVT_NOTIFY_SIGNAL,
54 ///
55 /// 0x80000000 Timer event without a notification function. It can be
56 /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
57 ///
58 EVT_TIMER,
59 ///
60 /// 0x00000100 Generic event with a notification function that
61 /// can be waited on with CheckEvent() or WaitForEvent()
62 ///
63 EVT_NOTIFY_WAIT,
64 ///
65 /// 0x00000200 Generic event with a notification function that
66 /// is queue when the event is signaled with SignalEvent()
67 ///
68 EVT_NOTIFY_SIGNAL,
69 ///
70 /// 0x00000201 ExitBootServicesEvent.
71 ///
72 EVT_SIGNAL_EXIT_BOOT_SERVICES,
73 ///
74 /// 0x60000202 SetVirtualAddressMapEvent.
75 ///
76 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
77
78 ///
79 /// 0x00000000 Generic event without a notification function.
80 /// It can be signaled with SignalEvent() and checked with CheckEvent()
81 /// or WaitForEvent().
82 ///
83 0x00000000,
84 ///
85 /// 0x80000100 Timer event with a notification function that can be
86 /// waited on with CheckEvent() or WaitForEvent()
87 ///
88 EVT_TIMER | EVT_NOTIFY_WAIT,
89 };
90
91 ///
92 /// gIdleLoopEvent - Event which is signalled when the core is idle
93 ///
94 EFI_EVENT gIdleLoopEvent = NULL;
95
96
97 /**
98 Enter critical section by acquiring the lock on gEventQueueLock.
99
100 **/
101 VOID
102 CoreAcquireEventLock (
103 VOID
104 )
105 {
106 CoreAcquireLock (&gEventQueueLock);
107 }
108
109
110 /**
111 Exit critical section by releasing the lock on gEventQueueLock.
112
113 **/
114 VOID
115 CoreReleaseEventLock (
116 VOID
117 )
118 {
119 CoreReleaseLock (&gEventQueueLock);
120 }
121
122
123
124 /**
125 Initializes "event" support.
126
127 @retval EFI_SUCCESS Always return success
128
129 **/
130 EFI_STATUS
131 CoreInitializeEventServices (
132 VOID
133 )
134 {
135 UINTN Index;
136
137 for (Index=0; Index <= TPL_HIGH_LEVEL; Index++) {
138 InitializeListHead (&gEventQueue[Index]);
139 }
140
141 CoreInitializeTimer ();
142
143 CoreCreateEventEx (
144 EVT_NOTIFY_SIGNAL,
145 TPL_NOTIFY,
146 EfiEventEmptyFunction,
147 NULL,
148 &gIdleLoopEventGuid,
149 &gIdleLoopEvent
150 );
151
152 return EFI_SUCCESS;
153 }
154
155
156
157 /**
158 Dispatches all pending events.
159
160 @param Priority The task priority level of event notifications
161 to dispatch
162
163 **/
164 VOID
165 CoreDispatchEventNotifies (
166 IN EFI_TPL Priority
167 )
168 {
169 IEVENT *Event;
170 LIST_ENTRY *Head;
171
172 CoreAcquireEventLock ();
173 ASSERT (gEventQueueLock.OwnerTpl == Priority);
174 Head = &gEventQueue[Priority];
175
176 //
177 // Dispatch all the pending notifications
178 //
179 while (!IsListEmpty (Head)) {
180
181 Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);
182 RemoveEntryList (&Event->NotifyLink);
183
184 Event->NotifyLink.ForwardLink = NULL;
185
186 //
187 // Only clear the SIGNAL status if it is a SIGNAL type event.
188 // WAIT type events are only cleared in CheckEvent()
189 //
190 if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
191 Event->SignalCount = 0;
192 }
193
194 CoreReleaseEventLock ();
195
196 //
197 // Notify this event
198 //
199 ASSERT (Event->NotifyFunction != NULL);
200 Event->NotifyFunction (Event, Event->NotifyContext);
201
202 //
203 // Check for next pending event
204 //
205 CoreAcquireEventLock ();
206 }
207
208 gEventPending &= ~(UINTN)(1 << Priority);
209 CoreReleaseEventLock ();
210 }
211
212
213
214 /**
215 Queues the event's notification function to fire.
216
217 @param Event The Event to notify
218
219 **/
220 VOID
221 CoreNotifyEvent (
222 IN IEVENT *Event
223 )
224 {
225
226 //
227 // Event database must be locked
228 //
229 ASSERT_LOCKED (&gEventQueueLock);
230
231 //
232 // If the event is queued somewhere, remove it
233 //
234
235 if (Event->NotifyLink.ForwardLink != NULL) {
236 RemoveEntryList (&Event->NotifyLink);
237 Event->NotifyLink.ForwardLink = NULL;
238 }
239
240 //
241 // Queue the event to the pending notification list
242 //
243
244 InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
245 gEventPending |= (UINTN)(1 << Event->NotifyTpl);
246 }
247
248
249
250
251 /**
252 Signals all events in the EventGroup.
253
254 @param EventGroup The list to signal
255
256 **/
257 VOID
258 CoreNotifySignalList (
259 IN EFI_GUID *EventGroup
260 )
261 {
262 LIST_ENTRY *Link;
263 LIST_ENTRY *Head;
264 IEVENT *Event;
265
266 CoreAcquireEventLock ();
267
268 Head = &gEventSignalQueue;
269 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
270 Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);
271 if (CompareGuid (&Event->EventGroup, EventGroup)) {
272 CoreNotifyEvent (Event);
273 }
274 }
275
276 CoreReleaseEventLock ();
277 }
278
279
280 /**
281 Creates an event.
282
283 @param Type The type of event to create and its mode and
284 attributes
285 @param NotifyTpl The task priority level of event notifications
286 @param NotifyFunction Pointer to the events notification function
287 @param NotifyContext Pointer to the notification functions context;
288 corresponds to parameter "Context" in the
289 notification function
290 @param Event Pointer to the newly created event if the call
291 succeeds; undefined otherwise
292
293 @retval EFI_SUCCESS The event structure was created
294 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
295 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
296
297 **/
298 EFI_STATUS
299 EFIAPI
300 CoreCreateEvent (
301 IN UINT32 Type,
302 IN EFI_TPL NotifyTpl,
303 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
304 IN VOID *NotifyContext, OPTIONAL
305 OUT EFI_EVENT *Event
306 )
307 {
308 return CoreCreateEventEx (Type, NotifyTpl, NotifyFunction, NotifyContext, NULL, Event);
309 }
310
311
312
313 /**
314 Creates an event in a group.
315
316 @param Type The type of event to create and its mode and
317 attributes
318 @param NotifyTpl The task priority level of event notifications
319 @param NotifyFunction Pointer to the events notification function
320 @param NotifyContext Pointer to the notification functions context;
321 corresponds to parameter "Context" in the
322 notification function
323 @param EventGroup GUID for EventGroup if NULL act the same as
324 gBS->CreateEvent().
325 @param Event Pointer to the newly created event if the call
326 succeeds; undefined otherwise
327
328 @retval EFI_SUCCESS The event structure was created
329 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
330 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
331
332 **/
333 EFI_STATUS
334 EFIAPI
335 CoreCreateEventEx (
336 IN UINT32 Type,
337 IN EFI_TPL NotifyTpl,
338 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
339 IN CONST VOID *NotifyContext, OPTIONAL
340 IN CONST EFI_GUID *EventGroup, OPTIONAL
341 OUT EFI_EVENT *Event
342 )
343 {
344 //
345 // If it's a notify type of event, check for invalid NotifyTpl
346 //
347 if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
348 if (NotifyTpl != TPL_APPLICATION &&
349 NotifyTpl != TPL_CALLBACK &&
350 NotifyTpl != TPL_NOTIFY) {
351 return EFI_INVALID_PARAMETER;
352 }
353 }
354
355 return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);
356 }
357
358 /**
359 Creates a general-purpose event structure
360
361 @param Type The type of event to create and its mode and
362 attributes
363 @param NotifyTpl The task priority level of event notifications
364 @param NotifyFunction Pointer to the events notification function
365 @param NotifyContext Pointer to the notification functions context;
366 corresponds to parameter "Context" in the
367 notification function
368 @param EventGroup GUID for EventGroup if NULL act the same as
369 gBS->CreateEvent().
370 @param Event Pointer to the newly created event if the call
371 succeeds; undefined otherwise
372
373 @retval EFI_SUCCESS The event structure was created
374 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
375 @retval EFI_OUT_OF_RESOURCES The event could not be allocated
376
377 **/
378 EFI_STATUS
379 EFIAPI
380 CoreCreateEventInternal (
381 IN UINT32 Type,
382 IN EFI_TPL NotifyTpl,
383 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
384 IN CONST VOID *NotifyContext, OPTIONAL
385 IN CONST EFI_GUID *EventGroup, OPTIONAL
386 OUT EFI_EVENT *Event
387 )
388 {
389 EFI_STATUS Status;
390 IEVENT *IEvent;
391 INTN Index;
392
393
394 if (Event == NULL) {
395 return EFI_INVALID_PARAMETER;
396 }
397
398 //
399 // Check to make sure no reserved flags are set
400 //
401 Status = EFI_INVALID_PARAMETER;
402 for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
403 if (Type == mEventTable[Index]) {
404 Status = EFI_SUCCESS;
405 break;
406 }
407 }
408 if(EFI_ERROR (Status)) {
409 return EFI_INVALID_PARAMETER;
410 }
411
412 //
413 // Convert Event type for pre-defined Event groups
414 //
415 if (EventGroup != NULL) {
416 //
417 // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
418 // are not valid
419 //
420 if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {
421 return EFI_INVALID_PARAMETER;
422 }
423 if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {
424 Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;
425 } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {
426 Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;
427 }
428 } else {
429 //
430 // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping
431 //
432 if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {
433 EventGroup = &gEfiEventExitBootServicesGuid;
434 } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
435 EventGroup = &gEfiEventVirtualAddressChangeGuid;
436 }
437 }
438
439 //
440 // If it's a notify type of event, check its parameters
441 //
442 if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
443 //
444 // Check for an invalid NotifyFunction or NotifyTpl
445 //
446 if ((NotifyFunction == NULL) ||
447 (NotifyTpl <= TPL_APPLICATION) ||
448 (NotifyTpl >= TPL_HIGH_LEVEL)) {
449 return EFI_INVALID_PARAMETER;
450 }
451
452 } else {
453 //
454 // No notification needed, zero ignored values
455 //
456 NotifyTpl = 0;
457 NotifyFunction = NULL;
458 NotifyContext = NULL;
459 }
460
461 //
462 // Allocate and initialize a new event structure.
463 //
464 if ((Type & EVT_RUNTIME) != 0) {
465 IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));
466 } else {
467 IEvent = AllocateZeroPool (sizeof (IEVENT));
468 }
469 if (IEvent == NULL) {
470 return EFI_OUT_OF_RESOURCES;
471 }
472
473 IEvent->Signature = EVENT_SIGNATURE;
474 IEvent->Type = Type;
475
476 IEvent->NotifyTpl = NotifyTpl;
477 IEvent->NotifyFunction = NotifyFunction;
478 IEvent->NotifyContext = (VOID *)NotifyContext;
479 if (EventGroup != NULL) {
480 CopyGuid (&IEvent->EventGroup, EventGroup);
481 IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;
482 }
483
484 *Event = IEvent;
485
486 if ((Type & EVT_RUNTIME) != 0) {
487 //
488 // Keep a list of all RT events so we can tell the RT AP.
489 //
490 IEvent->RuntimeData.Type = Type;
491 IEvent->RuntimeData.NotifyTpl = NotifyTpl;
492 IEvent->RuntimeData.NotifyFunction = NotifyFunction;
493 IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;
494 IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;
495 InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);
496 }
497
498 CoreAcquireEventLock ();
499
500 if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {
501 //
502 // The Event's NotifyFunction must be queued whenever the event is signaled
503 //
504 InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
505 }
506
507 CoreReleaseEventLock ();
508
509 //
510 // Done
511 //
512 return EFI_SUCCESS;
513 }
514
515
516
517
518 /**
519 Signals the event. Queues the event to be notified if needed.
520
521 @param UserEvent The event to signal .
522
523 @retval EFI_INVALID_PARAMETER Parameters are not valid.
524 @retval EFI_SUCCESS The event was signaled.
525
526 **/
527 EFI_STATUS
528 EFIAPI
529 CoreSignalEvent (
530 IN EFI_EVENT UserEvent
531 )
532 {
533 IEVENT *Event;
534
535 Event = UserEvent;
536
537 if (Event == NULL) {
538 return EFI_INVALID_PARAMETER;
539 }
540
541 if (Event->Signature != EVENT_SIGNATURE) {
542 return EFI_INVALID_PARAMETER;
543 }
544
545 CoreAcquireEventLock ();
546
547 //
548 // If the event is not already signalled, do so
549 //
550
551 if (Event->SignalCount == 0x00000000) {
552 Event->SignalCount++;
553
554 //
555 // If signalling type is a notify function, queue it
556 //
557 if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
558 if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {
559 //
560 // The CreateEventEx() style requires all members of the Event Group
561 // to be signaled.
562 //
563 CoreReleaseEventLock ();
564 CoreNotifySignalList (&Event->EventGroup);
565 CoreAcquireEventLock ();
566 } else {
567 CoreNotifyEvent (Event);
568 }
569 }
570 }
571
572 CoreReleaseEventLock ();
573 return EFI_SUCCESS;
574 }
575
576
577
578 /**
579 Check the status of an event.
580
581 @param UserEvent The event to check
582
583 @retval EFI_SUCCESS The event is in the signaled state
584 @retval EFI_NOT_READY The event is not in the signaled state
585 @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL
586
587 **/
588 EFI_STATUS
589 EFIAPI
590 CoreCheckEvent (
591 IN EFI_EVENT UserEvent
592 )
593 {
594 IEVENT *Event;
595 EFI_STATUS Status;
596
597 Event = UserEvent;
598
599 if (Event == NULL) {
600 return EFI_INVALID_PARAMETER;
601 }
602
603 if (Event->Signature != EVENT_SIGNATURE) {
604 return EFI_INVALID_PARAMETER;
605 }
606
607 if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
608 return EFI_INVALID_PARAMETER;
609 }
610
611 Status = EFI_NOT_READY;
612
613 if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {
614
615 //
616 // Queue the wait notify function
617 //
618 CoreAcquireEventLock ();
619 if (Event->SignalCount == 0) {
620 CoreNotifyEvent (Event);
621 }
622 CoreReleaseEventLock ();
623 }
624
625 //
626 // If the even looks signalled, get the lock and clear it
627 //
628
629 if (Event->SignalCount != 0) {
630 CoreAcquireEventLock ();
631
632 if (Event->SignalCount != 0) {
633 Event->SignalCount = 0;
634 Status = EFI_SUCCESS;
635 }
636
637 CoreReleaseEventLock ();
638 }
639
640 return Status;
641 }
642
643
644
645 /**
646 Stops execution until an event is signaled.
647
648 @param NumberOfEvents The number of events in the UserEvents array
649 @param UserEvents An array of EFI_EVENT
650 @param UserIndex Pointer to the index of the event which
651 satisfied the wait condition
652
653 @retval EFI_SUCCESS The event indicated by Index was signaled.
654 @retval EFI_INVALID_PARAMETER The event indicated by Index has a notification
655 function or Event was not a valid type
656 @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION
657
658 **/
659 EFI_STATUS
660 EFIAPI
661 CoreWaitForEvent (
662 IN UINTN NumberOfEvents,
663 IN EFI_EVENT *UserEvents,
664 OUT UINTN *UserIndex
665 )
666 {
667 EFI_STATUS Status;
668 UINTN Index;
669
670 //
671 // Can only WaitForEvent at TPL_APPLICATION
672 //
673 if (gEfiCurrentTpl != TPL_APPLICATION) {
674 return EFI_UNSUPPORTED;
675 }
676
677 if (NumberOfEvents == 0) {
678 return EFI_INVALID_PARAMETER;
679 }
680
681 if (UserEvents == NULL) {
682 return EFI_INVALID_PARAMETER;
683 }
684
685 for(;;) {
686
687 for(Index = 0; Index < NumberOfEvents; Index++) {
688
689 Status = CoreCheckEvent (UserEvents[Index]);
690
691 //
692 // provide index of event that caused problem
693 //
694 if (Status != EFI_NOT_READY) {
695 if (UserIndex != NULL) {
696 *UserIndex = Index;
697 }
698 return Status;
699 }
700 }
701
702 //
703 // Signal the Idle event
704 //
705 CoreSignalEvent (gIdleLoopEvent);
706 }
707 }
708
709
710 /**
711 Closes an event and frees the event structure.
712
713 @param UserEvent Event to close
714
715 @retval EFI_INVALID_PARAMETER Parameters are not valid.
716 @retval EFI_SUCCESS The event has been closed
717
718 **/
719 EFI_STATUS
720 EFIAPI
721 CoreCloseEvent (
722 IN EFI_EVENT UserEvent
723 )
724 {
725 EFI_STATUS Status;
726 IEVENT *Event;
727
728 Event = UserEvent;
729
730 if (Event == NULL) {
731 return EFI_INVALID_PARAMETER;
732 }
733
734 if (Event->Signature != EVENT_SIGNATURE) {
735 return EFI_INVALID_PARAMETER;
736 }
737
738 //
739 // If it's a timer event, make sure it's not pending
740 //
741 if ((Event->Type & EVT_TIMER) != 0) {
742 CoreSetTimer (Event, TimerCancel, 0);
743 }
744
745 CoreAcquireEventLock ();
746
747 //
748 // If the event is queued somewhere, remove it
749 //
750
751 if (Event->RuntimeData.Link.ForwardLink != NULL) {
752 RemoveEntryList (&Event->RuntimeData.Link);
753 }
754
755 if (Event->NotifyLink.ForwardLink != NULL) {
756 RemoveEntryList (&Event->NotifyLink);
757 }
758
759 if (Event->SignalLink.ForwardLink != NULL) {
760 RemoveEntryList (&Event->SignalLink);
761 }
762
763 CoreReleaseEventLock ();
764
765 //
766 // If the event is registered on a protocol notify, then remove it from the protocol database
767 //
768 if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) {
769 CoreUnregisterProtocolNotify (Event);
770 }
771
772 //
773 // To avoid the Event to be signalled wrongly after closed,
774 // clear the Signature of Event before free pool.
775 //
776 Event->Signature = 0;
777 Status = CoreFreePool (Event);
778 ASSERT_EFI_ERROR (Status);
779
780 return Status;
781 }
782