]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Core/Dxe/Event/event.c
1. Removed #ifdef EDK_RELEASE_VERSION from all c files for all modules
[mirror_edk2.git] / EdkModulePkg / 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 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 //
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 EFI_EVENT_TIMER | EFI_EVENT_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 <= EFI_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 & EFI_EVENT_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 EFI_GUID *GuidPtr;
327 EFI_EVENT_NOTIFY Function;
328
329 GuidPtr = NULL;
330 Function = NotifyFunction;
331
332 //
333 // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping
334 //
335 if (Type == EVENT_SIGNAL_EXIT_BOOT_SERVICES) {
336 GuidPtr = &gEfiEventExitBootServicesGuid;
337 } else if (Type == EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
338 GuidPtr = &gEfiEventVirtualAddressChangeGuid;
339 }
340
341 return CoreCreateEventEx (Type, NotifyTpl, Function, NotifyContext, GuidPtr, Event);
342 }
343
344
345 EFI_STATUS
346 EFIAPI
347 CoreCreateEventEx (
348 IN UINT32 Type,
349 IN EFI_TPL NotifyTpl,
350 IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL
351 IN CONST VOID *NotifyContext, OPTIONAL
352 IN CONST EFI_GUID *EventGroup, OPTIONAL
353 OUT EFI_EVENT *Event
354 )
355 /*++
356
357 Routine Description:
358 Creates a general-purpose event structure
359
360 Arguments:
361 Type - The type of event to create and its mode and attributes
362 NotifyTpl - The task priority level of event notifications
363 NotifyFunction - Pointer to the events notification function
364 NotifyContext - Pointer to the notification functions context; corresponds to
365 parameter "Context" in the notification function
366 EventGrout - GUID for EventGroup if NULL act the same as gBS->CreateEvent().
367 Event - Pointer to the newly created event if the call succeeds; undefined otherwise
368
369 Returns:
370 EFI_SUCCESS - The event structure was created
371 EFI_INVALID_PARAMETER - One of the parameters has an invalid value
372 EFI_OUT_OF_RESOURCES - The event could not be allocated
373
374 --*/
375 {
376 EFI_STATUS Status;
377 IEVENT *IEvent;
378 INTN Index;
379
380
381 if ((Event == NULL) || (NotifyTpl == EFI_TPL_APPLICATION)) {
382 return EFI_INVALID_PARAMETER;
383 }
384
385 //
386 // Check to make sure no reserved flags are set
387 //
388 Status = EFI_INVALID_PARAMETER;
389 for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
390 if (Type == mEventTable[Index]) {
391 Status = EFI_SUCCESS;
392 break;
393 }
394 }
395 if(EFI_ERROR (Status)) {
396 return EFI_INVALID_PARAMETER;
397 }
398
399 //
400 // If it's a notify type of event, check its parameters
401 //
402 if ((Type & (EFI_EVENT_NOTIFY_WAIT | EFI_EVENT_NOTIFY_SIGNAL))) {
403 //
404 // Check for an invalid NotifyFunction or NotifyTpl
405 //
406 if ((NotifyFunction == NULL) ||
407 (NotifyTpl < EFI_TPL_APPLICATION) ||
408 (NotifyTpl >= EFI_TPL_HIGH_LEVEL)) {
409 return EFI_INVALID_PARAMETER;
410 }
411
412 } else {
413 //
414 // No notification needed, zero ignored values
415 //
416 NotifyTpl = 0;
417 NotifyFunction = NULL;
418 NotifyContext = NULL;
419 }
420
421 //
422 // Allcoate and initialize a new event structure.
423 //
424 Status = CoreAllocatePool (
425 (Type & EFI_EVENT_RUNTIME) ? EfiRuntimeServicesData: EfiBootServicesData,
426 sizeof (IEVENT),
427 (VOID **)&IEvent
428 );
429 if (EFI_ERROR (Status)) {
430 return EFI_OUT_OF_RESOURCES;
431 }
432
433 SetMem (IEvent, sizeof (IEVENT), 0);
434
435 IEvent->Signature = EVENT_SIGNATURE;
436 IEvent->Type = Type;
437
438 IEvent->NotifyTpl = NotifyTpl;
439 IEvent->NotifyFunction = NotifyFunction;
440 IEvent->NotifyContext = (VOID *)NotifyContext;
441 if (EventGroup != NULL) {
442 CopyGuid (&IEvent->EventGroup, EventGroup);
443 IEvent->ExFlag = TRUE;
444 }
445
446 *Event = IEvent;
447
448 if (Type & EFI_EVENT_RUNTIME) {
449 //
450 // Keep a list of all RT events so we can tell the RT AP.
451 //
452 IEvent->RuntimeData.Type = Type;
453 IEvent->RuntimeData.NotifyTpl = NotifyTpl;
454 IEvent->RuntimeData.NotifyFunction = NotifyFunction;
455 IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext;
456 IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent;
457 InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);
458 }
459
460 CoreAcquireEventLock ();
461
462 if ((Type & EFI_EVENT_NOTIFY_SIGNAL) != 0x00000000) {
463 //
464 // The Event's NotifyFunction must be queued whenever the event is signaled
465 //
466 InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
467 }
468
469 CoreReleaseEventLock ();
470
471 //
472 // Done
473 //
474 return EFI_SUCCESS;
475 }
476
477
478
479 EFI_STATUS
480 EFIAPI
481 CoreSignalEvent (
482 IN EFI_EVENT UserEvent
483 )
484 /*++
485
486 Routine Description:
487
488 Signals the event. Queues the event to be notified if needed
489
490 Arguments:
491
492 UserEvent - The event to signal
493
494 Returns:
495
496 EFI_INVALID_PARAMETER - Parameters are not valid.
497
498 EFI_SUCCESS - The event was signaled.
499
500 --*/
501 {
502 IEVENT *Event;
503
504 Event = UserEvent;
505
506 if (Event == NULL) {
507 return EFI_INVALID_PARAMETER;
508 }
509
510 if (Event->Signature != EVENT_SIGNATURE) {
511 return EFI_INVALID_PARAMETER;
512 }
513
514 CoreAcquireEventLock ();
515
516 //
517 // If the event is not already signalled, do so
518 //
519
520 if (Event->SignalCount == 0x00000000) {
521 Event->SignalCount++;
522
523 //
524 // If signalling type is a notify function, queue it
525 //
526 if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {
527 if (Event->ExFlag) {
528 //
529 // The CreateEventEx() style requires all members of the Event Group
530 // to be signaled.
531 //
532 CoreReleaseEventLock ();
533 CoreNotifySignalList (&Event->EventGroup);
534 CoreAcquireEventLock ();
535 } else {
536 CoreNotifyEvent (Event);
537 }
538 }
539 }
540
541 CoreReleaseEventLock ();
542 return EFI_SUCCESS;
543 }
544
545
546 EFI_STATUS
547 EFIAPI
548 CoreCheckEvent (
549 IN EFI_EVENT UserEvent
550 )
551 /*++
552
553 Routine Description:
554
555 Check the status of an event
556
557 Arguments:
558
559 UserEvent - The event to check
560
561 Returns:
562
563 EFI_SUCCESS - The event is in the signaled state
564 EFI_NOT_READY - The event is not in the signaled state
565 EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL
566
567 --*/
568
569 {
570 IEVENT *Event;
571 EFI_STATUS Status;
572
573 Event = UserEvent;
574
575 if (Event == NULL) {
576 return EFI_INVALID_PARAMETER;
577 }
578
579 if (Event->Signature != EVENT_SIGNATURE) {
580 return EFI_INVALID_PARAMETER;
581 }
582
583 if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {
584 return EFI_INVALID_PARAMETER;
585 }
586
587 Status = EFI_NOT_READY;
588
589 if (!Event->SignalCount && (Event->Type & EFI_EVENT_NOTIFY_WAIT)) {
590
591 //
592 // Queue the wait notify function
593 //
594
595 CoreAcquireEventLock ();
596 if (!Event->SignalCount) {
597 CoreNotifyEvent (Event);
598 }
599 CoreReleaseEventLock ();
600 }
601
602 //
603 // If the even looks signalled, get the lock and clear it
604 //
605
606 if (Event->SignalCount) {
607 CoreAcquireEventLock ();
608
609 if (Event->SignalCount) {
610 Event->SignalCount = 0;
611 Status = EFI_SUCCESS;
612 }
613
614 CoreReleaseEventLock ();
615 }
616
617 return Status;
618 }
619
620
621
622 EFI_STATUS
623 EFIAPI
624 CoreWaitForEvent (
625 IN UINTN NumberOfEvents,
626 IN EFI_EVENT *UserEvents,
627 OUT UINTN *UserIndex
628 )
629 /*++
630
631 Routine Description:
632
633 Stops execution until an event is signaled.
634
635 Arguments:
636
637 NumberOfEvents - The number of events in the UserEvents array
638 UserEvents - An array of EFI_EVENT
639 UserIndex - Pointer to the index of the event which satisfied the wait condition
640
641 Returns:
642
643 EFI_SUCCESS - The event indicated by Index was signaled.
644 EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or
645 Event was not a valid type
646 EFI_UNSUPPORTED - The current TPL is not TPL_APPLICATION
647
648 --*/
649
650 {
651 EFI_STATUS Status;
652 UINTN Index;
653
654 //
655 // Can only WaitForEvent at TPL_APPLICATION
656 //
657 if (gEfiCurrentTpl != EFI_TPL_APPLICATION) {
658 return EFI_UNSUPPORTED;
659 }
660
661 for(;;) {
662
663 for(Index = 0; Index < NumberOfEvents; Index++) {
664
665 Status = CoreCheckEvent (UserEvents[Index]);
666
667 //
668 // provide index of event that caused problem
669 //
670 if (Status != EFI_NOT_READY) {
671 *UserIndex = Index;
672 return Status;
673 }
674 }
675
676 //
677 // This was the location of the Idle loop callback in EFI 1.x reference
678 // code. We don't have that concept in this base at this point.
679 //
680 }
681 }
682
683
684 EFI_STATUS
685 EFIAPI
686 CoreCloseEvent (
687 IN EFI_EVENT UserEvent
688 )
689 /*++
690
691 Routine Description:
692
693 Closes an event and frees the event structure.
694
695 Arguments:
696
697 UserEvent - Event to close
698
699 Returns:
700
701 EFI_INVALID_PARAMETER - Parameters are not valid.
702
703 EFI_SUCCESS - The event has been closed
704
705 --*/
706
707 {
708 EFI_STATUS Status;
709 IEVENT *Event;
710
711 Event = UserEvent;
712
713 if (Event == NULL) {
714 return EFI_INVALID_PARAMETER;
715 }
716
717 if (Event->Signature != EVENT_SIGNATURE) {
718 return EFI_INVALID_PARAMETER;
719 }
720
721 //
722 // If it's a timer event, make sure it's not pending
723 //
724 if (Event->Type & EFI_EVENT_TIMER) {
725 CoreSetTimer (Event, TimerCancel, 0);
726 }
727
728 CoreAcquireEventLock ();
729
730 //
731 // If the event is queued somewhere, remove it
732 //
733
734 if (Event->RuntimeData.Link.ForwardLink != NULL) {
735 RemoveEntryList (&Event->RuntimeData.Link);
736 }
737
738 if (Event->NotifyLink.ForwardLink != NULL) {
739 RemoveEntryList (&Event->NotifyLink);
740 }
741
742 if (Event->SignalLink.ForwardLink != NULL) {
743 RemoveEntryList (&Event->SignalLink);
744 }
745
746 CoreReleaseEventLock ();
747
748 //
749 // If the event is registered on a protocol notify, then remove it from the protocol database
750 //
751 CoreUnregisterProtocolNotify (Event);
752
753 Status = CoreFreePool (Event);
754 ASSERT_EFI_ERROR (Status);
755
756 return Status;
757 }