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