diff options
Diffstat (limited to 'MdePkg/Library/SmmPeriodicSmiLib/SmmPeriodicSmiLib.c')
-rw-r--r-- | MdePkg/Library/SmmPeriodicSmiLib/SmmPeriodicSmiLib.c | 1183 |
1 files changed, 0 insertions, 1183 deletions
diff --git a/MdePkg/Library/SmmPeriodicSmiLib/SmmPeriodicSmiLib.c b/MdePkg/Library/SmmPeriodicSmiLib/SmmPeriodicSmiLib.c deleted file mode 100644 index b6db31766c..0000000000 --- a/MdePkg/Library/SmmPeriodicSmiLib/SmmPeriodicSmiLib.c +++ /dev/null @@ -1,1183 +0,0 @@ -/** @file
- SMM Periodic SMI Library.
-
- Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
- 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.
-
-**/
-
-#include <PiSmm.h>
-
-#include <Protocol/SmmPeriodicTimerDispatch2.h>
-
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/SynchronizationLib.h>
-#include <Library/DebugLib.h>
-#include <Library/TimerLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/SmmServicesTableLib.h>
-
-#include <Library/SmmPeriodicSmiLib.h>
-
-///
-/// Define the number of periodic SMI handler entries that should be allocated to the list
-/// of free periodic SMI handlers when the list of free periodic SMI handlers is empty.
-///
-#define PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE 0x08
-
-///
-/// Signature for a PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT structure
-///
-#define PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE SIGNATURE_32 ('P', 'S', 'M', 'I')
-
-///
-/// Structure that contains state information for an enabled periodic SMI handler
-///
-typedef struct {
- ///
- /// Signature value that must be set to PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE
- ///
- UINT32 Signature;
- ///
- /// The link entry to be inserted to the list of periodic SMI handlers.
- ///
- LIST_ENTRY Link;
- ///
- /// The dispatch function to called to invoke an enabled periodic SMI handler.
- ///
- PERIODIC_SMI_LIBRARY_HANDLER DispatchFunction;
- ///
- /// The context to pass into DispatchFunction
- ///
- VOID *Context;
- ///
- /// The tick period in 100 ns units that DispatchFunction should be called.
- ///
- UINT64 TickPeriod;
- ///
- /// The Cpu number that is required to execute DispatchFunction. If Cpu is
- /// set to PERIODIC_SMI_LIBRARY_ANY_CPU, then DispatchFunction may be executed
- /// on any CPU.
- ///
- UINTN Cpu;
- ///
- /// The size, in bytes, of the stack allocated for a periodic SMI handler.
- /// This value must be a multiple of EFI_PAGE_SIZE.
- ///
- UINTN StackSize;
- ///
- /// A pointer to the stack allocated using AllocatePages(). This field will
- /// be NULL if StackSize is 0.
- ///
- VOID *Stack;
- ///
- /// Spin lock used to wait for an AP to complete the execution of a periodic SMI handler
- ///
- SPIN_LOCK DispatchLock;
- ///
- /// The rate in Hz of the performance counter that is used to measure the
- /// amount of time that a periodic SMI handler executes.
- ///
- UINT64 PerfomanceCounterRate;
- ///
- /// The start count value of the performance counter that is used to measure
- /// the amount of time that a periodic SMI handler executes.
- ///
- UINT64 PerfomanceCounterStartValue;
- ///
- /// The end count value of the performance counter that is used to measure
- /// the amount of time that a periodic SMI handler executes.
- ///
- UINT64 PerfomanceCounterEndValue;
- ///
- /// The context record passed into the Register() function of the SMM Periodic
- /// Timer Dispatch Protocol when a periodic SMI handler is enabled.
- ///
- EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT RegisterContext;
- ///
- /// The handle returned from the Register() function of the SMM Periodic
- /// Timer Dispatch Protocol when a periodic SMI handler is enabled.
- ///
- EFI_HANDLE DispatchHandle;
- ///
- /// The total number of performance counter ticks that the periodic SMI handler
- /// has been executing in its current invocation.
- ///
- UINT64 DispatchTotalTime;
- ///
- /// The performance counter value that was captured the last time that the
- /// periodic SMI handler called PeriodcSmiExecutionTime(). This allows the
- /// time value returned by PeriodcSmiExecutionTime() to be accurate even when
- /// the performance counter rolls over.
- ///
- UINT64 DispatchCheckPointTime;
- ///
- /// Buffer used to save the context when control is transfer from this library
- /// to an enabled periodic SMI handler. This saved context is used when the
- /// periodic SMI handler exits or yields.
- ///
- BASE_LIBRARY_JUMP_BUFFER DispatchJumpBuffer;
- ///
- /// Flag that is set to TRUE when a periodic SMI handler requests to yield
- /// using PeriodicSmiYield(). When this flag IS TRUE, YieldJumpBuffer is
- /// valid. When this flag is FALSE, YieldJumpBuffer is not valid.
- ///
- BOOLEAN YieldFlag;
- ///
- /// Buffer used to save the context when a periodic SMI handler requests to
- /// yield using PeriodicSmiYield(). This context is used to resume the
- /// execution of a periodic SMI handler the next time control is transferd
- /// to the periodic SMI handler that yielded.
- ///
- BASE_LIBRARY_JUMP_BUFFER YieldJumpBuffer;
- ///
- /// The amount of time, in 100 ns units, that have elapsed since the last
- /// time the periodic SMI handler was invoked.
- ///
- UINT64 ElapsedTime;
-} PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT;
-
-/**
- Macro that returns a pointer to a PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT
- structure based on a pointer to a RegisterContext field.
-
-**/
-#define PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_REGISTER_CONTEXT(a) \
- CR ( \
- a, \
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT, \
- RegisterContext, \
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE \
- )
-
-/**
- Macro that returns a pointer to a PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT
- structure based on a pointer to a Link field.
-
-**/
-#define PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK(a) \
- CR ( \
- a, \
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT, \
- Link, \
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE \
- )
-
-///
-/// Pointer to the SMM Periodic Timer Disatch Protocol that was located in the constuctor.
-///
-EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *gSmmPeriodicTimerDispatch2 = NULL;
-
-///
-/// Pointer to a table of supported periodic SMI tick periods in 100 ns units
-/// sorted from largest to smallest terminated by a tick period value of 0.
-/// This table is allocated using AllocatePool() in the constructor and filled
-/// in based on the values returned from the SMM Periodic Timer Dispatch 2 Protocol
-/// function GetNextShorterInterval().
-///
-UINT64 *gSmiTickPeriodTable = NULL;
-
-///
-/// Linked list of free periodic SMI handlers that this library can use.
-///
-LIST_ENTRY gFreePeriodicSmiLibraryHandlers =
- INITIALIZE_LIST_HEAD_VARIABLE (gFreePeriodicSmiLibraryHandlers);
-
-///
-/// Linked list of periodic SMI handlers that this library is currently managing.
-///
-LIST_ENTRY gPeriodicSmiLibraryHandlers =
- INITIALIZE_LIST_HEAD_VARIABLE (gPeriodicSmiLibraryHandlers);
-
-///
-/// Pointer to the periodic SMI handler that is currently being executed.
-/// Is set to NULL if no periodic SMI handler is currently being executed.
-///
-PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *gActivePeriodicSmiLibraryHandler = NULL;
-
-/**
- Internal worker function that returns a pointer to the
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT structure associated with the periodic
- SMI handler that is currently being executed. If a periodic SMI handler is
- not currently being executed, the NULL is returned.
-
- @retval NULL A periodic SMI handler is not currently being executed.
- @retval other Pointer to the PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT
- associated with the active periodic SMI handler.
-
-**/
-PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *
-GetActivePeriodicSmiLibraryHandler (
- VOID
- )
-{
- return gActivePeriodicSmiLibraryHandler;
-}
-
-/**
- Internal worker function that returns a pointer to the
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT structure associated with the
- DispatchHandle that was returned when the periodic SMI handler was enabled
- with PeriodicSmiEnable(). If DispatchHandle is NULL, then the active
- periodic SMI handler is returned. If DispatchHandle is NULL and there is
- no active periodic SMI handler, then NULL is returned.
-
- @param[in] DispatchHandle DispatchHandle that was returned when the periodic
- SMI handler was enabled with PeriodicSmiEnable().
- This is an optional parameter that may be NULL.
- If this parameter is NULL, then the active periodic
- SMI handler is returned.
-
- @retval NULL DispatchHandle is NULL and there is no active periodic SMI
- handler.
- @retval NULL DispatchHandle does not match any of the periodic SMI handlers
- that have been enabled with PeriodicSmiEnable().
- @retval other Pointer to the PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT
- associated with the DispatchHandle.
-
-**/
-PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *
-LookupPeriodicSmiLibraryHandler (
- IN EFI_HANDLE DispatchHandle OPTIONAL
- )
-{
- LIST_ENTRY *Link;
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
-
- //
- // If DispatchHandle is NULL, then return the active periodic SMI handler
- //
- if (DispatchHandle == NULL) {
- return GetActivePeriodicSmiLibraryHandler ();
- }
-
- //
- // Search the periodic SMI handler entries for a a matching DispatchHandle
- //
- for ( Link = GetFirstNode (&gPeriodicSmiLibraryHandlers)
- ; !IsNull (&gPeriodicSmiLibraryHandlers, Link)
- ; Link = GetNextNode (&gPeriodicSmiLibraryHandlers, Link)
- ) {
- PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (Link);
-
- if (PeriodicSmiLibraryHandler->DispatchHandle == DispatchHandle) {
- return PeriodicSmiLibraryHandler;
- }
- }
-
- //
- // No entries match DispatchHandle, so return NULL
- //
- return NULL;
-}
-
-/**
- Internal worker function that sets that active periodic SMI handler based on
- the Context used when the periodic SMI handler was registered with the
- SMM Periodic Timer Dispatch 2 Protocol. If Context is NULL, then the
- state is updated to show that there is not active periodic SMI handler.
- A pointer to the active PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT structure
- is returned.
-
- @retval NULL Context is NULL.
- @retval other Pointer to the PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT
- associated with Context.
-
-**/
-PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *
-SetActivePeriodicSmiLibraryHandler (
- IN CONST VOID *Context OPTIONAL
- )
-{
- if (Context == NULL) {
- gActivePeriodicSmiLibraryHandler = NULL;
- } else {
- gActivePeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_REGISTER_CONTEXT (Context);
- }
- return gActivePeriodicSmiLibraryHandler;
-}
-
-/**
- Internal worker function that moves the specified periodic SMI handler from the
- list of managed periodic SMI handlers to the list of free periodic SMI handlers.
-
- @param[in] PeriodicSmiLibraryHandler Pointer to the periodic SMI handler to be reclaimed.
-**/
-VOID
-ReclaimPeriodicSmiLibraryHandler (
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler
- )
-{
- ASSERT (PeriodicSmiLibraryHandler->DispatchHandle == NULL);
- if (PeriodicSmiLibraryHandler->Stack != NULL) {
- FreePages (
- PeriodicSmiLibraryHandler->Stack,
- EFI_SIZE_TO_PAGES (PeriodicSmiLibraryHandler->StackSize)
- );
- PeriodicSmiLibraryHandler->Stack = NULL;
- }
- RemoveEntryList (&PeriodicSmiLibraryHandler->Link);
- InsertHeadList (&gFreePeriodicSmiLibraryHandlers, &PeriodicSmiLibraryHandler->Link);
-}
-
-/**
- Add the additional entries to the list of free periodic SMI handlers.
- The function is assumed to be called only when the list of free periodic SMI
- handlers is empty.
-
- @retval TRUE The additional entries were added.
- @retval FALSE There was no available resource for the additional entries.
-**/
-BOOLEAN
-EnlargeFreePeriodicSmiLibraryHandlerList (
- VOID
- )
-{
- UINTN Index;
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
-
- //
- // Add the entries to the list
- //
- for (Index = 0; Index < PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE; Index++) {
- PeriodicSmiLibraryHandler = AllocatePool (sizeof (PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT));
- if (PeriodicSmiLibraryHandler == NULL) {
- break;
- }
- PeriodicSmiLibraryHandler->Signature = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE;
- InsertHeadList (&gFreePeriodicSmiLibraryHandlers, &PeriodicSmiLibraryHandler->Link);
- }
-
- return (BOOLEAN) (Index > 0);
-}
-
-/**
- Internal worker function that returns a free entry for a new periodic
- SMI handler. If no free entries are available, then additional
- entries are allocated.
-
- @retval NULL There are not enough resources available to to allocate a free entry.
- @retval other Pointer to a free PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT structure.
-
-**/
-PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *
-FindFreePeriodicSmiLibraryHandler (
- VOID
- )
-{
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
-
- if (IsListEmpty (&gFreePeriodicSmiLibraryHandlers)) {
- if (!EnlargeFreePeriodicSmiLibraryHandlerList ()) {
- return NULL;
- }
- }
-
- //
- // Get one from the list of free periodic SMI handlers.
- //
- PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (
- GetFirstNode (&gFreePeriodicSmiLibraryHandlers)
- );
- RemoveEntryList (&PeriodicSmiLibraryHandler->Link);
- InsertTailList (&gPeriodicSmiLibraryHandlers, &PeriodicSmiLibraryHandler->Link);
-
- return PeriodicSmiLibraryHandler;
-}
-
-/**
- This function returns a pointer to a table of supported periodic
- SMI tick periods in 100 ns units sorted from largest to smallest.
- The table contains a array of UINT64 values terminated by a tick
- period value of 0. The returned table must be treated as read-only
- data and must not be freed.
-
- @return A pointer to a table of UINT64 tick period values in
- 100ns units sorted from largest to smallest terminated
- by a tick period of 0.
-
-**/
-UINT64 *
-EFIAPI
-PeriodicSmiSupportedTickPeriod (
- VOID
- )
-{
- //
- // Return the table allocated and populated by SmmPeriodicSmiLibConstructor()
- //
- return gSmiTickPeriodTable;
-}
-
-/**
- This function returns the time in 100ns units since the periodic SMI
- handler function was called. If the periodic SMI handler was resumed
- through PeriodicSmiYield(), then the time returned is the time in
- 100ns units since PeriodicSmiYield() returned.
-
- @return The actual time in 100ns units that the periodic SMI handler
- has been executing. If this function is not called from within
- an enabled periodic SMI handler, then 0 is returned.
-
-**/
-UINT64
-EFIAPI
-PeriodicSmiExecutionTime (
- VOID
- )
-{
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
- UINT64 Current;
- UINT64 Count;
-
- //
- // If there is no active periodic SMI handler, then return 0
- //
- PeriodicSmiLibraryHandler = GetActivePeriodicSmiLibraryHandler ();
- if (PeriodicSmiLibraryHandler == NULL) {
- return 0;
- }
-
- //
- // Get the current performance counter value
- //
- Current = GetPerformanceCounter ();
-
- //
- // Count the number of performance counter ticks since the periodic SMI handler
- // was dispatched or the last time this function was called.
- //
- if (PeriodicSmiLibraryHandler->PerfomanceCounterEndValue > PeriodicSmiLibraryHandler->PerfomanceCounterStartValue) {
- //
- // The performance counter counts up. Check for roll over condition.
- //
- if (Current > PeriodicSmiLibraryHandler->DispatchCheckPointTime) {
- Count = Current - PeriodicSmiLibraryHandler->DispatchCheckPointTime;
- } else {
- Count = (Current - PeriodicSmiLibraryHandler->PerfomanceCounterStartValue) + (PeriodicSmiLibraryHandler->PerfomanceCounterEndValue - PeriodicSmiLibraryHandler->DispatchCheckPointTime);
- }
- } else {
- //
- // The performance counter counts down. Check for roll over condition.
- //
- if (PeriodicSmiLibraryHandler->DispatchCheckPointTime > Current) {
- Count = PeriodicSmiLibraryHandler->DispatchCheckPointTime - Current;
- } else {
- Count = (PeriodicSmiLibraryHandler->DispatchCheckPointTime - PeriodicSmiLibraryHandler->PerfomanceCounterEndValue) + (PeriodicSmiLibraryHandler->PerfomanceCounterStartValue - Current);
- }
- }
-
- //
- // Accumulate the total number of performance counter ticks since the periodic
- // SMI handler was dispatched or resumed.
- //
- PeriodicSmiLibraryHandler->DispatchTotalTime += Count;
-
- //
- // Update the checkpoint value to the current performance counter value
- //
- PeriodicSmiLibraryHandler->DispatchCheckPointTime = Current;
-
- //
- // Convert the total number of performance counter ticks to 100 ns units
- //
- return DivU64x64Remainder (
- MultU64x32 (PeriodicSmiLibraryHandler->DispatchTotalTime, 10000000),
- PeriodicSmiLibraryHandler->PerfomanceCounterRate,
- NULL
- );
-}
-
-/**
- This function returns control back to the SMM Foundation. When the next
- periodic SMI for the currently executing handler is triggered, the periodic
- SMI handler will restarted from its registered DispatchFunction entry point.
- If this function is not called from within an enabled periodic SMI handler,
- then control is returned to the calling function.
-
-**/
-VOID
-EFIAPI
-PeriodicSmiExit (
- VOID
- )
-{
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
-
- //
- // If there is no active periodic SMI handler, then return
- //
- PeriodicSmiLibraryHandler = GetActivePeriodicSmiLibraryHandler ();
- if (PeriodicSmiLibraryHandler == NULL) {
- return;
- }
-
- //
- // Perform a long jump back to the point when the currently executing dispatch
- // function was dispatched.
- //
- LongJump (&PeriodicSmiLibraryHandler->DispatchJumpBuffer, 1);
-
- //
- // Must never return
- //
- ASSERT (FALSE);
- CpuDeadLoop();
-}
-
-/**
- This function yields control back to the SMM Foundation. When the next
- periodic SMI for the currently executing handler is triggered, the periodic
- SMI handler will be resumed and this function will return. Use of this
- function requires a seperate stack for the periodic SMI handler. A non zero
- stack size must be specified in PeriodicSmiEnable() for this function to be
- used.
-
- If the stack size passed into PeriodicSmiEnable() was zero, the 0 is returned.
-
- If this function is not called from within an enabled periodic SMI handler,
- then 0 is returned.
-
- @return The actual time in 100ns units elasped since this function was
- called. A value of 0 indicates an unknown amount of time.
-
-**/
-UINT64
-EFIAPI
-PeriodicSmiYield (
- VOID
- )
-{
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
- UINTN SetJumpFlag;
-
- //
- // If there is no active periodic SMI handler, then return
- //
- PeriodicSmiLibraryHandler = GetActivePeriodicSmiLibraryHandler ();
- if (PeriodicSmiLibraryHandler == NULL) {
- return 0;
- }
-
- //
- // If PeriodicSmiYield() is called without an allocated stack, then just return
- // immediately with an elapsed time of 0.
- //
- if (PeriodicSmiLibraryHandler->Stack == NULL) {
- return 0;
- }
-
- //
- // Set a flag so the next periodic SMI event will resume at where SetJump()
- // is called below.
- //
- PeriodicSmiLibraryHandler->YieldFlag = TRUE;
-
- //
- // Save context in YieldJumpBuffer
- //
- SetJumpFlag = SetJump (&PeriodicSmiLibraryHandler->YieldJumpBuffer);
- if (SetJumpFlag == 0) {
- //
- // The intial call to SetJump() always returns 0.
- // If this is the initial call, then exit the current periodic SMI handler
- //
- PeriodicSmiExit ();
- }
-
- //
- // We get here when a LongJump is performed from PeriodicSmiDispatchFunctionOnCpu()
- // to resume a periodic SMI handler that called PeriodicSmiYield() on the
- // previous time this periodic SMI handler was dispatched.
- //
- // Clear the flag so the next periodic SMI dispatch will not resume.
- //
- PeriodicSmiLibraryHandler->YieldFlag = FALSE;
-
- //
- // Return the amount elapsed time that occured while yielded
- //
- return PeriodicSmiLibraryHandler->ElapsedTime;
-}
-
-/**
- Internal worker function that transfers control to an enabled periodic SMI
- handler. If the enabled periodic SMI handler was allocated its own stack,
- then this function is called on that allocated stack through the BaseLin
- function SwitchStack().
-
- @param[in] Context1 Context1 parameter passed into SwitchStack().
- @param[in] Context2 Context2 parameter passed into SwitchStack().
-
-**/
-VOID
-EFIAPI
-PeriodicSmiDispatchFunctionSwitchStack (
- IN VOID *Context1, OPTIONAL
- IN VOID *Context2 OPTIONAL
- )
-{
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
-
- //
- // Convert Context1 to PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *
- //
- PeriodicSmiLibraryHandler = (PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *)Context1;
-
- //
- // Dispatch the registered handler passing in the context that was registered
- // and the amount of time that has elapsed since the previous time this
- // periodic SMI handler was dispacthed.
- //
- PeriodicSmiLibraryHandler->DispatchFunction (
- PeriodicSmiLibraryHandler->Context,
- PeriodicSmiLibraryHandler->ElapsedTime
- );
-
- //
- // If this DispatchFunction() returns, then unconditially call PeriodicSmiExit()
- // to perform a LongJump() back to PeriodicSmiDispatchFunctionOnCpu(). The
- // LongJump() will resume exection on the original stack.
- //
- PeriodicSmiExit ();
-}
-
-/**
- Internal worker function that transfers control to an enabled periodic SMI
- handler on the specified logial CPU. This function determines if the periodic
- SMI handler yielded and needs to be resumed. It also and switches to an
- allocated stack if one was allocated in PeriodicSmiEnable().
-
- @param[in] PeriodicSmiLibraryHandler A pointer to the context for the periodic
- SMI handler to execute.
-
-**/
-VOID
-EFIAPI
-PeriodicSmiDispatchFunctionOnCpu (
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler
- )
-{
- //
- // Save context in DispatchJumpBuffer. The intial call to SetJump() always
- // returns 0. If this is the initial call, then either resume from a prior
- // call to PeriodicSmiYield() or call the DispatchFunction registerd in
- // PeriodicSmiEnable() using an allocated stack if one was specified.
- //
- if (SetJump (&PeriodicSmiLibraryHandler->DispatchJumpBuffer) != 0) {
- return;
- }
-
- //
- // Capture the performance counter value just before the periodic SMI handler
- // is resumed so the amount of time the periodic SMI handler executes can be
- // calculated.
- //
- PeriodicSmiLibraryHandler->DispatchTotalTime = 0;
- PeriodicSmiLibraryHandler->DispatchCheckPointTime = GetPerformanceCounter();
-
- if (PeriodicSmiLibraryHandler->YieldFlag) {
- //
- // Perform a long jump back to the point where the previously dispatched
- // function called PeriodicSmiYield().
- //
- LongJump (&PeriodicSmiLibraryHandler->YieldJumpBuffer, 1);
- } else if (PeriodicSmiLibraryHandler->Stack == NULL) {
- //
- // If Stack is NULL then call DispatchFunction using current stack passing
- // in the context that was registered and the amount of time that has
- // elapsed since the previous time this periodic SMI handler was dispacthed.
- //
- PeriodicSmiLibraryHandler->DispatchFunction (
- PeriodicSmiLibraryHandler->Context,
- PeriodicSmiLibraryHandler->ElapsedTime
- );
-
- //
- // If this DispatchFunction() returns, then unconditially call PeriodicSmiExit()
- // to perform a LongJump() back to this function.
- //
- PeriodicSmiExit ();
- } else {
- //
- // If Stack is not NULL then call DispatchFunction switching to the allocated stack
- //
- SwitchStack (
- PeriodicSmiDispatchFunctionSwitchStack,
- PeriodicSmiLibraryHandler,
- NULL,
- (UINT8 *)PeriodicSmiLibraryHandler->Stack + PeriodicSmiLibraryHandler->StackSize
- );
- }
-
- //
- // Must never return
- //
- ASSERT (FALSE);
- CpuDeadLoop();
-}
-
-/**
- Internal worker function that transfers control to an enabled periodic SMI
- handler on the specified logial CPU. This worker function is only called
- using the SMM Services Table function SmmStartupThisAp() to execute the
- periodic SMI handler on a logical CPU that is different than the one that is
- running the SMM Foundation. When the periodic SMI handler returns, a lock is
- released to notify the CPU that is running the SMM Foundation that the periodic
- SMI handler execution has finished its execution.
-
- @param[in, out] Buffer A pointer to the context for the periodic SMI handler.
-
-**/
-VOID
-EFIAPI
-PeriodicSmiDispatchFunctionWithLock (
- IN OUT VOID *Buffer
- )
-{
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
-
- //
- // Get context
- //
- PeriodicSmiLibraryHandler = (PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *)Buffer;
-
- //
- // Execute dispatch function on the currently excuting logical CPU
- //
- PeriodicSmiDispatchFunctionOnCpu (PeriodicSmiLibraryHandler);
-
- //
- // Release the dispatch spin lock
- //
- ReleaseSpinLock (&PeriodicSmiLibraryHandler->DispatchLock);
-}
-
-/**
- Internal worker function that transfers control to a periodic SMI handler that
- was enabled using PeriodicSmiEnable().
-
- @param[in] DispatchHandle The unique handle assigned to this handler by
- SmiHandlerRegister().
- @param[in] Context Points to an optional handler context which was
- specified when the handler was registered.
- @param[in, out] CommBuffer A pointer to a collection of data in memory that
- will be conveyed from a non-SMM environment into
- an SMM environment.
- @param[in, out] CommBufferSize The size of the CommBuffer.
-
- @retval EFI_SUCCESS The interrupt was handled and quiesced.
- No other handlers should still be called.
- @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other
- handlers should still be called.
- @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other
- handlers should still be called.
- @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
-
-**/
-EFI_STATUS
-EFIAPI
-PeriodicSmiDispatchFunction (
- IN EFI_HANDLE DispatchHandle,
- IN CONST VOID *Context OPTIONAL,
- IN OUT VOID *CommBuffer OPTIONAL,
- IN OUT UINTN *CommBufferSize OPTIONAL
- )
-{
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
- EFI_SMM_PERIODIC_TIMER_CONTEXT *TimerContext;
- EFI_STATUS Status;
-
- //
- // Set the active periodic SMI handler
- //
- PeriodicSmiLibraryHandler = SetActivePeriodicSmiLibraryHandler (Context);
- if (PeriodicSmiLibraryHandler == NULL) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Retrieve the elapsed time since the last time this periodic SMI handler was called
- //
- PeriodicSmiLibraryHandler->ElapsedTime = 0;
- if (CommBuffer != NULL) {
- TimerContext = (EFI_SMM_PERIODIC_TIMER_CONTEXT *)CommBuffer;
- PeriodicSmiLibraryHandler->ElapsedTime = TimerContext->ElapsedTime;
- }
-
- //
- // Dispatch the periodic SMI handler
- //
- if ((PeriodicSmiLibraryHandler->Cpu == PERIODIC_SMI_LIBRARY_ANY_CPU) ||
- (PeriodicSmiLibraryHandler->Cpu == gSmst->CurrentlyExecutingCpu) ) {
- //
- // Dispatch on the currently execution CPU if the CPU specified in PeriodicSmiEnable()
- // was PERIODIC_SMI_LIBARRY_ANY_CPU or the currently executing CPU matches the CPU
- // that was specified in PeriodicSmiEnable().
- //
- PeriodicSmiDispatchFunctionOnCpu (PeriodicSmiLibraryHandler);
- } else {
- //
- // Acquire spin lock for ths periodic SMI handler. The AP will release the
- // spin lock when it is done executing the periodic SMI handler.
- //
- AcquireSpinLock (&PeriodicSmiLibraryHandler->DispatchLock);
-
- //
- // Execute the periodic SMI handler on the CPU that was specified in
- // PeriodicSmiEnable().
- //
- Status = gSmst->SmmStartupThisAp (
- PeriodicSmiDispatchFunctionWithLock,
- PeriodicSmiLibraryHandler->Cpu,
- PeriodicSmiLibraryHandler
- );
- if (!EFI_ERROR (Status)) {
- //
- // Wait for the AP to release the spin lock.
- //
- while (!AcquireSpinLockOrFail (&PeriodicSmiLibraryHandler->DispatchLock)) {
- CpuPause ();
- }
- }
-
- //
- // Release the spin lock for the periodic SMI handler.
- //
- ReleaseSpinLock (&PeriodicSmiLibraryHandler->DispatchLock);
- }
-
- //
- // Reclaim the active periodic SMI handler if it was disabled during the current dispatch.
- //
- if (PeriodicSmiLibraryHandler->DispatchHandle == NULL) {
- ReclaimPeriodicSmiLibraryHandler (PeriodicSmiLibraryHandler);
- }
-
- //
- // Update state to show that there is no active periodic SMI handler
- //
- SetActivePeriodicSmiLibraryHandler (NULL);
-
- return EFI_SUCCESS;
-}
-
-/**
- This function enables a periodic SMI handler.
-
- @param[in, out] DispatchHandle A pointer to the handle associated with the
- enabled periodic SMI handler. This is an
- optional parameter that may be NULL. If it is
- NULL, then the handle will not be returned,
- which means that the periodic SMI handler can
- never be disabled.
- @param[in] DispatchFunction A pointer to a periodic SMI handler function.
- @param[in] Context Optional content to pass into DispatchFunction.
- @param[in] TickPeriod The requested tick period in 100ns units that
- control should be givien to the periodic SMI
- handler. Must be one of the supported values
- returned by PeriodicSmiSupportedPickPeriod().
- @param[in] Cpu Specifies the CPU that is required to execute
- the periodic SMI handler. If Cpu is
- PERIODIC_SMI_LIBRARY_ANY_CPU, then the periodic
- SMI handler will always be executed on the SMST
- CurrentlyExecutingCpu, which may vary across
- periodic SMIs. If Cpu is between 0 and the SMST
- NumberOfCpus, then the periodic SMI will always
- be executed on the requested CPU.
- @param[in] StackSize The size, in bytes, of the stack to allocate for
- use by the periodic SMI handler. If 0, then the
- default stack will be used.
-
- @retval EFI_INVALID_PARAMETER DispatchFunction is NULL.
- @retval EFI_UNSUPPORTED TickPeriod is not a supported tick period. The
- supported tick periods can be retrieved using
- PeriodicSmiSupportedTickPeriod().
- @retval EFI_INVALID_PARAMETER Cpu is not PERIODIC_SMI_LIBRARY_ANY_CPU or in
- the range 0 to SMST NumberOfCpus.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources to enable the
- periodic SMI handler.
- @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate the
- stack speficied by StackSize.
- @retval EFI_SUCCESS The periodic SMI handler was enabled.
-
-**/
-EFI_STATUS
-EFIAPI
-PeriodicSmiEnable (
- IN OUT EFI_HANDLE *DispatchHandle, OPTIONAL
- IN PERIODIC_SMI_LIBRARY_HANDLER DispatchFunction,
- IN CONST VOID *Context, OPTIONAL
- IN UINT64 TickPeriod,
- IN UINTN Cpu,
- IN UINTN StackSize
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
-
- //
- // Make sure all the input parameters are valid
- //
- if (DispatchFunction == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- for (Index = 0; gSmiTickPeriodTable[Index] != 0; Index++) {
- if (gSmiTickPeriodTable[Index] == TickPeriod) {
- break;
- }
- }
- if (gSmiTickPeriodTable[Index] == 0) {
- return EFI_UNSUPPORTED;
- }
-
- if (Cpu != PERIODIC_SMI_LIBRARY_ANY_CPU && Cpu >= gSmst->NumberOfCpus) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Find a free periodic SMI handler entry
- //
- PeriodicSmiLibraryHandler = FindFreePeriodicSmiLibraryHandler();
- if (PeriodicSmiLibraryHandler == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Initialize a new periodic SMI handler entry
- //
- PeriodicSmiLibraryHandler->YieldFlag = FALSE;
- PeriodicSmiLibraryHandler->DispatchHandle = NULL;
- PeriodicSmiLibraryHandler->DispatchFunction = DispatchFunction;
- PeriodicSmiLibraryHandler->Context = (VOID *)Context;
- PeriodicSmiLibraryHandler->Cpu = Cpu;
- PeriodicSmiLibraryHandler->StackSize = ALIGN_VALUE (StackSize, EFI_PAGE_SIZE);
- if (PeriodicSmiLibraryHandler->StackSize > 0) {
- PeriodicSmiLibraryHandler->Stack = AllocatePages (EFI_SIZE_TO_PAGES (PeriodicSmiLibraryHandler->StackSize));
- if (PeriodicSmiLibraryHandler->Stack == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- ZeroMem (PeriodicSmiLibraryHandler->Stack, PeriodicSmiLibraryHandler->StackSize);
- } else {
- PeriodicSmiLibraryHandler->Stack = NULL;
- }
- InitializeSpinLock (&PeriodicSmiLibraryHandler->DispatchLock);
- PeriodicSmiLibraryHandler->PerfomanceCounterRate = GetPerformanceCounterProperties (
- &PeriodicSmiLibraryHandler->PerfomanceCounterStartValue,
- &PeriodicSmiLibraryHandler->PerfomanceCounterEndValue
- );
- PeriodicSmiLibraryHandler->RegisterContext.Period = TickPeriod;
- PeriodicSmiLibraryHandler->RegisterContext.SmiTickInterval = TickPeriod;
- Status = gSmmPeriodicTimerDispatch2->Register (
- gSmmPeriodicTimerDispatch2,
- PeriodicSmiDispatchFunction,
- &PeriodicSmiLibraryHandler->RegisterContext,
- &PeriodicSmiLibraryHandler->DispatchHandle
- );
- if (EFI_ERROR (Status)) {
- PeriodicSmiLibraryHandler->DispatchHandle = NULL;
- ReclaimPeriodicSmiLibraryHandler (PeriodicSmiLibraryHandler);
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Return the registered handle if the optional DispatchHandle parameter is not NULL
- //
- if (DispatchHandle != NULL) {
- *DispatchHandle = PeriodicSmiLibraryHandler->DispatchHandle;
- }
- return EFI_SUCCESS;
-}
-
-/**
- This function disables a periodic SMI handler that has been previously
- enabled with PeriodicSmiEnable().
-
- @param[in] DispatchHandle A handle associated with a previously enabled periodic
- SMI handler. This is an optional parameter that may
- be NULL. If it is NULL, then the active periodic SMI
- handlers is disabled.
-
- @retval FALSE DispatchHandle is NULL and there is no active periodic SMI handler.
- @retval FALSE The periodic SMI handler specified by DispatchHandle has
- not been enabled with PeriodicSmiEnable().
- @retval TRUE The periodic SMI handler specified by DispatchHandle has
- been disabled. If DispatchHandle is NULL, then the active
- periodic SMI handler has been disabled.
-
-**/
-BOOLEAN
-EFIAPI
-PeriodicSmiDisable (
- IN EFI_HANDLE DispatchHandle OPTIONAL
- )
-{
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
- EFI_STATUS Status;
-
- //
- // Lookup the periodic SMI handler specified by DispatchHandle
- //
- PeriodicSmiLibraryHandler = LookupPeriodicSmiLibraryHandler (DispatchHandle);
- if (PeriodicSmiLibraryHandler == NULL) {
- return FALSE;
- }
-
- //
- // Unregister the periodic SMI handler from the SMM Periodic Timer Dispatch 2 Protocol
- //
- Status = gSmmPeriodicTimerDispatch2->UnRegister (
- gSmmPeriodicTimerDispatch2,
- PeriodicSmiLibraryHandler->DispatchHandle
- );
- if (EFI_ERROR (Status)) {
- return FALSE;
- }
-
- //
- // Mark the entry for the disabled periodic SMI handler as free, and
- // call ReclaimPeriodicSmiLibraryHandler to move it to the list of free
- // periodic SMI handlers.
- //
- PeriodicSmiLibraryHandler->DispatchHandle = NULL;
- if (PeriodicSmiLibraryHandler != GetActivePeriodicSmiLibraryHandler ()) {
- ReclaimPeriodicSmiLibraryHandler (PeriodicSmiLibraryHandler);
- }
-
- return TRUE;
-}
-
-/**
- This constructor function caches the pointer to the SMM Periodic Timer
- Dispatch 2 Protocol and collects the list SMI tick rates that the hardware
- supports.
-
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmPeriodicSmiLibConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- UINT64 *SmiTickInterval;
- UINTN Count;
-
- //
- // Locate the SMM Periodic Timer Dispatch 2 Protocol
- //
- Status = gSmst->SmmLocateProtocol (
- &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,
- NULL,
- (VOID **)&gSmmPeriodicTimerDispatch2
- );
- ASSERT_EFI_ERROR (Status);
- ASSERT (gSmmPeriodicTimerDispatch2 != NULL);
-
- //
- // Count the number of periodic SMI tick intervals that the SMM Periodic Timer
- // Dipatch 2 Protocol supports.
- //
- SmiTickInterval = NULL;
- Count = 0;
- do {
- Status = gSmmPeriodicTimerDispatch2->GetNextShorterInterval (
- gSmmPeriodicTimerDispatch2,
- &SmiTickInterval
- );
- Count++;
- } while (SmiTickInterval != NULL);
-
- //
- // Allocate a buffer for the table of supported periodic SMI tick periods.
- //
- gSmiTickPeriodTable = AllocateZeroPool (Count * sizeof (UINT64));
- ASSERT (gSmiTickPeriodTable != NULL);
-
- //
- // Fill in the table of supported periodic SMI tick periods.
- //
- SmiTickInterval = NULL;
- Count = 0;
- do {
- gSmiTickPeriodTable[Count] = 0;
- Status = gSmmPeriodicTimerDispatch2->GetNextShorterInterval (
- gSmmPeriodicTimerDispatch2,
- &SmiTickInterval
- );
- if (SmiTickInterval != NULL) {
- gSmiTickPeriodTable[Count] = *SmiTickInterval;
- }
- Count++;
- } while (SmiTickInterval != NULL);
-
- //
- // Allocate buffer for initial set of periodic SMI handlers
- //
- EnlargeFreePeriodicSmiLibraryHandlerList ();
-
- return EFI_SUCCESS;
-}
-
-/**
- The constructor function caches the pointer to the SMM Periodic Timer Dispatch 2
- Protocol and collects the list SMI tick rates that the hardware supports.
-
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
-
-**/
-EFI_STATUS
-EFIAPI
-SmmPeriodicSmiLibDestructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- LIST_ENTRY *Link;
- PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;
-
- //
- // Free the table of supported periodic SMI tick rates
- //
- if (gSmiTickPeriodTable != NULL) {
- FreePool (gSmiTickPeriodTable);
- }
-
- //
- // Disable all periodic SMI handlers
- //
- for (Link = GetFirstNode (&gPeriodicSmiLibraryHandlers); !IsNull (&gPeriodicSmiLibraryHandlers, Link);) {
- PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (Link);
- Link = GetNextNode (&gPeriodicSmiLibraryHandlers, Link);
- PeriodicSmiDisable (PeriodicSmiLibraryHandler->DispatchHandle);
- }
-
- //
- // Free all the periodic SMI handler entries
- //
- for (Link = GetFirstNode (&gFreePeriodicSmiLibraryHandlers); !IsNull (&gFreePeriodicSmiLibraryHandlers, Link);) {
- PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (Link);
- Link = RemoveEntryList (Link);
- FreePool (PeriodicSmiLibraryHandler);
- }
-
- return EFI_SUCCESS;
-}
|