]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkModulePkg/Core/Dxe/Event/event.c
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@150 6f19259b...
[mirror_edk2.git] / EdkModulePkg / Core / Dxe / Event / event.c
index e8391419ab6768e3e2fc9a5c1f0bb7ee7ab2b422..6751b18e6f9c90358eb5bb0bf16f8af537eb6d5c 100644 (file)
-/*++\r
-\r
-Copyright (c) 2006, Intel Corporation                                                         \r
-All rights reserved. This program and the accompanying materials                          \r
-are licensed and made available under the terms and conditions of the BSD License         \r
-which accompanies this distribution.  The full text of the license may be found at        \r
-http://opensource.org/licenses/bsd-license.php                                            \r
-                                                                                          \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
-\r
-Module Name:\r
-\r
-    event.c\r
-\r
-Abstract:\r
-\r
-    EFI Event support\r
\r
---*/\r
-\r
-\r
-#include <DxeMain.h>\r
-\r
-//\r
-// Enumerate the valid types\r
-//\r
-UINT32 mEventTable[] = {\r
-  //\r
-  // 0x80000200       Timer event with a notification function that is\r
-  // queue when the event is signaled with SignalEvent()\r
-  //\r
-  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,\r
-  //\r
-  // 0x80000000       Timer event without a notification function. It can be\r
-  // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().\r
-  //\r
-  EFI_EVENT_TIMER,\r
-  //\r
-  // 0x00000100       Generic event with a notification function that \r
-  // can be waited on with CheckEvent() or WaitForEvent()\r
-  //\r
-  EFI_EVENT_NOTIFY_WAIT,\r
-  //\r
-  // 0x00000200       Generic event with a notification function that \r
-  // is queue when the event is signaled with SignalEvent()\r
-  //\r
-  EFI_EVENT_NOTIFY_SIGNAL,\r
-  //\r
-  // 0x00000201       ExitBootServicesEvent.  \r
-  //\r
-  EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES,\r
-  //\r
-  // 0x60000202       SetVirtualAddressMapEvent.\r
-  //\r
-  EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
-\r
-#if (EFI_SPECIFICATION_VERSION < 0x00020000)\r
-  //\r
-  // 0x00000203       ReadyToBootEvent.\r
-  //\r
-  EFI_EVENT_SIGNAL_READY_TO_BOOT,\r
-  //\r
-  // 0x00000204       LegacyBootEvent.\r
-  //\r
-  EFI_EVENT_SIGNAL_LEGACY_BOOT,\r
-  //\r
-  // 0x00000603       Signal all ReadyToBootEvents.\r
-  //\r
-  EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_READY_TO_BOOT,\r
-  //\r
-  // 0x00000604       Signal all LegacyBootEvents.\r
-  //\r
-  EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_LEGACY_BOOT,\r
-#endif\r
-\r
-  //\r
-  // 0x00000000       Generic event without a notification function. \r
-  // It can be signaled with SignalEvent() and checked with CheckEvent() \r
-  // or WaitForEvent().\r
-  //\r
-  0x00000000,\r
-  //\r
-  // 0x80000100       Timer event with a notification function that can be \r
-  // waited on with CheckEvent() or WaitForEvent()\r
-  //\r
-  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_WAIT,\r
-};\r
-\r
-\r
-VOID\r
-CoreAcquireEventLock (\r
-  VOID\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Enter critical section by acquiring the lock on gEventQueueLock.\r
-\r
-Arguments:\r
-\r
-  None\r
-\r
-Returns:\r
-\r
-  None\r
-\r
---*/\r
-{\r
-  CoreAcquireLock (&gEventQueueLock);\r
-}\r
-\r
-\r
-VOID\r
-CoreReleaseEventLock (\r
-  VOID\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Exit critical section by releasing the lock on gEventQueueLock.\r
-\r
-Arguments:\r
-\r
-  None\r
-\r
-Returns:\r
-\r
-  None\r
-\r
---*/\r
-{\r
-  CoreReleaseLock (&gEventQueueLock);\r
-}\r
-\r
-\r
-EFI_STATUS\r
-CoreInitializeEventServices (\r
-  VOID\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Initializes "event" support and populates parts of the System and Runtime Table.\r
-\r
-Arguments:\r
-\r
-  None\r
-    \r
-Returns:\r
-\r
-  EFI_SUCCESS - Always return success\r
-\r
---*/\r
-{\r
-  UINTN        Index;\r
-\r
-  for (Index=0; Index <= EFI_TPL_HIGH_LEVEL; Index++) {\r
-    InitializeListHead (&gEventQueue[Index]);\r
-  }\r
-\r
-  CoreInitializeTimer ();\r
-  \r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-CoreShutdownEventServices (\r
-  VOID\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Register all runtime events to make sure they are still available after ExitBootService.\r
-\r
-Arguments:\r
-\r
-  None\r
-    \r
-Returns:\r
-\r
-  EFI_SUCCESS - Always return success.\r
-\r
---*/\r
-{\r
-  LIST_ENTRY        *Link;\r
-  IEVENT            *Event;\r
-\r
-  //\r
-  // The Runtime AP is required for the core to function!\r
-  //\r
-  ASSERT (gRuntime != NULL);\r
-\r
-  for (Link = mRuntimeEventList.ForwardLink; Link != &mRuntimeEventList; Link = Link->ForwardLink) {\r
-    Event = CR (Link, IEVENT, RuntimeLink, EVENT_SIGNATURE);\r
-    gRuntime->RegisterEvent (\r
-                gRuntime, \r
-                Event->Type, \r
-                Event->NotifyTpl, \r
-                Event->NotifyFunction, \r
-                Event->NotifyContext, \r
-                (VOID **)Event\r
-                );\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
-VOID\r
-CoreDispatchEventNotifies (\r
-  IN EFI_TPL      Priority\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Dispatches all pending events. \r
-\r
-Arguments:\r
-\r
-  Priority - The task priority level of event notifications to dispatch\r
-    \r
-Returns:\r
-\r
-  None\r
-\r
---*/\r
-{\r
-  IEVENT          *Event;\r
-  LIST_ENTRY      *Head;\r
-  \r
-  CoreAcquireEventLock ();\r
-  ASSERT (gEventQueueLock.OwnerTpl == Priority);\r
-  Head = &gEventQueue[Priority];\r
-\r
-  //\r
-  // Dispatch all the pending notifications\r
-  //\r
-  while (!IsListEmpty (Head)) {\r
-      \r
-    Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);\r
-    RemoveEntryList (&Event->NotifyLink);\r
-\r
-    Event->NotifyLink.ForwardLink = NULL;\r
-\r
-    //\r
-    // Only clear the SIGNAL status if it is a SIGNAL type event.\r
-    // WAIT type events are only cleared in CheckEvent()\r
-    //\r
-    if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {\r
-      Event->SignalCount = 0;\r
-    }\r
-\r
-    CoreReleaseEventLock ();\r
-      \r
-    //\r
-    // Notify this event\r
-    //\r
-    ASSERT (Event->NotifyFunction != NULL);\r
-    Event->NotifyFunction (Event, Event->NotifyContext);\r
-\r
-    //\r
-    // Check for next pending event\r
-    //\r
-    CoreAcquireEventLock ();\r
-  }\r
-\r
-  gEventPending &= ~(1 << Priority);\r
-  CoreReleaseEventLock ();\r
-}\r
-\r
-\r
-VOID\r
-STATIC\r
-CoreNotifyEvent (\r
-  IN  IEVENT      *Event\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Queues the event's notification function to fire\r
-\r
-Arguments:\r
-\r
-  Event       - The Event to notify\r
-    \r
-Returns:\r
-\r
-  None\r
-\r
---*/\r
-{\r
-\r
-  //\r
-  // Event database must be locked\r
-  //\r
-  ASSERT_LOCKED (&gEventQueueLock);\r
-\r
-  //\r
-  // If the event is queued somewhere, remove it\r
-  //\r
-\r
-  if (Event->NotifyLink.ForwardLink != NULL) {\r
-    RemoveEntryList (&Event->NotifyLink);\r
-    Event->NotifyLink.ForwardLink = NULL;\r
-  }\r
-\r
-  // \r
-  // Queue the event to the pending notification list\r
-  //\r
-\r
-  InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);\r
-  gEventPending |= (UINTN)(1 << Event->NotifyTpl);\r
-}\r
-\r
-\r
-\r
-VOID\r
-CoreNotifySignalList (\r
-  IN EFI_GUID     *EventGroup\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  Signals all events in the EventGroup\r
-\r
-Arguments:\r
-  EventGroup - The list to signal\r
-    \r
-Returns:\r
-\r
-  None\r
-\r
---*/\r
-{\r
-  LIST_ENTRY              *Link;\r
-  LIST_ENTRY              *Head;\r
-  IEVENT                  *Event;\r
-\r
-  CoreAcquireEventLock ();\r
-\r
-  Head = &gEventSignalQueue;\r
-  for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
-    Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);\r
-    if (CompareGuid (&Event->EventGroup, EventGroup)) {\r
-      CoreNotifyEvent (Event);\r
-    }\r
-  }\r
-\r
-  CoreReleaseEventLock ();\r
-}\r
-\r
-\r
-#if (EFI_SPECIFICATION_VERSION < 0x00020000)\r
-\r
-static\r
-VOID\r
-EFIAPI\r
-EventNofitySignalAllNullEvent (\r
-  IN EFI_EVENT                Event,\r
-  IN VOID                     *Context\r
-  )\r
-{\r
-  //\r
-  // This null event is a size efficent way to enusre that \r
-  // EFI_EVENT_NOTIFY_SIGNAL_ALL is error checked correctly.\r
-  // EFI_EVENT_NOTIFY_SIGNAL_ALL is now mapped into \r
-  // CreateEventEx() and this function is used to make the\r
-  // old error checking in CreateEvent() for Tiano extensions\r
-  // function.\r
-  //\r
-  return;\r
-}\r
-\r
-#endif\r
-\r
-\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-CoreCreateEvent (\r
-  IN UINT32                   Type,\r
-  IN EFI_TPL                  NotifyTpl,\r
-  IN EFI_EVENT_NOTIFY         NotifyFunction, OPTIONAL\r
-  IN VOID                     *NotifyContext, OPTIONAL\r
-  OUT EFI_EVENT               *Event\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  Creates a general-purpose event structure\r
-\r
-Arguments:\r
-  Type                - The type of event to create and its mode and attributes\r
-  NotifyTpl           - The task priority level of event notifications\r
-  NotifyFunction      - Pointer to the events notification function\r
-  NotifyContext       - Pointer to the notification functions context; corresponds to\r
-                        parameter "Context" in the notification function\r
-  Event               - Pointer to the newly created event if the call succeeds; undefined otherwise\r
-\r
-Returns:\r
-  EFI_SUCCESS           - The event structure was created\r
-  EFI_INVALID_PARAMETER - One of the parameters has an invalid value\r
-  EFI_OUT_OF_RESOURCES  - The event could not be allocated\r
-\r
---*/\r
-{ \r
-  EFI_GUID            *GuidPtr;\r
-  EFI_EVENT_NOTIFY    Function;\r
-  \r
-  GuidPtr = NULL;\r
-  Function = NotifyFunction;\r
-\r
-#if (EFI_SPECIFICATION_VERSION < 0x00020000)\r
-  //\r
-  // Clear EFI_EVENT_NOFITY_SIGNAL_ALL (Tiano extension) as all events in the \r
-  //  EventGroup now have this property. So we need to filter it out.\r
-  //\r
-  if (Type & EFI_EVENT_NOTIFY_SIGNAL_ALL) {\r
-    Type &= ~EFI_EVENT_NOTIFY_SIGNAL_ALL;\r
-    Function = EventNofitySignalAllNullEvent;\r
-  }\r
-\r
-  //\r
-  // Map the Tiano extensions Events to CreateEventEx form\r
-  //\r
-  if (Type == EFI_EVENT_SIGNAL_READY_TO_BOOT) {\r
-    GuidPtr = &gEfiEventReadToBootGuid;\r
-  } else if (Type == EFI_EVENT_SIGNAL_LEGACY_BOOT) {\r
-    GuidPtr = &gEfiEventLegacyBootGuid\r
-  }\r
-#endif\r
-\r
-  //\r
-  // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping\r
-  // \r
-  if (Type == EVENT_SIGNAL_EXIT_BOOT_SERVICES) {\r
-    GuidPtr = &gEfiEventExitBootServicesGuid;\r
-  } else if (Type == EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {\r
-    GuidPtr = &gEfiEventVirtualAddressChangeGuid;\r
-  }\r
-  \r
-  return CoreCreateEventEx (Type, NotifyTpl, Function, NotifyContext, GuidPtr, Event);\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-CoreCreateEventEx (\r
-  IN UINT32                   Type,\r
-  IN EFI_TPL                  NotifyTpl,\r
-  IN EFI_EVENT_NOTIFY         NotifyFunction, OPTIONAL\r
-  IN CONST VOID               *NotifyContext, OPTIONAL\r
-  IN CONST EFI_GUID           *EventGroup,    OPTIONAL\r
-  OUT EFI_EVENT               *Event\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-  Creates a general-purpose event structure\r
-\r
-Arguments:\r
-  Type                - The type of event to create and its mode and attributes\r
-  NotifyTpl           - The task priority level of event notifications\r
-  NotifyFunction      - Pointer to the events notification function\r
-  NotifyContext       - Pointer to the notification functions context; corresponds to\r
-                        parameter "Context" in the notification function\r
-  EventGrout          - GUID for EventGroup if NULL act the same as gBS->CreateEvent().\r
-  Event               - Pointer to the newly created event if the call succeeds; undefined otherwise\r
-\r
-Returns:\r
-  EFI_SUCCESS           - The event structure was created\r
-  EFI_INVALID_PARAMETER - One of the parameters has an invalid value\r
-  EFI_OUT_OF_RESOURCES  - The event could not be allocated\r
-\r
---*/\r
-{\r
-  EFI_STATUS      Status;\r
-  IEVENT          *IEvent;\r
-  INTN            Index;\r
-\r
-\r
-  if ((Event == NULL) || (NotifyTpl == EFI_TPL_APPLICATION)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // Check to make sure no reserved flags are set\r
-  //\r
-  Status = EFI_INVALID_PARAMETER;\r
-  for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {\r
-     if (Type == mEventTable[Index]) {\r
-       Status = EFI_SUCCESS;\r
-       break;\r
-     }\r
-  }\r
-  if(EFI_ERROR (Status)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // If it's a notify type of event, check its parameters\r
-  //\r
-  if ((Type & (EFI_EVENT_NOTIFY_WAIT | EFI_EVENT_NOTIFY_SIGNAL))) {\r
-    //\r
-    // Check for an invalid NotifyFunction or NotifyTpl\r
-    //\r
-    if ((NotifyFunction == NULL) || \r
-        (NotifyTpl < EFI_TPL_APPLICATION) || \r
-       (NotifyTpl >= EFI_TPL_HIGH_LEVEL)) {\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-\r
-  } else {\r
-    //\r
-    // No notification needed, zero ignored values\r
-    //\r
-    NotifyTpl = 0;\r
-    NotifyFunction = NULL;\r
-    NotifyContext = NULL;\r
-  }\r
-\r
-  //\r
-  // Allcoate and initialize a new event structure.\r
-  //\r
-  Status = CoreAllocatePool (\r
-             (Type & EFI_EVENT_RUNTIME) ? EfiRuntimeServicesData: EfiBootServicesData, \r
-             sizeof (IEVENT),\r
-             (VOID **)&IEvent\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-\r
-  SetMem (IEvent, sizeof (IEVENT), 0);\r
-\r
-  IEvent->Signature = EVENT_SIGNATURE;\r
-  IEvent->Type = Type;\r
-  \r
-  IEvent->NotifyTpl      = NotifyTpl;\r
-  IEvent->NotifyFunction = NotifyFunction;\r
-  IEvent->NotifyContext  = (VOID *)NotifyContext;\r
-  if (EventGroup != NULL) {\r
-    CopyGuid (&IEvent->EventGroup, EventGroup);\r
-    IEvent->ExFlag = TRUE;\r
-  }\r
-\r
-  *Event = IEvent;\r
-\r
-  if (Type & EFI_EVENT_RUNTIME) {\r
-    //\r
-    // Keep a list of all RT events so we can tell the RT AP.\r
-    //\r
-    InsertTailList (&mRuntimeEventList, &IEvent->RuntimeLink);\r
-  }\r
-\r
-  CoreAcquireEventLock ();\r
-  \r
-  if ((Type & EFI_EVENT_NOTIFY_SIGNAL) != 0x00000000) {\r
-    //\r
-    // The Event's NotifyFunction must be queued whenever the event is signaled\r
-    //\r
-    InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);\r
-  }\r
-  \r
-  CoreReleaseEventLock ();\r
-  \r
-  //\r
-  // Done\r
-  //\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-CoreSignalEvent (\r
-  IN EFI_EVENT    UserEvent\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Signals the event.  Queues the event to be notified if needed\r
-    \r
-Arguments:\r
-\r
-  UserEvent - The event to signal\r
-    \r
-Returns:\r
-\r
-  EFI_INVALID_PARAMETER - Parameters are not valid.\r
-  \r
-  EFI_SUCCESS - The event was signaled.\r
-\r
---*/\r
-{\r
-  IEVENT          *Event;\r
-\r
-  Event = UserEvent;\r
-\r
-  if (Event == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (Event->Signature != EVENT_SIGNATURE) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  CoreAcquireEventLock ();\r
-\r
-  //\r
-  // If the event is not already signalled, do so\r
-  //\r
-\r
-  if (Event->SignalCount == 0x00000000) {\r
-    Event->SignalCount++;\r
-\r
-    //\r
-    // If signalling type is a notify function, queue it\r
-    //\r
-    if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {\r
-      if (Event->ExFlag) {\r
-        //\r
-        // The CreateEventEx() style requires all members of the Event Group \r
-        //  to be signaled. \r
-        //\r
-        CoreReleaseEventLock ();\r
-        CoreNotifySignalList (&Event->EventGroup);\r
-        CoreAcquireEventLock ();\r
-       } else {\r
-        CoreNotifyEvent (Event);\r
-      }\r
-    }\r
-  }\r
-\r
-  CoreReleaseEventLock ();\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-CoreCheckEvent (\r
-  IN EFI_EVENT        UserEvent\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Check the status of an event\r
-    \r
-Arguments:\r
-\r
-  UserEvent - The event to check\r
-    \r
-Returns:\r
-\r
-  EFI_SUCCESS           - The event is in the signaled state\r
-  EFI_NOT_READY         - The event is not in the signaled state\r
-  EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL\r
-\r
---*/\r
-\r
-{\r
-  IEVENT      *Event;\r
-  EFI_STATUS  Status;\r
-\r
-  Event = UserEvent;\r
-\r
-  if (Event == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (Event->Signature != EVENT_SIGNATURE) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  Status = EFI_NOT_READY;\r
-\r
-  if (!Event->SignalCount && (Event->Type & EFI_EVENT_NOTIFY_WAIT)) {\r
-\r
-    //\r
-    // Queue the wait notify function\r
-    //\r
-\r
-    CoreAcquireEventLock ();\r
-    if (!Event->SignalCount) {\r
-      CoreNotifyEvent (Event);\r
-    }\r
-    CoreReleaseEventLock ();\r
-  }\r
-\r
-  //\r
-  // If the even looks signalled, get the lock and clear it\r
-  //\r
-\r
-  if (Event->SignalCount) {\r
-    CoreAcquireEventLock ();\r
-\r
-    if (Event->SignalCount) {\r
-      Event->SignalCount = 0;\r
-      Status = EFI_SUCCESS;\r
-    }\r
-\r
-    CoreReleaseEventLock ();\r
-  }\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-CoreWaitForEvent (\r
-  IN UINTN        NumberOfEvents,\r
-  IN EFI_EVENT    *UserEvents,\r
-  OUT UINTN       *UserIndex\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Stops execution until an event is signaled.\r
-    \r
-Arguments:\r
-\r
-  NumberOfEvents  - The number of events in the UserEvents array\r
-  UserEvents      - An array of EFI_EVENT\r
-  UserIndex       - Pointer to the index of the event which satisfied the wait condition\r
-    \r
-Returns:\r
-\r
-  EFI_SUCCESS           - The event indicated by Index was signaled.\r
-  EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or \r
-                          Event was not a valid type\r
-  EFI_UNSUPPORTED       - The current TPL is not TPL_APPLICATION\r
-\r
---*/\r
-\r
-{\r
-  EFI_STATUS      Status;\r
-  UINTN           Index;\r
-\r
-  //\r
-  // Can only WaitForEvent at TPL_APPLICATION\r
-  //\r
-  if (gEfiCurrentTpl != EFI_TPL_APPLICATION) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  for(;;) {\r
-      \r
-    for(Index = 0; Index < NumberOfEvents; Index++) {\r
-\r
-      Status = CoreCheckEvent (UserEvents[Index]);\r
-\r
-      //\r
-      // provide index of event that caused problem\r
-      //\r
-      if (Status != EFI_NOT_READY) {\r
-        *UserIndex = Index;\r
-        return Status;\r
-      }\r
-    }\r
-\r
-    //\r
-    // This was the location of the Idle loop callback in EFI 1.x reference\r
-    // code. We don't have that concept in this base at this point.\r
-    // \r
-  }\r
-}\r
-\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-CoreCloseEvent (\r
-  IN EFI_EVENT    UserEvent\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Closes an event and frees the event structure.\r
-    \r
-Arguments:\r
-\r
-  UserEvent - Event to close\r
-    \r
-Returns:\r
-\r
-  EFI_INVALID_PARAMETER - Parameters are not valid.\r
-  \r
-  EFI_SUCCESS - The event has been closed\r
-\r
---*/\r
-\r
-{\r
-  EFI_STATUS  Status;\r
-  IEVENT      *Event;\r
-\r
-  Event = UserEvent;\r
-\r
-  if (Event == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (Event->Signature != EVENT_SIGNATURE) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // If it's a timer event, make sure it's not pending\r
-  //\r
-  if (Event->Type & EFI_EVENT_TIMER) {\r
-    CoreSetTimer (Event, TimerCancel, 0);\r
-  }\r
-\r
-  CoreAcquireEventLock ();\r
-\r
-  //\r
-  // If the event is queued somewhere, remove it\r
-  //\r
-\r
-  if (Event->RuntimeLink.ForwardLink != NULL) {\r
-    RemoveEntryList (&Event->RuntimeLink);\r
-  }\r
-\r
-  if (Event->NotifyLink.ForwardLink != NULL) {\r
-    RemoveEntryList (&Event->NotifyLink);\r
-  }\r
-\r
-  if (Event->SignalLink.ForwardLink != NULL) {\r
-    RemoveEntryList (&Event->SignalLink);\r
-  }\r
-\r
-  CoreReleaseEventLock ();\r
-\r
-  //\r
-  // If the event is registered on a protocol notify, then remove it from the protocol database\r
-  //\r
-  CoreUnregisterProtocolNotify (Event);\r
-\r
-  Status = CoreFreePool (Event);\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  return Status;\r
-}\r
+/*++
+
+Copyright (c) 2006, Intel Corporation                                                         
+All rights reserved. This program and the accompanying materials                          
+are licensed and made available under the terms and conditions of the BSD License         
+which accompanies this distribution.  The full text of the license may be found at        
+http://opensource.org/licenses/bsd-license.php                                            
+                                                                                          
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+
+Module Name:
+
+    event.c
+
+Abstract:
+
+    EFI Event support
+--*/
+
+
+#include <DxeMain.h>
+
+//
+// Enumerate the valid types
+//
+UINT32 mEventTable[] = {
+  //
+  // 0x80000200       Timer event with a notification function that is
+  // queue when the event is signaled with SignalEvent()
+  //
+  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
+  //
+  // 0x80000000       Timer event without a notification function. It can be
+  // signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().
+  //
+  EFI_EVENT_TIMER,
+  //
+  // 0x00000100       Generic event with a notification function that 
+  // can be waited on with CheckEvent() or WaitForEvent()
+  //
+  EFI_EVENT_NOTIFY_WAIT,
+  //
+  // 0x00000200       Generic event with a notification function that 
+  // is queue when the event is signaled with SignalEvent()
+  //
+  EFI_EVENT_NOTIFY_SIGNAL,
+  //
+  // 0x00000201       ExitBootServicesEvent.  
+  //
+  EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES,
+  //
+  // 0x60000202       SetVirtualAddressMapEvent.
+  //
+  EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
+
+#if (EFI_SPECIFICATION_VERSION < 0x00020000)
+  //
+  // 0x00000203       ReadyToBootEvent.
+  //
+  EFI_EVENT_SIGNAL_READY_TO_BOOT,
+  //
+  // 0x00000204       LegacyBootEvent.
+  //
+  EFI_EVENT_SIGNAL_LEGACY_BOOT,
+  //
+  // 0x00000603       Signal all ReadyToBootEvents.
+  //
+  EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_READY_TO_BOOT,
+  //
+  // 0x00000604       Signal all LegacyBootEvents.
+  //
+  EFI_EVENT_NOTIFY_SIGNAL_ALL | EFI_EVENT_SIGNAL_LEGACY_BOOT,
+#endif
+
+  //
+  // 0x00000000       Generic event without a notification function. 
+  // It can be signaled with SignalEvent() and checked with CheckEvent() 
+  // or WaitForEvent().
+  //
+  0x00000000,
+  //
+  // 0x80000100       Timer event with a notification function that can be 
+  // waited on with CheckEvent() or WaitForEvent()
+  //
+  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_WAIT,
+};
+
+
+VOID
+CoreAcquireEventLock (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Enter critical section by acquiring the lock on gEventQueueLock.
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  CoreAcquireLock (&gEventQueueLock);
+}
+
+
+VOID
+CoreReleaseEventLock (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Exit critical section by releasing the lock on gEventQueueLock.
+
+Arguments:
+
+  None
+
+Returns:
+
+  None
+
+--*/
+{
+  CoreReleaseLock (&gEventQueueLock);
+}
+
+
+EFI_STATUS
+CoreInitializeEventServices (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Initializes "event" support and populates parts of the System and Runtime Table.
+
+Arguments:
+
+  None
+    
+Returns:
+
+  EFI_SUCCESS - Always return success
+
+--*/
+{
+  UINTN        Index;
+
+  for (Index=0; Index <= EFI_TPL_HIGH_LEVEL; Index++) {
+    InitializeListHead (&gEventQueue[Index]);
+  }
+
+  CoreInitializeTimer ();
+  
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+CoreShutdownEventServices (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Register all runtime events to make sure they are still available after ExitBootService.
+
+Arguments:
+
+  None
+    
+Returns:
+
+  EFI_SUCCESS - Always return success.
+
+--*/
+{
+  LIST_ENTRY        *Link;
+  IEVENT            *Event;
+
+  //
+  // The Runtime AP is required for the core to function!
+  //
+  ASSERT (gRuntime != NULL);
+
+  for (Link = mRuntimeEventList.ForwardLink; Link != &mRuntimeEventList; Link = Link->ForwardLink) {
+    Event = CR (Link, IEVENT, RuntimeLink, EVENT_SIGNATURE);
+    gRuntime->RegisterEvent (
+                gRuntime, 
+                Event->Type, 
+                Event->NotifyTpl, 
+                Event->NotifyFunction, 
+                Event->NotifyContext, 
+                (VOID **)Event
+                );
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+VOID
+CoreDispatchEventNotifies (
+  IN EFI_TPL      Priority
+  )
+/*++
+
+Routine Description:
+
+  Dispatches all pending events. 
+
+Arguments:
+
+  Priority - The task priority level of event notifications to dispatch
+    
+Returns:
+
+  None
+
+--*/
+{
+  IEVENT          *Event;
+  LIST_ENTRY      *Head;
+  
+  CoreAcquireEventLock ();
+  ASSERT (gEventQueueLock.OwnerTpl == Priority);
+  Head = &gEventQueue[Priority];
+
+  //
+  // Dispatch all the pending notifications
+  //
+  while (!IsListEmpty (Head)) {
+      
+    Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE);
+    RemoveEntryList (&Event->NotifyLink);
+
+    Event->NotifyLink.ForwardLink = NULL;
+
+    //
+    // Only clear the SIGNAL status if it is a SIGNAL type event.
+    // WAIT type events are only cleared in CheckEvent()
+    //
+    if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {
+      Event->SignalCount = 0;
+    }
+
+    CoreReleaseEventLock ();
+      
+    //
+    // Notify this event
+    //
+    ASSERT (Event->NotifyFunction != NULL);
+    Event->NotifyFunction (Event, Event->NotifyContext);
+
+    //
+    // Check for next pending event
+    //
+    CoreAcquireEventLock ();
+  }
+
+  gEventPending &= ~(1 << Priority);
+  CoreReleaseEventLock ();
+}
+
+
+VOID
+STATIC
+CoreNotifyEvent (
+  IN  IEVENT      *Event
+  )
+/*++
+
+Routine Description:
+
+  Queues the event's notification function to fire
+
+Arguments:
+
+  Event       - The Event to notify
+    
+Returns:
+
+  None
+
+--*/
+{
+
+  //
+  // Event database must be locked
+  //
+  ASSERT_LOCKED (&gEventQueueLock);
+
+  //
+  // If the event is queued somewhere, remove it
+  //
+
+  if (Event->NotifyLink.ForwardLink != NULL) {
+    RemoveEntryList (&Event->NotifyLink);
+    Event->NotifyLink.ForwardLink = NULL;
+  }
+
+  // 
+  // Queue the event to the pending notification list
+  //
+
+  InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
+  gEventPending |= (UINTN)(1 << Event->NotifyTpl);
+}
+
+
+
+VOID
+CoreNotifySignalList (
+  IN EFI_GUID     *EventGroup
+  )
+/*++
+
+Routine Description:
+  Signals all events in the EventGroup
+
+Arguments:
+  EventGroup - The list to signal
+    
+Returns:
+
+  None
+
+--*/
+{
+  LIST_ENTRY              *Link;
+  LIST_ENTRY              *Head;
+  IEVENT                  *Event;
+
+  CoreAcquireEventLock ();
+
+  Head = &gEventSignalQueue;
+  for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
+    Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE);
+    if (CompareGuid (&Event->EventGroup, EventGroup)) {
+      CoreNotifyEvent (Event);
+    }
+  }
+
+  CoreReleaseEventLock ();
+}
+
+
+#if (EFI_SPECIFICATION_VERSION < 0x00020000)
+
+static
+VOID
+EFIAPI
+EventNofitySignalAllNullEvent (
+  IN EFI_EVENT                Event,
+  IN VOID                     *Context
+  )
+{
+  //
+  // This null event is a size efficent way to enusre that 
+  // EFI_EVENT_NOTIFY_SIGNAL_ALL is error checked correctly.
+  // EFI_EVENT_NOTIFY_SIGNAL_ALL is now mapped into 
+  // CreateEventEx() and this function is used to make the
+  // old error checking in CreateEvent() for Tiano extensions
+  // function.
+  //
+  return;
+}
+
+#endif
+
+
+
+
+EFI_STATUS
+EFIAPI
+CoreCreateEvent (
+  IN UINT32                   Type,
+  IN EFI_TPL                  NotifyTpl,
+  IN EFI_EVENT_NOTIFY         NotifyFunction, OPTIONAL
+  IN VOID                     *NotifyContext, OPTIONAL
+  OUT EFI_EVENT               *Event
+  )
+/*++
+
+Routine Description:
+  Creates a general-purpose event structure
+
+Arguments:
+  Type                - The type of event to create and its mode and attributes
+  NotifyTpl           - The task priority level of event notifications
+  NotifyFunction      - Pointer to the events notification function
+  NotifyContext       - Pointer to the notification functions context; corresponds to
+                        parameter "Context" in the notification function
+  Event               - Pointer to the newly created event if the call succeeds; undefined otherwise
+
+Returns:
+  EFI_SUCCESS           - The event structure was created
+  EFI_INVALID_PARAMETER - One of the parameters has an invalid value
+  EFI_OUT_OF_RESOURCES  - The event could not be allocated
+
+--*/
+{ 
+  EFI_GUID            *GuidPtr;
+  EFI_EVENT_NOTIFY    Function;
+  
+  GuidPtr = NULL;
+  Function = NotifyFunction;
+
+#if (EFI_SPECIFICATION_VERSION < 0x00020000)
+  //
+  // Clear EFI_EVENT_NOFITY_SIGNAL_ALL (Tiano extension) as all events in the 
+  //  EventGroup now have this property. So we need to filter it out.
+  //
+  if (Type & EFI_EVENT_NOTIFY_SIGNAL_ALL) {
+    Type &= ~EFI_EVENT_NOTIFY_SIGNAL_ALL;
+    Function = EventNofitySignalAllNullEvent;
+  }
+
+  //
+  // Map the Tiano extensions Events to CreateEventEx form
+  //
+  if (Type == EFI_EVENT_SIGNAL_READY_TO_BOOT) {
+    GuidPtr = &gEfiEventReadyToBootGuid;
+  } else if (Type == EFI_EVENT_SIGNAL_LEGACY_BOOT) {
+    GuidPtr = &gEfiEventLegacyBootGuid
+  }
+#endif
+
+  //
+  // Convert EFI 1.10 Events to thier UEFI 2.0 CreateEventEx mapping
+  // 
+  if (Type == EVENT_SIGNAL_EXIT_BOOT_SERVICES) {
+    GuidPtr = &gEfiEventExitBootServicesGuid;
+  } else if (Type == EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
+    GuidPtr = &gEfiEventVirtualAddressChangeGuid;
+  }
+  
+  return CoreCreateEventEx (Type, NotifyTpl, Function, NotifyContext, GuidPtr, Event);
+}
+
+
+EFI_STATUS
+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
+  )
+/*++
+
+Routine Description:
+  Creates a general-purpose event structure
+
+Arguments:
+  Type                - The type of event to create and its mode and attributes
+  NotifyTpl           - The task priority level of event notifications
+  NotifyFunction      - Pointer to the events notification function
+  NotifyContext       - Pointer to the notification functions context; corresponds to
+                        parameter "Context" in the notification function
+  EventGrout          - GUID for EventGroup if NULL act the same as gBS->CreateEvent().
+  Event               - Pointer to the newly created event if the call succeeds; undefined otherwise
+
+Returns:
+  EFI_SUCCESS           - The event structure was created
+  EFI_INVALID_PARAMETER - One of the parameters has an invalid value
+  EFI_OUT_OF_RESOURCES  - The event could not be allocated
+
+--*/
+{
+  EFI_STATUS      Status;
+  IEVENT          *IEvent;
+  INTN            Index;
+
+
+  if ((Event == NULL) || (NotifyTpl == EFI_TPL_APPLICATION)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check to make sure no reserved flags are set
+  //
+  Status = EFI_INVALID_PARAMETER;
+  for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {
+     if (Type == mEventTable[Index]) {
+       Status = EFI_SUCCESS;
+       break;
+     }
+  }
+  if(EFI_ERROR (Status)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // If it's a notify type of event, check its parameters
+  //
+  if ((Type & (EFI_EVENT_NOTIFY_WAIT | EFI_EVENT_NOTIFY_SIGNAL))) {
+    //
+    // Check for an invalid NotifyFunction or NotifyTpl
+    //
+    if ((NotifyFunction == NULL) || 
+        (NotifyTpl < EFI_TPL_APPLICATION) || 
+       (NotifyTpl >= EFI_TPL_HIGH_LEVEL)) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+  } else {
+    //
+    // No notification needed, zero ignored values
+    //
+    NotifyTpl = 0;
+    NotifyFunction = NULL;
+    NotifyContext = NULL;
+  }
+
+  //
+  // Allcoate and initialize a new event structure.
+  //
+  Status = CoreAllocatePool (
+             (Type & EFI_EVENT_RUNTIME) ? EfiRuntimeServicesData: EfiBootServicesData, 
+             sizeof (IEVENT),
+             (VOID **)&IEvent
+             );
+  if (EFI_ERROR (Status)) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  SetMem (IEvent, sizeof (IEVENT), 0);
+
+  IEvent->Signature = EVENT_SIGNATURE;
+  IEvent->Type = Type;
+  
+  IEvent->NotifyTpl      = NotifyTpl;
+  IEvent->NotifyFunction = NotifyFunction;
+  IEvent->NotifyContext  = (VOID *)NotifyContext;
+  if (EventGroup != NULL) {
+    CopyGuid (&IEvent->EventGroup, EventGroup);
+    IEvent->ExFlag = TRUE;
+  }
+
+  *Event = IEvent;
+
+  if (Type & EFI_EVENT_RUNTIME) {
+    //
+    // Keep a list of all RT events so we can tell the RT AP.
+    //
+    InsertTailList (&mRuntimeEventList, &IEvent->RuntimeLink);
+  }
+
+  CoreAcquireEventLock ();
+  
+  if ((Type & EFI_EVENT_NOTIFY_SIGNAL) != 0x00000000) {
+    //
+    // The Event's NotifyFunction must be queued whenever the event is signaled
+    //
+    InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);
+  }
+  
+  CoreReleaseEventLock ();
+  
+  //
+  // Done
+  //
+  return EFI_SUCCESS;
+}
+
+
+
+EFI_STATUS
+EFIAPI
+CoreSignalEvent (
+  IN EFI_EVENT    UserEvent
+  )
+/*++
+
+Routine Description:
+
+  Signals the event.  Queues the event to be notified if needed
+    
+Arguments:
+
+  UserEvent - The event to signal
+    
+Returns:
+
+  EFI_INVALID_PARAMETER - Parameters are not valid.
+  
+  EFI_SUCCESS - The event was signaled.
+
+--*/
+{
+  IEVENT          *Event;
+
+  Event = UserEvent;
+
+  if (Event == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Event->Signature != EVENT_SIGNATURE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CoreAcquireEventLock ();
+
+  //
+  // If the event is not already signalled, do so
+  //
+
+  if (Event->SignalCount == 0x00000000) {
+    Event->SignalCount++;
+
+    //
+    // If signalling type is a notify function, queue it
+    //
+    if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {
+      if (Event->ExFlag) {
+        //
+        // The CreateEventEx() style requires all members of the Event Group 
+        //  to be signaled. 
+        //
+        CoreReleaseEventLock ();
+        CoreNotifySignalList (&Event->EventGroup);
+        CoreAcquireEventLock ();
+       } else {
+        CoreNotifyEvent (Event);
+      }
+    }
+  }
+
+  CoreReleaseEventLock ();
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+CoreCheckEvent (
+  IN EFI_EVENT        UserEvent
+  )
+/*++
+
+Routine Description:
+
+  Check the status of an event
+    
+Arguments:
+
+  UserEvent - The event to check
+    
+Returns:
+
+  EFI_SUCCESS           - The event is in the signaled state
+  EFI_NOT_READY         - The event is not in the signaled state
+  EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL
+
+--*/
+
+{
+  IEVENT      *Event;
+  EFI_STATUS  Status;
+
+  Event = UserEvent;
+
+  if (Event == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Event->Signature != EVENT_SIGNATURE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = EFI_NOT_READY;
+
+  if (!Event->SignalCount && (Event->Type & EFI_EVENT_NOTIFY_WAIT)) {
+
+    //
+    // Queue the wait notify function
+    //
+
+    CoreAcquireEventLock ();
+    if (!Event->SignalCount) {
+      CoreNotifyEvent (Event);
+    }
+    CoreReleaseEventLock ();
+  }
+
+  //
+  // If the even looks signalled, get the lock and clear it
+  //
+
+  if (Event->SignalCount) {
+    CoreAcquireEventLock ();
+
+    if (Event->SignalCount) {
+      Event->SignalCount = 0;
+      Status = EFI_SUCCESS;
+    }
+
+    CoreReleaseEventLock ();
+  }
+
+  return Status;
+}
+
+
+
+EFI_STATUS
+EFIAPI
+CoreWaitForEvent (
+  IN UINTN        NumberOfEvents,
+  IN EFI_EVENT    *UserEvents,
+  OUT UINTN       *UserIndex
+  )
+/*++
+
+Routine Description:
+
+  Stops execution until an event is signaled.
+    
+Arguments:
+
+  NumberOfEvents  - The number of events in the UserEvents array
+  UserEvents      - An array of EFI_EVENT
+  UserIndex       - Pointer to the index of the event which satisfied the wait condition
+    
+Returns:
+
+  EFI_SUCCESS           - The event indicated by Index was signaled.
+  EFI_INVALID_PARAMETER - The event indicated by Index has a notification function or 
+                          Event was not a valid type
+  EFI_UNSUPPORTED       - The current TPL is not TPL_APPLICATION
+
+--*/
+
+{
+  EFI_STATUS      Status;
+  UINTN           Index;
+
+  //
+  // Can only WaitForEvent at TPL_APPLICATION
+  //
+  if (gEfiCurrentTpl != EFI_TPL_APPLICATION) {
+    return EFI_UNSUPPORTED;
+  }
+
+  for(;;) {
+      
+    for(Index = 0; Index < NumberOfEvents; Index++) {
+
+      Status = CoreCheckEvent (UserEvents[Index]);
+
+      //
+      // provide index of event that caused problem
+      //
+      if (Status != EFI_NOT_READY) {
+        *UserIndex = Index;
+        return Status;
+      }
+    }
+
+    //
+    // This was the location of the Idle loop callback in EFI 1.x reference
+    // code. We don't have that concept in this base at this point.
+    // 
+  }
+}
+
+
+EFI_STATUS
+EFIAPI
+CoreCloseEvent (
+  IN EFI_EVENT    UserEvent
+  )
+/*++
+
+Routine Description:
+
+  Closes an event and frees the event structure.
+    
+Arguments:
+
+  UserEvent - Event to close
+    
+Returns:
+
+  EFI_INVALID_PARAMETER - Parameters are not valid.
+  
+  EFI_SUCCESS - The event has been closed
+
+--*/
+
+{
+  EFI_STATUS  Status;
+  IEVENT      *Event;
+
+  Event = UserEvent;
+
+  if (Event == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Event->Signature != EVENT_SIGNATURE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // If it's a timer event, make sure it's not pending
+  //
+  if (Event->Type & EFI_EVENT_TIMER) {
+    CoreSetTimer (Event, TimerCancel, 0);
+  }
+
+  CoreAcquireEventLock ();
+
+  //
+  // If the event is queued somewhere, remove it
+  //
+
+  if (Event->RuntimeLink.ForwardLink != NULL) {
+    RemoveEntryList (&Event->RuntimeLink);
+  }
+
+  if (Event->NotifyLink.ForwardLink != NULL) {
+    RemoveEntryList (&Event->NotifyLink);
+  }
+
+  if (Event->SignalLink.ForwardLink != NULL) {
+    RemoveEntryList (&Event->SignalLink);
+  }
+
+  CoreReleaseEventLock ();
+
+  //
+  // If the event is registered on a protocol notify, then remove it from the protocol database
+  //
+  CoreUnregisterProtocolNotify (Event);
+
+  Status = CoreFreePool (Event);
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}