]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdePkg/Library/SmmPeriodicSmiLib/SmmPeriodicSmiLib.c
Use linked list to replace the current array solution to store the periodic SMI handl...
[mirror_edk2.git] / MdePkg / Library / SmmPeriodicSmiLib / SmmPeriodicSmiLib.c
index af456e922c6d623b1b106c914e5b0d75e750ba13..1a9659616c884b137cf758f6c58ff807fe84f981 100644 (file)
 #include <Library/SmmPeriodicSmiLib.h>\r
 \r
 ///\r
-/// Define the number of periodic SMI handler entries that should be allocated in \r
-/// the constructor for gPeriodicSmiLibraryHandlers and also use this value as the \r
-/// number of entries to add to gPeriodicSmiLibraryHandlers when gPeriodicSmiLibraryHandlers\r
-/// is full.\r
+/// Define the number of periodic SMI handler entries that should be allocated to the list\r
+/// of free periodic SMI handlers when the list of free periodic SMI handlers is empty.\r
 ///\r
 #define PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE  0x08\r
 \r
@@ -48,6 +46,10 @@ typedef struct {
   ///\r
   UINT32                                   Signature;\r
   ///\r
+  /// The link entry to be inserted to the list of periodic SMI handlers.\r
+  ///\r
+  LIST_ENTRY                               Link;\r
+  ///\r
   /// The dispatch function to called to invoke an enabled periodic SMI handler.\r
   ///\r
   PERIODIC_SMI_LIBRARY_HANDLER             DispatchFunction;\r
@@ -155,6 +157,19 @@ typedef struct {
     PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE                    \\r
     )\r
 \r
+/**\r
+ Macro that returns a pointer to a PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT \r
+ structure based on a pointer to a Link field.\r
+\r
+**/\r
+#define PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK(a)             \\r
+  CR (                                                                \\r
+    a,                                                                \\r
+    PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT,                             \\r
+    Link,                                                             \\r
+    PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE                    \\r
+    )\r
+\r
 ///\r
 /// Pointer to the SMM Periodic Timer Disatch Protocol that was located in the constuctor.\r
 ///\r
@@ -170,21 +185,22 @@ EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL  *gSmmPeriodicTimerDispatch2
 UINT64                                     *gSmiTickPeriodTable                  = NULL;\r
 \r
 ///\r
-/// The number entries in gPeriodicSmiLibraryHandlers\r
+/// Linked list of free periodic SMI handlers that this library can use.\r
 ///\r
-UINTN                                      gNumberOfPeriodicSmiLibraryHandlers   = 0;\r
+LIST_ENTRY                                 gFreePeriodicSmiLibraryHandlers       =\r
+                                           INITIALIZE_LIST_HEAD_VARIABLE (gFreePeriodicSmiLibraryHandlers);\r
 \r
 ///\r
-/// Table of periodic SMI handlers that this library is currently managing.  This\r
-/// table is allocated using AllocatePool()\r
+/// Linked list of periodic SMI handlers that this library is currently managing.\r
 ///\r
-PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT       *gPeriodicSmiLibraryHandlers          = NULL;\r
+LIST_ENTRY                                 gPeriodicSmiLibraryHandlers           =\r
+                                           INITIALIZE_LIST_HEAD_VARIABLE (gPeriodicSmiLibraryHandlers);\r
 \r
 ///\r
-/// The index of gPeriodicSmiLibraryHandlers that is currently being executed.  \r
-/// Is set to -1 if no periodic SMI handler is currently being executed.\r
+/// Pointer to the periodic SMI handler that is currently being executed.\r
+/// Is set to NULL if no periodic SMI handler is currently being executed.\r
 ///\r
-INTN                                       gActivePeriodicSmiLibraryHandlerIndex = -1;\r
+PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT       *gActivePeriodicSmiLibraryHandler     = NULL;\r
 \r
 /**\r
   Internal worker function that returns a pointer to the \r
@@ -202,18 +218,7 @@ GetActivePeriodicSmiLibraryHandler (
   VOID\r
   )\r
 {\r
-  if (gActivePeriodicSmiLibraryHandlerIndex < 0) {\r
-    //\r
-    // Return NULL if index is negative, which means that there is no active \r
-    // periodic SMI handler.\r
-    //\r
-    return NULL;\r
-  }\r
-  \r
-  //\r
-  // Return a pointer to the active periodic SMI handler context\r
-  //\r
-  return &gPeriodicSmiLibraryHandlers[gActivePeriodicSmiLibraryHandlerIndex];\r
+  return gActivePeriodicSmiLibraryHandler;\r
 }\r
 \r
 /**\r
@@ -240,24 +245,30 @@ GetActivePeriodicSmiLibraryHandler (
 **/\r
 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *\r
 LookupPeriodicSmiLibraryHandler (\r
-  IN EFI_HANDLE  DispatchHandle    OPTIONAL\r
+  IN EFI_HANDLE                         DispatchHandle    OPTIONAL\r
   )\r
 {\r
-  UINTN  Index;\r
+  LIST_ENTRY                            *Link;\r
+  PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT  *PeriodicSmiLibraryHandler;\r
 \r
   //\r
   // If DispatchHandle is NULL, then return the active periodic SMI handler\r
-  //  \r
+  //\r
   if (DispatchHandle == NULL) {\r
     return GetActivePeriodicSmiLibraryHandler ();\r
   }\r
 \r
   //\r
   // Search the periodic SMI handler entries for a a matching DispatchHandle\r
-  //  \r
-  for (Index = 0; Index < gNumberOfPeriodicSmiLibraryHandlers; Index++) {\r
-    if (gPeriodicSmiLibraryHandlers[Index].DispatchHandle == DispatchHandle) {\r
-      return &gPeriodicSmiLibraryHandlers[Index];\r
+  //\r
+  for ( Link = GetFirstNode (&gPeriodicSmiLibraryHandlers)\r
+      ; !IsNull (&gPeriodicSmiLibraryHandlers, Link)\r
+      ; Link = GetNextNode (&gPeriodicSmiLibraryHandlers, Link)\r
+      ) {\r
+    PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (Link);\r
+\r
+    if (PeriodicSmiLibraryHandler->DispatchHandle == DispatchHandle) {\r
+      return PeriodicSmiLibraryHandler;\r
     }\r
   }\r
   \r
@@ -285,15 +296,88 @@ SetActivePeriodicSmiLibraryHandler (
   IN CONST VOID  *Context  OPTIONAL\r
   )\r
 {\r
-  PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT  *PeriodicSmiLibraryHandler;\r
-\r
   if (Context == NULL) {\r
-    gActivePeriodicSmiLibraryHandlerIndex = -1;\r
-    return NULL;\r
+    gActivePeriodicSmiLibraryHandler = NULL;\r
+  } else {\r
+    gActivePeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_REGISTER_CONTEXT (Context);\r
   }\r
-  PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_REGISTER_CONTEXT (Context);\r
-  gActivePeriodicSmiLibraryHandlerIndex = PeriodicSmiLibraryHandler - gPeriodicSmiLibraryHandlers;\r
-  return PeriodicSmiLibraryHandler;\r
+  return gActivePeriodicSmiLibraryHandler;\r
+}\r
+\r
+/**\r
+  Internal worker function that moves the specified periodic SMI handler from the\r
+  list of managed periodic SMI handlers to the list of free periodic SMI handlers.\r
+\r
+  @param[in] PeriodicSmiLibraryHandler  Pointer to the periodic SMI handler to be reclaimed.\r
+**/\r
+VOID\r
+ReclaimPeriodicSmiLibraryHandler (\r
+  PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT     *PeriodicSmiLibraryHandler\r
+  )\r
+{\r
+  LIST_ENTRY                               *Link;\r
+\r
+  ASSERT (PeriodicSmiLibraryHandler->DispatchHandle == NULL);\r
+  if (PeriodicSmiLibraryHandler->Stack != NULL) {\r
+    FreePages (\r
+      PeriodicSmiLibraryHandler->Stack,\r
+      EFI_SIZE_TO_PAGES (PeriodicSmiLibraryHandler->StackSize)\r
+      );\r
+    PeriodicSmiLibraryHandler->Stack = NULL;\r
+  }\r
+  RemoveEntryList (&PeriodicSmiLibraryHandler->Link);\r
+  //\r
+  // Insert to gFreePeriodicSmiLibraryHandlers in the reverse order of the address of PeriodicSmiLibraryHandler\r
+  //\r
+  for ( Link = GetFirstNode (&gFreePeriodicSmiLibraryHandlers)\r
+      ; !IsNull (&gFreePeriodicSmiLibraryHandlers, Link)\r
+      ; Link = GetNextNode (&gFreePeriodicSmiLibraryHandlers, Link)\r
+      ) {\r
+    if (Link < &PeriodicSmiLibraryHandler->Link) {\r
+      break;\r
+    }\r
+  }\r
+  InsertTailList (Link, &PeriodicSmiLibraryHandler->Link);\r
+}\r
+\r
+/**\r
+  Add the additional entries to the list of free periodic SMI handlers.\r
+  The function is assumed to be called only when the list of free periodic SMI\r
+  handlers is empty.\r
+\r
+  @retval TRUE  The additional entries were added.\r
+  @retval FALSE There was no available resource for the additional entries.\r
+**/\r
+BOOLEAN\r
+EnlargeFreePeriodicSmiLibraryHandlerList (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                                 Index;\r
+  PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT  *PeriodicSmiLibraryHandlers;\r
+\r
+  //\r
+  // The function is assumed to be called only when the list of free periodic SMI library\r
+  // handlers is empty.\r
+  //\r
+  ASSERT (IsListEmpty (&gFreePeriodicSmiLibraryHandlers));\r
+\r
+  PeriodicSmiLibraryHandlers = AllocatePool (\r
+                                 PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE * sizeof (PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT)\r
+                                 );\r
+  if (PeriodicSmiLibraryHandlers == NULL) {\r
+    return FALSE;\r
+  }\r
+  \r
+  //\r
+  // Add the entries to the list in the reverse order of the their memory address\r
+  //\r
+  for (Index = 0; Index < PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE; Index++) {\r
+    PeriodicSmiLibraryHandlers[Index].Signature  = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE;\r
+    InsertHeadList (&gFreePeriodicSmiLibraryHandlers, &PeriodicSmiLibraryHandlers[Index].Link);\r
+  }\r
+\r
+  return TRUE;\r
 }\r
 \r
 /**\r
@@ -310,40 +394,24 @@ FindFreePeriodicSmiLibraryHandler (
   VOID\r
   )\r
 {\r
-  UINTN                                 Index;\r
   PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT  *PeriodicSmiLibraryHandler;\r
   \r
-  //\r
-  // Search for a free entry in gPeriodicSmiLibraryHandlers\r
-  // A free entry must have a NULL DispatchHandle and a NULL Stack.\r
-  //  \r
-  for (Index = 0; Index < gNumberOfPeriodicSmiLibraryHandlers; Index++) {\r
-    if (gPeriodicSmiLibraryHandlers[Index].DispatchHandle != NULL) {\r
-      continue;\r
-    }\r
-    if (gPeriodicSmiLibraryHandlers[Index].Stack != NULL) {\r
-      continue;\r
+  if (IsListEmpty (&gFreePeriodicSmiLibraryHandlers)) {\r
+    if (!EnlargeFreePeriodicSmiLibraryHandlerList ()) {\r
+      return NULL;\r
     }\r
-    return &gPeriodicSmiLibraryHandlers[Index];\r
   }\r
 \r
   //\r
-  // If no free entries were found, then grow the table of periodic SMI handler entries\r
+  // Get one from the list of free periodic SMI handlers.\r
   //\r
-  if (Index == gNumberOfPeriodicSmiLibraryHandlers) {\r
-    PeriodicSmiLibraryHandler = ReallocatePool (\r
-                                  gNumberOfPeriodicSmiLibraryHandlers * sizeof (PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT),\r
-                                  (gNumberOfPeriodicSmiLibraryHandlers + PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE) * sizeof (PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT),\r
-                                  gPeriodicSmiLibraryHandlers\r
-                                  );\r
-    if (PeriodicSmiLibraryHandler == NULL) {\r
-      return NULL;\r
-    }\r
-    gPeriodicSmiLibraryHandlers = PeriodicSmiLibraryHandler;\r
-    gNumberOfPeriodicSmiLibraryHandlers += PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE;\r
-  }\r
+  PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (\r
+                                GetFirstNode (&gFreePeriodicSmiLibraryHandlers)\r
+                                );\r
+  RemoveEntryList (&PeriodicSmiLibraryHandler->Link);\r
+  InsertTailList (&gPeriodicSmiLibraryHandlers, &PeriodicSmiLibraryHandler->Link);\r
 \r
-  return &gPeriodicSmiLibraryHandlers[Index];\r
+  return PeriodicSmiLibraryHandler;\r
 }\r
 \r
 /**\r
@@ -807,27 +875,12 @@ PeriodicSmiDispatchFunction (
     //\r
     ReleaseSpinLock (&PeriodicSmiLibraryHandler->DispatchLock);\r
   }\r
-  \r
+\r
   //\r
-  // Retrieve the active periodic SMI handler in case the entries were reallocated\r
-  // when the active periodic SMI handler was dispatched.\r
+  // Reclaim the active periodic SMI handler if it was disabled during the current dispatch.\r
   //\r
-  PeriodicSmiLibraryHandler = GetActivePeriodicSmiLibraryHandler ();\r
-  if (PeriodicSmiLibraryHandler != NULL) {\r
-    //\r
-    // If the active periodic SMI handler was disabled during the current dispatch \r
-    // and the periodic SMI handler was allocated a stack when it was enabled, then \r
-    // free that stack here.\r
-    //\r
-    if (PeriodicSmiLibraryHandler->DispatchHandle == NULL) {\r
-      if (PeriodicSmiLibraryHandler->Stack != NULL) {\r
-        FreePages (\r
-          PeriodicSmiLibraryHandler->Stack, \r
-          EFI_SIZE_TO_PAGES (PeriodicSmiLibraryHandler->StackSize)\r
-          );\r
-        PeriodicSmiLibraryHandler->Stack = NULL;  \r
-      }\r
-    }\r
+  if (PeriodicSmiLibraryHandler->DispatchHandle == NULL) {\r
+    ReclaimPeriodicSmiLibraryHandler (PeriodicSmiLibraryHandler);\r
   }\r
   \r
   //\r
@@ -923,8 +976,7 @@ PeriodicSmiEnable (
 \r
   //\r
   // Initialize a new periodic SMI handler entry\r
-  //  \r
-  PeriodicSmiLibraryHandler->Signature        = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE;\r
+  //\r
   PeriodicSmiLibraryHandler->YieldFlag        = FALSE;\r
   PeriodicSmiLibraryHandler->DispatchHandle   = NULL;\r
   PeriodicSmiLibraryHandler->DispatchFunction = DispatchFunction;\r
@@ -937,6 +989,8 @@ PeriodicSmiEnable (
       return EFI_OUT_OF_RESOURCES;\r
     }\r
     ZeroMem (PeriodicSmiLibraryHandler->Stack, PeriodicSmiLibraryHandler->StackSize);\r
+  } else {\r
+    PeriodicSmiLibraryHandler->Stack = NULL;\r
   }\r
   InitializeSpinLock (&PeriodicSmiLibraryHandler->DispatchLock);\r
   PeriodicSmiLibraryHandler->PerfomanceCounterRate = GetPerformanceCounterProperties (\r
@@ -951,18 +1005,9 @@ PeriodicSmiEnable (
                                          &PeriodicSmiLibraryHandler->RegisterContext,\r
                                          &PeriodicSmiLibraryHandler->DispatchHandle\r
                                          );\r
-  if (EFI_ERROR (Status) || PeriodicSmiLibraryHandler->DispatchHandle == NULL) {\r
-    //\r
-    // If the registration failed or the handle is invalid, free the stack if one was allocated\r
-    //\r
-    if (PeriodicSmiLibraryHandler->Stack != NULL) {\r
-      FreePages (\r
-        PeriodicSmiLibraryHandler->Stack, \r
-        EFI_SIZE_TO_PAGES (PeriodicSmiLibraryHandler->StackSize)\r
-        );\r
-      PeriodicSmiLibraryHandler->Stack = NULL;  \r
-    }\r
+  if (EFI_ERROR (Status)) {\r
     PeriodicSmiLibraryHandler->DispatchHandle = NULL;\r
+    ReclaimPeriodicSmiLibraryHandler (PeriodicSmiLibraryHandler);\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
   \r
@@ -1021,25 +1066,15 @@ PeriodicSmiDisable (
   }\r
 \r
   //\r
-  // If active periodic SMI handler is not the periodic SMI handler being \r
-  // disabled, and the periodic SMI handler being disabled was allocated a \r
-  // stack when it was enabled, then free the stack.\r
+  // Mark the entry for the disabled periodic SMI handler as free, and\r
+  // call ReclaimPeriodicSmiLibraryHandler to move it to the list of free\r
+  // periodic SMI handlers.\r
   //\r
+  PeriodicSmiLibraryHandler->DispatchHandle = NULL;\r
   if (PeriodicSmiLibraryHandler != GetActivePeriodicSmiLibraryHandler ()) {\r
-    if (PeriodicSmiLibraryHandler->Stack != NULL) {\r
-      FreePages (\r
-        PeriodicSmiLibraryHandler->Stack, \r
-        EFI_SIZE_TO_PAGES (PeriodicSmiLibraryHandler->StackSize)\r
-        );\r
-      PeriodicSmiLibraryHandler->Stack = NULL;  \r
-    }\r
+    ReclaimPeriodicSmiLibraryHandler (PeriodicSmiLibraryHandler);\r
   }\r
-  \r
-  //\r
-  // Mark the entry for the disabled periodic SMI handler as free\r
-  //\r
-  PeriodicSmiLibraryHandler->DispatchHandle = NULL;\r
-  \r
+\r
   return TRUE;\r
 }\r
 \r
@@ -1111,12 +1146,12 @@ SmmPeriodicSmiLibConstructor (
       gSmiTickPeriodTable[Count] = *SmiTickInterval;\r
     }\r
     Count++;\r
-  } while (SmiTickInterval != NULL);                                           \r
+  } while (SmiTickInterval != NULL);\r
 \r
   //\r
   // Allocate buffer for initial set of periodic SMI handlers\r
   //\r
-  FindFreePeriodicSmiLibraryHandler ();\r
+  EnlargeFreePeriodicSmiLibraryHandlerList ();\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -1138,28 +1173,43 @@ SmmPeriodicSmiLibDestructor (
   IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
-  UINTN  Index;\r
+  LIST_ENTRY                            *Link;\r
+  PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT  *PeriodicSmiLibraryHandler;\r
+  UINTN                                 Index;\r
 \r
   //\r
   // Free the table of supported periodic SMI tick rates\r
-  //  \r
+  //\r
   if (gSmiTickPeriodTable != NULL) {\r
     FreePool (gSmiTickPeriodTable);\r
   }\r
 \r
   //\r
   // Disable all periodic SMI handlers\r
-  //  \r
-  for (Index = 0; Index < gNumberOfPeriodicSmiLibraryHandlers; Index++) {\r
-    PeriodicSmiDisable (gPeriodicSmiLibraryHandlers[Index].DispatchHandle);\r
+  //\r
+  for (Link = GetFirstNode (&gPeriodicSmiLibraryHandlers); !IsNull (&gPeriodicSmiLibraryHandlers, Link);) {\r
+    PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (Link);\r
+    Link = GetNextNode (&gPeriodicSmiLibraryHandlers, Link);\r
+    PeriodicSmiDisable (PeriodicSmiLibraryHandler->DispatchHandle);\r
   }\r
-  \r
+\r
   //\r
   // Free all the periodic SMI handler entries\r
   //\r
-  if (gPeriodicSmiLibraryHandlers != NULL) {\r
-    FreePool (gPeriodicSmiLibraryHandlers);\r
+  Index = 0;\r
+  for (Link = GetFirstNode (&gFreePeriodicSmiLibraryHandlers); !IsNull (&gFreePeriodicSmiLibraryHandlers, Link);) {    \r
+    PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (Link);\r
+    Link = RemoveEntryList (Link);\r
+    Index++;\r
+    //\r
+    // Because the entries in the list are in the reverse order of the address of PeriodicSmiLibraryHandler and\r
+    // every PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE entries are in the same pool returned by AllocatePool(),\r
+    // every PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE'th entry is the header of allocated pool.\r
+    //\r
+    if ((Index % PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE) == 0) {\r
+      FreePool (PeriodicSmiLibraryHandler);\r
+    }\r
   }\r
-  \r
+\r
   return EFI_SUCCESS;\r
 }\r