]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/SmmPeriodicSmiLib/SmmPeriodicSmiLib.c
MdePkg: Fix typos in comments
[mirror_edk2.git] / MdePkg / Library / SmmPeriodicSmiLib / SmmPeriodicSmiLib.c
CommitLineData
40039e28 1/** @file\r
2 SMM Periodic SMI Library.\r
3\r
4 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php.\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <PiSmm.h>\r
16\r
17#include <Protocol/SmmPeriodicTimerDispatch2.h>\r
18\r
19#include <Library/BaseLib.h>\r
20#include <Library/BaseMemoryLib.h>\r
21#include <Library/SynchronizationLib.h>\r
22#include <Library/DebugLib.h>\r
23#include <Library/TimerLib.h>\r
24#include <Library/MemoryAllocationLib.h>\r
25#include <Library/SmmServicesTableLib.h>\r
26\r
27#include <Library/SmmPeriodicSmiLib.h>\r
28\r
29///\r
569224f9
RN
30/// Define the number of periodic SMI handler entries that should be allocated to the list\r
31/// of free periodic SMI handlers when the list of free periodic SMI handlers is empty.\r
40039e28 32///\r
33#define PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE 0x08\r
34\r
35///\r
36/// Signature for a PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT structure\r
37///\r
38#define PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE SIGNATURE_32 ('P', 'S', 'M', 'I')\r
39\r
40///\r
41/// Structure that contains state information for an enabled periodic SMI handler\r
42///\r
43typedef struct {\r
44 ///\r
45 /// Signature value that must be set to PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE\r
46 ///\r
47 UINT32 Signature;\r
48 ///\r
569224f9
RN
49 /// The link entry to be inserted to the list of periodic SMI handlers.\r
50 ///\r
51 LIST_ENTRY Link;\r
52 ///\r
40039e28 53 /// The dispatch function to called to invoke an enabled periodic SMI handler.\r
54 ///\r
55 PERIODIC_SMI_LIBRARY_HANDLER DispatchFunction;\r
56 ///\r
57 /// The context to pass into DispatchFunction\r
58 ///\r
59 VOID *Context;\r
60 ///\r
61 /// The tick period in 100 ns units that DispatchFunction should be called.\r
62 ///\r
63 UINT64 TickPeriod;\r
64 ///\r
65 /// The Cpu number that is required to execute DispatchFunction. If Cpu is \r
66 /// set to PERIODIC_SMI_LIBRARY_ANY_CPU, then DispatchFunction may be executed \r
67 /// on any CPU.\r
68 ///\r
69 UINTN Cpu;\r
70 ///\r
71 /// The size, in bytes, of the stack allocated for a periodic SMI handler. \r
72 /// This value must be a multiple of EFI_PAGE_SIZE.\r
73 ///\r
74 UINTN StackSize;\r
75 ///\r
76 /// A pointer to the stack allocated using AllocatePages(). This field will\r
77 /// be NULL if StackSize is 0.\r
78 ///\r
79 VOID *Stack;\r
80 ///\r
81 /// Spin lock used to wait for an AP to complete the execution of a periodic SMI handler\r
82 ///\r
83 SPIN_LOCK DispatchLock;\r
84 ///\r
85 /// The rate in Hz of the performance counter that is used to measure the \r
86 /// amount of time that a periodic SMI handler executes.\r
87 ///\r
88 UINT64 PerfomanceCounterRate;\r
89 ///\r
90 /// The start count value of the performance counter that is used to measure \r
91 /// the amount of time that a periodic SMI handler executes.\r
92 ///\r
93 UINT64 PerfomanceCounterStartValue;\r
94 ///\r
95 /// The end count value of the performance counter that is used to measure \r
96 /// the amount of time that a periodic SMI handler executes.\r
97 ///\r
98 UINT64 PerfomanceCounterEndValue;\r
99 ///\r
100 /// The context record passed into the Register() function of the SMM Periodic \r
101 /// Timer Dispatch Protocol when a periodic SMI handler is enabled.\r
102 ///\r
103 EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT RegisterContext;\r
104 ///\r
105 /// The handle returned from the Register() function of the SMM Periodic \r
106 /// Timer Dispatch Protocol when a periodic SMI handler is enabled.\r
107 ///\r
108 EFI_HANDLE DispatchHandle;\r
109 ///\r
110 /// The total number of performance counter ticks that the periodic SMI handler\r
111 /// has been executing in its current invocation.\r
112 ///\r
113 UINT64 DispatchTotalTime;\r
114 ///\r
115 /// The performance counter value that was captured the last time that the \r
116 /// periodic SMI handler called PeriodcSmiExecutionTime(). This allows the\r
117 /// time value returned by PeriodcSmiExecutionTime() to be accurate even when\r
118 /// the performance counter rolls over.\r
119 ///\r
120 UINT64 DispatchCheckPointTime;\r
121 ///\r
122 /// Buffer used to save the context when control is transfer from this library\r
123 /// to an enabled periodic SMI handler. This saved context is used when the \r
124 /// periodic SMI handler exits or yields. \r
125 ///\r
126 BASE_LIBRARY_JUMP_BUFFER DispatchJumpBuffer;\r
127 ///\r
128 /// Flag that is set to TRUE when a periodic SMI handler requests to yield \r
129 /// using PeriodicSmiYield(). When this flag IS TRUE, YieldJumpBuffer is \r
130 /// valid. When this flag is FALSE, YieldJumpBuffer is not valid.\r
131 ///\r
132 BOOLEAN YieldFlag;\r
133 ///\r
134 /// Buffer used to save the context when a periodic SMI handler requests to \r
135 /// yield using PeriodicSmiYield(). This context is used to resume the \r
136 /// execution of a periodic SMI handler the next time control is transferd\r
137 /// to the periodic SMI handler that yielded.\r
138 ///\r
139 BASE_LIBRARY_JUMP_BUFFER YieldJumpBuffer;\r
140 ///\r
141 /// The amount of time, in 100 ns units, that have elapsed since the last\r
142 /// time the periodic SMI handler was invoked.\r
143 ///\r
144 UINT64 ElapsedTime;\r
145} PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT;\r
146\r
147/**\r
148 Macro that returns a pointer to a PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT \r
149 structure based on a pointer to a RegisterContext field.\r
150\r
151**/\r
152#define PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_REGISTER_CONTEXT(a) \\r
153 CR ( \\r
154 a, \\r
155 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT, \\r
156 RegisterContext, \\r
157 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE \\r
158 )\r
159\r
569224f9
RN
160/**\r
161 Macro that returns a pointer to a PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT \r
162 structure based on a pointer to a Link field.\r
163\r
164**/\r
165#define PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK(a) \\r
166 CR ( \\r
167 a, \\r
168 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT, \\r
169 Link, \\r
170 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE \\r
171 )\r
172\r
40039e28 173///\r
174/// Pointer to the SMM Periodic Timer Disatch Protocol that was located in the constuctor.\r
175///\r
176EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *gSmmPeriodicTimerDispatch2 = NULL;\r
177\r
178///\r
179/// Pointer to a table of supported periodic SMI tick periods in 100 ns units \r
180/// sorted from largest to smallest terminated by a tick period value of 0.\r
181/// This table is allocated using AllocatePool() in the constructor and filled \r
182/// in based on the values returned from the SMM Periodic Timer Dispatch 2 Protocol \r
183/// function GetNextShorterInterval().\r
184///\r
185UINT64 *gSmiTickPeriodTable = NULL;\r
186\r
187///\r
569224f9 188/// Linked list of free periodic SMI handlers that this library can use.\r
40039e28 189///\r
569224f9
RN
190LIST_ENTRY gFreePeriodicSmiLibraryHandlers =\r
191 INITIALIZE_LIST_HEAD_VARIABLE (gFreePeriodicSmiLibraryHandlers);\r
40039e28 192\r
193///\r
569224f9 194/// Linked list of periodic SMI handlers that this library is currently managing.\r
40039e28 195///\r
569224f9
RN
196LIST_ENTRY gPeriodicSmiLibraryHandlers =\r
197 INITIALIZE_LIST_HEAD_VARIABLE (gPeriodicSmiLibraryHandlers);\r
40039e28 198\r
199///\r
569224f9
RN
200/// Pointer to the periodic SMI handler that is currently being executed.\r
201/// Is set to NULL if no periodic SMI handler is currently being executed.\r
40039e28 202///\r
569224f9 203PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *gActivePeriodicSmiLibraryHandler = NULL;\r
40039e28 204\r
205/**\r
206 Internal worker function that returns a pointer to the \r
207 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT structure associated with the periodic \r
208 SMI handler that is currently being executed. If a periodic SMI handler is \r
209 not currently being executed, the NULL is returned.\r
210 \r
211 @retval NULL A periodic SMI handler is not currently being executed.\r
212 @retval other Pointer to the PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT\r
213 associated with the active periodic SMI handler.\r
214 \r
215**/\r
216PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *\r
217GetActivePeriodicSmiLibraryHandler (\r
218 VOID\r
219 )\r
220{\r
569224f9 221 return gActivePeriodicSmiLibraryHandler;\r
40039e28 222}\r
223\r
224/**\r
225 Internal worker function that returns a pointer to the \r
226 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT structure associated with the \r
227 DispatchHandle that was returned when the periodic SMI handler was enabled\r
228 with PeriodicSmiEnable(). If DispatchHandle is NULL, then the active \r
229 periodic SMI handler is returned. If DispatchHandle is NULL and there is\r
230 no active periodic SMI handler, then NULL is returned.\r
231 \r
232 @param[in] DispatchHandle DispatchHandle that was returned when the periodic \r
233 SMI handler was enabled with PeriodicSmiEnable(). \r
234 This is an optional parameter that may be NULL.\r
235 If this parameter is NULL, then the active periodic\r
236 SMI handler is returned.\r
237 \r
238 @retval NULL DispatchHandle is NULL and there is no active periodic SMI \r
239 handler.\r
240 @retval NULL DispatchHandle does not match any of the periodic SMI handlers\r
241 that have been enabled with PeriodicSmiEnable().\r
242 @retval other Pointer to the PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT\r
243 associated with the DispatchHandle.\r
244 \r
245**/\r
246PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *\r
247LookupPeriodicSmiLibraryHandler (\r
569224f9 248 IN EFI_HANDLE DispatchHandle OPTIONAL\r
40039e28 249 )\r
250{\r
569224f9
RN
251 LIST_ENTRY *Link;\r
252 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
40039e28 253\r
254 //\r
255 // If DispatchHandle is NULL, then return the active periodic SMI handler\r
569224f9 256 //\r
40039e28 257 if (DispatchHandle == NULL) {\r
258 return GetActivePeriodicSmiLibraryHandler ();\r
259 }\r
260\r
261 //\r
262 // Search the periodic SMI handler entries for a a matching DispatchHandle\r
569224f9
RN
263 //\r
264 for ( Link = GetFirstNode (&gPeriodicSmiLibraryHandlers)\r
265 ; !IsNull (&gPeriodicSmiLibraryHandlers, Link)\r
266 ; Link = GetNextNode (&gPeriodicSmiLibraryHandlers, Link)\r
267 ) {\r
268 PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (Link);\r
269\r
270 if (PeriodicSmiLibraryHandler->DispatchHandle == DispatchHandle) {\r
271 return PeriodicSmiLibraryHandler;\r
40039e28 272 }\r
273 }\r
274 \r
275 //\r
276 // No entries match DispatchHandle, so return NULL\r
277 //\r
278 return NULL;\r
279}\r
280\r
281/**\r
282 Internal worker function that sets that active periodic SMI handler based on \r
283 the Context used when the periodic SMI handler was registered with the \r
284 SMM Periodic Timer Dispatch 2 Protocol. If Context is NULL, then the \r
285 state is updated to show that there is not active periodic SMI handler.\r
286 A pointer to the active PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT structure \r
287 is returned.\r
288 \r
289 @retval NULL Context is NULL.\r
290 @retval other Pointer to the PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT\r
291 associated with Context.\r
292 \r
293**/\r
294PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *\r
295SetActivePeriodicSmiLibraryHandler (\r
296 IN CONST VOID *Context OPTIONAL\r
297 )\r
298{\r
40039e28 299 if (Context == NULL) {\r
569224f9
RN
300 gActivePeriodicSmiLibraryHandler = NULL;\r
301 } else {\r
302 gActivePeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_REGISTER_CONTEXT (Context);\r
40039e28 303 }\r
569224f9
RN
304 return gActivePeriodicSmiLibraryHandler;\r
305}\r
306\r
307/**\r
308 Internal worker function that moves the specified periodic SMI handler from the\r
309 list of managed periodic SMI handlers to the list of free periodic SMI handlers.\r
310\r
311 @param[in] PeriodicSmiLibraryHandler Pointer to the periodic SMI handler to be reclaimed.\r
312**/\r
313VOID\r
314ReclaimPeriodicSmiLibraryHandler (\r
315 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler\r
316 )\r
317{\r
569224f9
RN
318 ASSERT (PeriodicSmiLibraryHandler->DispatchHandle == NULL);\r
319 if (PeriodicSmiLibraryHandler->Stack != NULL) {\r
320 FreePages (\r
321 PeriodicSmiLibraryHandler->Stack,\r
322 EFI_SIZE_TO_PAGES (PeriodicSmiLibraryHandler->StackSize)\r
323 );\r
324 PeriodicSmiLibraryHandler->Stack = NULL;\r
325 }\r
326 RemoveEntryList (&PeriodicSmiLibraryHandler->Link);\r
3e5cfe98 327 InsertHeadList (&gFreePeriodicSmiLibraryHandlers, &PeriodicSmiLibraryHandler->Link);\r
569224f9
RN
328}\r
329\r
330/**\r
331 Add the additional entries to the list of free periodic SMI handlers.\r
332 The function is assumed to be called only when the list of free periodic SMI\r
333 handlers is empty.\r
334\r
335 @retval TRUE The additional entries were added.\r
336 @retval FALSE There was no available resource for the additional entries.\r
337**/\r
338BOOLEAN\r
339EnlargeFreePeriodicSmiLibraryHandlerList (\r
340 VOID\r
341 )\r
342{\r
343 UINTN Index;\r
3e5cfe98 344 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
569224f9
RN
345\r
346 //\r
3e5cfe98 347 // Add the entries to the list\r
569224f9
RN
348 //\r
349 for (Index = 0; Index < PERIODIC_SMI_LIBRARY_ALLOCATE_SIZE; Index++) {\r
3e5cfe98
RN
350 PeriodicSmiLibraryHandler = AllocatePool (sizeof (PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT));\r
351 if (PeriodicSmiLibraryHandler == NULL) {\r
352 break;\r
353 }\r
354 PeriodicSmiLibraryHandler->Signature = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_SIGNATURE;\r
355 InsertHeadList (&gFreePeriodicSmiLibraryHandlers, &PeriodicSmiLibraryHandler->Link);\r
569224f9
RN
356 }\r
357\r
3e5cfe98 358 return (BOOLEAN) (Index > 0);\r
40039e28 359}\r
360\r
361/**\r
362 Internal worker function that returns a free entry for a new periodic\r
363 SMI handler. If no free entries are available, then additional\r
364 entries are allocated.\r
365 \r
366 @retval NULL There are not enough resources available to to allocate a free entry.\r
367 @retval other Pointer to a free PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT structure.\r
368 \r
369**/\r
370PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *\r
371FindFreePeriodicSmiLibraryHandler (\r
372 VOID\r
373 )\r
374{\r
40039e28 375 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
376 \r
569224f9
RN
377 if (IsListEmpty (&gFreePeriodicSmiLibraryHandlers)) {\r
378 if (!EnlargeFreePeriodicSmiLibraryHandlerList ()) {\r
379 return NULL;\r
40039e28 380 }\r
40039e28 381 }\r
382\r
383 //\r
569224f9 384 // Get one from the list of free periodic SMI handlers.\r
40039e28 385 //\r
569224f9
RN
386 PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (\r
387 GetFirstNode (&gFreePeriodicSmiLibraryHandlers)\r
388 );\r
389 RemoveEntryList (&PeriodicSmiLibraryHandler->Link);\r
390 InsertTailList (&gPeriodicSmiLibraryHandlers, &PeriodicSmiLibraryHandler->Link);\r
40039e28 391\r
569224f9 392 return PeriodicSmiLibraryHandler;\r
40039e28 393}\r
394\r
395/**\r
396 This function returns a pointer to a table of supported periodic\r
397 SMI tick periods in 100 ns units sorted from largest to smallest. \r
398 The table contains a array of UINT64 values terminated by a tick \r
399 period value of 0. The returned table must be treated as read-only\r
400 data and must not be freed.\r
401 \r
402 @return A pointer to a table of UINT64 tick period values in \r
403 100ns units sorted from largest to smallest terminated \r
404 by a tick period of 0.\r
405 \r
406**/\r
407UINT64 *\r
408EFIAPI\r
409PeriodicSmiSupportedTickPeriod (\r
410 VOID\r
411 )\r
412{\r
413 //\r
414 // Return the table allocated and populated by SmmPeriodicSmiLibConstructor()\r
415 //\r
416 return gSmiTickPeriodTable;\r
417}\r
418\r
419/**\r
420 This function returns the time in 100ns units since the periodic SMI\r
421 handler function was called. If the periodic SMI handler was resumed\r
422 through PeriodicSmiYield(), then the time returned is the time in\r
423 100ns units since PeriodicSmiYield() returned.\r
424\r
425 @return The actual time in 100ns units that the periodic SMI handler\r
426 has been executing. If this function is not called from within\r
427 an enabled periodic SMI handler, then 0 is returned.\r
428\r
429**/\r
430UINT64\r
431EFIAPI\r
432PeriodicSmiExecutionTime (\r
433 VOID\r
434 )\r
435{\r
436 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
437 UINT64 Current;\r
438 UINT64 Count;\r
439\r
440 //\r
441 // If there is no active periodic SMI handler, then return 0 \r
442 //\r
443 PeriodicSmiLibraryHandler = GetActivePeriodicSmiLibraryHandler ();\r
444 if (PeriodicSmiLibraryHandler == NULL) {\r
445 return 0;\r
446 }\r
447 \r
448 //\r
449 // Get the current performance counter value\r
450 //\r
451 Current = GetPerformanceCounter ();\r
452 \r
453 //\r
454 // Count the number of performance counter ticks since the periodic SMI handler \r
455 // was dispatched or the last time this function was called. \r
456 //\r
457 if (PeriodicSmiLibraryHandler->PerfomanceCounterEndValue > PeriodicSmiLibraryHandler->PerfomanceCounterStartValue) {\r
458 //\r
459 // The performance counter counts up. Check for roll over condition.\r
460 //\r
461 if (Current > PeriodicSmiLibraryHandler->DispatchCheckPointTime) {\r
462 Count = Current - PeriodicSmiLibraryHandler->DispatchCheckPointTime;\r
463 } else {\r
464 Count = (Current - PeriodicSmiLibraryHandler->PerfomanceCounterStartValue) + (PeriodicSmiLibraryHandler->PerfomanceCounterEndValue - PeriodicSmiLibraryHandler->DispatchCheckPointTime);\r
465 }\r
466 } else {\r
467 //\r
468 // The performance counter counts down. Check for roll over condition.\r
469 //\r
470 if (PeriodicSmiLibraryHandler->DispatchCheckPointTime > Current) {\r
471 Count = PeriodicSmiLibraryHandler->DispatchCheckPointTime - Current;\r
472 } else {\r
473 Count = (PeriodicSmiLibraryHandler->DispatchCheckPointTime - PeriodicSmiLibraryHandler->PerfomanceCounterEndValue) + (PeriodicSmiLibraryHandler->PerfomanceCounterStartValue - Current);\r
474 }\r
475 }\r
476 \r
477 //\r
478 // Accumulate the total number of performance counter ticks since the periodic \r
479 // SMI handler was dispatched or resumed.\r
480 //\r
481 PeriodicSmiLibraryHandler->DispatchTotalTime += Count;\r
482 \r
483 //\r
484 // Update the checkpoint value to the current performance counter value\r
485 //\r
486 PeriodicSmiLibraryHandler->DispatchCheckPointTime = Current;\r
487 \r
488 //\r
489 // Convert the total number of performance counter ticks to 100 ns units\r
490 //\r
491 return DivU64x64Remainder (\r
492 MultU64x32 (PeriodicSmiLibraryHandler->DispatchTotalTime, 10000000), \r
493 PeriodicSmiLibraryHandler->PerfomanceCounterRate, \r
494 NULL\r
495 );\r
496}\r
497\r
498/**\r
499 This function returns control back to the SMM Foundation. When the next \r
500 periodic SMI for the currently executing handler is triggered, the periodic\r
501 SMI handler will restarted from its registered DispatchFunction entry point.\r
502 If this function is not called from within an enabled periodic SMI handler, \r
503 then control is returned to the calling function.\r
504\r
505**/\r
506VOID\r
507EFIAPI \r
508PeriodicSmiExit (\r
509 VOID\r
510 )\r
511{\r
512 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
513 \r
514 //\r
515 // If there is no active periodic SMI handler, then return \r
516 //\r
517 PeriodicSmiLibraryHandler = GetActivePeriodicSmiLibraryHandler ();\r
518 if (PeriodicSmiLibraryHandler == NULL) {\r
519 return;\r
520 }\r
521 \r
522 //\r
523 // Perform a long jump back to the point when the currently executing dispatch \r
524 // function was dispatched.\r
525 //\r
526 LongJump (&PeriodicSmiLibraryHandler->DispatchJumpBuffer, 1);\r
527 \r
528 //\r
529 // Must never return\r
530 //\r
531 ASSERT (FALSE);\r
532 CpuDeadLoop();\r
533}\r
534\r
535/**\r
536 This function yields control back to the SMM Foundation. When the next \r
537 periodic SMI for the currently executing handler is triggered, the periodic\r
538 SMI handler will be resumed and this function will return. Use of this \r
539 function requires a seperate stack for the periodic SMI handler. A non zero\r
540 stack size must be specified in PeriodicSmiEnable() for this function to be \r
541 used. \r
542 \r
543 If the stack size passed into PeriodicSmiEnable() was zero, the 0 is returned.\r
544 \r
545 If this function is not called from within an enabled periodic SMI handler, \r
546 then 0 is returned.\r
547\r
a750b4ae 548 @return The actual time in 100ns units elapsed since this function was\r
40039e28 549 called. A value of 0 indicates an unknown amount of time.\r
550\r
551**/\r
552UINT64\r
553EFIAPI \r
554PeriodicSmiYield (\r
555 VOID\r
556 )\r
557{\r
558 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
559 UINTN SetJumpFlag;\r
560\r
561 //\r
562 // If there is no active periodic SMI handler, then return \r
563 //\r
564 PeriodicSmiLibraryHandler = GetActivePeriodicSmiLibraryHandler ();\r
565 if (PeriodicSmiLibraryHandler == NULL) {\r
566 return 0;\r
567 }\r
568 \r
569 //\r
570 // If PeriodicSmiYield() is called without an allocated stack, then just return \r
571 // immediately with an elapsed time of 0.\r
572 //\r
573 if (PeriodicSmiLibraryHandler->Stack == NULL) {\r
574 return 0;\r
575 }\r
576 \r
577 //\r
578 // Set a flag so the next periodic SMI event will resume at where SetJump() \r
579 // is called below.\r
580 //\r
581 PeriodicSmiLibraryHandler->YieldFlag = TRUE;\r
582\r
583 //\r
584 // Save context in YieldJumpBuffer\r
585 // \r
586 SetJumpFlag = SetJump (&PeriodicSmiLibraryHandler->YieldJumpBuffer);\r
587 if (SetJumpFlag == 0) {\r
588 //\r
589 // The intial call to SetJump() always returns 0.\r
590 // If this is the initial call, then exit the current periodic SMI handler\r
591 //\r
592 PeriodicSmiExit ();\r
593 }\r
594 \r
595 //\r
596 // We get here when a LongJump is performed from PeriodicSmiDispatchFunctionOnCpu()\r
597 // to resume a periodic SMI handler that called PeriodicSmiYield() on the \r
598 // previous time this periodic SMI handler was dispatched.\r
599 //\r
600 // Clear the flag so the next periodic SMI dispatch will not resume.\r
601 //\r
602 PeriodicSmiLibraryHandler->YieldFlag = FALSE;\r
603\r
604 //\r
605 // Return the amount elapsed time that occured while yielded\r
606 // \r
607 return PeriodicSmiLibraryHandler->ElapsedTime;\r
608}\r
609\r
610/**\r
611 Internal worker function that transfers control to an enabled periodic SMI \r
612 handler. If the enabled periodic SMI handler was allocated its own stack, \r
613 then this function is called on that allocated stack through the BaseLin \r
614 function SwitchStack().\r
615\r
616 @param[in] Context1 Context1 parameter passed into SwitchStack().\r
617 @param[in] Context2 Context2 parameter passed into SwitchStack().\r
618\r
619**/\r
620VOID\r
621EFIAPI\r
622PeriodicSmiDispatchFunctionSwitchStack (\r
623 IN VOID *Context1, OPTIONAL\r
624 IN VOID *Context2 OPTIONAL\r
625 )\r
626{\r
627 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
628\r
629 //\r
630 // Convert Context1 to PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT * \r
631 // \r
632 PeriodicSmiLibraryHandler = (PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *)Context1;\r
633\r
634 //\r
635 // Dispatch the registered handler passing in the context that was registered\r
636 // and the amount of time that has elapsed since the previous time this \r
637 // periodic SMI handler was dispacthed.\r
638 // \r
639 PeriodicSmiLibraryHandler->DispatchFunction (\r
640 PeriodicSmiLibraryHandler->Context,\r
641 PeriodicSmiLibraryHandler->ElapsedTime\r
642 );\r
643 \r
644 //\r
645 // If this DispatchFunction() returns, then unconditially call PeriodicSmiExit()\r
646 // to perform a LongJump() back to PeriodicSmiDispatchFunctionOnCpu(). The \r
647 // LongJump() will resume exection on the original stack.\r
648 // \r
649 PeriodicSmiExit ();\r
650}\r
651\r
652/**\r
653 Internal worker function that transfers control to an enabled periodic SMI \r
654 handler on the specified logial CPU. This function determines if the periodic \r
655 SMI handler yielded and needs to be resumed. It also and switches to an \r
656 allocated stack if one was allocated in PeriodicSmiEnable().\r
657\r
658 @param[in] PeriodicSmiLibraryHandler A pointer to the context for the periodic\r
659 SMI handler to execute.\r
660 \r
661**/\r
662VOID\r
663EFIAPI\r
664PeriodicSmiDispatchFunctionOnCpu (\r
665 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler\r
666 )\r
667{\r
668 //\r
669 // Save context in DispatchJumpBuffer. The intial call to SetJump() always \r
670 // returns 0. If this is the initial call, then either resume from a prior \r
671 // call to PeriodicSmiYield() or call the DispatchFunction registerd in \r
672 // PeriodicSmiEnable() using an allocated stack if one was specified.\r
673 // \r
674 if (SetJump (&PeriodicSmiLibraryHandler->DispatchJumpBuffer) != 0) {\r
675 return;\r
676 }\r
677 \r
678 //\r
679 // Capture the performance counter value just before the periodic SMI handler \r
680 // is resumed so the amount of time the periodic SMI handler executes can be \r
681 // calculated.\r
682 //\r
683 PeriodicSmiLibraryHandler->DispatchTotalTime = 0;\r
684 PeriodicSmiLibraryHandler->DispatchCheckPointTime = GetPerformanceCounter();\r
685 \r
686 if (PeriodicSmiLibraryHandler->YieldFlag) {\r
687 //\r
688 // Perform a long jump back to the point where the previously dispatched \r
689 // function called PeriodicSmiYield(). \r
690 //\r
691 LongJump (&PeriodicSmiLibraryHandler->YieldJumpBuffer, 1);\r
692 } else if (PeriodicSmiLibraryHandler->Stack == NULL) {\r
693 //\r
694 // If Stack is NULL then call DispatchFunction using current stack passing \r
695 // in the context that was registered and the amount of time that has \r
696 // elapsed since the previous time this periodic SMI handler was dispacthed.\r
697 // \r
698 PeriodicSmiLibraryHandler->DispatchFunction (\r
699 PeriodicSmiLibraryHandler->Context,\r
700 PeriodicSmiLibraryHandler->ElapsedTime\r
701 );\r
702 \r
703 //\r
704 // If this DispatchFunction() returns, then unconditially call PeriodicSmiExit()\r
705 // to perform a LongJump() back to this function.\r
706 // \r
707 PeriodicSmiExit ();\r
708 } else {\r
709 //\r
710 // If Stack is not NULL then call DispatchFunction switching to the allocated stack\r
711 //\r
712 SwitchStack (\r
713 PeriodicSmiDispatchFunctionSwitchStack,\r
714 PeriodicSmiLibraryHandler,\r
715 NULL,\r
716 (UINT8 *)PeriodicSmiLibraryHandler->Stack + PeriodicSmiLibraryHandler->StackSize\r
717 );\r
718 } \r
719\r
720 //\r
721 // Must never return\r
722 //\r
723 ASSERT (FALSE);\r
724 CpuDeadLoop();\r
725}\r
726\r
727/**\r
728 Internal worker function that transfers control to an enabled periodic SMI \r
729 handler on the specified logial CPU. This worker function is only called \r
730 using the SMM Services Table function SmmStartupThisAp() to execute the \r
731 periodic SMI handler on a logical CPU that is different than the one that is \r
732 running the SMM Foundation. When the periodic SMI handler returns, a lock is\r
733 released to notify the CPU that is running the SMM Foundation that the periodic\r
734 SMI handler execution has finished its execution.\r
735\r
ba319b96 736 @param[in, out] Buffer A pointer to the context for the periodic SMI handler.\r
40039e28 737\r
738**/\r
739VOID\r
740EFIAPI\r
741PeriodicSmiDispatchFunctionWithLock (\r
742 IN OUT VOID *Buffer\r
743 )\r
744{\r
745 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
746 \r
747 //\r
748 // Get context\r
749 // \r
750 PeriodicSmiLibraryHandler = (PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *)Buffer;\r
751\r
752 //\r
753 // Execute dispatch function on the currently excuting logical CPU\r
754 // \r
755 PeriodicSmiDispatchFunctionOnCpu (PeriodicSmiLibraryHandler);\r
756 \r
757 //\r
758 // Release the dispatch spin lock\r
759 //\r
760 ReleaseSpinLock (&PeriodicSmiLibraryHandler->DispatchLock);\r
761}\r
762\r
763/**\r
764 Internal worker function that transfers control to a periodic SMI handler that\r
765 was enabled using PeriodicSmiEnable().\r
766\r
767 @param[in] DispatchHandle The unique handle assigned to this handler by \r
768 SmiHandlerRegister().\r
769 @param[in] Context Points to an optional handler context which was \r
770 specified when the handler was registered.\r
ba319b96 771 @param[in, out] CommBuffer A pointer to a collection of data in memory that\r
40039e28 772 will be conveyed from a non-SMM environment into \r
773 an SMM environment.\r
ba319b96 774 @param[in, out] CommBufferSize The size of the CommBuffer.\r
40039e28 775\r
776 @retval EFI_SUCCESS The interrupt was handled and quiesced.\r
777 No other handlers should still be called.\r
778 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other\r
779 handlers should still be called.\r
780 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other\r
781 handlers should still be called.\r
782 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
783 \r
784**/\r
785EFI_STATUS\r
786EFIAPI\r
787PeriodicSmiDispatchFunction (\r
788 IN EFI_HANDLE DispatchHandle,\r
789 IN CONST VOID *Context OPTIONAL,\r
790 IN OUT VOID *CommBuffer OPTIONAL,\r
791 IN OUT UINTN *CommBufferSize OPTIONAL\r
792 )\r
793{\r
794 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
795 EFI_SMM_PERIODIC_TIMER_CONTEXT *TimerContext;\r
796 EFI_STATUS Status;\r
797 \r
798 //\r
799 // Set the active periodic SMI handler\r
800 // \r
801 PeriodicSmiLibraryHandler = SetActivePeriodicSmiLibraryHandler (Context);\r
802 if (PeriodicSmiLibraryHandler == NULL) {\r
803 return EFI_NOT_FOUND;\r
804 }\r
805 \r
806 //\r
807 // Retrieve the elapsed time since the last time this periodic SMI handler was called\r
808 //\r
809 PeriodicSmiLibraryHandler->ElapsedTime = 0;\r
810 if (CommBuffer != NULL) {\r
811 TimerContext = (EFI_SMM_PERIODIC_TIMER_CONTEXT *)CommBuffer;\r
812 PeriodicSmiLibraryHandler->ElapsedTime = TimerContext->ElapsedTime;\r
813 }\r
814\r
815 //\r
816 // Dispatch the periodic SMI handler\r
817 //\r
818 if ((PeriodicSmiLibraryHandler->Cpu == PERIODIC_SMI_LIBRARY_ANY_CPU) ||\r
819 (PeriodicSmiLibraryHandler->Cpu == gSmst->CurrentlyExecutingCpu) ) {\r
820 //\r
821 // Dispatch on the currently execution CPU if the CPU specified in PeriodicSmiEnable()\r
822 // was PERIODIC_SMI_LIBARRY_ANY_CPU or the currently executing CPU matches the CPU\r
823 // that was specified in PeriodicSmiEnable().\r
824 //\r
825 PeriodicSmiDispatchFunctionOnCpu (PeriodicSmiLibraryHandler);\r
826 } else {\r
827 //\r
828 // Acquire spin lock for ths periodic SMI handler. The AP will release the\r
829 // spin lock when it is done executing the periodic SMI handler.\r
830 //\r
831 AcquireSpinLock (&PeriodicSmiLibraryHandler->DispatchLock);\r
832 \r
833 //\r
834 // Execute the periodic SMI handler on the CPU that was specified in \r
835 // PeriodicSmiEnable().\r
836 //\r
837 Status = gSmst->SmmStartupThisAp (\r
838 PeriodicSmiDispatchFunctionWithLock,\r
839 PeriodicSmiLibraryHandler->Cpu,\r
840 PeriodicSmiLibraryHandler\r
841 );\r
842 if (!EFI_ERROR (Status)) {\r
843 //\r
844 // Wait for the AP to release the spin lock.\r
845 //\r
846 while (!AcquireSpinLockOrFail (&PeriodicSmiLibraryHandler->DispatchLock)) {\r
847 CpuPause ();\r
848 }\r
849 }\r
850 \r
851 //\r
852 // Release the spin lock for the periodic SMI handler.\r
853 //\r
854 ReleaseSpinLock (&PeriodicSmiLibraryHandler->DispatchLock);\r
855 }\r
569224f9 856\r
40039e28 857 //\r
569224f9 858 // Reclaim the active periodic SMI handler if it was disabled during the current dispatch.\r
40039e28 859 //\r
569224f9
RN
860 if (PeriodicSmiLibraryHandler->DispatchHandle == NULL) {\r
861 ReclaimPeriodicSmiLibraryHandler (PeriodicSmiLibraryHandler);\r
40039e28 862 }\r
863 \r
864 //\r
865 // Update state to show that there is no active periodic SMI handler\r
866 // \r
867 SetActivePeriodicSmiLibraryHandler (NULL);\r
868\r
869 return EFI_SUCCESS;\r
870}\r
871 \r
872/**\r
873 This function enables a periodic SMI handler.\r
874 \r
ba319b96 875 @param[in, out] DispatchHandle A pointer to the handle associated with the \r
40039e28 876 enabled periodic SMI handler. This is an \r
877 optional parameter that may be NULL. If it is \r
878 NULL, then the handle will not be returned, \r
879 which means that the periodic SMI handler can \r
880 never be disabled.\r
881 @param[in] DispatchFunction A pointer to a periodic SMI handler function.\r
882 @param[in] Context Optional content to pass into DispatchFunction.\r
883 @param[in] TickPeriod The requested tick period in 100ns units that \r
884 control should be givien to the periodic SMI\r
885 handler. Must be one of the supported values\r
886 returned by PeriodicSmiSupportedPickPeriod().\r
887 @param[in] Cpu Specifies the CPU that is required to execute\r
888 the periodic SMI handler. If Cpu is \r
889 PERIODIC_SMI_LIBRARY_ANY_CPU, then the periodic \r
890 SMI handler will always be executed on the SMST \r
891 CurrentlyExecutingCpu, which may vary across \r
892 periodic SMIs. If Cpu is between 0 and the SMST \r
893 NumberOfCpus, then the periodic SMI will always\r
894 be executed on the requested CPU.\r
895 @param[in] StackSize The size, in bytes, of the stack to allocate for\r
896 use by the periodic SMI handler. If 0, then the\r
897 default stack will be used.\r
898 \r
899 @retval EFI_INVALID_PARAMETER DispatchFunction is NULL.\r
900 @retval EFI_UNSUPPORTED TickPeriod is not a supported tick period. The \r
901 supported tick periods can be retrieved using \r
902 PeriodicSmiSupportedTickPeriod().\r
903 @retval EFI_INVALID_PARAMETER Cpu is not PERIODIC_SMI_LIBRARY_ANY_CPU or in \r
904 the range 0 to SMST NumberOfCpus.\r
905 @retval EFI_OUT_OF_RESOURCES There are not enough resources to enable the \r
906 periodic SMI handler.\r
907 @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate the \r
908 stack speficied by StackSize.\r
909 @retval EFI_SUCCESS The periodic SMI handler was enabled.\r
910 \r
911**/\r
912EFI_STATUS \r
913EFIAPI\r
914PeriodicSmiEnable (\r
915 IN OUT EFI_HANDLE *DispatchHandle, OPTIONAL\r
916 IN PERIODIC_SMI_LIBRARY_HANDLER DispatchFunction,\r
917 IN CONST VOID *Context, OPTIONAL\r
918 IN UINT64 TickPeriod,\r
919 IN UINTN Cpu,\r
920 IN UINTN StackSize\r
921 )\r
922{\r
923 EFI_STATUS Status;\r
924 UINTN Index;\r
925 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
926\r
927 //\r
928 // Make sure all the input parameters are valid\r
929 // \r
930 if (DispatchFunction == NULL) {\r
931 return EFI_INVALID_PARAMETER;\r
932 }\r
933 \r
934 for (Index = 0; gSmiTickPeriodTable[Index] != 0; Index++) {\r
935 if (gSmiTickPeriodTable[Index] == TickPeriod) {\r
936 break;\r
937 }\r
938 } \r
939 if (gSmiTickPeriodTable[Index] == 0) {\r
940 return EFI_UNSUPPORTED;\r
941 }\r
942 \r
943 if (Cpu != PERIODIC_SMI_LIBRARY_ANY_CPU && Cpu >= gSmst->NumberOfCpus) {\r
944 return EFI_INVALID_PARAMETER;\r
945 }\r
946\r
947 //\r
948 // Find a free periodic SMI handler entry\r
949 // \r
950 PeriodicSmiLibraryHandler = FindFreePeriodicSmiLibraryHandler();\r
951 if (PeriodicSmiLibraryHandler == NULL) {\r
952 return EFI_OUT_OF_RESOURCES;\r
953 }\r
954\r
955 //\r
956 // Initialize a new periodic SMI handler entry\r
569224f9 957 //\r
40039e28 958 PeriodicSmiLibraryHandler->YieldFlag = FALSE;\r
959 PeriodicSmiLibraryHandler->DispatchHandle = NULL;\r
960 PeriodicSmiLibraryHandler->DispatchFunction = DispatchFunction;\r
961 PeriodicSmiLibraryHandler->Context = (VOID *)Context;\r
962 PeriodicSmiLibraryHandler->Cpu = Cpu;\r
963 PeriodicSmiLibraryHandler->StackSize = ALIGN_VALUE (StackSize, EFI_PAGE_SIZE);\r
964 if (PeriodicSmiLibraryHandler->StackSize > 0) {\r
965 PeriodicSmiLibraryHandler->Stack = AllocatePages (EFI_SIZE_TO_PAGES (PeriodicSmiLibraryHandler->StackSize));\r
966 if (PeriodicSmiLibraryHandler->Stack == NULL) {\r
967 return EFI_OUT_OF_RESOURCES;\r
968 }\r
969 ZeroMem (PeriodicSmiLibraryHandler->Stack, PeriodicSmiLibraryHandler->StackSize);\r
569224f9
RN
970 } else {\r
971 PeriodicSmiLibraryHandler->Stack = NULL;\r
40039e28 972 }\r
973 InitializeSpinLock (&PeriodicSmiLibraryHandler->DispatchLock);\r
974 PeriodicSmiLibraryHandler->PerfomanceCounterRate = GetPerformanceCounterProperties (\r
975 &PeriodicSmiLibraryHandler->PerfomanceCounterStartValue,\r
976 &PeriodicSmiLibraryHandler->PerfomanceCounterEndValue\r
977 );\r
978 PeriodicSmiLibraryHandler->RegisterContext.Period = TickPeriod;\r
979 PeriodicSmiLibraryHandler->RegisterContext.SmiTickInterval = TickPeriod;\r
980 Status = gSmmPeriodicTimerDispatch2->Register (\r
981 gSmmPeriodicTimerDispatch2,\r
982 PeriodicSmiDispatchFunction,\r
983 &PeriodicSmiLibraryHandler->RegisterContext,\r
984 &PeriodicSmiLibraryHandler->DispatchHandle\r
985 );\r
569224f9 986 if (EFI_ERROR (Status)) {\r
40039e28 987 PeriodicSmiLibraryHandler->DispatchHandle = NULL;\r
569224f9 988 ReclaimPeriodicSmiLibraryHandler (PeriodicSmiLibraryHandler);\r
40039e28 989 return EFI_OUT_OF_RESOURCES;\r
990 }\r
991 \r
992 //\r
993 // Return the registered handle if the optional DispatchHandle parameter is not NULL\r
994 //\r
995 if (DispatchHandle != NULL) {\r
996 *DispatchHandle = PeriodicSmiLibraryHandler->DispatchHandle;\r
997 }\r
998 return EFI_SUCCESS; \r
999}\r
1000\r
1001/**\r
1002 This function disables a periodic SMI handler that has been previously\r
1003 enabled with PeriodicSmiEnable().\r
1004 \r
1005 @param[in] DispatchHandle A handle associated with a previously enabled periodic \r
1006 SMI handler. This is an optional parameter that may\r
1007 be NULL. If it is NULL, then the active periodic SMI\r
1008 handlers is disabled.\r
1009\r
1010 @retval FALSE DispatchHandle is NULL and there is no active periodic SMI handler.\r
1011 @retval FALSE The periodic SMI handler specified by DispatchHandle has \r
1012 not been enabled with PeriodicSmiEnable().\r
1013 @retval TRUE The periodic SMI handler specified by DispatchHandle has \r
1014 been disabled. If DispatchHandle is NULL, then the active\r
1015 periodic SMI handler has been disabled.\r
1016 \r
1017**/\r
1018BOOLEAN \r
1019EFIAPI\r
1020PeriodicSmiDisable (\r
1021 IN EFI_HANDLE DispatchHandle OPTIONAL\r
1022 )\r
1023{\r
1024 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
1025 EFI_STATUS Status;\r
1026\r
1027 //\r
1028 // Lookup the periodic SMI handler specified by DispatchHandle\r
1029 //\r
1030 PeriodicSmiLibraryHandler = LookupPeriodicSmiLibraryHandler (DispatchHandle);\r
1031 if (PeriodicSmiLibraryHandler == NULL) {\r
1032 return FALSE;\r
1033 }\r
1034 \r
1035 //\r
1036 // Unregister the periodic SMI handler from the SMM Periodic Timer Dispatch 2 Protocol\r
1037 //\r
1038 Status = gSmmPeriodicTimerDispatch2->UnRegister (\r
1039 gSmmPeriodicTimerDispatch2,\r
1040 PeriodicSmiLibraryHandler->DispatchHandle\r
1041 );\r
1042 if (EFI_ERROR (Status)) {\r
1043 return FALSE;\r
1044 }\r
1045\r
1046 //\r
569224f9
RN
1047 // Mark the entry for the disabled periodic SMI handler as free, and\r
1048 // call ReclaimPeriodicSmiLibraryHandler to move it to the list of free\r
1049 // periodic SMI handlers.\r
40039e28 1050 //\r
569224f9 1051 PeriodicSmiLibraryHandler->DispatchHandle = NULL;\r
40039e28 1052 if (PeriodicSmiLibraryHandler != GetActivePeriodicSmiLibraryHandler ()) {\r
569224f9 1053 ReclaimPeriodicSmiLibraryHandler (PeriodicSmiLibraryHandler);\r
40039e28 1054 }\r
569224f9 1055\r
40039e28 1056 return TRUE;\r
1057}\r
1058\r
1059/**\r
1060 This constructor function caches the pointer to the SMM Periodic Timer \r
1061 Dispatch 2 Protocol and collects the list SMI tick rates that the hardware\r
1062 supports.\r
1063\r
1064 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1065 @param[in] SystemTable A pointer to the EFI System Table.\r
1066\r
1067 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
1068\r
1069**/\r
1070EFI_STATUS\r
1071EFIAPI\r
1072SmmPeriodicSmiLibConstructor (\r
1073 IN EFI_HANDLE ImageHandle,\r
1074 IN EFI_SYSTEM_TABLE *SystemTable\r
1075 )\r
1076{\r
1077 EFI_STATUS Status;\r
1078 UINT64 *SmiTickInterval;\r
1079 UINTN Count;\r
1080\r
1081 //\r
1082 // Locate the SMM Periodic Timer Dispatch 2 Protocol\r
1083 //\r
1084 Status = gSmst->SmmLocateProtocol (\r
1085 &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,\r
1086 NULL,\r
1087 (VOID **)&gSmmPeriodicTimerDispatch2\r
1088 );\r
1089 ASSERT_EFI_ERROR (Status);\r
1090 ASSERT (gSmmPeriodicTimerDispatch2 != NULL);\r
1091\r
1092 //\r
1093 // Count the number of periodic SMI tick intervals that the SMM Periodic Timer \r
1094 // Dipatch 2 Protocol supports.\r
1095 //\r
1096 SmiTickInterval = NULL;\r
1097 Count = 0;\r
1098 do {\r
1099 Status = gSmmPeriodicTimerDispatch2->GetNextShorterInterval (\r
1100 gSmmPeriodicTimerDispatch2,\r
1101 &SmiTickInterval\r
1102 );\r
1103 Count++; \r
1104 } while (SmiTickInterval != NULL); \r
1105\r
1106 //\r
1107 // Allocate a buffer for the table of supported periodic SMI tick periods.\r
1108 // \r
1109 gSmiTickPeriodTable = AllocateZeroPool (Count * sizeof (UINT64));\r
1110 ASSERT (gSmiTickPeriodTable != NULL);\r
1111 \r
1112 //\r
1113 // Fill in the table of supported periodic SMI tick periods.\r
1114 //\r
1115 SmiTickInterval = NULL;\r
1116 Count = 0;\r
1117 do {\r
1118 gSmiTickPeriodTable[Count] = 0;\r
1119 Status = gSmmPeriodicTimerDispatch2->GetNextShorterInterval (\r
1120 gSmmPeriodicTimerDispatch2,\r
1121 &SmiTickInterval\r
1122 );\r
1123 if (SmiTickInterval != NULL) {\r
1124 gSmiTickPeriodTable[Count] = *SmiTickInterval;\r
1125 }\r
1126 Count++;\r
569224f9 1127 } while (SmiTickInterval != NULL);\r
40039e28 1128\r
1129 //\r
1130 // Allocate buffer for initial set of periodic SMI handlers\r
1131 //\r
569224f9 1132 EnlargeFreePeriodicSmiLibraryHandlerList ();\r
40039e28 1133\r
1134 return EFI_SUCCESS;\r
1135}\r
1136\r
1137/**\r
1138 The constructor function caches the pointer to the SMM Periodic Timer Dispatch 2 \r
1139 Protocol and collects the list SMI tick rates that the hardware supports.\r
1140\r
1141 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1142 @param[in] SystemTable A pointer to the EFI System Table.\r
1143\r
1144 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
1145\r
1146**/\r
1147EFI_STATUS\r
1148EFIAPI\r
1149SmmPeriodicSmiLibDestructor (\r
1150 IN EFI_HANDLE ImageHandle,\r
1151 IN EFI_SYSTEM_TABLE *SystemTable\r
1152 )\r
1153{\r
569224f9
RN
1154 LIST_ENTRY *Link;\r
1155 PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT *PeriodicSmiLibraryHandler;\r
40039e28 1156\r
1157 //\r
1158 // Free the table of supported periodic SMI tick rates\r
569224f9 1159 //\r
40039e28 1160 if (gSmiTickPeriodTable != NULL) {\r
1161 FreePool (gSmiTickPeriodTable);\r
1162 }\r
1163\r
1164 //\r
1165 // Disable all periodic SMI handlers\r
569224f9
RN
1166 //\r
1167 for (Link = GetFirstNode (&gPeriodicSmiLibraryHandlers); !IsNull (&gPeriodicSmiLibraryHandlers, Link);) {\r
1168 PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (Link);\r
1169 Link = GetNextNode (&gPeriodicSmiLibraryHandlers, Link);\r
1170 PeriodicSmiDisable (PeriodicSmiLibraryHandler->DispatchHandle);\r
40039e28 1171 }\r
569224f9 1172\r
40039e28 1173 //\r
1174 // Free all the periodic SMI handler entries\r
1175 //\r
569224f9
RN
1176 for (Link = GetFirstNode (&gFreePeriodicSmiLibraryHandlers); !IsNull (&gFreePeriodicSmiLibraryHandlers, Link);) { \r
1177 PeriodicSmiLibraryHandler = PERIODIC_SMI_LIBRARY_HANDLER_CONTEXT_FROM_LINK (Link);\r
1178 Link = RemoveEntryList (Link);\r
3e5cfe98 1179 FreePool (PeriodicSmiLibraryHandler);\r
40039e28 1180 }\r
569224f9 1181\r
40039e28 1182 return EFI_SUCCESS;\r
1183}\r