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 - 2018, 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"
33 #define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
34 #define FIRMWARE_RECORD_BUFFER 0x1000
35 #define CACHE_HANDLE_GUID_COUNT 0x100
37 SMM_BOOT_PERFORMANCE_TABLE
*mSmmBootPerformanceTable
= NULL
;
41 CHAR8 NameString
[FPDT_STRING_EVENT_RECORD_NAME_LENGTH
];
45 HANDLE_GUID_MAP mCacheHandleGuidTable
[CACHE_HANDLE_GUID_COUNT
];
46 UINTN mCachePairCount
= 0;
48 UINT32 mPerformanceLength
= 0;
49 UINT32 mMaxPerformanceLength
= 0;
50 BOOLEAN mFpdtDataIsReported
= FALSE
;
51 BOOLEAN mLackSpaceIsReport
= FALSE
;
52 CHAR8
*mPlatformLanguage
= NULL
;
53 SPIN_LOCK mSmmFpdtLock
;
54 PERFORMANCE_PROPERTY mPerformanceProperty
;
57 // Interfaces for SMM PerformanceMeasurement Protocol.
59 EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface
= {
60 CreatePerformanceMeasurement
,
64 Check whether the Token is a known one which is uesed by core.
66 @param Token Pointer to a Null-terminated ASCII string
68 @retval TRUE Is a known one used by core.
69 @retval FALSE Not a known one.
81 if (AsciiStrCmp (Token
, SEC_TOK
) == 0 ||
82 AsciiStrCmp (Token
, PEI_TOK
) == 0 ||
83 AsciiStrCmp (Token
, DXE_TOK
) == 0 ||
84 AsciiStrCmp (Token
, BDS_TOK
) == 0 ||
85 AsciiStrCmp (Token
, DRIVERBINDING_START_TOK
) == 0 ||
86 AsciiStrCmp (Token
, DRIVERBINDING_SUPPORT_TOK
) == 0 ||
87 AsciiStrCmp (Token
, DRIVERBINDING_STOP_TOK
) == 0 ||
88 AsciiStrCmp (Token
, LOAD_IMAGE_TOK
) == 0 ||
89 AsciiStrCmp (Token
, START_IMAGE_TOK
) == 0 ||
90 AsciiStrCmp (Token
, PEIM_TOK
) == 0) {
98 Check whether the ID is a known one which map to the known Token.
100 @param Identifier 32-bit identifier.
102 @retval TRUE Is a known one used by core.
103 @retval FALSE Not a known one.
111 if (Identifier
== MODULE_START_ID
||
112 Identifier
== MODULE_END_ID
||
113 Identifier
== MODULE_LOADIMAGE_START_ID
||
114 Identifier
== MODULE_LOADIMAGE_END_ID
||
115 Identifier
== MODULE_DB_START_ID
||
116 Identifier
== MODULE_DB_END_ID
||
117 Identifier
== MODULE_DB_SUPPORT_START_ID
||
118 Identifier
== MODULE_DB_SUPPORT_END_ID
||
119 Identifier
== MODULE_DB_STOP_START_ID
||
120 Identifier
== MODULE_DB_STOP_END_ID
) {
128 Get the FPDT record info.
130 @param IsStart TRUE if the performance log is start log.
131 @param Handle Pointer to environment specific context used
132 to identify the component being measured.
133 @param Token Pointer to a Null-terminated ASCII string
134 that identifies the component being measured.
135 @param Module Pointer to a Null-terminated ASCII string
136 that identifies the module being measured.
137 @param RecordInfo On return, pointer to the info of the record.
138 @param UseModuleName Only useful for FPDT_DYNAMIC_STRING_EVENT_TYPE, indicate that whether need use
139 Module name to fill the string field in the FPDT_DYNAMIC_STRING_EVENT_RECORD.
141 @retval EFI_SUCCESS Get record info successfully.
142 @retval EFI_UNSUPPORTED No matched FPDT record.
148 IN CONST VOID
*Handle
,
149 IN CONST CHAR8
*Token
,
150 IN CONST CHAR8
*Module
,
151 OUT FPDT_BASIC_RECORD_INFO
*RecordInfo
,
152 IN OUT BOOLEAN
*UseModuleName
158 RecordType
= FPDT_DYNAMIC_STRING_EVENT_TYPE
;
161 // Token to Type and Id.
164 if (AsciiStrCmp (Token
, START_IMAGE_TOK
) == 0) { // "StartImage:"
165 *UseModuleName
= TRUE
;
166 RecordType
= FPDT_GUID_EVENT_TYPE
;
168 RecordInfo
->ProgressID
= MODULE_START_ID
;
170 RecordInfo
->ProgressID
= MODULE_END_ID
;
172 } else if (AsciiStrCmp (Token
, LOAD_IMAGE_TOK
) == 0) { // "LoadImage:"
173 *UseModuleName
= TRUE
;
174 RecordType
= FPDT_GUID_QWORD_EVENT_TYPE
;
176 RecordInfo
->ProgressID
= MODULE_LOADIMAGE_START_ID
;
178 RecordInfo
->ProgressID
= MODULE_LOADIMAGE_END_ID
;
180 } else { // Pref used in Modules
182 RecordInfo
->ProgressID
= PERF_INMODULE_START_ID
;
184 RecordInfo
->ProgressID
= PERF_INMODULE_END_ID
;
187 } else if (Handle
!= NULL
|| Module
!= NULL
) { // Pref used in Modules
189 RecordInfo
->ProgressID
= PERF_INMODULE_START_ID
;
191 RecordInfo
->ProgressID
= PERF_INMODULE_END_ID
;
194 return EFI_UNSUPPORTED
;
197 if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly
)) {
198 RecordType
= FPDT_DYNAMIC_STRING_EVENT_TYPE
;
199 RecordInfo
->RecordSize
= sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD
) + STRING_SIZE
;
201 switch (RecordType
) {
202 case FPDT_GUID_EVENT_TYPE
:
203 RecordInfo
->RecordSize
= sizeof (FPDT_GUID_EVENT_RECORD
);
206 case FPDT_DYNAMIC_STRING_EVENT_TYPE
:
207 if (*UseModuleName
) {
208 StringSize
= STRING_SIZE
;
209 } else if (Token
!= NULL
) {
210 StringSize
= AsciiStrSize (Token
);
211 } else if (Module
!= NULL
) {
212 StringSize
= AsciiStrSize (Module
);
214 StringSize
= STRING_SIZE
;
216 if (StringSize
> STRING_SIZE
) {
217 StringSize
= STRING_SIZE
;
219 RecordInfo
->RecordSize
= (UINT8
)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD
) + StringSize
);
222 case FPDT_GUID_QWORD_EVENT_TYPE
:
223 RecordInfo
->RecordSize
= (UINT8
)sizeof (FPDT_GUID_QWORD_EVENT_RECORD
);
228 // Record type is unsupported in SMM phase.
230 return EFI_UNSUPPORTED
;
234 RecordInfo
->Type
= RecordType
;
239 Get a human readable module name and module guid for the given image handle.
240 If module name can't be found, "" string will return.
241 If module guid can't be found, Zero Guid will return.
243 @param Handle Image handle or Controller handle.
244 @param NameString The ascii string will be filled into it. If not found, null string will return.
245 @param BufferSize Size of the input NameString buffer.
246 @param ModuleGuid Point to the guid buffer to store the got module guid value.
248 @retval EFI_SUCCESS Successfully get module name and guid.
249 @retval EFI_INVALID_PARAMETER The input parameter NameString is NULL.
250 @retval other value Module Name can't be got.
254 GetModuleInfoFromHandle (
255 IN EFI_HANDLE Handle
,
256 OUT CHAR8
*NameString
,
258 OUT EFI_GUID
*ModuleGuid OPTIONAL
262 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
263 EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
;
269 BOOLEAN ModuleGuidIsGet
;
272 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*FvFilePath
;
274 if (NameString
== NULL
|| BufferSize
== 0) {
275 return EFI_INVALID_PARAMETER
;
279 // Try to get the ModuleGuid and name string form the caached array.
281 if (mCachePairCount
> 0) {
282 for (Count
= mCachePairCount
- 1; Count
>= 0; Count
--) {
283 if (Handle
== mCacheHandleGuidTable
[Count
].Handle
) {
284 CopyGuid (ModuleGuid
, &mCacheHandleGuidTable
[Count
].ModuleGuid
);
285 AsciiStrCpyS (NameString
, FPDT_STRING_EVENT_RECORD_NAME_LENGTH
, mCacheHandleGuidTable
[Count
].NameString
);
291 Status
= EFI_INVALID_PARAMETER
;
293 ModuleGuidIsGet
= FALSE
;
296 // Initialize GUID as zero value.
298 TempGuid
= &gZeroGuid
;
300 // Initialize it as "" string.
304 if (Handle
!= NULL
) {
306 // Try Handle as ImageHandle.
308 Status
= gBS
->HandleProtocol (
310 &gEfiLoadedImageProtocolGuid
,
311 (VOID
**) &LoadedImage
314 if (EFI_ERROR (Status
)) {
316 // Try Handle as Controller Handle
318 Status
= gBS
->OpenProtocol (
320 &gEfiDriverBindingProtocolGuid
,
321 (VOID
**) &DriverBinding
,
324 EFI_OPEN_PROTOCOL_GET_PROTOCOL
326 if (!EFI_ERROR (Status
)) {
328 // Get Image protocol from ImageHandle
330 Status
= gBS
->HandleProtocol (
331 DriverBinding
->ImageHandle
,
332 &gEfiLoadedImageProtocolGuid
,
333 (VOID
**) &LoadedImage
339 if (!EFI_ERROR (Status
) && LoadedImage
!= NULL
) {
341 // Get Module Guid from DevicePath.
343 if (LoadedImage
->FilePath
!= NULL
&&
344 LoadedImage
->FilePath
->Type
== MEDIA_DEVICE_PATH
&&
345 LoadedImage
->FilePath
->SubType
== MEDIA_PIWG_FW_FILE_DP
348 // Determine GUID associated with module logging performance
350 ModuleGuidIsGet
= TRUE
;
351 FvFilePath
= (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) LoadedImage
->FilePath
;
352 TempGuid
= &FvFilePath
->FvFileName
;
356 // Method 1 Get Module Name from PDB string.
358 PdbFileName
= PeCoffLoaderGetPdbPointer (LoadedImage
->ImageBase
);
359 if (PdbFileName
!= NULL
&& BufferSize
> 0) {
361 for (Index
= 0; PdbFileName
[Index
] != 0; Index
++) {
362 if ((PdbFileName
[Index
] == '\\') || (PdbFileName
[Index
] == '/')) {
363 StartIndex
= Index
+ 1;
367 // Copy the PDB file name to our temporary string.
368 // If the length is bigger than BufferSize, trim the redudant characters to avoid overflow in array boundary.
370 for (Index
= 0; Index
< BufferSize
- 1; Index
++) {
371 NameString
[Index
] = PdbFileName
[Index
+ StartIndex
];
372 if (NameString
[Index
] == 0 || NameString
[Index
] == '.') {
373 NameString
[Index
] = 0;
378 if (Index
== BufferSize
- 1) {
379 NameString
[Index
] = 0;
382 // Module Name is got.
388 if (ModuleGuidIsGet
) {
390 // Method 2 Try to get the image's FFS UI section by image GUID
394 Status
= GetSectionFromAnyFv (
396 EFI_SECTION_USER_INTERFACE
,
398 (VOID
**) &StringPtr
,
402 if (!EFI_ERROR (Status
)) {
404 // Method 3. Get the name string from FFS UI section
406 for (Index
= 0; Index
< BufferSize
- 1 && StringPtr
[Index
] != 0; Index
++) {
407 NameString
[Index
] = (CHAR8
) StringPtr
[Index
];
409 NameString
[Index
] = 0;
410 FreePool (StringPtr
);
418 if (ModuleGuid
!= NULL
) {
419 CopyGuid (ModuleGuid
, TempGuid
);
420 if (IsZeroGuid(TempGuid
) && (Handle
!= NULL
) && !ModuleGuidIsGet
) {
422 CopyGuid (ModuleGuid
, (EFI_GUID
*) Handle
);
427 // Cache the Handle and Guid pairs.
429 if (mCachePairCount
< CACHE_HANDLE_GUID_COUNT
) {
430 mCacheHandleGuidTable
[mCachePairCount
].Handle
= Handle
;
431 CopyGuid (&mCacheHandleGuidTable
[mCachePairCount
].ModuleGuid
, ModuleGuid
);
432 AsciiStrCpyS (mCacheHandleGuidTable
[mCachePairCount
].NameString
, FPDT_STRING_EVENT_RECORD_NAME_LENGTH
, NameString
);
440 Add performance log to FPDT boot record table.
442 @param IsStart TRUE if the performance log is start log.
443 @param Handle Pointer to environment specific context used
444 to identify the component being measured.
445 @param Token Pointer to a Null-terminated ASCII string
446 that identifies the component being measured.
447 @param Module Pointer to a Null-terminated ASCII string
448 that identifies the module being measured.
449 @param Ticker 64-bit time stamp.
450 @param Identifier 32-bit identifier. If the value is 0, the created record
451 is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
453 @retval EFI_SUCCESS Add FPDT boot record.
454 @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
455 @retval EFI_UNSUPPORTED No matched FPDT record.
459 InsertFpdtMeasurement (
461 IN CONST VOID
*Handle
, OPTIONAL
462 IN CONST CHAR8
*Token
, OPTIONAL
463 IN CONST CHAR8
*Module
, OPTIONAL
469 CHAR8 ModuleName
[FPDT_STRING_EVENT_RECORD_NAME_LENGTH
];
471 FPDT_RECORD_PTR FpdtRecordPtr
;
473 FPDT_BASIC_RECORD_INFO RecordInfo
;
476 CONST CHAR8
*StringPtr
;
477 BOOLEAN UseModuleName
;
480 UseModuleName
= FALSE
;
481 ZeroMem (ModuleName
, sizeof (ModuleName
));
484 // Get record info includes type, size, ProgressID.
486 Status
= GetFpdtRecordInfo (IsStart
, Handle
, Token
, Module
, &RecordInfo
, &UseModuleName
);
487 if (EFI_ERROR (Status
)) {
492 // If PERF_START()/PERF_END() have specified the ProgressID,it has high priority.
493 // !!! Note: If the Perf is not the known Token used in the core but have same
494 // ID with the core Token, this case will not be supported.
495 // And in currtnt usage mode, for the unkown ID, there is a general rule:
496 // If it is start pref: the lower 4 bits of the ID should be 0.
497 // If it is end pref: the lower 4 bits of the ID should not be 0.
498 // If input ID doesn't follow the rule, we will adjust it.
500 if ((Identifier
!= 0) && (IsKnownID (Identifier
)) && (!IsKnownTokens (Token
))) {
501 return EFI_UNSUPPORTED
;
502 } else if ((Identifier
!= 0) && (!IsKnownID (Identifier
)) && (!IsKnownTokens (Token
))) {
503 if (IsStart
&& ((Identifier
& 0x000F) != 0)) {
504 Identifier
&= 0xFFF0;
505 } else if ((!IsStart
) && ((Identifier
& 0x000F) == 0)) {
508 RecordInfo
.ProgressID
= (UINT16
)Identifier
;
511 if (mFpdtDataIsReported
) {
513 // Append Boot records after Smm boot performance records have been reported.
515 if (mPerformanceLength
+ RecordInfo
.RecordSize
> mMaxPerformanceLength
) {
516 if (!mLackSpaceIsReport
) {
517 DEBUG ((DEBUG_INFO
, "SmmCorePerformanceLib: No enough space to save boot records\n"));
518 mLackSpaceIsReport
= TRUE
;
520 return EFI_OUT_OF_RESOURCES
;
523 // Covert buffer to FPDT Ptr Union type.
525 FpdtRecordPtr
.RecordHeader
= (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER
*)((UINT8
*)mSmmBootPerformanceTable
+ mSmmBootPerformanceTable
->Header
.Length
);
529 // Check if pre-allocated buffer is full
531 if (mPerformanceLength
+ RecordInfo
.RecordSize
> mMaxPerformanceLength
) {
532 mSmmBootPerformanceTable
= ReallocatePool (
534 mPerformanceLength
+ sizeof (SMM_BOOT_PERFORMANCE_TABLE
) + RecordInfo
.RecordSize
+ FIRMWARE_RECORD_BUFFER
,
535 mSmmBootPerformanceTable
538 if (mSmmBootPerformanceTable
== NULL
) {
539 return EFI_OUT_OF_RESOURCES
;
541 mSmmBootPerformanceTable
->Header
.Length
= sizeof (SMM_BOOT_PERFORMANCE_TABLE
) + mPerformanceLength
;
542 mMaxPerformanceLength
= mPerformanceLength
+ sizeof (SMM_BOOT_PERFORMANCE_TABLE
) + RecordInfo
.RecordSize
+ FIRMWARE_RECORD_BUFFER
;
545 // Covert buffer to FPDT Ptr Union type.
547 FpdtRecordPtr
.RecordHeader
= (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER
*)((UINT8
*)mSmmBootPerformanceTable
+ mSmmBootPerformanceTable
->Header
.Length
);
549 FpdtRecordPtr
.RecordHeader
->Length
= 0;
552 // Get the TimeStamp.
555 Ticker
= GetPerformanceCounter ();
556 TimeStamp
= GetTimeInNanoSecond (Ticker
);
557 } else if (Ticker
== 1) {
560 TimeStamp
= GetTimeInNanoSecond (Ticker
);
564 // Get the ModuleName and ModuleGuid form the handle.
566 GetModuleInfoFromHandle ((EFI_HANDLE
*)Handle
, ModuleName
, sizeof (ModuleName
), &ModuleGuid
);
569 // Fill in the record information.
571 switch (RecordInfo
.Type
) {
572 case FPDT_GUID_EVENT_TYPE
:
573 FpdtRecordPtr
.GuidEvent
->Header
.Type
= FPDT_GUID_EVENT_TYPE
;
574 FpdtRecordPtr
.GuidEvent
->Header
.Length
= RecordInfo
.RecordSize
;
575 FpdtRecordPtr
.GuidEvent
->Header
.Revision
= FPDT_RECORD_REVISION_1
;
576 FpdtRecordPtr
.GuidEvent
->ProgressID
= RecordInfo
.ProgressID
;
577 FpdtRecordPtr
.GuidEvent
->Timestamp
= TimeStamp
;
578 CopyMem (&FpdtRecordPtr
.GuidEvent
->Guid
, &ModuleGuid
, sizeof (FpdtRecordPtr
.GuidEvent
->Guid
));
581 case FPDT_DYNAMIC_STRING_EVENT_TYPE
:
582 FpdtRecordPtr
.DynamicStringEvent
->Header
.Type
= FPDT_DYNAMIC_STRING_EVENT_TYPE
;
583 FpdtRecordPtr
.DynamicStringEvent
->Header
.Length
= RecordInfo
.RecordSize
;
584 FpdtRecordPtr
.DynamicStringEvent
->Header
.Revision
= FPDT_RECORD_REVISION_1
;
585 FpdtRecordPtr
.DynamicStringEvent
->ProgressID
= RecordInfo
.ProgressID
;
586 FpdtRecordPtr
.DynamicStringEvent
->Timestamp
= TimeStamp
;
587 CopyMem (&FpdtRecordPtr
.DynamicStringEvent
->Guid
, &ModuleGuid
, sizeof (FpdtRecordPtr
.DynamicStringEvent
->Guid
));
590 StringPtr
= ModuleName
;
591 } else if (Token
!= NULL
) {
593 } else if (Module
!= NULL
) {
595 } else if (ModuleName
!= NULL
) {
596 StringPtr
= ModuleName
;
598 if (StringPtr
!= NULL
&& AsciiStrLen (StringPtr
) != 0) {
599 StrLength
= AsciiStrLen (StringPtr
);
600 DestMax
= (RecordInfo
.RecordSize
- sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD
)) / sizeof (CHAR8
);
601 if (StrLength
>= DestMax
) {
602 StrLength
= DestMax
-1;
604 AsciiStrnCpyS (FpdtRecordPtr
.DynamicStringEvent
->String
, DestMax
, StringPtr
, StrLength
);
606 AsciiStrCpyS (FpdtRecordPtr
.DynamicStringEvent
->String
, FPDT_STRING_EVENT_RECORD_NAME_LENGTH
, "unknown name");
610 case FPDT_GUID_QWORD_EVENT_TYPE
:
611 FpdtRecordPtr
.GuidQwordEvent
->Header
.Type
= FPDT_GUID_QWORD_EVENT_TYPE
;
612 FpdtRecordPtr
.GuidQwordEvent
->Header
.Length
= RecordInfo
.RecordSize
;
613 FpdtRecordPtr
.GuidQwordEvent
->Header
.Revision
= FPDT_RECORD_REVISION_1
;
614 FpdtRecordPtr
.GuidQwordEvent
->ProgressID
= RecordInfo
.ProgressID
;
615 FpdtRecordPtr
.GuidQwordEvent
->Timestamp
= TimeStamp
;
616 CopyMem (&FpdtRecordPtr
.GuidQwordEvent
->Guid
, &ModuleGuid
, sizeof (FpdtRecordPtr
.GuidQwordEvent
->Guid
));
621 // Record is not supported in current SMM phase, return EFI_UNSUPPORTED
623 return EFI_UNSUPPORTED
;
627 // Update the cached FPDT record buffer.
629 mPerformanceLength
+= FpdtRecordPtr
.RecordHeader
->Length
;
630 mSmmBootPerformanceTable
->Header
.Length
+= FpdtRecordPtr
.RecordHeader
->Length
;
636 SmmReadyToBoot protocol notification event handler.
638 @param Protocol Points to the protocol's unique identifier
639 @param Interface Points to the interface instance
640 @param Handle The handle on which the interface was installed
642 @retval EFI_SUCCESS SmmReadyToBootCallback runs successfully
647 SmmReportFpdtRecordData (
648 IN CONST EFI_GUID
*Protocol
,
655 if (!mFpdtDataIsReported
&& mSmmBootPerformanceTable
!= NULL
) {
656 SmmBPDTddr
= (UINT64
)(UINTN
)mSmmBootPerformanceTable
;
657 REPORT_STATUS_CODE_EX (
659 EFI_SOFTWARE_SMM_DRIVER
,
662 &gEdkiiFpdtExtendedFirmwarePerformanceGuid
,
667 // Set FPDT report state to TRUE.
669 mFpdtDataIsReported
= TRUE
;
675 SmmBase2 protocol notify callback function, when SMST and SMM memory service get initialized
676 this function is callbacked to initialize the Smm Performance Lib
678 @param Event The event of notify protocol.
679 @param Context Notify event context.
684 InitializeSmmCorePerformanceLib (
691 VOID
*SmmReadyToBootRegistration
;
692 PERFORMANCE_PROPERTY
*PerformanceProperty
;
695 // Initialize spin lock
697 InitializeSpinLock (&mSmmFpdtLock
);
700 // Install the protocol interfaces for SMM performance library instance.
703 Status
= gSmst
->SmmInstallProtocolInterface (
705 &gEdkiiSmmPerformanceMeasurementProtocolGuid
,
706 EFI_NATIVE_INTERFACE
,
707 &mPerformanceMeasurementInterface
709 ASSERT_EFI_ERROR (Status
);
711 Status
= gSmst
->SmmRegisterProtocolNotify (
712 &gEdkiiSmmReadyToBootProtocolGuid
,
713 SmmReportFpdtRecordData
,
714 &SmmReadyToBootRegistration
716 Status
= EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid
, (VOID
**) &PerformanceProperty
);
717 if (EFI_ERROR (Status
)) {
719 // Install configuration table for performance property.
721 mPerformanceProperty
.Revision
= PERFORMANCE_PROPERTY_REVISION
;
722 mPerformanceProperty
.Reserved
= 0;
723 mPerformanceProperty
.Frequency
= GetPerformanceCounterProperties (
724 &mPerformanceProperty
.TimerStartValue
,
725 &mPerformanceProperty
.TimerEndValue
727 Status
= gBS
->InstallConfigurationTable (&gPerformanceProtocolGuid
, &mPerformanceProperty
);
728 ASSERT_EFI_ERROR (Status
);
733 The constructor function initializes the Performance Measurement Enable flag and
734 registers SmmBase2 protocol notify callback.
735 It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
737 @param ImageHandle The firmware allocated handle for the EFI image.
738 @param SystemTable A pointer to the EFI System Table.
740 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
745 SmmCorePerformanceLibConstructor (
746 IN EFI_HANDLE ImageHandle
,
747 IN EFI_SYSTEM_TABLE
*SystemTable
754 if (!PerformanceMeasurementEnabled ()) {
756 // Do not initialize performance infrastructure if not required.
762 // Create the events to do the library init.
764 Status
= gBS
->CreateEvent (
767 InitializeSmmCorePerformanceLib
,
771 ASSERT_EFI_ERROR (Status
);
774 // Register for protocol notifications on this event
776 Status
= gBS
->RegisterProtocolNotify (
777 &gEfiSmmBase2ProtocolGuid
,
782 ASSERT_EFI_ERROR (Status
);
788 Create performance record with event description and a timestamp.
790 @param CallerIdentifier - Image handle or pointer to caller ID GUID.
791 @param Guid - Pointer to a GUID.
792 @param String - Pointer to a string describing the measurement.
793 @param TimeStamp - 64-bit time stamp.
794 @param Address - Pointer to a location in memory relevant to the measurement.
795 @param Identifier - Performance identifier describing the type of measurement.
796 @param Attribute - The attribute of the measurement. According to attribute can create a start
797 record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
798 or a general record for other Perf macros.
800 @retval EFI_SUCCESS - Successfully created performance record.
801 @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
802 @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
803 pointer or invalid PerfId.
807 CreatePerformanceMeasurement(
808 IN CONST VOID
*CallerIdentifier
, OPTIONAL
809 IN CONST VOID
*Guid
, OPTIONAL
810 IN CONST CHAR8
*String
, OPTIONAL
811 IN UINT64 TimeStamp
, OPTIONAL
812 IN UINT64 Address
, OPTIONAL
813 IN UINT32 Identifier
,
814 IN PERF_MEASUREMENT_ATTRIBUTE Attribute
819 AcquireSpinLock (&mSmmFpdtLock
);
820 if (Attribute
== PerfStartEntry
) {
821 Status
= InsertFpdtMeasurement (TRUE
, CallerIdentifier
, String
, String
, TimeStamp
, Identifier
);
822 } else if (Attribute
== PerfEndEntry
) {
823 Status
= InsertFpdtMeasurement (FALSE
, CallerIdentifier
, String
, String
, TimeStamp
, Identifier
);
825 ReleaseSpinLock (&mSmmFpdtLock
);
830 Adds a record at the end of the performance measurement log
831 that records the start time of a performance measurement.
833 Adds a record to the end of the performance measurement log
834 that contains the Handle, Token, Module and Identifier.
835 The end time of the new record must be set to zero.
836 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
837 If TimeStamp is zero, the start time in the record is filled in with the value
838 read from the current time stamp.
840 @param Handle Pointer to environment specific context used
841 to identify the component being measured.
842 @param Token Pointer to a Null-terminated ASCII string
843 that identifies the component being measured.
844 @param Module Pointer to a Null-terminated ASCII string
845 that identifies the module being measured.
846 @param TimeStamp 64-bit time stamp.
847 @param Identifier 32-bit identifier. If the value is 0, the created record
848 is same as the one created by StartPerformanceMeasurement.
850 @retval RETURN_SUCCESS The start of the measurement was recorded.
851 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
856 StartPerformanceMeasurementEx (
857 IN CONST VOID
*Handle
, OPTIONAL
858 IN CONST CHAR8
*Token
, OPTIONAL
859 IN CONST CHAR8
*Module
, OPTIONAL
868 } else if (Module
!= NULL
) {
874 return (RETURN_STATUS
)CreatePerformanceMeasurement (Handle
, NULL
, String
, TimeStamp
, 0, Identifier
, PerfStartEntry
);
878 Searches the performance measurement log from the beginning of the log
879 for the first matching record that contains a zero end time and fills in a valid end time.
881 Searches the performance measurement log from the beginning of the log
882 for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
883 If the record can not be found then return RETURN_NOT_FOUND.
884 If the record is found and TimeStamp is not zero,
885 then the end time in the record is filled in with the value specified by TimeStamp.
886 If the record is found and TimeStamp is zero, then the end time in the matching record
887 is filled in with the current time stamp value.
889 @param Handle Pointer to environment specific context used
890 to identify the component being measured.
891 @param Token Pointer to a Null-terminated ASCII string
892 that identifies the component being measured.
893 @param Module Pointer to a Null-terminated ASCII string
894 that identifies the module being measured.
895 @param TimeStamp 64-bit time stamp.
896 @param Identifier 32-bit identifier. If the value is 0, the found record
897 is same as the one found by EndPerformanceMeasurement.
899 @retval RETURN_SUCCESS The end of the measurement was recorded.
900 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
905 EndPerformanceMeasurementEx (
906 IN CONST VOID
*Handle
, OPTIONAL
907 IN CONST CHAR8
*Token
, OPTIONAL
908 IN CONST CHAR8
*Module
, OPTIONAL
917 } else if (Module
!= NULL
) {
923 return (RETURN_STATUS
)CreatePerformanceMeasurement (Handle
, NULL
, String
, TimeStamp
, 0, Identifier
, PerfEndEntry
);
927 Attempts to retrieve a performance measurement log entry from the performance measurement log.
928 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
929 and then assign the Identifier with 0.
933 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
934 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
935 and the key for the second entry in the log is returned. If the performance log is empty,
936 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
937 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
938 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
939 retrieved and an implementation specific non-zero key value that specifies the end of the performance
940 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
941 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
942 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
943 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
944 If Handle is NULL, then ASSERT().
945 If Token is NULL, then ASSERT().
946 If Module is NULL, then ASSERT().
947 If StartTimeStamp is NULL, then ASSERT().
948 If EndTimeStamp is NULL, then ASSERT().
949 If Identifier is NULL, then ASSERT().
951 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
952 0, then the first performance measurement log entry is retrieved.
953 On exit, the key of the next performance log entry.
954 @param Handle Pointer to environment specific context used to identify the component
956 @param Token Pointer to a Null-terminated ASCII string that identifies the component
958 @param Module Pointer to a Null-terminated ASCII string that identifies the module
960 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
962 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
964 @param Identifier Pointer to the 32-bit identifier that was recorded.
966 @return The key for the next performance log entry (in general case).
971 GetPerformanceMeasurementEx (
972 IN UINTN LogEntryKey
,
973 OUT CONST VOID
**Handle
,
974 OUT CONST CHAR8
**Token
,
975 OUT CONST CHAR8
**Module
,
976 OUT UINT64
*StartTimeStamp
,
977 OUT UINT64
*EndTimeStamp
,
978 OUT UINT32
*Identifier
985 Adds a record at the end of the performance measurement log
986 that records the start time of a performance measurement.
988 Adds a record to the end of the performance measurement log
989 that contains the Handle, Token, and Module.
990 The end time of the new record must be set to zero.
991 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
992 If TimeStamp is zero, the start time in the record is filled in with the value
993 read from the current time stamp.
995 @param Handle Pointer to environment specific context used
996 to identify the component being measured.
997 @param Token Pointer to a Null-terminated ASCII string
998 that identifies the component being measured.
999 @param Module Pointer to a Null-terminated ASCII string
1000 that identifies the module being measured.
1001 @param TimeStamp 64-bit time stamp.
1003 @retval RETURN_SUCCESS The start of the measurement was recorded.
1004 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
1009 StartPerformanceMeasurement (
1010 IN CONST VOID
*Handle
, OPTIONAL
1011 IN CONST CHAR8
*Token
, OPTIONAL
1012 IN CONST CHAR8
*Module
, OPTIONAL
1016 return StartPerformanceMeasurementEx (Handle
, Token
, Module
, TimeStamp
, 0);
1020 Searches the performance measurement log from the beginning of the log
1021 for the first matching record that contains a zero end time and fills in a valid end time.
1023 Searches the performance measurement log from the beginning of the log
1024 for the first record that matches Handle, Token, and Module and has an end time value of zero.
1025 If the record can not be found then return RETURN_NOT_FOUND.
1026 If the record is found and TimeStamp is not zero,
1027 then the end time in the record is filled in with the value specified by TimeStamp.
1028 If the record is found and TimeStamp is zero, then the end time in the matching record
1029 is filled in with the current time stamp value.
1031 @param Handle Pointer to environment specific context used
1032 to identify the component being measured.
1033 @param Token Pointer to a Null-terminated ASCII string
1034 that identifies the component being measured.
1035 @param Module Pointer to a Null-terminated ASCII string
1036 that identifies the module being measured.
1037 @param TimeStamp 64-bit time stamp.
1039 @retval RETURN_SUCCESS The end of the measurement was recorded.
1040 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
1045 EndPerformanceMeasurement (
1046 IN CONST VOID
*Handle
, OPTIONAL
1047 IN CONST CHAR8
*Token
, OPTIONAL
1048 IN CONST CHAR8
*Module
, OPTIONAL
1052 return EndPerformanceMeasurementEx (Handle
, Token
, Module
, TimeStamp
, 0);
1056 Attempts to retrieve a performance measurement log entry from the performance measurement log.
1057 It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
1058 and then eliminate the Identifier.
1062 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
1063 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
1064 and the key for the second entry in the log is returned. If the performance log is empty,
1065 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
1066 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
1067 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
1068 retrieved and an implementation specific non-zero key value that specifies the end of the performance
1069 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
1070 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
1071 the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
1072 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
1073 If Handle is NULL, then ASSERT().
1074 If Token is NULL, then ASSERT().
1075 If Module is NULL, then ASSERT().
1076 If StartTimeStamp is NULL, then ASSERT().
1077 If EndTimeStamp is NULL, then ASSERT().
1079 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
1080 0, then the first performance measurement log entry is retrieved.
1081 On exit, the key of the next performance log entry.
1082 @param Handle Pointer to environment specific context used to identify the component
1084 @param Token Pointer to a Null-terminated ASCII string that identifies the component
1086 @param Module Pointer to a Null-terminated ASCII string that identifies the module
1088 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1090 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1093 @return The key for the next performance log entry (in general case).
1098 GetPerformanceMeasurement (
1099 IN UINTN LogEntryKey
,
1100 OUT CONST VOID
**Handle
,
1101 OUT CONST CHAR8
**Token
,
1102 OUT CONST CHAR8
**Module
,
1103 OUT UINT64
*StartTimeStamp
,
1104 OUT UINT64
*EndTimeStamp
1111 Returns TRUE if the performance measurement macros are enabled.
1113 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1114 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
1116 @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1117 PcdPerformanceLibraryPropertyMask is set.
1118 @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1119 PcdPerformanceLibraryPropertyMask is clear.
1124 PerformanceMeasurementEnabled (
1128 return (BOOLEAN
) ((PcdGet8(PcdPerformanceLibraryPropertyMask
) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED
) != 0);