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