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