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