]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
MdeModulePkg: Update Performance instances to use new protocol
[mirror_edk2.git] / MdeModulePkg / Library / SmmCorePerformanceLib / SmmCorePerformanceLib.c
1 /** @file
2 Performance library instance used by SMM Core.
3
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.
8
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.
11
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.
16
17 SmmPerformanceHandlerEx(), SmmPerformanceHandler() will receive untrusted input and do basic validation.
18
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
24
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.
27
28 **/
29
30
31 #include "SmmCorePerformanceLibInternal.h"
32
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
36
37 SMM_BOOT_PERFORMANCE_TABLE *mSmmBootPerformanceTable = NULL;
38
39 typedef struct {
40 EFI_HANDLE Handle;
41 CHAR8 NameString[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
42 EFI_GUID ModuleGuid;
43 } HANDLE_GUID_MAP;
44
45 HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];
46 UINTN mCachePairCount = 0;
47
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;
55
56 //
57 // Interfaces for SMM PerformanceMeasurement Protocol.
58 //
59 EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = {
60 CreatePerformanceMeasurement,
61 };
62
63 /**
64 Check whether the Token is a known one which is uesed by core.
65
66 @param Token Pointer to a Null-terminated ASCII string
67
68 @retval TRUE Is a known one used by core.
69 @retval FALSE Not a known one.
70
71 **/
72 BOOLEAN
73 IsKnownTokens (
74 IN CONST CHAR8 *Token
75 )
76 {
77 if (Token == NULL) {
78 return FALSE;
79 }
80
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) {
91 return TRUE;
92 } else {
93 return FALSE;
94 }
95 }
96
97 /**
98 Check whether the ID is a known one which map to the known Token.
99
100 @param Identifier 32-bit identifier.
101
102 @retval TRUE Is a known one used by core.
103 @retval FALSE Not a known one.
104
105 **/
106 BOOLEAN
107 IsKnownID (
108 IN UINT32 Identifier
109 )
110 {
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) {
121 return TRUE;
122 } else {
123 return FALSE;
124 }
125 }
126
127 /**
128 Get the FPDT record info.
129
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.
140
141 @retval EFI_SUCCESS Get record info successfully.
142 @retval EFI_UNSUPPORTED No matched FPDT record.
143
144 **/
145 EFI_STATUS
146 GetFpdtRecordInfo (
147 IN BOOLEAN IsStart,
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
153 )
154 {
155 UINT16 RecordType;
156 UINTN StringSize;
157
158 RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE;
159
160 //
161 // Token to Type and Id.
162 //
163 if (Token != NULL) {
164 if (AsciiStrCmp (Token, START_IMAGE_TOK) == 0) { // "StartImage:"
165 *UseModuleName = TRUE;
166 RecordType = FPDT_GUID_EVENT_TYPE;
167 if (IsStart) {
168 RecordInfo->ProgressID = MODULE_START_ID;
169 } else {
170 RecordInfo->ProgressID = MODULE_END_ID;
171 }
172 } else if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) { // "LoadImage:"
173 *UseModuleName = TRUE;
174 RecordType = FPDT_GUID_QWORD_EVENT_TYPE;
175 if (IsStart) {
176 RecordInfo->ProgressID = MODULE_LOADIMAGE_START_ID;
177 } else {
178 RecordInfo->ProgressID = MODULE_LOADIMAGE_END_ID;
179 }
180 } else { // Pref used in Modules
181 if (IsStart) {
182 RecordInfo->ProgressID = PERF_INMODULE_START_ID;
183 } else {
184 RecordInfo->ProgressID = PERF_INMODULE_END_ID;
185 }
186 }
187 } else if (Handle != NULL || Module != NULL) { // Pref used in Modules
188 if (IsStart) {
189 RecordInfo->ProgressID = PERF_INMODULE_START_ID;
190 } else {
191 RecordInfo->ProgressID = PERF_INMODULE_END_ID;
192 }
193 } else {
194 return EFI_UNSUPPORTED;
195 }
196
197 if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
198 RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE;
199 RecordInfo->RecordSize = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE;
200 } else {
201 switch (RecordType) {
202 case FPDT_GUID_EVENT_TYPE:
203 RecordInfo->RecordSize = sizeof (FPDT_GUID_EVENT_RECORD);
204 break;
205
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);
213 } else {
214 StringSize = STRING_SIZE;
215 }
216 if (StringSize > STRING_SIZE) {
217 StringSize = STRING_SIZE;
218 }
219 RecordInfo->RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize);
220 break;
221
222 case FPDT_GUID_QWORD_EVENT_TYPE:
223 RecordInfo->RecordSize = (UINT8)sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
224 break;
225
226 default:
227 //
228 // Record type is unsupported in SMM phase.
229 //
230 return EFI_UNSUPPORTED;
231 }
232 }
233
234 RecordInfo->Type = RecordType;
235 return EFI_SUCCESS;
236 }
237
238 /**
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.
242
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.
247
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.
251 **/
252 EFI_STATUS
253 EFIAPI
254 GetModuleInfoFromHandle (
255 IN EFI_HANDLE Handle,
256 OUT CHAR8 *NameString,
257 IN UINTN BufferSize,
258 OUT EFI_GUID *ModuleGuid OPTIONAL
259 )
260 {
261 EFI_STATUS Status;
262 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
263 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
264 CHAR8 *PdbFileName;
265 EFI_GUID *TempGuid;
266 UINTN StartIndex;
267 UINTN Index;
268 INTN Count;
269 BOOLEAN ModuleGuidIsGet;
270 UINTN StringSize;
271 CHAR16 *StringPtr;
272 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
273
274 if (NameString == NULL || BufferSize == 0) {
275 return EFI_INVALID_PARAMETER;
276 }
277
278 //
279 // Try to get the ModuleGuid and name string form the caached array.
280 //
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);
286 return EFI_SUCCESS;
287 }
288 }
289 }
290
291 Status = EFI_INVALID_PARAMETER;
292 LoadedImage = NULL;
293 ModuleGuidIsGet = FALSE;
294
295 //
296 // Initialize GUID as zero value.
297 //
298 TempGuid = &gZeroGuid;
299 //
300 // Initialize it as "" string.
301 //
302 NameString[0] = 0;
303
304 if (Handle != NULL) {
305 //
306 // Try Handle as ImageHandle.
307 //
308 Status = gBS->HandleProtocol (
309 Handle,
310 &gEfiLoadedImageProtocolGuid,
311 (VOID**) &LoadedImage
312 );
313
314 if (EFI_ERROR (Status)) {
315 //
316 // Try Handle as Controller Handle
317 //
318 Status = gBS->OpenProtocol (
319 Handle,
320 &gEfiDriverBindingProtocolGuid,
321 (VOID **) &DriverBinding,
322 NULL,
323 NULL,
324 EFI_OPEN_PROTOCOL_GET_PROTOCOL
325 );
326 if (!EFI_ERROR (Status)) {
327 //
328 // Get Image protocol from ImageHandle
329 //
330 Status = gBS->HandleProtocol (
331 DriverBinding->ImageHandle,
332 &gEfiLoadedImageProtocolGuid,
333 (VOID**) &LoadedImage
334 );
335 }
336 }
337 }
338
339 if (!EFI_ERROR (Status) && LoadedImage != NULL) {
340 //
341 // Get Module Guid from DevicePath.
342 //
343 if (LoadedImage->FilePath != NULL &&
344 LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH &&
345 LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP
346 ) {
347 //
348 // Determine GUID associated with module logging performance
349 //
350 ModuleGuidIsGet = TRUE;
351 FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath;
352 TempGuid = &FvFilePath->FvFileName;
353 }
354
355 //
356 // Method 1 Get Module Name from PDB string.
357 //
358 PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);
359 if (PdbFileName != NULL && BufferSize > 0) {
360 StartIndex = 0;
361 for (Index = 0; PdbFileName[Index] != 0; Index++) {
362 if ((PdbFileName[Index] == '\\') || (PdbFileName[Index] == '/')) {
363 StartIndex = Index + 1;
364 }
365 }
366 //
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.
369 //
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;
374 break;
375 }
376 }
377
378 if (Index == BufferSize - 1) {
379 NameString[Index] = 0;
380 }
381 //
382 // Module Name is got.
383 //
384 goto Done;
385 }
386 }
387
388 if (ModuleGuidIsGet) {
389 //
390 // Method 2 Try to get the image's FFS UI section by image GUID
391 //
392 StringPtr = NULL;
393 StringSize = 0;
394 Status = GetSectionFromAnyFv (
395 TempGuid,
396 EFI_SECTION_USER_INTERFACE,
397 0,
398 (VOID **) &StringPtr,
399 &StringSize
400 );
401
402 if (!EFI_ERROR (Status)) {
403 //
404 // Method 3. Get the name string from FFS UI section
405 //
406 for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
407 NameString[Index] = (CHAR8) StringPtr[Index];
408 }
409 NameString[Index] = 0;
410 FreePool (StringPtr);
411 }
412 }
413
414 Done:
415 //
416 // Copy Module Guid
417 //
418 if (ModuleGuid != NULL) {
419 CopyGuid (ModuleGuid, TempGuid);
420 if (IsZeroGuid(TempGuid) && (Handle != NULL) && !ModuleGuidIsGet) {
421 // Handle is GUID
422 CopyGuid (ModuleGuid, (EFI_GUID *) Handle);
423 }
424 }
425
426 //
427 // Cache the Handle and Guid pairs.
428 //
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);
433 mCachePairCount ++;
434 }
435
436 return Status;
437 }
438
439 /**
440 Add performance log to FPDT boot record table.
441
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.
452
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.
456
457 **/
458 EFI_STATUS
459 InsertFpdtMeasurement (
460 IN BOOLEAN IsStart,
461 IN CONST VOID *Handle, OPTIONAL
462 IN CONST CHAR8 *Token, OPTIONAL
463 IN CONST CHAR8 *Module, OPTIONAL
464 IN UINT64 Ticker,
465 IN UINT32 Identifier
466 )
467 {
468 EFI_GUID ModuleGuid;
469 CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
470 EFI_STATUS Status;
471 FPDT_RECORD_PTR FpdtRecordPtr;
472 UINT64 TimeStamp;
473 FPDT_BASIC_RECORD_INFO RecordInfo;
474 UINTN DestMax;
475 UINTN StrLength;
476 CONST CHAR8 *StringPtr;
477 BOOLEAN UseModuleName;
478
479 StringPtr = NULL;
480 UseModuleName = FALSE;
481 ZeroMem (ModuleName, sizeof (ModuleName));
482
483 //
484 // Get record info includes type, size, ProgressID.
485 //
486 Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo, &UseModuleName);
487 if (EFI_ERROR (Status)) {
488 return Status;
489 }
490
491 //
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.
499 //
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)) {
506 Identifier += 1;
507 }
508 RecordInfo.ProgressID = (UINT16)Identifier;
509 }
510
511 if (mFpdtDataIsReported) {
512 //
513 // Append Boot records after Smm boot performance records have been reported.
514 //
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;
519 }
520 return EFI_OUT_OF_RESOURCES;
521 } else {
522 //
523 // Covert buffer to FPDT Ptr Union type.
524 //
525 FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
526 }
527 } else {
528 //
529 // Check if pre-allocated buffer is full
530 //
531 if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength) {
532 mSmmBootPerformanceTable = ReallocatePool (
533 mPerformanceLength,
534 mPerformanceLength + sizeof (SMM_BOOT_PERFORMANCE_TABLE) + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER,
535 mSmmBootPerformanceTable
536 );
537
538 if (mSmmBootPerformanceTable == NULL) {
539 return EFI_OUT_OF_RESOURCES;
540 }
541 mSmmBootPerformanceTable->Header.Length = sizeof (SMM_BOOT_PERFORMANCE_TABLE) + mPerformanceLength;
542 mMaxPerformanceLength = mPerformanceLength + sizeof (SMM_BOOT_PERFORMANCE_TABLE) + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER;
543 }
544 //
545 // Covert buffer to FPDT Ptr Union type.
546 //
547 FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
548 }
549 FpdtRecordPtr.RecordHeader->Length = 0;
550
551 //
552 // Get the TimeStamp.
553 //
554 if (Ticker == 0) {
555 Ticker = GetPerformanceCounter ();
556 TimeStamp = GetTimeInNanoSecond (Ticker);
557 } else if (Ticker == 1) {
558 TimeStamp = 0;
559 } else {
560 TimeStamp = GetTimeInNanoSecond (Ticker);
561 }
562
563 //
564 // Get the ModuleName and ModuleGuid form the handle.
565 //
566 GetModuleInfoFromHandle ((EFI_HANDLE *)Handle, ModuleName, sizeof (ModuleName), &ModuleGuid);
567
568 //
569 // Fill in the record information.
570 //
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));
579 break;
580
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));
588
589 if (UseModuleName) {
590 StringPtr = ModuleName;
591 } else if (Token != NULL) {
592 StringPtr = Token;
593 } else if (Module != NULL) {
594 StringPtr = Module;
595 } else if (ModuleName != NULL) {
596 StringPtr = ModuleName;
597 }
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;
603 }
604 AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StrLength);
605 } else {
606 AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name");
607 }
608 break;
609
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));
617 break;
618
619 default:
620 //
621 // Record is not supported in current SMM phase, return EFI_UNSUPPORTED
622 //
623 return EFI_UNSUPPORTED;
624 }
625
626 //
627 // Update the cached FPDT record buffer.
628 //
629 mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
630 mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length;
631
632 return EFI_SUCCESS;
633 }
634
635 /**
636 SmmReadyToBoot protocol notification event handler.
637
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
641
642 @retval EFI_SUCCESS SmmReadyToBootCallback runs successfully
643
644 **/
645 EFI_STATUS
646 EFIAPI
647 SmmReportFpdtRecordData (
648 IN CONST EFI_GUID *Protocol,
649 IN VOID *Interface,
650 IN EFI_HANDLE Handle
651 )
652 {
653 UINT64 SmmBPDTddr;
654
655 if (!mFpdtDataIsReported && mSmmBootPerformanceTable != NULL) {
656 SmmBPDTddr = (UINT64)(UINTN)mSmmBootPerformanceTable;
657 REPORT_STATUS_CODE_EX (
658 EFI_PROGRESS_CODE,
659 EFI_SOFTWARE_SMM_DRIVER,
660 0,
661 NULL,
662 &gEdkiiFpdtExtendedFirmwarePerformanceGuid,
663 &SmmBPDTddr,
664 sizeof (UINT64)
665 );
666 //
667 // Set FPDT report state to TRUE.
668 //
669 mFpdtDataIsReported = TRUE;
670 }
671 return EFI_SUCCESS;
672 }
673
674 /**
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
677
678 @param Event The event of notify protocol.
679 @param Context Notify event context.
680
681 **/
682 VOID
683 EFIAPI
684 InitializeSmmCorePerformanceLib (
685 IN EFI_EVENT Event,
686 IN VOID *Context
687 )
688 {
689 EFI_HANDLE Handle;
690 EFI_STATUS Status;
691 VOID *SmmReadyToBootRegistration;
692 PERFORMANCE_PROPERTY *PerformanceProperty;
693
694 //
695 // Initialize spin lock
696 //
697 InitializeSpinLock (&mSmmFpdtLock);
698
699 //
700 // Install the protocol interfaces for SMM performance library instance.
701 //
702 Handle = NULL;
703 Status = gSmst->SmmInstallProtocolInterface (
704 &Handle,
705 &gEdkiiSmmPerformanceMeasurementProtocolGuid,
706 EFI_NATIVE_INTERFACE,
707 &mPerformanceMeasurementInterface
708 );
709 ASSERT_EFI_ERROR (Status);
710
711 Status = gSmst->SmmRegisterProtocolNotify (
712 &gEdkiiSmmReadyToBootProtocolGuid,
713 SmmReportFpdtRecordData,
714 &SmmReadyToBootRegistration
715 );
716 Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);
717 if (EFI_ERROR (Status)) {
718 //
719 // Install configuration table for performance property.
720 //
721 mPerformanceProperty.Revision = PERFORMANCE_PROPERTY_REVISION;
722 mPerformanceProperty.Reserved = 0;
723 mPerformanceProperty.Frequency = GetPerformanceCounterProperties (
724 &mPerformanceProperty.TimerStartValue,
725 &mPerformanceProperty.TimerEndValue
726 );
727 Status = gBS->InstallConfigurationTable (&gPerformanceProtocolGuid, &mPerformanceProperty);
728 ASSERT_EFI_ERROR (Status);
729 }
730 }
731
732 /**
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.
736
737 @param ImageHandle The firmware allocated handle for the EFI image.
738 @param SystemTable A pointer to the EFI System Table.
739
740 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
741
742 **/
743 EFI_STATUS
744 EFIAPI
745 SmmCorePerformanceLibConstructor (
746 IN EFI_HANDLE ImageHandle,
747 IN EFI_SYSTEM_TABLE *SystemTable
748 )
749 {
750 EFI_STATUS Status;
751 EFI_EVENT Event;
752 VOID *Registration;
753
754 if (!PerformanceMeasurementEnabled ()) {
755 //
756 // Do not initialize performance infrastructure if not required.
757 //
758 return EFI_SUCCESS;
759 }
760
761 //
762 // Create the events to do the library init.
763 //
764 Status = gBS->CreateEvent (
765 EVT_NOTIFY_SIGNAL,
766 TPL_CALLBACK,
767 InitializeSmmCorePerformanceLib,
768 NULL,
769 &Event
770 );
771 ASSERT_EFI_ERROR (Status);
772
773 //
774 // Register for protocol notifications on this event
775 //
776 Status = gBS->RegisterProtocolNotify (
777 &gEfiSmmBase2ProtocolGuid,
778 Event,
779 &Registration
780 );
781
782 ASSERT_EFI_ERROR (Status);
783
784 return EFI_SUCCESS;
785 }
786
787 /**
788 Create performance record with event description and a timestamp.
789
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.
799
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.
804 **/
805 EFI_STATUS
806 EFIAPI
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
815 )
816 {
817 EFI_STATUS Status;
818
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);
824 }
825 ReleaseSpinLock (&mSmmFpdtLock);
826 return Status;
827 }
828
829 /**
830 Adds a record at the end of the performance measurement log
831 that records the start time of a performance measurement.
832
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.
839
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.
849
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.
852
853 **/
854 RETURN_STATUS
855 EFIAPI
856 StartPerformanceMeasurementEx (
857 IN CONST VOID *Handle, OPTIONAL
858 IN CONST CHAR8 *Token, OPTIONAL
859 IN CONST CHAR8 *Module, OPTIONAL
860 IN UINT64 TimeStamp,
861 IN UINT32 Identifier
862 )
863 {
864 CONST CHAR8 *String;
865
866 if (Token != NULL) {
867 String = Token;
868 } else if (Module != NULL) {
869 String = Module;
870 } else {
871 String = NULL;
872 }
873
874 return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);
875 }
876
877 /**
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.
880
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.
888
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.
898
899 @retval RETURN_SUCCESS The end of the measurement was recorded.
900 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
901
902 **/
903 RETURN_STATUS
904 EFIAPI
905 EndPerformanceMeasurementEx (
906 IN CONST VOID *Handle, OPTIONAL
907 IN CONST CHAR8 *Token, OPTIONAL
908 IN CONST CHAR8 *Module, OPTIONAL
909 IN UINT64 TimeStamp,
910 IN UINT32 Identifier
911 )
912 {
913 CONST CHAR8 *String;
914
915 if (Token != NULL) {
916 String = Token;
917 } else if (Module != NULL) {
918 String = Module;
919 } else {
920 String = NULL;
921 }
922
923 return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);
924 }
925
926 /**
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.
930
931 !!! Not Support!!!
932
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().
950
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
955 being measured.
956 @param Token Pointer to a Null-terminated ASCII string that identifies the component
957 being measured.
958 @param Module Pointer to a Null-terminated ASCII string that identifies the module
959 being measured.
960 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
961 was started.
962 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
963 was ended.
964 @param Identifier Pointer to the 32-bit identifier that was recorded.
965
966 @return The key for the next performance log entry (in general case).
967
968 **/
969 UINTN
970 EFIAPI
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
979 )
980 {
981 return 0;
982 }
983
984 /**
985 Adds a record at the end of the performance measurement log
986 that records the start time of a performance measurement.
987
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.
994
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.
1002
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.
1005
1006 **/
1007 RETURN_STATUS
1008 EFIAPI
1009 StartPerformanceMeasurement (
1010 IN CONST VOID *Handle, OPTIONAL
1011 IN CONST CHAR8 *Token, OPTIONAL
1012 IN CONST CHAR8 *Module, OPTIONAL
1013 IN UINT64 TimeStamp
1014 )
1015 {
1016 return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
1017 }
1018
1019 /**
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.
1022
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.
1030
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.
1038
1039 @retval RETURN_SUCCESS The end of the measurement was recorded.
1040 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
1041
1042 **/
1043 RETURN_STATUS
1044 EFIAPI
1045 EndPerformanceMeasurement (
1046 IN CONST VOID *Handle, OPTIONAL
1047 IN CONST CHAR8 *Token, OPTIONAL
1048 IN CONST CHAR8 *Module, OPTIONAL
1049 IN UINT64 TimeStamp
1050 )
1051 {
1052 return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
1053 }
1054
1055 /**
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.
1059
1060 !!! Not Support!!!
1061
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().
1078
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
1083 being measured.
1084 @param Token Pointer to a Null-terminated ASCII string that identifies the component
1085 being measured.
1086 @param Module Pointer to a Null-terminated ASCII string that identifies the module
1087 being measured.
1088 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1089 was started.
1090 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1091 was ended.
1092
1093 @return The key for the next performance log entry (in general case).
1094
1095 **/
1096 UINTN
1097 EFIAPI
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
1105 )
1106 {
1107 return 0;
1108 }
1109
1110 /**
1111 Returns TRUE if the performance measurement macros are enabled.
1112
1113 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1114 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
1115
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.
1120
1121 **/
1122 BOOLEAN
1123 EFIAPI
1124 PerformanceMeasurementEnabled (
1125 VOID
1126 )
1127 {
1128 return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
1129 }