2 Performance library instance used by SMM Core.
4 This library provides the performance measurement interfaces and initializes performance
5 logging for the SMM phase.
6 It initializes SMM phase performance logging by publishing the SMM Performance and PerformanceEx Protocol,
7 which is consumed by SmmPerformanceLib to logging performance data in SMM phase.
9 This library is mainly used by SMM Core to start performance logging to ensure that
10 SMM Performance and PerformanceEx Protocol are installed at the very beginning of SMM phase.
12 Caution: This module requires additional review when modified.
13 This driver will have external input - performance data and communicate buffer in SMM mode.
14 This external input must be validated carefully to avoid security issue like
15 buffer overflow, integer overflow.
17 SmmPerformanceHandlerEx(), SmmPerformanceHandler() will receive untrusted input and do basic validation.
19 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
20 This program and the accompanying materials
21 are licensed and made available under the terms and conditions of the BSD License
22 which accompanies this distribution. The full text of the license may be found at
23 http://opensource.org/licenses/bsd-license.php
25 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
26 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
31 #include "SmmCorePerformanceLibInternal.h"
34 // The data structure to hold global performance data.
36 GAUGE_DATA_HEADER
*mGaugeData
;
39 // The current maximum number of logging entries. If current number of
40 // entries exceeds this value, it will re-allocate a larger array and
41 // migration the old data to the larger array.
43 UINT32 mMaxGaugeRecords
;
46 // The handle to install Performance Protocol instance.
48 EFI_HANDLE mHandle
= NULL
;
50 BOOLEAN mPerformanceMeasurementEnabled
;
52 SPIN_LOCK mSmmPerfLock
;
55 // Interfaces for SMM Performance Protocol.
57 PERFORMANCE_PROTOCOL mPerformanceInterface
= {
64 // Interfaces for SMM PerformanceEx Protocol.
66 PERFORMANCE_EX_PROTOCOL mPerformanceExInterface
= {
73 Searches in the gauge array with keyword Handle, Token, Module and Identfier.
75 This internal function searches for the gauge entry in the gauge array.
76 If there is an entry that exactly matches the given keywords
77 and its end time stamp is zero, then the index of that gauge entry is returned;
78 otherwise, the the number of gauge entries in the array is returned.
80 @param Handle Pointer to environment specific context used
81 to identify the component being measured.
82 @param Token Pointer to a Null-terminated ASCII string
83 that identifies the component being measured.
84 @param Module Pointer to a Null-terminated ASCII string
85 that identifies the module being measured.
86 @param Identifier 32-bit identifier.
88 @retval The index of gauge entry in the array.
92 SmmSearchForGaugeEntry (
93 IN CONST VOID
*Handle
, OPTIONAL
94 IN CONST CHAR8
*Token
, OPTIONAL
95 IN CONST CHAR8
*Module
, OPTIONAL
96 IN CONST UINT32 Identifier
101 UINT32 NumberOfEntries
;
102 GAUGE_DATA_ENTRY_EX
*GaugeEntryExArray
;
107 if (Module
== NULL
) {
111 NumberOfEntries
= mGaugeData
->NumberOfEntries
;
112 GaugeEntryExArray
= (GAUGE_DATA_ENTRY_EX
*) (mGaugeData
+ 1);
116 for (Index
= 0; Index
< NumberOfEntries
; Index
++) {
117 Index2
= NumberOfEntries
- 1 - Index
;
118 if (GaugeEntryExArray
[Index2
].EndTimeStamp
== 0 &&
119 (GaugeEntryExArray
[Index2
].Handle
== (EFI_PHYSICAL_ADDRESS
) (UINTN
) Handle
) &&
120 AsciiStrnCmp (GaugeEntryExArray
[Index2
].Token
, Token
, SMM_PERFORMANCE_STRING_LENGTH
) == 0 &&
121 AsciiStrnCmp (GaugeEntryExArray
[Index2
].Module
, Module
, SMM_PERFORMANCE_STRING_LENGTH
) == 0) {
131 Adds a record at the end of the performance measurement log
132 that records the start time of a performance measurement.
134 Adds a record to the end of the performance measurement log
135 that contains the Handle, Token, Module and Identifier.
136 The end time of the new record must be set to zero.
137 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
138 If TimeStamp is zero, the start time in the record is filled in with the value
139 read from the current time stamp.
141 @param Handle Pointer to environment specific context used
142 to identify the component being measured.
143 @param Token Pointer to a Null-terminated ASCII string
144 that identifies the component being measured.
145 @param Module Pointer to a Null-terminated ASCII string
146 that identifies the module being measured.
147 @param TimeStamp 64-bit time stamp.
148 @param Identifier 32-bit identifier. If the value is 0, the created record
149 is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
151 @retval EFI_SUCCESS The data was read correctly from the device.
152 @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
158 IN CONST VOID
*Handle
, OPTIONAL
159 IN CONST CHAR8
*Token
, OPTIONAL
160 IN CONST CHAR8
*Module
, OPTIONAL
165 GAUGE_DATA_ENTRY_EX
*GaugeEntryExArray
;
167 GAUGE_DATA_HEADER
*NewGaugeData
;
168 UINTN OldGaugeDataSize
;
169 GAUGE_DATA_HEADER
*OldGaugeData
;
172 AcquireSpinLock (&mSmmPerfLock
);
174 Index
= mGaugeData
->NumberOfEntries
;
175 if (Index
>= mMaxGaugeRecords
) {
177 // Try to enlarge the scale of gauge array.
179 OldGaugeData
= mGaugeData
;
180 OldGaugeDataSize
= sizeof (GAUGE_DATA_HEADER
) + sizeof (GAUGE_DATA_ENTRY_EX
) * mMaxGaugeRecords
;
182 GaugeDataSize
= sizeof (GAUGE_DATA_HEADER
) + sizeof (GAUGE_DATA_ENTRY_EX
) * mMaxGaugeRecords
* 2;
184 NewGaugeData
= AllocateZeroPool (GaugeDataSize
);
185 if (NewGaugeData
== NULL
) {
186 ReleaseSpinLock (&mSmmPerfLock
);
187 return EFI_OUT_OF_RESOURCES
;
190 mGaugeData
= NewGaugeData
;
191 mMaxGaugeRecords
*= 2;
194 // Initialize new data array and migrate old data one.
196 mGaugeData
= CopyMem (mGaugeData
, OldGaugeData
, OldGaugeDataSize
);
198 FreePool (OldGaugeData
);
201 GaugeEntryExArray
= (GAUGE_DATA_ENTRY_EX
*) (mGaugeData
+ 1);
202 GaugeEntryExArray
[Index
].Handle
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Handle
;
205 AsciiStrnCpyS (GaugeEntryExArray
[Index
].Token
, SMM_PERFORMANCE_STRING_SIZE
, Token
, SMM_PERFORMANCE_STRING_LENGTH
);
207 if (Module
!= NULL
) {
208 AsciiStrnCpyS (GaugeEntryExArray
[Index
].Module
, SMM_PERFORMANCE_STRING_SIZE
, Module
, SMM_PERFORMANCE_STRING_LENGTH
);
211 GaugeEntryExArray
[Index
].EndTimeStamp
= 0;
212 GaugeEntryExArray
[Index
].Identifier
= Identifier
;
214 if (TimeStamp
== 0) {
215 TimeStamp
= GetPerformanceCounter ();
217 GaugeEntryExArray
[Index
].StartTimeStamp
= TimeStamp
;
219 mGaugeData
->NumberOfEntries
++;
221 ReleaseSpinLock (&mSmmPerfLock
);
227 Searches the performance measurement log from the beginning of the log
228 for the first matching record that contains a zero end time and fills in a valid end time.
230 Searches the performance measurement log from the beginning of the log
231 for the first record that matches Handle, Token and Module and has an end time value of zero.
232 If the record can not be found then return EFI_NOT_FOUND.
233 If the record is found and TimeStamp is not zero,
234 then the end time in the record is filled in with the value specified by TimeStamp.
235 If the record is found and TimeStamp is zero, then the end time in the matching record
236 is filled in with the current time stamp value.
238 @param Handle Pointer to environment specific context used
239 to identify the component being measured.
240 @param Token Pointer to a Null-terminated ASCII string
241 that identifies the component being measured.
242 @param Module Pointer to a Null-terminated ASCII string
243 that identifies the module being measured.
244 @param TimeStamp 64-bit time stamp.
245 @param Identifier 32-bit identifier. If the value is 0, the found record
246 is same as the one found by EndGauge of PERFORMANCE_PROTOCOL.
248 @retval EFI_SUCCESS The end of the measurement was recorded.
249 @retval EFI_NOT_FOUND The specified measurement record could not be found.
255 IN CONST VOID
*Handle
, OPTIONAL
256 IN CONST CHAR8
*Token
, OPTIONAL
257 IN CONST CHAR8
*Module
, OPTIONAL
262 GAUGE_DATA_ENTRY_EX
*GaugeEntryExArray
;
265 AcquireSpinLock (&mSmmPerfLock
);
267 if (TimeStamp
== 0) {
268 TimeStamp
= GetPerformanceCounter ();
271 Index
= SmmSearchForGaugeEntry (Handle
, Token
, Module
, Identifier
);
272 if (Index
>= mGaugeData
->NumberOfEntries
) {
273 ReleaseSpinLock (&mSmmPerfLock
);
274 return EFI_NOT_FOUND
;
276 GaugeEntryExArray
= (GAUGE_DATA_ENTRY_EX
*) (mGaugeData
+ 1);
277 GaugeEntryExArray
[Index
].EndTimeStamp
= TimeStamp
;
279 ReleaseSpinLock (&mSmmPerfLock
);
285 Retrieves a previously logged performance measurement.
286 It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,
287 and then assign the Identifier with 0.
289 Retrieves the performance log entry from the performance log specified by LogEntryKey.
290 If it stands for a valid entry, then EFI_SUCCESS is returned and
291 GaugeDataEntryEx stores the pointer to that entry.
293 @param LogEntryKey The key for the previous performance measurement log entry.
294 If 0, then the first performance measurement log entry is retrieved.
295 @param GaugeDataEntryEx The indirect pointer to the extended gauge data entry specified by LogEntryKey
296 if the retrieval is successful.
298 @retval EFI_SUCCESS The GuageDataEntryEx is successfully found based on LogEntryKey.
299 @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
300 @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
301 @retval EFI_INVALIDE_PARAMETER GaugeDataEntryEx is NULL.
307 IN UINTN LogEntryKey
,
308 OUT GAUGE_DATA_ENTRY_EX
**GaugeDataEntryEx
311 UINTN NumberOfEntries
;
312 GAUGE_DATA_ENTRY_EX
*GaugeEntryExArray
;
314 NumberOfEntries
= (UINTN
) (mGaugeData
->NumberOfEntries
);
315 if (LogEntryKey
> NumberOfEntries
) {
316 return EFI_INVALID_PARAMETER
;
318 if (LogEntryKey
== NumberOfEntries
) {
319 return EFI_NOT_FOUND
;
322 GaugeEntryExArray
= (GAUGE_DATA_ENTRY_EX
*) (mGaugeData
+ 1);
324 if (GaugeDataEntryEx
== NULL
) {
325 return EFI_INVALID_PARAMETER
;
327 *GaugeDataEntryEx
= &GaugeEntryExArray
[LogEntryKey
];
333 Adds a record at the end of the performance measurement log
334 that records the start time of a performance measurement.
336 Adds a record to the end of the performance measurement log
337 that contains the Handle, Token, and Module.
338 The end time of the new record must be set to zero.
339 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
340 If TimeStamp is zero, the start time in the record is filled in with the value
341 read from the current time stamp.
343 @param Handle Pointer to environment specific context used
344 to identify the component being measured.
345 @param Token Pointer to a Null-terminated ASCII string
346 that identifies the component being measured.
347 @param Module Pointer to a Null-terminated ASCII string
348 that identifies the module being measured.
349 @param TimeStamp 64-bit time stamp.
351 @retval EFI_SUCCESS The data was read correctly from the device.
352 @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
358 IN CONST VOID
*Handle
, OPTIONAL
359 IN CONST CHAR8
*Token
, OPTIONAL
360 IN CONST CHAR8
*Module
, OPTIONAL
364 return StartGaugeEx (Handle
, Token
, Module
, TimeStamp
, 0);
368 Searches the performance measurement log from the beginning of the log
369 for the first matching record that contains a zero end time and fills in a valid end time.
371 Searches the performance measurement log from the beginning of the log
372 for the first record that matches Handle, Token, and Module and has an end time value of zero.
373 If the record can not be found then return EFI_NOT_FOUND.
374 If the record is found and TimeStamp is not zero,
375 then the end time in the record is filled in with the value specified by TimeStamp.
376 If the record is found and TimeStamp is zero, then the end time in the matching record
377 is filled in with the current time stamp value.
379 @param Handle Pointer to environment specific context used
380 to identify the component being measured.
381 @param Token Pointer to a Null-terminated ASCII string
382 that identifies the component being measured.
383 @param Module Pointer to a Null-terminated ASCII string
384 that identifies the module being measured.
385 @param TimeStamp 64-bit time stamp.
387 @retval EFI_SUCCESS The end of the measurement was recorded.
388 @retval EFI_NOT_FOUND The specified measurement record could not be found.
394 IN CONST VOID
*Handle
, OPTIONAL
395 IN CONST CHAR8
*Token
, OPTIONAL
396 IN CONST CHAR8
*Module
, OPTIONAL
400 return EndGaugeEx (Handle
, Token
, Module
, TimeStamp
, 0);
404 Retrieves a previously logged performance measurement.
405 It can also retrieve the log created by StartGaugeEx and EndGaugeEx of PERFORMANCE_EX_PROTOCOL,
406 and then eliminate the Identifier.
408 Retrieves the performance log entry from the performance log specified by LogEntryKey.
409 If it stands for a valid entry, then EFI_SUCCESS is returned and
410 GaugeDataEntry stores the pointer to that entry.
412 @param LogEntryKey The key for the previous performance measurement log entry.
413 If 0, then the first performance measurement log entry is retrieved.
414 @param GaugeDataEntry The indirect pointer to the gauge data entry specified by LogEntryKey
415 if the retrieval is successful.
417 @retval EFI_SUCCESS The GuageDataEntry is successfully found based on LogEntryKey.
418 @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
419 @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
420 @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL.
426 IN UINTN LogEntryKey
,
427 OUT GAUGE_DATA_ENTRY
**GaugeDataEntry
431 GAUGE_DATA_ENTRY_EX
*GaugeEntryEx
;
435 Status
= GetGaugeEx (LogEntryKey
, &GaugeEntryEx
);
436 if (EFI_ERROR (Status
)) {
440 if (GaugeDataEntry
== NULL
) {
441 return EFI_INVALID_PARAMETER
;
444 *GaugeDataEntry
= (GAUGE_DATA_ENTRY
*) GaugeEntryEx
;
450 Communication service SMI Handler entry.
452 This SMI handler provides services for the performance wrapper driver.
454 Caution: This function may receive untrusted input.
455 Communicate buffer and buffer size are external input, so this function will do basic validation.
457 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
458 @param[in] RegisterContext Points to an optional handler context which was specified when the
459 handler was registered.
460 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
461 be conveyed from a non-SMM environment into an SMM environment.
462 @param[in, out] CommBufferSize The size of the CommBuffer.
464 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
465 should still be called.
466 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
468 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
470 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
474 SmmPerformanceHandlerEx (
475 IN EFI_HANDLE DispatchHandle
,
476 IN CONST VOID
*RegisterContext
,
477 IN OUT VOID
*CommBuffer
,
478 IN OUT UINTN
*CommBufferSize
482 SMM_PERF_COMMUNICATE_EX
*SmmPerfCommData
;
483 GAUGE_DATA_ENTRY_EX
*GaugeEntryExArray
;
486 GAUGE_DATA_ENTRY_EX
*GaugeDataEx
;
487 UINTN NumberOfEntries
;
489 UINTN TempCommBufferSize
;
491 GaugeEntryExArray
= NULL
;
494 // If input is invalid, stop processing this SMI
496 if (CommBuffer
== NULL
|| CommBufferSize
== NULL
) {
500 TempCommBufferSize
= *CommBufferSize
;
502 if(TempCommBufferSize
< sizeof (SMM_PERF_COMMUNICATE_EX
)) {
506 if (!SmmIsBufferOutsideSmmValid ((UINTN
)CommBuffer
, TempCommBufferSize
)) {
507 DEBUG ((EFI_D_ERROR
, "SmmPerformanceHandlerEx: SMM communcation data buffer in SMRAM or overflow!\n"));
511 SmmPerfCommData
= (SMM_PERF_COMMUNICATE_EX
*)CommBuffer
;
513 switch (SmmPerfCommData
->Function
) {
514 case SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER
:
515 SmmPerfCommData
->NumberOfEntries
= mGaugeData
->NumberOfEntries
;
516 Status
= EFI_SUCCESS
;
519 case SMM_PERF_FUNCTION_GET_GAUGE_DATA
:
520 GaugeDataEx
= SmmPerfCommData
->GaugeDataEx
;
521 NumberOfEntries
= SmmPerfCommData
->NumberOfEntries
;
522 LogEntryKey
= SmmPerfCommData
->LogEntryKey
;
523 if (GaugeDataEx
== NULL
|| NumberOfEntries
== 0 || LogEntryKey
> mGaugeData
->NumberOfEntries
||
524 NumberOfEntries
> mGaugeData
->NumberOfEntries
|| LogEntryKey
> (mGaugeData
->NumberOfEntries
- NumberOfEntries
)) {
525 Status
= EFI_INVALID_PARAMETER
;
532 DataSize
= MultU64x32 (NumberOfEntries
, sizeof(GAUGE_DATA_ENTRY_EX
));
533 if (!SmmIsBufferOutsideSmmValid ((UINTN
) GaugeDataEx
, DataSize
)) {
534 DEBUG ((EFI_D_ERROR
, "SmmPerformanceHandlerEx: SMM Performance Data buffer in SMRAM or overflow!\n"));
535 Status
= EFI_ACCESS_DENIED
;
539 GaugeEntryExArray
= (GAUGE_DATA_ENTRY_EX
*) (mGaugeData
+ 1);
541 for (Index
= 0; Index
< NumberOfEntries
; Index
++) {
543 (UINT8
*) &GaugeDataEx
[Index
],
544 (UINT8
*) &GaugeEntryExArray
[LogEntryKey
++],
545 sizeof (GAUGE_DATA_ENTRY_EX
)
548 Status
= EFI_SUCCESS
;
552 Status
= EFI_UNSUPPORTED
;
556 SmmPerfCommData
->ReturnStatus
= Status
;
562 Communication service SMI Handler entry.
564 This SMI handler provides services for the performance wrapper driver.
566 Caution: This function may receive untrusted input.
567 Communicate buffer and buffer size are external input, so this function will do basic validation.
569 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
570 @param[in] RegisterContext Points to an optional handler context which was specified when the
571 handler was registered.
572 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
573 be conveyed from a non-SMM environment into an SMM environment.
574 @param[in, out] CommBufferSize The size of the CommBuffer.
576 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
577 should still be called.
578 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
580 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
582 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
586 SmmPerformanceHandler (
587 IN EFI_HANDLE DispatchHandle
,
588 IN CONST VOID
*RegisterContext
,
589 IN OUT VOID
*CommBuffer
,
590 IN OUT UINTN
*CommBufferSize
594 SMM_PERF_COMMUNICATE
*SmmPerfCommData
;
595 GAUGE_DATA_ENTRY_EX
*GaugeEntryExArray
;
598 GAUGE_DATA_ENTRY
*GaugeData
;
599 UINTN NumberOfEntries
;
601 UINTN TempCommBufferSize
;
603 GaugeEntryExArray
= NULL
;
606 // If input is invalid, stop processing this SMI
608 if (CommBuffer
== NULL
|| CommBufferSize
== NULL
) {
612 TempCommBufferSize
= *CommBufferSize
;
614 if(TempCommBufferSize
< sizeof (SMM_PERF_COMMUNICATE
)) {
618 if (!SmmIsBufferOutsideSmmValid ((UINTN
)CommBuffer
, TempCommBufferSize
)) {
619 DEBUG ((EFI_D_ERROR
, "SmmPerformanceHandler: SMM communcation data buffer in SMRAM or overflow!\n"));
623 SmmPerfCommData
= (SMM_PERF_COMMUNICATE
*)CommBuffer
;
625 switch (SmmPerfCommData
->Function
) {
626 case SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER
:
627 SmmPerfCommData
->NumberOfEntries
= mGaugeData
->NumberOfEntries
;
628 Status
= EFI_SUCCESS
;
631 case SMM_PERF_FUNCTION_GET_GAUGE_DATA
:
632 GaugeData
= SmmPerfCommData
->GaugeData
;
633 NumberOfEntries
= SmmPerfCommData
->NumberOfEntries
;
634 LogEntryKey
= SmmPerfCommData
->LogEntryKey
;
635 if (GaugeData
== NULL
|| NumberOfEntries
== 0 || LogEntryKey
> mGaugeData
->NumberOfEntries
||
636 NumberOfEntries
> mGaugeData
->NumberOfEntries
|| LogEntryKey
> (mGaugeData
->NumberOfEntries
- NumberOfEntries
)) {
637 Status
= EFI_INVALID_PARAMETER
;
644 DataSize
= MultU64x32 (NumberOfEntries
, sizeof(GAUGE_DATA_ENTRY
));
645 if (!SmmIsBufferOutsideSmmValid ((UINTN
) GaugeData
, DataSize
)) {
646 DEBUG ((EFI_D_ERROR
, "SmmPerformanceHandler: SMM Performance Data buffer in SMRAM or overflow!\n"));
647 Status
= EFI_ACCESS_DENIED
;
651 GaugeEntryExArray
= (GAUGE_DATA_ENTRY_EX
*) (mGaugeData
+ 1);
653 for (Index
= 0; Index
< NumberOfEntries
; Index
++) {
655 (UINT8
*) &GaugeData
[Index
],
656 (UINT8
*) &GaugeEntryExArray
[LogEntryKey
++],
657 sizeof (GAUGE_DATA_ENTRY
)
660 Status
= EFI_SUCCESS
;
664 Status
= EFI_UNSUPPORTED
;
668 SmmPerfCommData
->ReturnStatus
= Status
;
674 SmmBase2 protocol notify callback function, when SMST and SMM memory service get initialized
675 this function is callbacked to initialize the Smm Performance Lib
677 @param Event The event of notify protocol.
678 @param Context Notify event context.
683 InitializeSmmCorePerformanceLib (
692 // Initialize spin lock
694 InitializeSpinLock (&mSmmPerfLock
);
696 mMaxGaugeRecords
= INIT_SMM_GAUGE_DATA_ENTRIES
;
698 mGaugeData
= AllocateZeroPool (sizeof (GAUGE_DATA_HEADER
) + (sizeof (GAUGE_DATA_ENTRY_EX
) * mMaxGaugeRecords
));
699 ASSERT (mGaugeData
!= NULL
);
702 // Install the protocol interfaces.
704 Status
= gSmst
->SmmInstallProtocolInterface (
706 &gSmmPerformanceProtocolGuid
,
707 EFI_NATIVE_INTERFACE
,
708 &mPerformanceInterface
710 ASSERT_EFI_ERROR (Status
);
712 Status
= gSmst
->SmmInstallProtocolInterface (
714 &gSmmPerformanceExProtocolGuid
,
715 EFI_NATIVE_INTERFACE
,
716 &mPerformanceExInterface
718 ASSERT_EFI_ERROR (Status
);
721 /// Register SMM Performance SMI handler
724 Status
= gSmst
->SmiHandlerRegister (SmmPerformanceHandler
, &gSmmPerformanceProtocolGuid
, &Handle
);
725 ASSERT_EFI_ERROR (Status
);
726 Status
= gSmst
->SmiHandlerRegister (SmmPerformanceHandlerEx
, &gSmmPerformanceExProtocolGuid
, &Handle
);
727 ASSERT_EFI_ERROR (Status
);
731 The constructor function initializes the Performance Measurement Enable flag and
732 registers SmmBase2 protocol notify callback.
733 It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
735 @param ImageHandle The firmware allocated handle for the EFI image.
736 @param SystemTable A pointer to the EFI System Table.
738 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
743 SmmCorePerformanceLibConstructor (
744 IN EFI_HANDLE ImageHandle
,
745 IN EFI_SYSTEM_TABLE
*SystemTable
752 mPerformanceMeasurementEnabled
= (BOOLEAN
) ((PcdGet8(PcdPerformanceLibraryPropertyMask
) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED
) != 0);
753 if (!mPerformanceMeasurementEnabled
) {
755 // Do not initialize performance infrastructure if not required.
761 // Create the events to do the library init.
763 Status
= gBS
->CreateEvent (
766 InitializeSmmCorePerformanceLib
,
770 ASSERT_EFI_ERROR (Status
);
773 // Register for protocol notifications on this event
775 Status
= gBS
->RegisterProtocolNotify (
776 &gEfiSmmBase2ProtocolGuid
,
781 ASSERT_EFI_ERROR (Status
);
787 Adds a record at the end of the performance measurement log
788 that records the start time of a performance measurement.
790 Adds a record to the end of the performance measurement log
791 that contains the Handle, Token, Module and Identifier.
792 The end time of the new record must be set to zero.
793 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
794 If TimeStamp is zero, the start time in the record is filled in with the value
795 read from the current time stamp.
797 @param Handle Pointer to environment specific context used
798 to identify the component being measured.
799 @param Token Pointer to a Null-terminated ASCII string
800 that identifies the component being measured.
801 @param Module Pointer to a Null-terminated ASCII string
802 that identifies the module being measured.
803 @param TimeStamp 64-bit time stamp.
804 @param Identifier 32-bit identifier. If the value is 0, the created record
805 is same as the one created by StartPerformanceMeasurement.
807 @retval RETURN_SUCCESS The start of the measurement was recorded.
808 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
813 StartPerformanceMeasurementEx (
814 IN CONST VOID
*Handle
, OPTIONAL
815 IN CONST CHAR8
*Token
, OPTIONAL
816 IN CONST CHAR8
*Module
, OPTIONAL
821 return (RETURN_STATUS
) StartGaugeEx (Handle
, Token
, Module
, TimeStamp
, Identifier
);
825 Searches the performance measurement log from the beginning of the log
826 for the first matching record that contains a zero end time and fills in a valid end time.
828 Searches the performance measurement log from the beginning of the log
829 for the first record that matches Handle, Token and Module and has an end time value of zero.
830 If the record can not be found then return RETURN_NOT_FOUND.
831 If the record is found and TimeStamp is not zero,
832 then the end time in the record is filled in with the value specified by TimeStamp.
833 If the record is found and TimeStamp is zero, then the end time in the matching record
834 is filled in with the current time stamp value.
836 @param Handle Pointer to environment specific context used
837 to identify the component being measured.
838 @param Token Pointer to a Null-terminated ASCII string
839 that identifies the component being measured.
840 @param Module Pointer to a Null-terminated ASCII string
841 that identifies the module being measured.
842 @param TimeStamp 64-bit time stamp.
843 @param Identifier 32-bit identifier. If the value is 0, the found record
844 is same as the one found by EndPerformanceMeasurement.
846 @retval RETURN_SUCCESS The end of the measurement was recorded.
847 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
852 EndPerformanceMeasurementEx (
853 IN CONST VOID
*Handle
, OPTIONAL
854 IN CONST CHAR8
*Token
, OPTIONAL
855 IN CONST CHAR8
*Module
, OPTIONAL
860 return (RETURN_STATUS
) EndGaugeEx (Handle
, Token
, Module
, TimeStamp
, Identifier
);
864 Attempts to retrieve a performance measurement log entry from the performance measurement log.
865 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
866 and then assign the Identifier with 0.
868 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
869 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
870 and the key for the second entry in the log is returned. If the performance log is empty,
871 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
872 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
873 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
874 retrieved and an implementation specific non-zero key value that specifies the end of the performance
875 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
876 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
877 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
878 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
879 If Handle is NULL, then ASSERT().
880 If Token is NULL, then ASSERT().
881 If Module is NULL, then ASSERT().
882 If StartTimeStamp is NULL, then ASSERT().
883 If EndTimeStamp is NULL, then ASSERT().
884 If Identifier is NULL, then ASSERT().
886 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
887 0, then the first performance measurement log entry is retrieved.
888 On exit, the key of the next performance log entry.
889 @param Handle Pointer to environment specific context used to identify the component
891 @param Token Pointer to a Null-terminated ASCII string that identifies the component
893 @param Module Pointer to a Null-terminated ASCII string that identifies the module
895 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
897 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
899 @param Identifier Pointer to the 32-bit identifier that was recorded.
901 @return The key for the next performance log entry (in general case).
906 GetPerformanceMeasurementEx (
907 IN UINTN LogEntryKey
,
908 OUT CONST VOID
**Handle
,
909 OUT CONST CHAR8
**Token
,
910 OUT CONST CHAR8
**Module
,
911 OUT UINT64
*StartTimeStamp
,
912 OUT UINT64
*EndTimeStamp
,
913 OUT UINT32
*Identifier
917 GAUGE_DATA_ENTRY_EX
*GaugeData
;
921 ASSERT (Handle
!= NULL
);
922 ASSERT (Token
!= NULL
);
923 ASSERT (Module
!= NULL
);
924 ASSERT (StartTimeStamp
!= NULL
);
925 ASSERT (EndTimeStamp
!= NULL
);
926 ASSERT (Identifier
!= NULL
);
928 Status
= GetGaugeEx (LogEntryKey
++, &GaugeData
);
931 // Make sure that LogEntryKey is a valid log entry key,
933 ASSERT (Status
!= EFI_INVALID_PARAMETER
);
935 if (EFI_ERROR (Status
)) {
937 // The LogEntryKey is the last entry (equals to the total entry number).
942 ASSERT (GaugeData
!= NULL
);
944 *Handle
= (VOID
*) (UINTN
) GaugeData
->Handle
;
945 *Token
= GaugeData
->Token
;
946 *Module
= GaugeData
->Module
;
947 *StartTimeStamp
= GaugeData
->StartTimeStamp
;
948 *EndTimeStamp
= GaugeData
->EndTimeStamp
;
949 *Identifier
= GaugeData
->Identifier
;
955 Adds a record at the end of the performance measurement log
956 that records the start time of a performance measurement.
958 Adds a record to the end of the performance measurement log
959 that contains the Handle, Token, and Module.
960 The end time of the new record must be set to zero.
961 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
962 If TimeStamp is zero, the start time in the record is filled in with the value
963 read from the current time stamp.
965 @param Handle Pointer to environment specific context used
966 to identify the component being measured.
967 @param Token Pointer to a Null-terminated ASCII string
968 that identifies the component being measured.
969 @param Module Pointer to a Null-terminated ASCII string
970 that identifies the module being measured.
971 @param TimeStamp 64-bit time stamp.
973 @retval RETURN_SUCCESS The start of the measurement was recorded.
974 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
979 StartPerformanceMeasurement (
980 IN CONST VOID
*Handle
, OPTIONAL
981 IN CONST CHAR8
*Token
, OPTIONAL
982 IN CONST CHAR8
*Module
, OPTIONAL
986 return StartPerformanceMeasurementEx (Handle
, Token
, Module
, TimeStamp
, 0);
990 Searches the performance measurement log from the beginning of the log
991 for the first matching record that contains a zero end time and fills in a valid end time.
993 Searches the performance measurement log from the beginning of the log
994 for the first record that matches Handle, Token, and Module and has an end time value of zero.
995 If the record can not be found then return RETURN_NOT_FOUND.
996 If the record is found and TimeStamp is not zero,
997 then the end time in the record is filled in with the value specified by TimeStamp.
998 If the record is found and TimeStamp is zero, then the end time in the matching record
999 is filled in with the current time stamp value.
1001 @param Handle Pointer to environment specific context used
1002 to identify the component being measured.
1003 @param Token Pointer to a Null-terminated ASCII string
1004 that identifies the component being measured.
1005 @param Module Pointer to a Null-terminated ASCII string
1006 that identifies the module being measured.
1007 @param TimeStamp 64-bit time stamp.
1009 @retval RETURN_SUCCESS The end of the measurement was recorded.
1010 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
1015 EndPerformanceMeasurement (
1016 IN CONST VOID
*Handle
, OPTIONAL
1017 IN CONST CHAR8
*Token
, OPTIONAL
1018 IN CONST CHAR8
*Module
, OPTIONAL
1022 return EndPerformanceMeasurementEx (Handle
, Token
, Module
, TimeStamp
, 0);
1026 Attempts to retrieve a performance measurement log entry from the performance measurement log.
1027 It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
1028 and then eliminate the Identifier.
1030 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
1031 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
1032 and the key for the second entry in the log is returned. If the performance log is empty,
1033 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
1034 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
1035 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
1036 retrieved and an implementation specific non-zero key value that specifies the end of the performance
1037 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
1038 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
1039 the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
1040 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
1041 If Handle is NULL, then ASSERT().
1042 If Token is NULL, then ASSERT().
1043 If Module is NULL, then ASSERT().
1044 If StartTimeStamp is NULL, then ASSERT().
1045 If EndTimeStamp is NULL, then ASSERT().
1047 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
1048 0, then the first performance measurement log entry is retrieved.
1049 On exit, the key of the next performance log entry.
1050 @param Handle Pointer to environment specific context used to identify the component
1052 @param Token Pointer to a Null-terminated ASCII string that identifies the component
1054 @param Module Pointer to a Null-terminated ASCII string that identifies the module
1056 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1058 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1061 @return The key for the next performance log entry (in general case).
1066 GetPerformanceMeasurement (
1067 IN UINTN LogEntryKey
,
1068 OUT CONST VOID
**Handle
,
1069 OUT CONST CHAR8
**Token
,
1070 OUT CONST CHAR8
**Module
,
1071 OUT UINT64
*StartTimeStamp
,
1072 OUT UINT64
*EndTimeStamp
1076 return GetPerformanceMeasurementEx (LogEntryKey
, Handle
, Token
, Module
, StartTimeStamp
, EndTimeStamp
, &Identifier
);
1080 Returns TRUE if the performance measurement macros are enabled.
1082 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1083 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
1085 @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1086 PcdPerformanceLibraryPropertyMask is set.
1087 @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1088 PcdPerformanceLibraryPropertyMask is clear.
1093 PerformanceMeasurementEnabled (
1097 return mPerformanceMeasurementEnabled
;