#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
///\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
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
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
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
**/\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
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
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
//\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
\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
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
&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
}\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
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
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