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