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 Performance 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 Protocol is installed at the very beginning of SMM phase.
12 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
13 This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
24 #include "SmmCorePerformanceLibInternal.h"
27 // The data structure to hold global performance data.
29 GAUGE_DATA_HEADER
*mGaugeData
;
32 // The current maximum number of logging entries. If current number of
33 // entries exceeds this value, it will re-allocate a larger array and
34 // migration the old data to the larger array.
36 UINT32 mMaxGaugeRecords
;
39 // The handle to install Performance Protocol instance.
41 EFI_HANDLE mHandle
= NULL
;
43 BOOLEAN mPerformanceMeasurementEnabled
;
45 SPIN_LOCK mSmmPerfLock
;
47 EFI_SMRAM_DESCRIPTOR
*mSmramRanges
;
48 UINTN mSmramRangeCount
;
51 // Interfaces for performance protocol.
53 PERFORMANCE_PROTOCOL mPerformanceInterface
= {
60 Searches in the gauge array with keyword Handle, Token and Module.
62 This internal function searches for the gauge entry in the gauge array.
63 If there is an entry that exactly matches the given key word triple
64 and its end time stamp is zero, then the index of that gauge entry is returned;
65 otherwise, the the number of gauge entries in the array is returned.
67 @param Handle Pointer to environment specific context used
68 to identify the component being measured.
69 @param Token Pointer to a Null-terminated ASCII string
70 that identifies the component being measured.
71 @param Module Pointer to a Null-terminated ASCII string
72 that identifies the module being measured.
74 @retval The index of gauge entry in the array.
78 SmmSearchForGaugeEntry (
79 IN CONST VOID
*Handle
, OPTIONAL
80 IN CONST CHAR8
*Token
, OPTIONAL
81 IN CONST CHAR8
*Module OPTIONAL
85 UINT32 NumberOfEntries
;
86 GAUGE_DATA_ENTRY
*GaugeEntryArray
;
95 NumberOfEntries
= mGaugeData
->NumberOfEntries
;
96 GaugeEntryArray
= (GAUGE_DATA_ENTRY
*) (mGaugeData
+ 1);
98 for (Index
= 0; Index
< NumberOfEntries
; Index
++) {
99 if ((GaugeEntryArray
[Index
].Handle
== (EFI_PHYSICAL_ADDRESS
) (UINTN
) Handle
) &&
100 AsciiStrnCmp (GaugeEntryArray
[Index
].Token
, Token
, SMM_PERFORMANCE_STRING_LENGTH
) == 0 &&
101 AsciiStrnCmp (GaugeEntryArray
[Index
].Module
, Module
, SMM_PERFORMANCE_STRING_LENGTH
) == 0 &&
102 GaugeEntryArray
[Index
].EndTimeStamp
== 0) {
111 Adds a record at the end of the performance measurement log
112 that records the start time of a performance measurement.
114 Adds a record to the end of the performance measurement log
115 that contains the Handle, Token, and Module.
116 The end time of the new record must be set to zero.
117 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
118 If TimeStamp is zero, the start time in the record is filled in with the value
119 read from the current time stamp.
121 @param Handle Pointer to environment specific context used
122 to identify the component being measured.
123 @param Token Pointer to a Null-terminated ASCII string
124 that identifies the component being measured.
125 @param Module Pointer to a Null-terminated ASCII string
126 that identifies the module being measured.
127 @param TimeStamp 64-bit time stamp.
129 @retval EFI_SUCCESS The data was read correctly from the device.
130 @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
136 IN CONST VOID
*Handle
, OPTIONAL
137 IN CONST CHAR8
*Token
, OPTIONAL
138 IN CONST CHAR8
*Module
, OPTIONAL
142 GAUGE_DATA_ENTRY
*GaugeEntryArray
;
144 UINTN OldGaugeDataSize
;
145 GAUGE_DATA_HEADER
*OldGaugeData
;
148 AcquireSpinLock (&mSmmPerfLock
);
150 Index
= mGaugeData
->NumberOfEntries
;
151 if (Index
>= mMaxGaugeRecords
) {
153 // Try to enlarge the scale of gauge array.
155 OldGaugeData
= mGaugeData
;
156 OldGaugeDataSize
= sizeof (GAUGE_DATA_HEADER
) + sizeof (GAUGE_DATA_ENTRY
) * mMaxGaugeRecords
;
158 mMaxGaugeRecords
*= 2;
159 GaugeDataSize
= sizeof (GAUGE_DATA_HEADER
) + sizeof (GAUGE_DATA_ENTRY
) * mMaxGaugeRecords
;
161 mGaugeData
= AllocateZeroPool (GaugeDataSize
);
162 if (mGaugeData
== NULL
) {
163 return EFI_OUT_OF_RESOURCES
;
166 // Initialize new data array and migrate old data one.
168 mGaugeData
= CopyMem (mGaugeData
, OldGaugeData
, OldGaugeDataSize
);
170 FreePool (OldGaugeData
);
173 GaugeEntryArray
= (GAUGE_DATA_ENTRY
*) (mGaugeData
+ 1);
174 GaugeEntryArray
[Index
].Handle
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Handle
;
177 AsciiStrnCpy (GaugeEntryArray
[Index
].Token
, Token
, SMM_PERFORMANCE_STRING_LENGTH
);
179 if (Module
!= NULL
) {
180 AsciiStrnCpy (GaugeEntryArray
[Index
].Module
, Module
, SMM_PERFORMANCE_STRING_LENGTH
);
183 if (TimeStamp
== 0) {
184 TimeStamp
= GetPerformanceCounter ();
186 GaugeEntryArray
[Index
].StartTimeStamp
= TimeStamp
;
188 mGaugeData
->NumberOfEntries
++;
190 ReleaseSpinLock (&mSmmPerfLock
);
196 Searches the performance measurement log from the beginning of the log
197 for the first matching record that contains a zero end time and fills in a valid end time.
199 Searches the performance measurement log from the beginning of the log
200 for the first record that matches Handle, Token, and Module and has an end time value of zero.
201 If the record can not be found then return EFI_NOT_FOUND.
202 If the record is found and TimeStamp is not zero,
203 then the end time in the record is filled in with the value specified by TimeStamp.
204 If the record is found and TimeStamp is zero, then the end time in the matching record
205 is filled in with the current time stamp value.
207 @param Handle Pointer to environment specific context used
208 to identify the component being measured.
209 @param Token Pointer to a Null-terminated ASCII string
210 that identifies the component being measured.
211 @param Module Pointer to a Null-terminated ASCII string
212 that identifies the module being measured.
213 @param TimeStamp 64-bit time stamp.
215 @retval EFI_SUCCESS The end of the measurement was recorded.
216 @retval EFI_NOT_FOUND The specified measurement record could not be found.
222 IN CONST VOID
*Handle
, OPTIONAL
223 IN CONST CHAR8
*Token
, OPTIONAL
224 IN CONST CHAR8
*Module
, OPTIONAL
228 GAUGE_DATA_ENTRY
*GaugeEntryArray
;
231 if (TimeStamp
== 0) {
232 TimeStamp
= GetPerformanceCounter ();
235 Index
= SmmSearchForGaugeEntry (Handle
, Token
, Module
);
236 if (Index
>= mGaugeData
->NumberOfEntries
) {
237 return EFI_NOT_FOUND
;
239 GaugeEntryArray
= (GAUGE_DATA_ENTRY
*) (mGaugeData
+ 1);
240 GaugeEntryArray
[Index
].EndTimeStamp
= TimeStamp
;
246 Retrieves a previously logged performance measurement.
248 Retrieves the performance log entry from the performance log specified by LogEntryKey.
249 If it stands for a valid entry, then EFI_SUCCESS is returned and
250 GaugeDataEntry stores the pointer to that entry.
252 @param LogEntryKey The key for the previous performance measurement log entry.
253 If 0, then the first performance measurement log entry is retrieved.
254 @param GaugeDataEntry The indirect pointer to the gauge data entry specified by LogEntryKey
255 if the retrieval is successful.
257 @retval EFI_SUCCESS The GuageDataEntry is successfully found based on LogEntryKey.
258 @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
259 @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
260 @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL.
266 IN UINTN LogEntryKey
,
267 OUT GAUGE_DATA_ENTRY
**GaugeDataEntry
270 UINTN NumberOfEntries
;
271 GAUGE_DATA_ENTRY
*LogEntryArray
;
273 NumberOfEntries
= (UINTN
) (mGaugeData
->NumberOfEntries
);
274 if (LogEntryKey
> NumberOfEntries
) {
275 return EFI_INVALID_PARAMETER
;
277 if (LogEntryKey
== NumberOfEntries
) {
278 return EFI_NOT_FOUND
;
281 LogEntryArray
= (GAUGE_DATA_ENTRY
*) (mGaugeData
+ 1);
283 if (GaugeDataEntry
== NULL
) {
284 return EFI_INVALID_PARAMETER
;
286 *GaugeDataEntry
= &LogEntryArray
[LogEntryKey
];
293 This function check if the address is in SMRAM.
295 @param Buffer the buffer address to be checked.
296 @param Length the buffer length to be checked.
298 @retval TRUE this address is in SMRAM.
299 @retval FALSE this address is NOT in SMRAM.
303 IN EFI_PHYSICAL_ADDRESS Buffer
,
309 for (Index
= 0; Index
< mSmramRangeCount
; Index
++) {
310 if (((Buffer
>= mSmramRanges
[Index
].CpuStart
) && (Buffer
< mSmramRanges
[Index
].CpuStart
+ mSmramRanges
[Index
].PhysicalSize
)) ||
311 ((mSmramRanges
[Index
].CpuStart
>= Buffer
) && (mSmramRanges
[Index
].CpuStart
< Buffer
+ Length
))) {
320 Communication service SMI Handler entry.
322 This SMI handler provides services for the variable wrapper driver.
324 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
325 @param[in] RegisterContext Points to an optional handler context which was specified when the
326 handler was registered.
327 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
328 be conveyed from a non-SMM environment into an SMM environment.
329 @param[in, out] CommBufferSize The size of the CommBuffer.
331 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
332 should still be called.
333 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
335 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
337 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
341 SmmPerformanceHandler (
342 IN EFI_HANDLE DispatchHandle
,
343 IN CONST VOID
*RegisterContext
,
344 IN OUT VOID
*CommBuffer
,
345 IN OUT UINTN
*CommBufferSize
349 SMM_PERF_COMMUNICATE
*SmmPerfCommData
;
350 GAUGE_DATA_ENTRY
*GaugeData
;
355 ASSERT (CommBuffer
!= NULL
);
357 SmmPerfCommData
= (SMM_PERF_COMMUNICATE
*)CommBuffer
;
359 switch (SmmPerfCommData
->Function
) {
360 case SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER
:
361 SmmPerfCommData
->NumberOfEntries
= mGaugeData
->NumberOfEntries
;
362 return Status
= EFI_SUCCESS
;
365 case SMM_PERF_FUNCTION_GET_GAUGE_DATA
:
366 if ( SmmPerfCommData
->GaugeData
== NULL
|| SmmPerfCommData
->NumberOfEntries
<= 0 ||
367 (SmmPerfCommData
->LogEntryKey
+ SmmPerfCommData
->NumberOfEntries
) > mGaugeData
->NumberOfEntries
) {
368 Status
= EFI_INVALID_PARAMETER
;
372 Status
= GetGauge(SmmPerfCommData
->LogEntryKey
, &GaugeData
);
373 if (EFI_ERROR(Status
)) {
380 DataSize
= SmmPerfCommData
->NumberOfEntries
* sizeof(GAUGE_DATA_ENTRY
);
381 if (IsAddressInSmram ((EFI_PHYSICAL_ADDRESS
)(UINTN
)SmmPerfCommData
->GaugeData
, DataSize
)) {
382 DEBUG ((EFI_D_ERROR
, "Smm Performance Data buffer is in SMRAM!\n"));
383 Status
= EFI_ACCESS_DENIED
;
388 (UINT8
*)SmmPerfCommData
->GaugeData
,
396 Status
= EFI_UNSUPPORTED
;
399 SmmPerfCommData
->ReturnStatus
= Status
;
404 SmmBase2 protocol notify callback function, when SMST and SMM memory service get initialized
405 this function is callbacked to to initialize the Smm Performance Lib
407 @param Event The event of notify protocol.
408 @param Context Notify event context.
413 InitializeSmmCorePerformanceLib (
420 EFI_SMM_ACCESS2_PROTOCOL
*SmmAccess
;
425 // Initialize spin lock
427 InitializeSpinLock (&mSmmPerfLock
);
429 mMaxGaugeRecords
= INIT_SMM_GAUGE_DATA_ENTRIES
+ PcdGet8 (PcdMaxPeiPerformanceLogEntries
);
431 mGaugeData
= AllocateZeroPool (sizeof (GAUGE_DATA_HEADER
) + (sizeof (GAUGE_DATA_ENTRY
) * mMaxGaugeRecords
));
432 ASSERT (mGaugeData
!= NULL
);
435 // Get SMRAM information
437 Status
= gBS
->LocateProtocol (&gEfiSmmAccess2ProtocolGuid
, NULL
, (VOID
**)&SmmAccess
);
438 ASSERT_EFI_ERROR (Status
);
441 Status
= SmmAccess
->GetCapabilities (SmmAccess
, &Size
, NULL
);
442 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
444 Status
= gSmst
->SmmAllocatePool (
445 EfiRuntimeServicesData
,
447 (VOID
**)&mSmramRanges
449 ASSERT_EFI_ERROR (Status
);
451 Status
= SmmAccess
->GetCapabilities (SmmAccess
, &Size
, mSmramRanges
);
452 ASSERT_EFI_ERROR (Status
);
454 mSmramRangeCount
= Size
/ sizeof (EFI_SMRAM_DESCRIPTOR
);
457 // Install the protocol interfaces.
459 Status
= gSmst
->SmmInstallProtocolInterface (
461 &gSmmPerformanceProtocolGuid
,
462 EFI_NATIVE_INTERFACE
,
463 &mPerformanceInterface
465 ASSERT_EFI_ERROR (Status
);
468 /// Register SMM Performance SMI handler
471 Status
= gSmst
->SmiHandlerRegister (SmmPerformanceHandler
, &gSmmPerformanceProtocolGuid
, &Handle
);
472 ASSERT_EFI_ERROR (Status
);
476 The constructor function initializes Performance infrastructure for DXE phase.
478 The constructor function publishes Performance protocol, allocates memory to log DXE performance
479 and merges PEI performance data to DXE performance log.
480 It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
482 @param ImageHandle The firmware allocated handle for the EFI image.
483 @param SystemTable A pointer to the EFI System Table.
485 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
490 SmmCorePerformanceLibConstructor (
491 IN EFI_HANDLE ImageHandle
,
492 IN EFI_SYSTEM_TABLE
*SystemTable
499 mPerformanceMeasurementEnabled
= (BOOLEAN
) ((PcdGet8(PcdPerformanceLibraryPropertyMask
) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED
) != 0);
500 if (!mPerformanceMeasurementEnabled
) {
502 // Do not initialize performance infrastructure if not required.
508 // Create the events to do the library init.
510 Status
= gBS
->CreateEvent (
513 InitializeSmmCorePerformanceLib
,
517 ASSERT_EFI_ERROR (Status
);
520 // Register for protocol notifications on this event
522 Status
= gBS
->RegisterProtocolNotify (
523 &gEfiSmmBase2ProtocolGuid
,
528 ASSERT_EFI_ERROR (Status
);
534 Adds a record at the end of the performance measurement log
535 that records the start time of a performance measurement.
537 Adds a record to the end of the performance measurement log
538 that contains the Handle, Token, and Module.
539 The end time of the new record must be set to zero.
540 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
541 If TimeStamp is zero, the start time in the record is filled in with the value
542 read from the current time stamp.
544 @param Handle Pointer to environment specific context used
545 to identify the component being measured.
546 @param Token Pointer to a Null-terminated ASCII string
547 that identifies the component being measured.
548 @param Module Pointer to a Null-terminated ASCII string
549 that identifies the module being measured.
550 @param TimeStamp 64-bit time stamp.
552 @retval RETURN_SUCCESS The start of the measurement was recorded.
553 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
558 StartPerformanceMeasurement (
559 IN CONST VOID
*Handle
, OPTIONAL
560 IN CONST CHAR8
*Token
, OPTIONAL
561 IN CONST CHAR8
*Module
, OPTIONAL
567 Status
= StartGauge (Handle
, Token
, Module
, TimeStamp
);
568 return (RETURN_STATUS
) Status
;
572 Searches the performance measurement log from the beginning of the log
573 for the first matching record that contains a zero end time and fills in a valid end time.
575 Searches the performance measurement log from the beginning of the log
576 for the first record that matches Handle, Token, and Module and has an end time value of zero.
577 If the record can not be found then return RETURN_NOT_FOUND.
578 If the record is found and TimeStamp is not zero,
579 then the end time in the record is filled in with the value specified by TimeStamp.
580 If the record is found and TimeStamp is zero, then the end time in the matching record
581 is filled in with the current time stamp value.
583 @param Handle Pointer to environment specific context used
584 to identify the component being measured.
585 @param Token Pointer to a Null-terminated ASCII string
586 that identifies the component being measured.
587 @param Module Pointer to a Null-terminated ASCII string
588 that identifies the module being measured.
589 @param TimeStamp 64-bit time stamp.
591 @retval RETURN_SUCCESS The end of the measurement was recorded.
592 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
597 EndPerformanceMeasurement (
598 IN CONST VOID
*Handle
, OPTIONAL
599 IN CONST CHAR8
*Token
, OPTIONAL
600 IN CONST CHAR8
*Module
, OPTIONAL
606 Status
= EndGauge (Handle
, Token
, Module
, TimeStamp
);
607 return (RETURN_STATUS
) Status
;
611 Attempts to retrieve a performance measurement log entry from the performance measurement log.
613 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
614 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
615 and the key for the second entry in the log is returned. If the performance log is empty,
616 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
617 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
618 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
619 retrieved and an implementation specific non-zero key value that specifies the end of the performance
620 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
621 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
622 the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
623 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
624 If Handle is NULL, then ASSERT().
625 If Token is NULL, then ASSERT().
626 If Module is NULL, then ASSERT().
627 If StartTimeStamp is NULL, then ASSERT().
628 If EndTimeStamp is NULL, then ASSERT().
630 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
631 0, then the first performance measurement log entry is retrieved.
632 On exit, the key of the next performance log entry.
633 @param Handle Pointer to environment specific context used to identify the component
635 @param Token Pointer to a Null-terminated ASCII string that identifies the component
637 @param Module Pointer to a Null-terminated ASCII string that identifies the module
639 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
641 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
644 @return The key for the next performance log entry (in general case).
649 GetPerformanceMeasurement (
650 IN UINTN LogEntryKey
,
651 OUT CONST VOID
**Handle
,
652 OUT CONST CHAR8
**Token
,
653 OUT CONST CHAR8
**Module
,
654 OUT UINT64
*StartTimeStamp
,
655 OUT UINT64
*EndTimeStamp
659 GAUGE_DATA_ENTRY
*GaugeData
;
663 ASSERT (Handle
!= NULL
);
664 ASSERT (Token
!= NULL
);
665 ASSERT (Module
!= NULL
);
666 ASSERT (StartTimeStamp
!= NULL
);
667 ASSERT (EndTimeStamp
!= NULL
);
669 Status
= GetGauge (LogEntryKey
++, &GaugeData
);
672 // Make sure that LogEntryKey is a valid log entry key,
674 ASSERT (Status
!= EFI_INVALID_PARAMETER
);
676 if (EFI_ERROR (Status
)) {
678 // The LogEntryKey is the last entry (equals to the total entry number).
683 ASSERT (GaugeData
!= NULL
);
685 *Handle
= (VOID
*) (UINTN
) GaugeData
->Handle
;
686 *Token
= GaugeData
->Token
;
687 *Module
= GaugeData
->Module
;
688 *StartTimeStamp
= GaugeData
->StartTimeStamp
;
689 *EndTimeStamp
= GaugeData
->EndTimeStamp
;
695 Returns TRUE if the performance measurement macros are enabled.
697 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
698 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
700 @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
701 PcdPerformanceLibraryPropertyMask is set.
702 @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
703 PcdPerformanceLibraryPropertyMask is clear.
708 PerformanceMeasurementEnabled (
712 return mPerformanceMeasurementEnabled
;