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