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