]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Dxe/Event/Event.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Event / Event.c
index 5cf54199edb451e43d5eb0d1c9454e84ed35f527..21db38aaf037466067bbde4d4056bdd79ffa7fa8 100644 (file)
@@ -1,66 +1,92 @@
 /** @file\r
   UEFI Event support functions implemented in this file.\r
 \r
-Copyright (c) 2006 - 2008, Intel Corporation. <BR>\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
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 \r
-#include <DxeMain.h>\r
+#include "DxeMain.h"\r
+#include "Event.h"\r
+\r
+///\r
+/// gEfiCurrentTpl - Current Task priority level\r
+///\r
+EFI_TPL  gEfiCurrentTpl = TPL_APPLICATION;\r
+\r
+///\r
+/// gEventQueueLock - Protects the event queues\r
+///\r
+EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);\r
+\r
+///\r
+/// gEventQueue - A list of event's to notify for each priority level\r
+///\r
+LIST_ENTRY      gEventQueue[TPL_HIGH_LEVEL + 1];\r
+\r
+///\r
+/// gEventPending - A bitmask of the EventQueues that are pending\r
+///\r
+UINTN           gEventPending = 0;\r
 \r
-//\r
-// Enumerate the valid types\r
-//\r
+///\r
+/// gEventSignalQueue - A list of events to signal based on EventGroup type\r
+///\r
+LIST_ENTRY      gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE (gEventSignalQueue);\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
+  ///\r
+  /// 0x80000200       Timer event with a notification function that is\r
+  /// queue when the event is signaled with SignalEvent()\r
+  ///\r
   EVT_TIMER | EVT_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
+  ///\r
+  /// 0x80000000       Timer event without a notification function. It can be\r
+  /// signaled with SignalEvent() and checked with CheckEvent() or WaitForEvent().\r
+  ///\r
   EVT_TIMER,\r
-  //\r
-  // 0x00000100       Generic event with a notification function that\r
-  // can be waited on with CheckEvent() or WaitForEvent()\r
-  //\r
+  ///\r
+  /// 0x00000100       Generic event with a notification function that\r
+  /// can be waited on with CheckEvent() or WaitForEvent()\r
+  ///\r
   EVT_NOTIFY_WAIT,\r
-  //\r
-  // 0x00000200       Generic event with a notification function that\r
-  // is queue when the event is signaled with SignalEvent()\r
-  //\r
+  ///\r
+  /// 0x00000200       Generic event with a notification function that\r
+  /// is queue when the event is signaled with SignalEvent()\r
+  ///\r
   EVT_NOTIFY_SIGNAL,\r
-  //\r
-  // 0x00000201       ExitBootServicesEvent.\r
-  //\r
+  ///\r
+  /// 0x00000201       ExitBootServicesEvent.\r
+  ///\r
   EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
-  //\r
-  // 0x60000202       SetVirtualAddressMapEvent.\r
-  //\r
+  ///\r
+  /// 0x60000202       SetVirtualAddressMapEvent.\r
+  ///\r
   EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\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
+  ///\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
+  ///\r
+  /// 0x80000100       Timer event with a notification function that can be\r
+  /// waited on with CheckEvent() or WaitForEvent()\r
+  ///\r
   EVT_TIMER | EVT_NOTIFY_WAIT,\r
 };\r
 \r
+///\r
+/// gIdleLoopEvent - Event which is signalled when the core is idle\r
+///\r
+EFI_EVENT       gIdleLoopEvent = NULL;\r
+\r
 \r
 /**\r
   Enter critical section by acquiring the lock on gEventQueueLock.\r
@@ -90,7 +116,7 @@ CoreReleaseEventLock (
 \r
 \r
 /**\r
-  Initializes "event" support and populates parts of the System and Runtime Table.\r
+  Initializes "event" support.\r
 \r
   @retval EFI_SUCCESS            Always return success\r
 \r
@@ -108,6 +134,15 @@ CoreInitializeEventServices (
 \r
   CoreInitializeTimer ();\r
 \r
+  CoreCreateEventEx (\r
+    EVT_NOTIFY_SIGNAL,\r
+    TPL_NOTIFY,\r
+    EfiEventEmptyFunction,\r
+    NULL,\r
+    &gIdleLoopEventGuid,\r
+    &gIdleLoopEvent\r
+    );\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -146,7 +181,7 @@ CoreDispatchEventNotifies (
     // 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 & EVT_NOTIFY_SIGNAL) {\r
+    if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {\r
       Event->SignalCount = 0;\r
     }\r
 \r
@@ -164,7 +199,7 @@ CoreDispatchEventNotifies (
     CoreAcquireEventLock ();\r
   }\r
 \r
-  gEventPending &= ~(1 << Priority);\r
+  gEventPending &= ~(UINTN)(1 << Priority);\r
   CoreReleaseEventLock ();\r
 }\r
 \r
@@ -237,7 +272,7 @@ CoreNotifySignalList (
 \r
 \r
 /**\r
-  Creates a general-purpose event structure.\r
+  Creates an event.\r
 \r
   @param  Type                   The type of event to create and its mode and\r
                                  attributes\r
@@ -270,7 +305,7 @@ CoreCreateEvent (
 \r
 \r
 /**\r
-  Creates a general-purpose event structure\r
+  Creates an event in a group.\r
 \r
   @param  Type                   The type of event to create and its mode and\r
                                  attributes\r
@@ -299,6 +334,51 @@ CoreCreateEventEx (
   IN CONST EFI_GUID           *EventGroup,    OPTIONAL\r
   OUT EFI_EVENT               *Event\r
   )\r
+{\r
+  //\r
+  // If it's a notify type of event, check for invalid NotifyTpl\r
+  //\r
+  if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {\r
+    if (NotifyTpl != TPL_APPLICATION &&\r
+        NotifyTpl != TPL_CALLBACK &&\r
+        NotifyTpl != TPL_NOTIFY) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  return CoreCreateEventInternal (Type, NotifyTpl, NotifyFunction, NotifyContext, EventGroup, Event);\r
+}\r
+\r
+/**\r
+  Creates a general-purpose event structure\r
+\r
+  @param  Type                   The type of event to create and its mode and\r
+                                 attributes\r
+  @param  NotifyTpl              The task priority level of event notifications\r
+  @param  NotifyFunction         Pointer to the events notification function\r
+  @param  NotifyContext          Pointer to the notification functions context;\r
+                                 corresponds to parameter "Context" in the\r
+                                 notification function\r
+  @param  EventGroup             GUID for EventGroup if NULL act the same as\r
+                                 gBS->CreateEvent().\r
+  @param  Event                  Pointer to the newly created event if the call\r
+                                 succeeds; undefined otherwise\r
+\r
+  @retval EFI_SUCCESS            The event structure was created\r
+  @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value\r
+  @retval EFI_OUT_OF_RESOURCES   The event could not be allocated\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CoreCreateEventInternal (\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
   EFI_STATUS      Status;\r
   IEVENT          *IEvent;\r
@@ -373,19 +453,17 @@ CoreCreateEventEx (
   }\r
 \r
   //\r
-  // Allcoate and initialize a new event structure.\r
+  // Allocate and initialize a new event structure.\r
   //\r
-  Status = CoreAllocatePool (\r
-             ((Type & EVT_RUNTIME) != 0) ? EfiRuntimeServicesData: EfiBootServicesData,\r
-             sizeof (IEVENT),\r
-             (VOID **)&IEvent\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
+  if ((Type & EVT_RUNTIME) != 0) {\r
+    IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));\r
+  } else {\r
+    IEvent = AllocateZeroPool (sizeof (IEVENT));\r
+  }\r
+  if (IEvent == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  ZeroMem (IEvent, sizeof (IEVENT));\r
-\r
   IEvent->Signature = EVENT_SIGNATURE;\r
   IEvent->Type = Type;\r
 \r
@@ -394,7 +472,7 @@ CoreCreateEventEx (
   IEvent->NotifyContext  = (VOID *)NotifyContext;\r
   if (EventGroup != NULL) {\r
     CopyGuid (&IEvent->EventGroup, EventGroup);\r
-    IEvent->ExFlag = TRUE;\r
+    IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;\r
   }\r
 \r
   *Event = IEvent;\r
@@ -470,8 +548,8 @@ CoreSignalEvent (
     //\r
     // If signalling type is a notify function, queue it\r
     //\r
-    if (Event->Type & EVT_NOTIFY_SIGNAL) {\r
-      if (Event->ExFlag) {\r
+    if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {\r
+      if ((Event->ExFlag & EVT_EXFLAG_EVENT_GROUP) != 0) {\r
         //\r
         // The CreateEventEx() style requires all members of the Event Group\r
         //  to be signaled.\r
@@ -526,13 +604,13 @@ CoreCheckEvent (
 \r
   Status = EFI_NOT_READY;\r
 \r
-  if (!Event->SignalCount && (Event->Type & EVT_NOTIFY_WAIT)) {\r
+  if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) {\r
 \r
     //\r
     // Queue the wait notify function\r
     //\r
     CoreAcquireEventLock ();\r
-    if (!Event->SignalCount) {\r
+    if (Event->SignalCount == 0) {\r
       CoreNotifyEvent (Event);\r
     }\r
     CoreReleaseEventLock ();\r
@@ -542,10 +620,10 @@ CoreCheckEvent (
   // If the even looks signalled, get the lock and clear it\r
   //\r
 \r
-  if (Event->SignalCount) {\r
+  if (Event->SignalCount != 0) {\r
     CoreAcquireEventLock ();\r
 \r
-    if (Event->SignalCount) {\r
+    if (Event->SignalCount != 0) {\r
       Event->SignalCount = 0;\r
       Status = EFI_SUCCESS;\r
     }\r
@@ -590,6 +668,14 @@ CoreWaitForEvent (
     return EFI_UNSUPPORTED;\r
   }\r
 \r
+  if (NumberOfEvents == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (UserEvents == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   for(;;) {\r
 \r
     for(Index = 0; Index < NumberOfEvents; Index++) {\r
@@ -600,15 +686,17 @@ CoreWaitForEvent (
       // provide index of event that caused problem\r
       //\r
       if (Status != EFI_NOT_READY) {\r
-        *UserIndex = Index;\r
+        if (UserIndex != NULL) {\r
+          *UserIndex = Index;\r
+        }\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
+    // Signal the Idle event\r
     //\r
+    CoreSignalEvent (gIdleLoopEvent);\r
   }\r
 }\r
 \r
@@ -671,10 +759,18 @@ CoreCloseEvent (
   //\r
   // If the event is registered on a protocol notify, then remove it from the protocol database\r
   //\r
-  CoreUnregisterProtocolNotify (Event);\r
+  if ((Event->ExFlag & EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION) != 0) {\r
+    CoreUnregisterProtocolNotify (Event);\r
+  }\r
 \r
+  //\r
+  // To avoid the Event to be signalled wrongly after closed,\r
+  // clear the Signature of Event before free pool.\r
+  //\r
+  Event->Signature = 0;\r
   Status = CoreFreePool (Event);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   return Status;\r
 }\r
+\r