]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
MdeModulePkg: Change OPTIONAL keyword usage style
[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 - 2021, Intel Corporation. All rights reserved.<BR>
20 SPDX-License-Identifier: BSD-2-Clause-Patent
21
22 **/
23
24
25 #include "SmmCorePerformanceLibInternal.h"
26
27 #define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
28 #define FIRMWARE_RECORD_BUFFER 0x1000
29 #define CACHE_HANDLE_GUID_COUNT 0x100
30
31 SMM_BOOT_PERFORMANCE_TABLE *mSmmBootPerformanceTable = NULL;
32
33 typedef struct {
34 EFI_HANDLE Handle;
35 CHAR8 NameString[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
36 EFI_GUID ModuleGuid;
37 } HANDLE_GUID_MAP;
38
39 HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];
40 UINTN mCachePairCount = 0;
41
42 UINT32 mPerformanceLength = sizeof (SMM_BOOT_PERFORMANCE_TABLE);
43 UINT32 mMaxPerformanceLength = 0;
44 UINT32 mLoadImageCount = 0;
45 BOOLEAN mFpdtDataIsReported = FALSE;
46 BOOLEAN mLackSpaceIsReport = FALSE;
47 CHAR8 *mPlatformLanguage = NULL;
48 SPIN_LOCK mSmmFpdtLock;
49 PERFORMANCE_PROPERTY mPerformanceProperty;
50 UINT32 mCachedLength = 0;
51 UINT32 mBootRecordSize = 0;
52
53 //
54 // Interfaces for SMM PerformanceMeasurement Protocol.
55 //
56 EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = {
57 CreatePerformanceMeasurement,
58 };
59
60 /**
61 Return the pointer to the FPDT record in the allocated memory.
62
63 @param RecordSize The size of FPDT record.
64 @param FpdtRecordPtr Pointer the FPDT record in the allocated memory.
65
66 @retval EFI_SUCCESS Successfully get the pointer to the FPDT record.
67 @retval EFI_OUT_OF_RESOURCES Ran out of space to store the records.
68 **/
69 EFI_STATUS
70 GetFpdtRecordPtr (
71 IN UINT8 RecordSize,
72 IN OUT FPDT_RECORD_PTR *FpdtRecordPtr
73 )
74 {
75 if (mFpdtDataIsReported) {
76 //
77 // Append Boot records after Smm boot performance records have been reported.
78 //
79 if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
80 if (!mLackSpaceIsReport) {
81 DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to save boot records\n"));
82 mLackSpaceIsReport = TRUE;
83 }
84 return EFI_OUT_OF_RESOURCES;
85 } else {
86 //
87 // Covert buffer to FPDT Ptr Union type.
88 //
89 FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
90 }
91 } else {
92 //
93 // Check if pre-allocated buffer is full
94 //
95 if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
96 mSmmBootPerformanceTable = ReallocatePool (
97 mPerformanceLength,
98 mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER,
99 mSmmBootPerformanceTable
100 );
101
102 if (mSmmBootPerformanceTable == NULL) {
103 return EFI_OUT_OF_RESOURCES;
104 }
105 mSmmBootPerformanceTable->Header.Length = mPerformanceLength;
106 mMaxPerformanceLength = mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER;
107 }
108 //
109 // Covert buffer to FPDT Ptr Union type.
110 //
111 FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
112 }
113 FpdtRecordPtr->RecordHeader->Length = 0;
114 return EFI_SUCCESS;
115 }
116
117
118 /**
119 Check whether the Token is a known one which is uesed by core.
120
121 @param Token Pointer to a Null-terminated ASCII string
122
123 @retval TRUE Is a known one used by core.
124 @retval FALSE Not a known one.
125
126 **/
127 BOOLEAN
128 IsKnownTokens (
129 IN CONST CHAR8 *Token
130 )
131 {
132 if (Token == NULL) {
133 return FALSE;
134 }
135
136 if (AsciiStrCmp (Token, SEC_TOK) == 0 ||
137 AsciiStrCmp (Token, PEI_TOK) == 0 ||
138 AsciiStrCmp (Token, DXE_TOK) == 0 ||
139 AsciiStrCmp (Token, BDS_TOK) == 0 ||
140 AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0 ||
141 AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0 ||
142 AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0 ||
143 AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0 ||
144 AsciiStrCmp (Token, START_IMAGE_TOK) == 0 ||
145 AsciiStrCmp (Token, PEIM_TOK) == 0) {
146 return TRUE;
147 } else {
148 return FALSE;
149 }
150 }
151
152 /**
153 Check whether the ID is a known one which map to the known Token.
154
155 @param Identifier 32-bit identifier.
156
157 @retval TRUE Is a known one used by core.
158 @retval FALSE Not a known one.
159
160 **/
161 BOOLEAN
162 IsKnownID (
163 IN UINT32 Identifier
164 )
165 {
166 if (Identifier == MODULE_START_ID ||
167 Identifier == MODULE_END_ID ||
168 Identifier == MODULE_LOADIMAGE_START_ID ||
169 Identifier == MODULE_LOADIMAGE_END_ID ||
170 Identifier == MODULE_DB_START_ID ||
171 Identifier == MODULE_DB_END_ID ||
172 Identifier == MODULE_DB_SUPPORT_START_ID ||
173 Identifier == MODULE_DB_SUPPORT_END_ID ||
174 Identifier == MODULE_DB_STOP_START_ID ||
175 Identifier == MODULE_DB_STOP_END_ID) {
176 return TRUE;
177 } else {
178 return FALSE;
179 }
180 }
181
182 /**
183 Get the FPDT record identifier.
184
185 @param Attribute The attribute of the Record.
186 PerfStartEntry: Start Record.
187 PerfEndEntry: End Record.
188 @param Handle Pointer to environment specific context used to identify the component being measured.
189 @param String Pointer to a Null-terminated ASCII string that identifies the component being measured.
190 @param ProgressID On return, pointer to the ProgressID.
191
192 @retval EFI_SUCCESS Get record info successfully.
193 @retval EFI_INVALID_PARAMETER No matched FPDT record.
194
195 **/
196 EFI_STATUS
197 GetFpdtRecordId (
198 IN PERF_MEASUREMENT_ATTRIBUTE Attribute,
199 IN CONST VOID *Handle,
200 IN CONST CHAR8 *String,
201 OUT UINT16 *ProgressID
202 )
203 {
204 //
205 // Token to Id.
206 //
207 if (String != NULL) {
208 if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) { // "StartImage:"
209 if (Attribute == PerfStartEntry) {
210 *ProgressID = MODULE_START_ID;
211 } else {
212 *ProgressID = MODULE_END_ID;
213 }
214 } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) { // "LoadImage:"
215 if (Attribute == PerfStartEntry) {
216 *ProgressID = MODULE_LOADIMAGE_START_ID;
217 } else {
218 *ProgressID = MODULE_LOADIMAGE_END_ID;
219 }
220 } else { // Pref used in Modules
221 if (Attribute == PerfStartEntry) {
222 *ProgressID = PERF_INMODULE_START_ID;
223 } else {
224 *ProgressID = PERF_INMODULE_END_ID;
225 }
226 }
227 } else if (Handle != NULL) { // Pref used in Modules
228 if (Attribute == PerfStartEntry) {
229 *ProgressID = PERF_INMODULE_START_ID;
230 } else {
231 *ProgressID = PERF_INMODULE_END_ID;
232 }
233 } else {
234 return EFI_UNSUPPORTED;
235 }
236 return EFI_SUCCESS;
237 }
238
239 /**
240 Get a human readable module name and module guid for the given image handle.
241 If module name can't be found, "" string will return.
242 If module guid can't be found, Zero Guid will return.
243
244 @param Handle Image handle or Controller handle.
245 @param NameString The ascii string will be filled into it. If not found, null string will return.
246 @param BufferSize Size of the input NameString buffer.
247 @param ModuleGuid Point to the guid buffer to store the got module guid value.
248
249 @retval EFI_SUCCESS Successfully get module name and guid.
250 @retval EFI_INVALID_PARAMETER The input parameter NameString is NULL.
251 @retval other value Module Name can't be got.
252 **/
253 EFI_STATUS
254 EFIAPI
255 GetModuleInfoFromHandle (
256 IN EFI_HANDLE Handle,
257 OUT CHAR8 *NameString,
258 IN UINTN BufferSize,
259 OUT EFI_GUID *ModuleGuid OPTIONAL
260 )
261 {
262 EFI_STATUS Status;
263 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
264 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
265 CHAR8 *PdbFileName;
266 EFI_GUID *TempGuid;
267 UINTN StartIndex;
268 UINTN Index;
269 INTN Count;
270 BOOLEAN ModuleGuidIsGet;
271 UINTN StringSize;
272 CHAR16 *StringPtr;
273 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
274
275 if (NameString == NULL || BufferSize == 0) {
276 return EFI_INVALID_PARAMETER;
277 }
278
279 //
280 // Try to get the ModuleGuid and name string form the caached array.
281 //
282 if (mCachePairCount > 0) {
283 for (Count = mCachePairCount - 1; Count >= 0; Count--) {
284 if (Handle == mCacheHandleGuidTable[Count].Handle) {
285 CopyGuid (ModuleGuid, &mCacheHandleGuidTable[Count].ModuleGuid);
286 AsciiStrCpyS (NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, mCacheHandleGuidTable[Count].NameString);
287 return EFI_SUCCESS;
288 }
289 }
290 }
291
292 Status = EFI_INVALID_PARAMETER;
293 LoadedImage = NULL;
294 ModuleGuidIsGet = FALSE;
295
296 //
297 // Initialize GUID as zero value.
298 //
299 TempGuid = &gZeroGuid;
300 //
301 // Initialize it as "" string.
302 //
303 NameString[0] = 0;
304
305 if (Handle != NULL) {
306 //
307 // Try Handle as ImageHandle.
308 //
309 Status = gBS->HandleProtocol (
310 Handle,
311 &gEfiLoadedImageProtocolGuid,
312 (VOID**) &LoadedImage
313 );
314
315 if (EFI_ERROR (Status)) {
316 //
317 // Try Handle as Controller Handle
318 //
319 Status = gBS->OpenProtocol (
320 Handle,
321 &gEfiDriverBindingProtocolGuid,
322 (VOID **) &DriverBinding,
323 NULL,
324 NULL,
325 EFI_OPEN_PROTOCOL_GET_PROTOCOL
326 );
327 if (!EFI_ERROR (Status)) {
328 //
329 // Get Image protocol from ImageHandle
330 //
331 Status = gBS->HandleProtocol (
332 DriverBinding->ImageHandle,
333 &gEfiLoadedImageProtocolGuid,
334 (VOID**) &LoadedImage
335 );
336 }
337 }
338 }
339
340 if (!EFI_ERROR (Status) && LoadedImage != NULL) {
341 //
342 // Get Module Guid from DevicePath.
343 //
344 if (LoadedImage->FilePath != NULL &&
345 LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH &&
346 LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP
347 ) {
348 //
349 // Determine GUID associated with module logging performance
350 //
351 ModuleGuidIsGet = TRUE;
352 FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath;
353 TempGuid = &FvFilePath->FvFileName;
354 }
355
356 //
357 // Method 1 Get Module Name from PDB string.
358 //
359 PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);
360 if (PdbFileName != NULL && BufferSize > 0) {
361 StartIndex = 0;
362 for (Index = 0; PdbFileName[Index] != 0; Index++) {
363 if ((PdbFileName[Index] == '\\') || (PdbFileName[Index] == '/')) {
364 StartIndex = Index + 1;
365 }
366 }
367 //
368 // Copy the PDB file name to our temporary string.
369 // If the length is bigger than BufferSize, trim the redudant characters to avoid overflow in array boundary.
370 //
371 for (Index = 0; Index < BufferSize - 1; Index++) {
372 NameString[Index] = PdbFileName[Index + StartIndex];
373 if (NameString[Index] == 0 || NameString[Index] == '.') {
374 NameString[Index] = 0;
375 break;
376 }
377 }
378
379 if (Index == BufferSize - 1) {
380 NameString[Index] = 0;
381 }
382 //
383 // Module Name is got.
384 //
385 goto Done;
386 }
387 }
388
389 if (ModuleGuidIsGet) {
390 //
391 // Method 2 Try to get the image's FFS UI section by image GUID
392 //
393 StringPtr = NULL;
394 StringSize = 0;
395 Status = GetSectionFromAnyFv (
396 TempGuid,
397 EFI_SECTION_USER_INTERFACE,
398 0,
399 (VOID **) &StringPtr,
400 &StringSize
401 );
402
403 if (!EFI_ERROR (Status)) {
404 //
405 // Method 3. Get the name string from FFS UI section
406 //
407 for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
408 NameString[Index] = (CHAR8) StringPtr[Index];
409 }
410 NameString[Index] = 0;
411 FreePool (StringPtr);
412 }
413 }
414
415 Done:
416 //
417 // Copy Module Guid
418 //
419 if (ModuleGuid != NULL) {
420 CopyGuid (ModuleGuid, TempGuid);
421 if (IsZeroGuid(TempGuid) && (Handle != NULL) && !ModuleGuidIsGet) {
422 // Handle is GUID
423 CopyGuid (ModuleGuid, (EFI_GUID *) Handle);
424 }
425 }
426
427 //
428 // Cache the Handle and Guid pairs.
429 //
430 if (mCachePairCount < CACHE_HANDLE_GUID_COUNT) {
431 mCacheHandleGuidTable[mCachePairCount].Handle = Handle;
432 CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, ModuleGuid);
433 AsciiStrCpyS (mCacheHandleGuidTable[mCachePairCount].NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, NameString);
434 mCachePairCount ++;
435 }
436
437 return Status;
438 }
439
440 /**
441 Copies the string from Source into Destination and updates Length with the
442 size of the string.
443
444 @param Destination - destination of the string copy
445 @param Source - pointer to the source string which will get copied
446 @param Length - pointer to a length variable to be updated
447
448 **/
449 VOID
450 CopyStringIntoPerfRecordAndUpdateLength (
451 IN OUT CHAR8 *Destination,
452 IN CONST CHAR8 *Source,
453 IN OUT UINT8 *Length
454 )
455 {
456 UINTN StringLen;
457 UINTN DestMax;
458
459 ASSERT (Source != NULL);
460
461 if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
462 DestMax = STRING_SIZE;
463 } else {
464 DestMax = AsciiStrSize (Source);
465 if (DestMax > STRING_SIZE) {
466 DestMax = STRING_SIZE;
467 }
468 }
469 StringLen = AsciiStrLen (Source);
470 if (StringLen >= DestMax) {
471 StringLen = DestMax -1;
472 }
473
474 AsciiStrnCpyS(Destination, DestMax, Source, StringLen);
475 *Length += (UINT8)DestMax;
476
477 return;
478 }
479
480 /**
481 Create performance record with event description and a timestamp.
482
483 @param CallerIdentifier - Image handle or pointer to caller ID GUID.
484 @param Guid - Pointer to a GUID.
485 @param String - Pointer to a string describing the measurement.
486 @param Ticker - 64-bit time stamp.
487 @param Address - Pointer to a location in memory relevant to the measurement.
488 @param PerfId - Performance identifier describing the type of measurement.
489 @param Attribute - The attribute of the measurement. According to attribute can create a start
490 record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
491 or a general record for other Perf macros.
492
493 @retval EFI_SUCCESS - Successfully created performance record.
494 @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
495 @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
496 pointer or invalid PerfId.
497
498 @retval EFI_SUCCESS - Successfully created performance record
499 @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records
500 @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
501 pointer or invalid PerfId
502
503 **/
504 EFI_STATUS
505 InsertFpdtRecord (
506 IN CONST VOID *CallerIdentifier OPTIONAL,
507 IN CONST VOID *Guid OPTIONAL,
508 IN CONST CHAR8 *String OPTIONAL,
509 IN UINT64 Ticker,
510 IN UINT64 Address OPTIONAL,
511 IN UINT16 PerfId,
512 IN PERF_MEASUREMENT_ATTRIBUTE Attribute
513 )
514
515 {
516 EFI_STATUS Status;
517 EFI_GUID ModuleGuid;
518 CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
519 FPDT_RECORD_PTR FpdtRecordPtr;
520 FPDT_RECORD_PTR CachedFpdtRecordPtr;
521 UINT64 TimeStamp;
522 CONST CHAR8 *StringPtr;
523 UINTN DestMax;
524 UINTN StringLen;
525 UINT16 ProgressId;
526
527 StringPtr = NULL;
528 ZeroMem (ModuleName, sizeof (ModuleName));
529
530 //
531 // 1. Get the Perf Id for records from PERF_START/PERF_END, PERF_START_EX/PERF_END_EX.
532 // notes: For other Perf macros (Attribute == PerfEntry), their Id is known.
533 //
534 if (Attribute != PerfEntry) {
535 //
536 // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has high priority.
537 // !!! Note: If the Perf is not the known Token used in the core but have same
538 // ID with the core Token, this case will not be supported.
539 // And in currtnt usage mode, for the unkown ID, there is a general rule:
540 // If it is start pref: the lower 4 bits of the ID should be 0.
541 // If it is end pref: the lower 4 bits of the ID should not be 0.
542 // If input ID doesn't follow the rule, we will adjust it.
543 //
544 if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
545 return EFI_INVALID_PARAMETER;
546 } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
547 if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) {
548 PerfId &= 0xFFF0;
549 } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {
550 PerfId += 1;
551 }
552 }
553 if (PerfId == 0) {
554 //
555 // Get ProgressID form the String Token.
556 //
557 Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId);
558 if (EFI_ERROR (Status)) {
559 return Status;
560 }
561 PerfId = ProgressId;
562 }
563 }
564
565 //
566 // 2. Get the buffer to store the FPDT record.
567 //
568 Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr);
569 if (EFI_ERROR (Status)) {
570 return Status;
571 }
572
573 //
574 // 3. Get the TimeStamp.
575 //
576 if (Ticker == 0) {
577 Ticker = GetPerformanceCounter ();
578 TimeStamp = GetTimeInNanoSecond (Ticker);
579 } else if (Ticker == 1) {
580 TimeStamp = 0;
581 } else {
582 TimeStamp = GetTimeInNanoSecond (Ticker);
583 }
584
585 //
586 // 4. Fill in the FPDT record according to different Performance Identifier.
587 //
588 switch (PerfId) {
589 case MODULE_START_ID:
590 case MODULE_END_ID:
591 GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
592 StringPtr = ModuleName;
593 //
594 // Cache the offset of start image start record and use to update the start image end record if needed.
595 //
596 if (PerfId == MODULE_START_ID && Attribute == PerfEntry) {
597 mCachedLength = mSmmBootPerformanceTable->Header.Length;
598 }
599 if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
600 FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE;
601 FpdtRecordPtr.GuidEvent->Header.Length = sizeof (FPDT_GUID_EVENT_RECORD);
602 FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1;
603 FpdtRecordPtr.GuidEvent->ProgressID = PerfId;
604 FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp;
605 CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
606 if (CallerIdentifier == NULL && PerfId == MODULE_END_ID && mCachedLength != 0) {
607 CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
608 CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
609 mCachedLength = 0;
610 }
611 }
612 break;
613
614 case MODULE_LOADIMAGE_START_ID:
615 case MODULE_LOADIMAGE_END_ID:
616 GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
617 StringPtr = ModuleName;
618 if (PerfId == MODULE_LOADIMAGE_START_ID) {
619 mLoadImageCount++;
620 //
621 // Cache the offset of load image start record and use to be updated by the load image end record if needed.
622 //
623 if (CallerIdentifier == NULL && Attribute == PerfEntry) {
624 mCachedLength = mSmmBootPerformanceTable->Header.Length;
625 }
626 }
627 if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
628 FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE;
629 FpdtRecordPtr.GuidQwordEvent->Header.Length = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
630 FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
631 FpdtRecordPtr.GuidQwordEvent->ProgressID = PerfId;
632 FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp;
633 FpdtRecordPtr.GuidQwordEvent->Qword = mLoadImageCount;
634 CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));
635 if (PerfId == MODULE_LOADIMAGE_END_ID && mCachedLength != 0) {
636 CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
637 CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid));
638 mCachedLength = 0;
639 }
640 }
641 break;
642
643 case PERF_EVENTSIGNAL_START_ID:
644 case PERF_EVENTSIGNAL_END_ID:
645 case PERF_CALLBACK_START_ID:
646 case PERF_CALLBACK_END_ID:
647 if (String == NULL || Guid == NULL) {
648 return EFI_INVALID_PARAMETER;
649 }
650 StringPtr = String;
651 if (AsciiStrLen (String) == 0) {
652 StringPtr = "unknown name";
653 }
654 if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
655 FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE;
656 FpdtRecordPtr.DualGuidStringEvent->Header.Length = sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD);
657 FpdtRecordPtr.DualGuidStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
658 FpdtRecordPtr.DualGuidStringEvent->ProgressID = PerfId;
659 FpdtRecordPtr.DualGuidStringEvent->Timestamp = TimeStamp;
660 CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));
661 CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2));
662 CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, &FpdtRecordPtr.DualGuidStringEvent->Header.Length);
663 }
664 break;
665
666 case PERF_EVENT_ID:
667 case PERF_FUNCTION_START_ID:
668 case PERF_FUNCTION_END_ID:
669 case PERF_INMODULE_START_ID:
670 case PERF_INMODULE_END_ID:
671 case PERF_CROSSMODULE_START_ID:
672 case PERF_CROSSMODULE_END_ID:
673 GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
674 if (String != NULL) {
675 StringPtr = String;
676 } else {
677 StringPtr = ModuleName;
678 }
679 if (AsciiStrLen (StringPtr) == 0) {
680 StringPtr = "unknown name";
681 }
682 if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
683 FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
684 FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
685 FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
686 FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
687 FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
688 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
689 CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
690 }
691 break;
692
693 default:
694 if (Attribute != PerfEntry) {
695 GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
696 if (String != NULL) {
697 StringPtr = String;
698 } else {
699 StringPtr = ModuleName;
700 }
701 if (AsciiStrLen (StringPtr) == 0) {
702 StringPtr = "unknown name";
703 }
704 if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
705 FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
706 FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
707 FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
708 FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
709 FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
710 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
711 CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
712 }
713 } else {
714 return EFI_INVALID_PARAMETER;
715 }
716 break;
717 }
718
719 //
720 // 4.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries.
721 //
722 if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
723 if (StringPtr == NULL) {
724 return EFI_INVALID_PARAMETER;
725 }
726 FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
727 FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
728 FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
729 FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;
730 FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
731 if (Guid != NULL) {
732 //
733 // Cache the event guid in string event record.
734 //
735 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
736 } else {
737 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
738 }
739 if (AsciiStrLen (StringPtr) == 0) {
740 StringPtr = "unknown name";
741 }
742 CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
743
744 if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) {
745 FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE);
746 }
747 if ((PerfId == MODULE_LOADIMAGE_END_ID || PerfId == MODULE_END_ID) && mCachedLength != 0) {
748 CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
749 if (PerfId == MODULE_LOADIMAGE_END_ID) {
750 DestMax = CachedFpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
751 StringLen = AsciiStrLen (StringPtr);
752 if (StringLen >= DestMax) {
753 StringLen = DestMax -1;
754 }
755 CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
756 AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen);
757 } else if (PerfId == MODULE_END_ID) {
758 DestMax = FpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
759 StringLen = AsciiStrLen (CachedFpdtRecordPtr.DynamicStringEvent->String);
760 if (StringLen >= DestMax) {
761 StringLen = DestMax -1;
762 }
763 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &CachedFpdtRecordPtr.DynamicStringEvent->Guid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
764 AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, CachedFpdtRecordPtr.DynamicStringEvent->String, StringLen);
765 }
766 mCachedLength = 0;
767 }
768 }
769
770 //
771 // 5. Update the length of the used buffer after fill in the record.
772 //
773 mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
774 mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length;
775
776 return EFI_SUCCESS;
777 }
778
779 /**
780 Communication service SMI Handler entry.
781
782 This SMI handler provides services for report MM boot records.
783
784 Caution: This function may receive untrusted input.
785 Communicate buffer and buffer size are external input, so this function will do basic validation.
786
787 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
788 @param[in] RegisterContext Points to an optional handler context which was specified when the
789 handler was registered.
790 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
791 be conveyed from a non-MM environment into an MM environment.
792 @param[in, out] CommBufferSize The size of the CommBuffer.
793
794 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
795 should still be called.
796 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
797 still be called.
798 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
799 be called.
800 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
801
802 **/
803 EFI_STATUS
804 EFIAPI
805 FpdtSmiHandler (
806 IN EFI_HANDLE DispatchHandle,
807 IN CONST VOID *RegisterContext,
808 IN OUT VOID *CommBuffer,
809 IN OUT UINTN *CommBufferSize
810 )
811 {
812 EFI_STATUS Status;
813 SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;
814 UINTN BootRecordOffset;
815 UINTN BootRecordSize;
816 VOID *BootRecordData;
817 UINTN TempCommBufferSize;
818 UINT8 *BootRecordBuffer;
819
820 //
821 // If input is invalid, stop processing this SMI
822 //
823 if (CommBuffer == NULL || CommBufferSize == NULL) {
824 return EFI_SUCCESS;
825 }
826
827 TempCommBufferSize = *CommBufferSize;
828
829 if(TempCommBufferSize < sizeof (SMM_BOOT_RECORD_COMMUNICATE)) {
830 return EFI_SUCCESS;
831 }
832
833 if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
834 DEBUG ((DEBUG_ERROR, "FpdtSmiHandler: MM communication data buffer in MMRAM or overflow!\n"));
835 return EFI_SUCCESS;
836 }
837
838 SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)CommBuffer;
839
840 Status = EFI_SUCCESS;
841
842 switch (SmmCommData->Function) {
843 case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE :
844 if (mSmmBootPerformanceTable != NULL) {
845 mBootRecordSize = mSmmBootPerformanceTable->Header.Length - sizeof (SMM_BOOT_PERFORMANCE_TABLE);
846 }
847 SmmCommData->BootRecordSize = mBootRecordSize;
848 break;
849
850 case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA :
851 Status = EFI_UNSUPPORTED;
852 break;
853
854 case SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET :
855 BootRecordOffset = SmmCommData->BootRecordOffset;
856 BootRecordData = SmmCommData->BootRecordData;
857 BootRecordSize = SmmCommData->BootRecordSize;
858 if (BootRecordData == NULL || BootRecordOffset >= mBootRecordSize) {
859 Status = EFI_INVALID_PARAMETER;
860 break;
861 }
862
863 //
864 // Sanity check
865 //
866 if (BootRecordSize > mBootRecordSize - BootRecordOffset) {
867 BootRecordSize = mBootRecordSize - BootRecordOffset;
868 }
869 SmmCommData->BootRecordSize = BootRecordSize;
870 if (!SmmIsBufferOutsideSmmValid ((UINTN)BootRecordData, BootRecordSize)) {
871 DEBUG ((DEBUG_ERROR, "FpdtSmiHandler: MM Data buffer in MMRAM or overflow!\n"));
872 Status = EFI_ACCESS_DENIED;
873 break;
874 }
875 BootRecordBuffer = ((UINT8 *) (mSmmBootPerformanceTable)) + sizeof (SMM_BOOT_PERFORMANCE_TABLE);
876 CopyMem (
877 (UINT8*)BootRecordData,
878 BootRecordBuffer + BootRecordOffset,
879 BootRecordSize
880 );
881 mFpdtDataIsReported = TRUE;
882 break;
883
884 default:
885 Status = EFI_UNSUPPORTED;
886 }
887
888 SmmCommData->ReturnStatus = Status;
889
890 return EFI_SUCCESS;
891 }
892
893 /**
894 SmmBase2 protocol notify callback function, when SMST and SMM memory service get initialized
895 this function is callbacked to initialize the Smm Performance Lib
896
897 @param Event The event of notify protocol.
898 @param Context Notify event context.
899
900 **/
901 VOID
902 EFIAPI
903 InitializeSmmCorePerformanceLib (
904 IN EFI_EVENT Event,
905 IN VOID *Context
906 )
907 {
908 EFI_HANDLE Handle;
909 EFI_HANDLE SmiHandle;
910 EFI_STATUS Status;
911 PERFORMANCE_PROPERTY *PerformanceProperty;
912
913 //
914 // Initialize spin lock
915 //
916 InitializeSpinLock (&mSmmFpdtLock);
917
918 //
919 // Install the protocol interfaces for SMM performance library instance.
920 //
921 Handle = NULL;
922 Status = gSmst->SmmInstallProtocolInterface (
923 &Handle,
924 &gEdkiiSmmPerformanceMeasurementProtocolGuid,
925 EFI_NATIVE_INTERFACE,
926 &mPerformanceMeasurementInterface
927 );
928 ASSERT_EFI_ERROR (Status);
929
930 //
931 // Register SMI handler.
932 //
933 SmiHandle = NULL;
934 Status = gSmst->SmiHandlerRegister (FpdtSmiHandler, &gEfiFirmwarePerformanceGuid, &SmiHandle);
935 ASSERT_EFI_ERROR (Status);
936
937 Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);
938 if (EFI_ERROR (Status)) {
939 //
940 // Install configuration table for performance property.
941 //
942 mPerformanceProperty.Revision = PERFORMANCE_PROPERTY_REVISION;
943 mPerformanceProperty.Reserved = 0;
944 mPerformanceProperty.Frequency = GetPerformanceCounterProperties (
945 &mPerformanceProperty.TimerStartValue,
946 &mPerformanceProperty.TimerEndValue
947 );
948 Status = gBS->InstallConfigurationTable (&gPerformanceProtocolGuid, &mPerformanceProperty);
949 ASSERT_EFI_ERROR (Status);
950 }
951 }
952
953 /**
954 The constructor function initializes the Performance Measurement Enable flag and
955 registers SmmBase2 protocol notify callback.
956 It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
957
958 @param ImageHandle The firmware allocated handle for the EFI image.
959 @param SystemTable A pointer to the EFI System Table.
960
961 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
962
963 **/
964 EFI_STATUS
965 EFIAPI
966 SmmCorePerformanceLibConstructor (
967 IN EFI_HANDLE ImageHandle,
968 IN EFI_SYSTEM_TABLE *SystemTable
969 )
970 {
971 EFI_STATUS Status;
972 EFI_EVENT Event;
973 VOID *Registration;
974
975 if (!PerformanceMeasurementEnabled ()) {
976 //
977 // Do not initialize performance infrastructure if not required.
978 //
979 return EFI_SUCCESS;
980 }
981
982 //
983 // Create the events to do the library init.
984 //
985 Status = gBS->CreateEvent (
986 EVT_NOTIFY_SIGNAL,
987 TPL_CALLBACK,
988 InitializeSmmCorePerformanceLib,
989 NULL,
990 &Event
991 );
992 ASSERT_EFI_ERROR (Status);
993
994 //
995 // Register for protocol notifications on this event
996 //
997 Status = gBS->RegisterProtocolNotify (
998 &gEfiSmmBase2ProtocolGuid,
999 Event,
1000 &Registration
1001 );
1002
1003 ASSERT_EFI_ERROR (Status);
1004
1005 return EFI_SUCCESS;
1006 }
1007
1008 /**
1009 Create performance record with event description and a timestamp.
1010
1011 @param CallerIdentifier - Image handle or pointer to caller ID GUID.
1012 @param Guid - Pointer to a GUID.
1013 @param String - Pointer to a string describing the measurement.
1014 @param TimeStamp - 64-bit time stamp.
1015 @param Address - Pointer to a location in memory relevant to the measurement.
1016 @param Identifier - Performance identifier describing the type of measurement.
1017 @param Attribute - The attribute of the measurement. According to attribute can create a start
1018 record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
1019 or a general record for other Perf macros.
1020
1021 @retval EFI_SUCCESS - Successfully created performance record.
1022 @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.
1023 @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
1024 pointer or invalid PerfId.
1025 **/
1026 EFI_STATUS
1027 EFIAPI
1028 CreatePerformanceMeasurement(
1029 IN CONST VOID *CallerIdentifier OPTIONAL,
1030 IN CONST VOID *Guid OPTIONAL,
1031 IN CONST CHAR8 *String OPTIONAL,
1032 IN UINT64 TimeStamp OPTIONAL,
1033 IN UINT64 Address OPTIONAL,
1034 IN UINT32 Identifier,
1035 IN PERF_MEASUREMENT_ATTRIBUTE Attribute
1036 )
1037 {
1038 EFI_STATUS Status;
1039
1040 Status = EFI_SUCCESS;
1041
1042 AcquireSpinLock (&mSmmFpdtLock);
1043 Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute);
1044 ReleaseSpinLock (&mSmmFpdtLock);
1045 return Status;
1046 }
1047
1048 /**
1049 Adds a record at the end of the performance measurement log
1050 that records the start time of a performance measurement.
1051
1052 Adds a record to the end of the performance measurement log
1053 that contains the Handle, Token, Module and Identifier.
1054 The end time of the new record must be set to zero.
1055 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
1056 If TimeStamp is zero, the start time in the record is filled in with the value
1057 read from the current time stamp.
1058
1059 @param Handle Pointer to environment specific context used
1060 to identify the component being measured.
1061 @param Token Pointer to a Null-terminated ASCII string
1062 that identifies the component being measured.
1063 @param Module Pointer to a Null-terminated ASCII string
1064 that identifies the module being measured.
1065 @param TimeStamp 64-bit time stamp.
1066 @param Identifier 32-bit identifier. If the value is 0, the created record
1067 is same as the one created by StartPerformanceMeasurement.
1068
1069 @retval RETURN_SUCCESS The start of the measurement was recorded.
1070 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
1071
1072 **/
1073 RETURN_STATUS
1074 EFIAPI
1075 StartPerformanceMeasurementEx (
1076 IN CONST VOID *Handle OPTIONAL,
1077 IN CONST CHAR8 *Token OPTIONAL,
1078 IN CONST CHAR8 *Module OPTIONAL,
1079 IN UINT64 TimeStamp,
1080 IN UINT32 Identifier
1081 )
1082 {
1083 CONST CHAR8 *String;
1084
1085 if (Token != NULL) {
1086 String = Token;
1087 } else if (Module != NULL) {
1088 String = Module;
1089 } else {
1090 String = NULL;
1091 }
1092
1093 return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);
1094 }
1095
1096 /**
1097 Searches the performance measurement log from the beginning of the log
1098 for the first matching record that contains a zero end time and fills in a valid end time.
1099
1100 Searches the performance measurement log from the beginning of the log
1101 for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
1102 If the record can not be found then return RETURN_NOT_FOUND.
1103 If the record is found and TimeStamp is not zero,
1104 then the end time in the record is filled in with the value specified by TimeStamp.
1105 If the record is found and TimeStamp is zero, then the end time in the matching record
1106 is filled in with the current time stamp value.
1107
1108 @param Handle Pointer to environment specific context used
1109 to identify the component being measured.
1110 @param Token Pointer to a Null-terminated ASCII string
1111 that identifies the component being measured.
1112 @param Module Pointer to a Null-terminated ASCII string
1113 that identifies the module being measured.
1114 @param TimeStamp 64-bit time stamp.
1115 @param Identifier 32-bit identifier. If the value is 0, the found record
1116 is same as the one found by EndPerformanceMeasurement.
1117
1118 @retval RETURN_SUCCESS The end of the measurement was recorded.
1119 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
1120
1121 **/
1122 RETURN_STATUS
1123 EFIAPI
1124 EndPerformanceMeasurementEx (
1125 IN CONST VOID *Handle OPTIONAL,
1126 IN CONST CHAR8 *Token OPTIONAL,
1127 IN CONST CHAR8 *Module OPTIONAL,
1128 IN UINT64 TimeStamp,
1129 IN UINT32 Identifier
1130 )
1131 {
1132 CONST CHAR8 *String;
1133
1134 if (Token != NULL) {
1135 String = Token;
1136 } else if (Module != NULL) {
1137 String = Module;
1138 } else {
1139 String = NULL;
1140 }
1141
1142 return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);
1143 }
1144
1145 /**
1146 Attempts to retrieve a performance measurement log entry from the performance measurement log.
1147 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
1148 and then assign the Identifier with 0.
1149
1150 !!! Not Support!!!
1151
1152 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
1153 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
1154 and the key for the second entry in the log is returned. If the performance log is empty,
1155 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
1156 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
1157 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
1158 retrieved and an implementation specific non-zero key value that specifies the end of the performance
1159 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
1160 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
1161 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
1162 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
1163 If Handle is NULL, then ASSERT().
1164 If Token is NULL, then ASSERT().
1165 If Module is NULL, then ASSERT().
1166 If StartTimeStamp is NULL, then ASSERT().
1167 If EndTimeStamp is NULL, then ASSERT().
1168 If Identifier is NULL, then ASSERT().
1169
1170 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
1171 0, then the first performance measurement log entry is retrieved.
1172 On exit, the key of the next performance log entry.
1173 @param Handle Pointer to environment specific context used to identify the component
1174 being measured.
1175 @param Token Pointer to a Null-terminated ASCII string that identifies the component
1176 being measured.
1177 @param Module Pointer to a Null-terminated ASCII string that identifies the module
1178 being measured.
1179 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1180 was started.
1181 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1182 was ended.
1183 @param Identifier Pointer to the 32-bit identifier that was recorded.
1184
1185 @return The key for the next performance log entry (in general case).
1186
1187 **/
1188 UINTN
1189 EFIAPI
1190 GetPerformanceMeasurementEx (
1191 IN UINTN LogEntryKey,
1192 OUT CONST VOID **Handle,
1193 OUT CONST CHAR8 **Token,
1194 OUT CONST CHAR8 **Module,
1195 OUT UINT64 *StartTimeStamp,
1196 OUT UINT64 *EndTimeStamp,
1197 OUT UINT32 *Identifier
1198 )
1199 {
1200 return 0;
1201 }
1202
1203 /**
1204 Adds a record at the end of the performance measurement log
1205 that records the start time of a performance measurement.
1206
1207 Adds a record to the end of the performance measurement log
1208 that contains the Handle, Token, and Module.
1209 The end time of the new record must be set to zero.
1210 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
1211 If TimeStamp is zero, the start time in the record is filled in with the value
1212 read from the current time stamp.
1213
1214 @param Handle Pointer to environment specific context used
1215 to identify the component being measured.
1216 @param Token Pointer to a Null-terminated ASCII string
1217 that identifies the component being measured.
1218 @param Module Pointer to a Null-terminated ASCII string
1219 that identifies the module being measured.
1220 @param TimeStamp 64-bit time stamp.
1221
1222 @retval RETURN_SUCCESS The start of the measurement was recorded.
1223 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
1224
1225 **/
1226 RETURN_STATUS
1227 EFIAPI
1228 StartPerformanceMeasurement (
1229 IN CONST VOID *Handle OPTIONAL,
1230 IN CONST CHAR8 *Token OPTIONAL,
1231 IN CONST CHAR8 *Module OPTIONAL,
1232 IN UINT64 TimeStamp
1233 )
1234 {
1235 return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
1236 }
1237
1238 /**
1239 Searches the performance measurement log from the beginning of the log
1240 for the first matching record that contains a zero end time and fills in a valid end time.
1241
1242 Searches the performance measurement log from the beginning of the log
1243 for the first record that matches Handle, Token, and Module and has an end time value of zero.
1244 If the record can not be found then return RETURN_NOT_FOUND.
1245 If the record is found and TimeStamp is not zero,
1246 then the end time in the record is filled in with the value specified by TimeStamp.
1247 If the record is found and TimeStamp is zero, then the end time in the matching record
1248 is filled in with the current time stamp value.
1249
1250 @param Handle Pointer to environment specific context used
1251 to identify the component being measured.
1252 @param Token Pointer to a Null-terminated ASCII string
1253 that identifies the component being measured.
1254 @param Module Pointer to a Null-terminated ASCII string
1255 that identifies the module being measured.
1256 @param TimeStamp 64-bit time stamp.
1257
1258 @retval RETURN_SUCCESS The end of the measurement was recorded.
1259 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
1260
1261 **/
1262 RETURN_STATUS
1263 EFIAPI
1264 EndPerformanceMeasurement (
1265 IN CONST VOID *Handle OPTIONAL,
1266 IN CONST CHAR8 *Token OPTIONAL,
1267 IN CONST CHAR8 *Module OPTIONAL,
1268 IN UINT64 TimeStamp
1269 )
1270 {
1271 return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
1272 }
1273
1274 /**
1275 Attempts to retrieve a performance measurement log entry from the performance measurement log.
1276 It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
1277 and then eliminate the Identifier.
1278
1279 !!! Not Support!!!
1280
1281 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
1282 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
1283 and the key for the second entry in the log is returned. If the performance log is empty,
1284 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
1285 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
1286 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
1287 retrieved and an implementation specific non-zero key value that specifies the end of the performance
1288 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
1289 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
1290 the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
1291 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
1292 If Handle is NULL, then ASSERT().
1293 If Token is NULL, then ASSERT().
1294 If Module is NULL, then ASSERT().
1295 If StartTimeStamp is NULL, then ASSERT().
1296 If EndTimeStamp is NULL, then ASSERT().
1297
1298 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
1299 0, then the first performance measurement log entry is retrieved.
1300 On exit, the key of the next performance log entry.
1301 @param Handle Pointer to environment specific context used to identify the component
1302 being measured.
1303 @param Token Pointer to a Null-terminated ASCII string that identifies the component
1304 being measured.
1305 @param Module Pointer to a Null-terminated ASCII string that identifies the module
1306 being measured.
1307 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1308 was started.
1309 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1310 was ended.
1311
1312 @return The key for the next performance log entry (in general case).
1313
1314 **/
1315 UINTN
1316 EFIAPI
1317 GetPerformanceMeasurement (
1318 IN UINTN LogEntryKey,
1319 OUT CONST VOID **Handle,
1320 OUT CONST CHAR8 **Token,
1321 OUT CONST CHAR8 **Module,
1322 OUT UINT64 *StartTimeStamp,
1323 OUT UINT64 *EndTimeStamp
1324 )
1325 {
1326 return 0;
1327 }
1328
1329 /**
1330 Returns TRUE if the performance measurement macros are enabled.
1331
1332 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1333 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
1334
1335 @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1336 PcdPerformanceLibraryPropertyMask is set.
1337 @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1338 PcdPerformanceLibraryPropertyMask is clear.
1339
1340 **/
1341 BOOLEAN
1342 EFIAPI
1343 PerformanceMeasurementEnabled (
1344 VOID
1345 )
1346 {
1347 return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
1348 }
1349
1350 /**
1351 Create performance record with event description and a timestamp.
1352
1353 @param CallerIdentifier - Image handle or pointer to caller ID GUID
1354 @param Guid - Pointer to a GUID
1355 @param String - Pointer to a string describing the measurement
1356 @param Address - Pointer to a location in memory relevant to the measurement
1357 @param Identifier - Performance identifier describing the type of measurement
1358
1359 @retval RETURN_SUCCESS - Successfully created performance record
1360 @retval RETURN_OUT_OF_RESOURCES - Ran out of space to store the records
1361 @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL
1362 pointer or invalid PerfId
1363
1364 **/
1365 RETURN_STATUS
1366 EFIAPI
1367 LogPerformanceMeasurement (
1368 IN CONST VOID *CallerIdentifier,
1369 IN CONST VOID *Guid OPTIONAL,
1370 IN CONST CHAR8 *String OPTIONAL,
1371 IN UINT64 Address OPTIONAL,
1372 IN UINT32 Identifier
1373 )
1374 {
1375 return (RETURN_STATUS)CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);
1376 }
1377
1378 /**
1379 Check whether the specified performance measurement can be logged.
1380
1381 This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set
1382 and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
1383
1384 @param Type - Type of the performance measurement entry.
1385
1386 @retval TRUE The performance measurement can be logged.
1387 @retval FALSE The performance measurement can NOT be logged.
1388
1389 **/
1390 BOOLEAN
1391 EFIAPI
1392 LogPerformanceMeasurementEnabled (
1393 IN CONST UINTN Type
1394 )
1395 {
1396 //
1397 // When Performance measurement is enabled and the type is not filtered, the performance can be logged.
1398 //
1399 if (PerformanceMeasurementEnabled () && (PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
1400 return TRUE;
1401 }
1402 return FALSE;
1403 }