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 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 
52 //
53 // Interfaces for SMM PerformanceMeasurement Protocol.
54 //
55 EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = {
56   CreatePerformanceMeasurement,
57 };
58 
59 /**
60   Return the pointer to the FPDT record in the allocated memory.
61 
62   @param  RecordSize             The size of FPDT record.
63   @param  FpdtRecordPtr          Pointer the FPDT record in the allocated memory.
64 
65   @retval EFI_SUCCESS            Successfully get the pointer to the FPDT record.
66   @retval EFI_OUT_OF_RESOURCES   Ran out of space to store the records.
67 **/
68 EFI_STATUS
GetFpdtRecordPtr(IN UINT8 RecordSize,IN OUT FPDT_RECORD_PTR * FpdtRecordPtr)69 GetFpdtRecordPtr (
70   IN     UINT8               RecordSize,
71   IN OUT FPDT_RECORD_PTR     *FpdtRecordPtr
72 )
73 {
74   if (mFpdtDataIsReported) {
75     //
76     // Append Boot records after Smm boot performance records have been reported.
77     //
78     if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
79       if (!mLackSpaceIsReport) {
80         DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to save boot records\n"));
81         mLackSpaceIsReport = TRUE;
82       }
83       return EFI_OUT_OF_RESOURCES;
84     } else {
85       //
86       // Covert buffer to FPDT Ptr Union type.
87       //
88       FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
89     }
90   } else {
91     //
92     // Check if pre-allocated buffer is full
93     //
94     if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
95       mSmmBootPerformanceTable = ReallocatePool (
96                                    mPerformanceLength,
97                                    mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER,
98                                    mSmmBootPerformanceTable
99                               );
100 
101       if (mSmmBootPerformanceTable == NULL) {
102         return EFI_OUT_OF_RESOURCES;
103       }
104       mSmmBootPerformanceTable->Header.Length = mPerformanceLength;
105       mMaxPerformanceLength = mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER;
106     }
107     //
108     // Covert buffer to FPDT Ptr Union type.
109     //
110     FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
111   }
112   FpdtRecordPtr->RecordHeader->Length = 0;
113   return EFI_SUCCESS;
114 }
115 
116 
117 /**
118 Check whether the Token is a known one which is uesed by core.
119 
120 @param  Token      Pointer to a Null-terminated ASCII string
121 
122 @retval TRUE       Is a known one used by core.
123 @retval FALSE      Not a known one.
124 
125 **/
126 BOOLEAN
IsKnownTokens(IN CONST CHAR8 * Token)127 IsKnownTokens (
128   IN CONST CHAR8  *Token
129   )
130 {
131   if (Token == NULL) {
132     return FALSE;
133   }
134 
135   if (AsciiStrCmp (Token, SEC_TOK) == 0 ||
136       AsciiStrCmp (Token, PEI_TOK) == 0 ||
137       AsciiStrCmp (Token, DXE_TOK) == 0 ||
138       AsciiStrCmp (Token, BDS_TOK) == 0 ||
139       AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0 ||
140       AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0 ||
141       AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0 ||
142       AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0 ||
143       AsciiStrCmp (Token, START_IMAGE_TOK) == 0 ||
144       AsciiStrCmp (Token, PEIM_TOK) == 0) {
145     return TRUE;
146   } else {
147     return FALSE;
148   }
149 }
150 
151 /**
152 Check whether the ID is a known one which map to the known Token.
153 
154 @param  Identifier  32-bit identifier.
155 
156 @retval TRUE        Is a known one used by core.
157 @retval FALSE       Not a known one.
158 
159 **/
160 BOOLEAN
IsKnownID(IN UINT32 Identifier)161 IsKnownID (
162   IN UINT32       Identifier
163   )
164 {
165   if (Identifier == MODULE_START_ID ||
166       Identifier == MODULE_END_ID ||
167       Identifier == MODULE_LOADIMAGE_START_ID ||
168       Identifier == MODULE_LOADIMAGE_END_ID ||
169       Identifier == MODULE_DB_START_ID ||
170       Identifier == MODULE_DB_END_ID ||
171       Identifier == MODULE_DB_SUPPORT_START_ID ||
172       Identifier == MODULE_DB_SUPPORT_END_ID ||
173       Identifier == MODULE_DB_STOP_START_ID ||
174       Identifier == MODULE_DB_STOP_END_ID) {
175     return TRUE;
176   } else {
177     return FALSE;
178   }
179 }
180 
181 /**
182   Get the FPDT record identifier.
183 
184   @param Attribute                The attribute of the Record.
185                                   PerfStartEntry: Start Record.
186                                   PerfEndEntry: End Record.
187   @param  Handle                  Pointer to environment specific context used to identify the component being measured.
188   @param  String                  Pointer to a Null-terminated ASCII string that identifies the component being measured.
189   @param  ProgressID              On return, pointer to the ProgressID.
190 
191   @retval EFI_SUCCESS              Get record info successfully.
192   @retval EFI_INVALID_PARAMETER    No matched FPDT record.
193 
194 **/
195 EFI_STATUS
GetFpdtRecordId(IN PERF_MEASUREMENT_ATTRIBUTE Attribute,IN CONST VOID * Handle,IN CONST CHAR8 * String,OUT UINT16 * ProgressID)196 GetFpdtRecordId (
197   IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute,
198   IN CONST VOID                        *Handle,
199   IN CONST CHAR8                       *String,
200   OUT UINT16                           *ProgressID
201   )
202 {
203   //
204   // Token to Id.
205   //
206   if (String != NULL) {
207     if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) {              // "StartImage:"
208       if (Attribute == PerfStartEntry) {
209         *ProgressID  = MODULE_START_ID;
210       } else {
211         *ProgressID  = MODULE_END_ID;
212       }
213     } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) {        // "LoadImage:"
214       if (Attribute == PerfStartEntry) {
215         *ProgressID  = MODULE_LOADIMAGE_START_ID;
216       } else {
217         *ProgressID  = MODULE_LOADIMAGE_END_ID;
218       }
219     } else {                                                      // Pref used in Modules
220       if (Attribute == PerfStartEntry) {
221         *ProgressID  = PERF_INMODULE_START_ID;
222       } else {
223         *ProgressID  = PERF_INMODULE_END_ID;
224       }
225     }
226   } else if (Handle != NULL) {                                    // Pref used in Modules
227     if (Attribute == PerfStartEntry) {
228       *ProgressID    = PERF_INMODULE_START_ID;
229     } else {
230       *ProgressID    = PERF_INMODULE_END_ID;
231     }
232   } else {
233     return EFI_UNSUPPORTED;
234   }
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
GetModuleInfoFromHandle(IN EFI_HANDLE Handle,OUT CHAR8 * NameString,IN UINTN BufferSize,OUT EFI_GUID * ModuleGuid OPTIONAL)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   Copies the string from Source into Destination and updates Length with the
441   size of the string.
442 
443   @param Destination - destination of the string copy
444   @param Source      - pointer to the source string which will get copied
445   @param Length      - pointer to a length variable to be updated
446 
447 **/
448 VOID
CopyStringIntoPerfRecordAndUpdateLength(IN OUT CHAR8 * Destination,IN CONST CHAR8 * Source,IN OUT UINT8 * Length)449 CopyStringIntoPerfRecordAndUpdateLength (
450   IN OUT CHAR8  *Destination,
451   IN     CONST CHAR8  *Source,
452   IN OUT UINT8  *Length
453   )
454 {
455   UINTN  StringLen;
456   UINTN  DestMax;
457 
458   ASSERT (Source != NULL);
459 
460   if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
461     DestMax = STRING_SIZE;
462   } else {
463     DestMax = AsciiStrSize (Source);
464     if (DestMax > STRING_SIZE) {
465       DestMax = STRING_SIZE;
466     }
467   }
468   StringLen = AsciiStrLen (Source);
469   if (StringLen >= DestMax) {
470     StringLen = DestMax -1;
471   }
472 
473   AsciiStrnCpyS(Destination, DestMax, Source, StringLen);
474   *Length += (UINT8)DestMax;
475 
476   return;
477 }
478 
479 /**
480   Create performance record with event description and a timestamp.
481 
482   @param CallerIdentifier  - Image handle or pointer to caller ID GUID.
483   @param Guid              - Pointer to a GUID.
484   @param String            - Pointer to a string describing the measurement.
485   @param Ticker            - 64-bit time stamp.
486   @param Address           - Pointer to a location in memory relevant to the measurement.
487   @param PerfId            - Performance identifier describing the type of measurement.
488   @param Attribute         - The attribute of the measurement. According to attribute can create a start
489                              record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
490                              or a general record for other Perf macros.
491 
492   @retval EFI_SUCCESS           - Successfully created performance record.
493   @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records.
494   @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
495                                   pointer or invalid PerfId.
496 
497   @retval EFI_SUCCESS           - Successfully created performance record
498   @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records
499   @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
500                                   pointer or invalid PerfId
501 
502 **/
503 EFI_STATUS
InsertFpdtRecord(IN CONST VOID * CallerIdentifier,OPTIONAL IN CONST VOID * Guid,OPTIONAL IN CONST CHAR8 * String,OPTIONAL IN UINT64 Ticker,IN UINT64 Address,OPTIONAL IN UINT16 PerfId,IN PERF_MEASUREMENT_ATTRIBUTE Attribute)504 InsertFpdtRecord (
505   IN CONST VOID                        *CallerIdentifier,  OPTIONAL
506   IN CONST VOID                        *Guid,    OPTIONAL
507   IN CONST CHAR8                       *String,  OPTIONAL
508   IN       UINT64                      Ticker,
509   IN       UINT64                      Address,  OPTIONAL
510   IN       UINT16                      PerfId,
511   IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute
512   )
513 
514 {
515   EFI_STATUS                   Status;
516   EFI_GUID                     ModuleGuid;
517   CHAR8                        ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
518   FPDT_RECORD_PTR              FpdtRecordPtr;
519   FPDT_RECORD_PTR              CachedFpdtRecordPtr;
520   UINT64                       TimeStamp;
521   CONST CHAR8                  *StringPtr;
522   UINTN                        DestMax;
523   UINTN                        StringLen;
524   UINT16                       ProgressId;
525 
526   StringPtr     = NULL;
527   ZeroMem (ModuleName, sizeof (ModuleName));
528 
529   //
530   // 1. Get the Perf Id for records from PERF_START/PERF_END, PERF_START_EX/PERF_END_EX.
531   //    notes: For other Perf macros (Attribute == PerfEntry), their Id is known.
532   //
533   if (Attribute != PerfEntry) {
534     //
535     // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has high priority.
536     // !!! Note: If the Perf is not the known Token used in the core but have same
537     // ID with the core Token, this case will not be supported.
538     // And in currtnt usage mode, for the unkown ID, there is a general rule:
539     // If it is start pref: the lower 4 bits of the ID should be 0.
540     // If it is end pref: the lower 4 bits of the ID should not be 0.
541     // If input ID doesn't follow the rule, we will adjust it.
542     //
543     if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
544       return EFI_INVALID_PARAMETER;
545     } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
546       if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) {
547         PerfId &= 0xFFF0;
548       } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {
549         PerfId += 1;
550       }
551     }
552     if (PerfId == 0) {
553       //
554       // Get ProgressID form the String Token.
555       //
556       Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId);
557       if (EFI_ERROR (Status)) {
558         return Status;
559       }
560       PerfId = ProgressId;
561     }
562   }
563 
564   //
565   // 2. Get the buffer to store the FPDT record.
566   //
567   Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr);
568   if (EFI_ERROR (Status)) {
569     return Status;
570   }
571 
572   //
573   // 3. Get the TimeStamp.
574   //
575   if (Ticker == 0) {
576     Ticker    = GetPerformanceCounter ();
577     TimeStamp = GetTimeInNanoSecond (Ticker);
578   } else if (Ticker == 1) {
579     TimeStamp = 0;
580   } else {
581     TimeStamp = GetTimeInNanoSecond (Ticker);
582   }
583 
584   //
585   // 4. Fill in the FPDT record according to different Performance Identifier.
586   //
587   switch (PerfId) {
588   case MODULE_START_ID:
589   case MODULE_END_ID:
590     GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
591     StringPtr = ModuleName;
592     //
593     // Cache the offset of start image start record and use to update the start image end record if needed.
594     //
595     if (PerfId == MODULE_START_ID && Attribute == PerfEntry) {
596       mCachedLength = mSmmBootPerformanceTable->Header.Length;
597     }
598     if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
599       FpdtRecordPtr.GuidEvent->Header.Type                = FPDT_GUID_EVENT_TYPE;
600       FpdtRecordPtr.GuidEvent->Header.Length              = sizeof (FPDT_GUID_EVENT_RECORD);
601       FpdtRecordPtr.GuidEvent->Header.Revision            = FPDT_RECORD_REVISION_1;
602       FpdtRecordPtr.GuidEvent->ProgressID                 = PerfId;
603       FpdtRecordPtr.GuidEvent->Timestamp                  = TimeStamp;
604       CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
605       if (CallerIdentifier == NULL && PerfId == MODULE_END_ID && mCachedLength != 0) {
606         CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
607         CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
608         mCachedLength = 0;
609       }
610     }
611     break;
612 
613   case MODULE_LOADIMAGE_START_ID:
614   case MODULE_LOADIMAGE_END_ID:
615     GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
616     StringPtr = ModuleName;
617     if (PerfId == MODULE_LOADIMAGE_START_ID) {
618       mLoadImageCount++;
619       //
620       // Cache the offset of load image start record and use to be updated by the load image end record if needed.
621       //
622       if (CallerIdentifier == NULL && Attribute == PerfEntry) {
623         mCachedLength = mSmmBootPerformanceTable->Header.Length;
624       }
625     }
626     if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
627       FpdtRecordPtr.GuidQwordEvent->Header.Type           = FPDT_GUID_QWORD_EVENT_TYPE;
628       FpdtRecordPtr.GuidQwordEvent->Header.Length         = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
629       FpdtRecordPtr.GuidQwordEvent->Header.Revision       = FPDT_RECORD_REVISION_1;
630       FpdtRecordPtr.GuidQwordEvent->ProgressID            = PerfId;
631       FpdtRecordPtr.GuidQwordEvent->Timestamp             = TimeStamp;
632       FpdtRecordPtr.GuidQwordEvent->Qword                 = mLoadImageCount;
633       CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));
634       if (PerfId == MODULE_LOADIMAGE_END_ID && mCachedLength != 0) {
635         CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
636         CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid));
637         mCachedLength = 0;
638       }
639     }
640     break;
641 
642   case PERF_EVENTSIGNAL_START_ID:
643   case PERF_EVENTSIGNAL_END_ID:
644   case PERF_CALLBACK_START_ID:
645   case PERF_CALLBACK_END_ID:
646     if (String == NULL || Guid == NULL) {
647       return EFI_INVALID_PARAMETER;
648     }
649     StringPtr = String;
650     if (AsciiStrLen (String) == 0) {
651       StringPtr = "unknown name";
652     }
653     if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
654       FpdtRecordPtr.DualGuidStringEvent->Header.Type      = FPDT_DUAL_GUID_STRING_EVENT_TYPE;
655       FpdtRecordPtr.DualGuidStringEvent->Header.Length    = sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD);
656       FpdtRecordPtr.DualGuidStringEvent->Header.Revision  = FPDT_RECORD_REVISION_1;
657       FpdtRecordPtr.DualGuidStringEvent->ProgressID       = PerfId;
658       FpdtRecordPtr.DualGuidStringEvent->Timestamp        = TimeStamp;
659       CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));
660       CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2));
661       CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, &FpdtRecordPtr.DualGuidStringEvent->Header.Length);
662     }
663     break;
664 
665   case PERF_EVENT_ID:
666   case PERF_FUNCTION_START_ID:
667   case PERF_FUNCTION_END_ID:
668   case PERF_INMODULE_START_ID:
669   case PERF_INMODULE_END_ID:
670   case PERF_CROSSMODULE_START_ID:
671   case PERF_CROSSMODULE_END_ID:
672     GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
673     if (String != NULL) {
674       StringPtr = String;
675     } else {
676       StringPtr = ModuleName;
677     }
678     if (AsciiStrLen (StringPtr) == 0) {
679       StringPtr = "unknown name";
680     }
681     if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
682       FpdtRecordPtr.DynamicStringEvent->Header.Type       = FPDT_DYNAMIC_STRING_EVENT_TYPE;
683       FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
684       FpdtRecordPtr.DynamicStringEvent->Header.Revision   = FPDT_RECORD_REVISION_1;
685       FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
686       FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
687       CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
688       CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
689     }
690     break;
691 
692   default:
693     if (Attribute != PerfEntry) {
694       GetModuleInfoFromHandle ((EFI_HANDLE)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);
695       if (String != NULL) {
696         StringPtr = String;
697       } else {
698         StringPtr = ModuleName;
699       }
700       if (AsciiStrLen (StringPtr) == 0) {
701         StringPtr = "unknown name";
702       }
703       if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
704         FpdtRecordPtr.DynamicStringEvent->Header.Type       = FPDT_DYNAMIC_STRING_EVENT_TYPE;
705         FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
706         FpdtRecordPtr.DynamicStringEvent->Header.Revision   = FPDT_RECORD_REVISION_1;
707         FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
708         FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
709         CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
710         CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
711       }
712     } else {
713       return EFI_INVALID_PARAMETER;
714     }
715     break;
716   }
717 
718   //
719   // 4.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries.
720   //
721   if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
722     if (StringPtr == NULL) {
723       return EFI_INVALID_PARAMETER;
724     }
725     FpdtRecordPtr.DynamicStringEvent->Header.Type       = FPDT_DYNAMIC_STRING_EVENT_TYPE;
726     FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
727     FpdtRecordPtr.DynamicStringEvent->Header.Revision   = FPDT_RECORD_REVISION_1;
728     FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
729     FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
730     if (Guid != NULL) {
731       //
732       // Cache the event guid in string event record.
733       //
734       CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
735     } else {
736       CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
737     }
738     if (AsciiStrLen (StringPtr) == 0) {
739       StringPtr = "unknown name";
740     }
741     CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);
742 
743     if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) {
744       FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE);
745     }
746     if ((PerfId == MODULE_LOADIMAGE_END_ID || PerfId == MODULE_END_ID) && mCachedLength != 0) {
747       CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
748       if (PerfId == MODULE_LOADIMAGE_END_ID) {
749         DestMax = CachedFpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
750         StringLen = AsciiStrLen (StringPtr);
751         if (StringLen >= DestMax) {
752           StringLen = DestMax -1;
753         }
754         CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
755         AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen);
756       } else if (PerfId == MODULE_END_ID) {
757         DestMax = FpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
758         StringLen = AsciiStrLen (CachedFpdtRecordPtr.DynamicStringEvent->String);
759         if (StringLen >= DestMax) {
760           StringLen = DestMax -1;
761         }
762         CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &CachedFpdtRecordPtr.DynamicStringEvent->Guid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
763         AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, CachedFpdtRecordPtr.DynamicStringEvent->String, StringLen);
764       }
765       mCachedLength = 0;
766     }
767   }
768 
769   //
770   // 5. Update the length of the used buffer after fill in the record.
771   //
772   mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
773   mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length;
774 
775   return EFI_SUCCESS;
776 }
777 
778 /**
779   SmmReadyToBoot protocol notification event handler.
780 
781   @param  Protocol   Points to the protocol's unique identifier
782   @param  Interface  Points to the interface instance
783   @param  Handle     The handle on which the interface was installed
784 
785   @retval EFI_SUCCESS   SmmReadyToBootCallback runs successfully
786 
787 **/
788 EFI_STATUS
789 EFIAPI
SmmReportFpdtRecordData(IN CONST EFI_GUID * Protocol,IN VOID * Interface,IN EFI_HANDLE Handle)790 SmmReportFpdtRecordData (
791   IN CONST EFI_GUID                       *Protocol,
792   IN VOID                                 *Interface,
793   IN EFI_HANDLE                           Handle
794   )
795 {
796   UINT64          SmmBPDTddr;
797 
798   if (!mFpdtDataIsReported && mSmmBootPerformanceTable != NULL) {
799     SmmBPDTddr = (UINT64)(UINTN)mSmmBootPerformanceTable;
800     REPORT_STATUS_CODE_EX (
801         EFI_PROGRESS_CODE,
802         EFI_SOFTWARE_SMM_DRIVER,
803         0,
804         NULL,
805         &gEdkiiFpdtExtendedFirmwarePerformanceGuid,
806         &SmmBPDTddr,
807         sizeof (UINT64)
808         );
809     //
810     // Set FPDT report state to TRUE.
811     //
812     mFpdtDataIsReported = TRUE;
813   }
814   return EFI_SUCCESS;
815 }
816 
817 /**
818   SmmBase2 protocol notify callback function, when SMST and SMM memory service get initialized
819   this function is callbacked to initialize the Smm Performance Lib
820 
821   @param  Event    The event of notify protocol.
822   @param  Context  Notify event context.
823 
824 **/
825 VOID
826 EFIAPI
InitializeSmmCorePerformanceLib(IN EFI_EVENT Event,IN VOID * Context)827 InitializeSmmCorePerformanceLib (
828   IN EFI_EVENT     Event,
829   IN VOID          *Context
830   )
831 {
832   EFI_HANDLE                Handle;
833   EFI_STATUS                Status;
834   VOID                      *SmmReadyToBootRegistration;
835   PERFORMANCE_PROPERTY      *PerformanceProperty;
836 
837   //
838   // Initialize spin lock
839   //
840   InitializeSpinLock (&mSmmFpdtLock);
841 
842   //
843   // Install the protocol interfaces for SMM performance library instance.
844   //
845   Handle = NULL;
846   Status = gSmst->SmmInstallProtocolInterface (
847                     &Handle,
848                     &gEdkiiSmmPerformanceMeasurementProtocolGuid,
849                     EFI_NATIVE_INTERFACE,
850                     &mPerformanceMeasurementInterface
851                     );
852   ASSERT_EFI_ERROR (Status);
853 
854   Status = gSmst->SmmRegisterProtocolNotify (
855                     &gEdkiiSmmReadyToBootProtocolGuid,
856                     SmmReportFpdtRecordData,
857                     &SmmReadyToBootRegistration
858                     );
859   Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);
860   if (EFI_ERROR (Status)) {
861     //
862     // Install configuration table for performance property.
863     //
864     mPerformanceProperty.Revision  = PERFORMANCE_PROPERTY_REVISION;
865     mPerformanceProperty.Reserved  = 0;
866     mPerformanceProperty.Frequency = GetPerformanceCounterProperties (
867                                        &mPerformanceProperty.TimerStartValue,
868                                        &mPerformanceProperty.TimerEndValue
869                                        );
870     Status = gBS->InstallConfigurationTable (&gPerformanceProtocolGuid, &mPerformanceProperty);
871     ASSERT_EFI_ERROR (Status);
872   }
873 }
874 
875 /**
876   The constructor function initializes the Performance Measurement Enable flag and
877   registers SmmBase2 protocol notify callback.
878   It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
879 
880   @param  ImageHandle   The firmware allocated handle for the EFI image.
881   @param  SystemTable   A pointer to the EFI System Table.
882 
883   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
884 
885 **/
886 EFI_STATUS
887 EFIAPI
SmmCorePerformanceLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)888 SmmCorePerformanceLibConstructor (
889   IN EFI_HANDLE        ImageHandle,
890   IN EFI_SYSTEM_TABLE  *SystemTable
891   )
892 {
893   EFI_STATUS  Status;
894   EFI_EVENT   Event;
895   VOID        *Registration;
896 
897   if (!PerformanceMeasurementEnabled ()) {
898     //
899     // Do not initialize performance infrastructure if not required.
900     //
901     return EFI_SUCCESS;
902   }
903 
904   //
905   // Create the events to do the library init.
906   //
907   Status = gBS->CreateEvent (
908                   EVT_NOTIFY_SIGNAL,
909                   TPL_CALLBACK,
910                   InitializeSmmCorePerformanceLib,
911                   NULL,
912                   &Event
913                   );
914   ASSERT_EFI_ERROR (Status);
915 
916   //
917   // Register for protocol notifications on this event
918   //
919   Status = gBS->RegisterProtocolNotify (
920                   &gEfiSmmBase2ProtocolGuid,
921                   Event,
922                   &Registration
923                   );
924 
925   ASSERT_EFI_ERROR (Status);
926 
927   return EFI_SUCCESS;
928 }
929 
930 /**
931   Create performance record with event description and a timestamp.
932 
933   @param CallerIdentifier  - Image handle or pointer to caller ID GUID.
934   @param Guid              - Pointer to a GUID.
935   @param String            - Pointer to a string describing the measurement.
936   @param TimeStamp         - 64-bit time stamp.
937   @param Address           - Pointer to a location in memory relevant to the measurement.
938   @param Identifier        - Performance identifier describing the type of measurement.
939   @param Attribute         - The attribute of the measurement. According to attribute can create a start
940                              record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,
941                              or a general record for other Perf macros.
942 
943   @retval EFI_SUCCESS           - Successfully created performance record.
944   @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records.
945   @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
946                                   pointer or invalid PerfId.
947 **/
948 EFI_STATUS
949 EFIAPI
CreatePerformanceMeasurement(IN CONST VOID * CallerIdentifier,OPTIONAL IN CONST VOID * Guid,OPTIONAL IN CONST CHAR8 * String,OPTIONAL IN UINT64 TimeStamp,OPTIONAL IN UINT64 Address,OPTIONAL IN UINT32 Identifier,IN PERF_MEASUREMENT_ATTRIBUTE Attribute)950 CreatePerformanceMeasurement(
951   IN CONST VOID                        *CallerIdentifier, OPTIONAL
952   IN CONST VOID                        *Guid,     OPTIONAL
953   IN CONST CHAR8                       *String,   OPTIONAL
954   IN       UINT64                      TimeStamp, OPTIONAL
955   IN       UINT64                      Address,   OPTIONAL
956   IN       UINT32                      Identifier,
957   IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute
958   )
959 {
960   EFI_STATUS   Status;
961 
962   Status = EFI_SUCCESS;
963 
964   AcquireSpinLock (&mSmmFpdtLock);
965   Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute);
966   ReleaseSpinLock (&mSmmFpdtLock);
967   return Status;
968 }
969 
970 /**
971   Adds a record at the end of the performance measurement log
972   that records the start time of a performance measurement.
973 
974   Adds a record to the end of the performance measurement log
975   that contains the Handle, Token, Module and Identifier.
976   The end time of the new record must be set to zero.
977   If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
978   If TimeStamp is zero, the start time in the record is filled in with the value
979   read from the current time stamp.
980 
981   @param  Handle                  Pointer to environment specific context used
982                                   to identify the component being measured.
983   @param  Token                   Pointer to a Null-terminated ASCII string
984                                   that identifies the component being measured.
985   @param  Module                  Pointer to a Null-terminated ASCII string
986                                   that identifies the module being measured.
987   @param  TimeStamp               64-bit time stamp.
988   @param  Identifier              32-bit identifier. If the value is 0, the created record
989                                   is same as the one created by StartPerformanceMeasurement.
990 
991   @retval RETURN_SUCCESS          The start of the measurement was recorded.
992   @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
993 
994 **/
995 RETURN_STATUS
996 EFIAPI
StartPerformanceMeasurementEx(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp,IN UINT32 Identifier)997 StartPerformanceMeasurementEx (
998   IN CONST VOID   *Handle,  OPTIONAL
999   IN CONST CHAR8  *Token,   OPTIONAL
1000   IN CONST CHAR8  *Module,  OPTIONAL
1001   IN UINT64       TimeStamp,
1002   IN UINT32       Identifier
1003   )
1004 {
1005   CONST CHAR8     *String;
1006 
1007   if (Token != NULL) {
1008     String = Token;
1009   } else if (Module != NULL) {
1010     String = Module;
1011   } else {
1012     String = NULL;
1013   }
1014 
1015   return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);
1016 }
1017 
1018 /**
1019   Searches the performance measurement log from the beginning of the log
1020   for the first matching record that contains a zero end time and fills in a valid end time.
1021 
1022   Searches the performance measurement log from the beginning of the log
1023   for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
1024   If the record can not be found then return RETURN_NOT_FOUND.
1025   If the record is found and TimeStamp is not zero,
1026   then the end time in the record is filled in with the value specified by TimeStamp.
1027   If the record is found and TimeStamp is zero, then the end time in the matching record
1028   is filled in with the current time stamp value.
1029 
1030   @param  Handle                  Pointer to environment specific context used
1031                                   to identify the component being measured.
1032   @param  Token                   Pointer to a Null-terminated ASCII string
1033                                   that identifies the component being measured.
1034   @param  Module                  Pointer to a Null-terminated ASCII string
1035                                   that identifies the module being measured.
1036   @param  TimeStamp               64-bit time stamp.
1037   @param  Identifier              32-bit identifier. If the value is 0, the found record
1038                                   is same as the one found by EndPerformanceMeasurement.
1039 
1040   @retval RETURN_SUCCESS          The end of  the measurement was recorded.
1041   @retval RETURN_NOT_FOUND        The specified measurement record could not be found.
1042 
1043 **/
1044 RETURN_STATUS
1045 EFIAPI
EndPerformanceMeasurementEx(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp,IN UINT32 Identifier)1046 EndPerformanceMeasurementEx (
1047   IN CONST VOID   *Handle,  OPTIONAL
1048   IN CONST CHAR8  *Token,   OPTIONAL
1049   IN CONST CHAR8  *Module,  OPTIONAL
1050   IN UINT64       TimeStamp,
1051   IN UINT32       Identifier
1052   )
1053 {
1054   CONST CHAR8     *String;
1055 
1056   if (Token != NULL) {
1057     String = Token;
1058   } else if (Module != NULL) {
1059     String = Module;
1060   } else {
1061     String = NULL;
1062   }
1063 
1064   return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);
1065 }
1066 
1067 /**
1068   Attempts to retrieve a performance measurement log entry from the performance measurement log.
1069   It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
1070   and then assign the Identifier with 0.
1071 
1072   !!! Not Support!!!
1073 
1074   Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
1075   zero on entry, then an attempt is made to retrieve the first entry from the performance log,
1076   and the key for the second entry in the log is returned.  If the performance log is empty,
1077   then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
1078   log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
1079   returned.  If LogEntryKey is the key for the last entry in the log, then the last log entry is
1080   retrieved and an implementation specific non-zero key value that specifies the end of the performance
1081   log is returned.  If LogEntryKey is equal this implementation specific non-zero key value, then no entry
1082   is retrieved and zero is returned.  In the cases where a performance log entry can be returned,
1083   the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
1084   If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
1085   If Handle is NULL, then ASSERT().
1086   If Token is NULL, then ASSERT().
1087   If Module is NULL, then ASSERT().
1088   If StartTimeStamp is NULL, then ASSERT().
1089   If EndTimeStamp is NULL, then ASSERT().
1090   If Identifier is NULL, then ASSERT().
1091 
1092   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
1093                                   0, then the first performance measurement log entry is retrieved.
1094                                   On exit, the key of the next performance log entry.
1095   @param  Handle                  Pointer to environment specific context used to identify the component
1096                                   being measured.
1097   @param  Token                   Pointer to a Null-terminated ASCII string that identifies the component
1098                                   being measured.
1099   @param  Module                  Pointer to a Null-terminated ASCII string that identifies the module
1100                                   being measured.
1101   @param  StartTimeStamp          Pointer to the 64-bit time stamp that was recorded when the measurement
1102                                   was started.
1103   @param  EndTimeStamp            Pointer to the 64-bit time stamp that was recorded when the measurement
1104                                   was ended.
1105   @param  Identifier              Pointer to the 32-bit identifier that was recorded.
1106 
1107   @return The key for the next performance log entry (in general case).
1108 
1109 **/
1110 UINTN
1111 EFIAPI
GetPerformanceMeasurementEx(IN UINTN LogEntryKey,OUT CONST VOID ** Handle,OUT CONST CHAR8 ** Token,OUT CONST CHAR8 ** Module,OUT UINT64 * StartTimeStamp,OUT UINT64 * EndTimeStamp,OUT UINT32 * Identifier)1112 GetPerformanceMeasurementEx (
1113   IN  UINTN       LogEntryKey,
1114   OUT CONST VOID  **Handle,
1115   OUT CONST CHAR8 **Token,
1116   OUT CONST CHAR8 **Module,
1117   OUT UINT64      *StartTimeStamp,
1118   OUT UINT64      *EndTimeStamp,
1119   OUT UINT32      *Identifier
1120   )
1121 {
1122   return 0;
1123 }
1124 
1125 /**
1126   Adds a record at the end of the performance measurement log
1127   that records the start time of a performance measurement.
1128 
1129   Adds a record to the end of the performance measurement log
1130   that contains the Handle, Token, and Module.
1131   The end time of the new record must be set to zero.
1132   If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
1133   If TimeStamp is zero, the start time in the record is filled in with the value
1134   read from the current time stamp.
1135 
1136   @param  Handle                  Pointer to environment specific context used
1137                                   to identify the component being measured.
1138   @param  Token                   Pointer to a Null-terminated ASCII string
1139                                   that identifies the component being measured.
1140   @param  Module                  Pointer to a Null-terminated ASCII string
1141                                   that identifies the module being measured.
1142   @param  TimeStamp               64-bit time stamp.
1143 
1144   @retval RETURN_SUCCESS          The start of the measurement was recorded.
1145   @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
1146 
1147 **/
1148 RETURN_STATUS
1149 EFIAPI
StartPerformanceMeasurement(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp)1150 StartPerformanceMeasurement (
1151   IN CONST VOID   *Handle,  OPTIONAL
1152   IN CONST CHAR8  *Token,   OPTIONAL
1153   IN CONST CHAR8  *Module,  OPTIONAL
1154   IN UINT64       TimeStamp
1155   )
1156 {
1157   return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
1158 }
1159 
1160 /**
1161   Searches the performance measurement log from the beginning of the log
1162   for the first matching record that contains a zero end time and fills in a valid end time.
1163 
1164   Searches the performance measurement log from the beginning of the log
1165   for the first record that matches Handle, Token, and Module and has an end time value of zero.
1166   If the record can not be found then return RETURN_NOT_FOUND.
1167   If the record is found and TimeStamp is not zero,
1168   then the end time in the record is filled in with the value specified by TimeStamp.
1169   If the record is found and TimeStamp is zero, then the end time in the matching record
1170   is filled in with the current time stamp value.
1171 
1172   @param  Handle                  Pointer to environment specific context used
1173                                   to identify the component being measured.
1174   @param  Token                   Pointer to a Null-terminated ASCII string
1175                                   that identifies the component being measured.
1176   @param  Module                  Pointer to a Null-terminated ASCII string
1177                                   that identifies the module being measured.
1178   @param  TimeStamp               64-bit time stamp.
1179 
1180   @retval RETURN_SUCCESS          The end of  the measurement was recorded.
1181   @retval RETURN_NOT_FOUND        The specified measurement record could not be found.
1182 
1183 **/
1184 RETURN_STATUS
1185 EFIAPI
EndPerformanceMeasurement(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp)1186 EndPerformanceMeasurement (
1187   IN CONST VOID   *Handle,  OPTIONAL
1188   IN CONST CHAR8  *Token,   OPTIONAL
1189   IN CONST CHAR8  *Module,  OPTIONAL
1190   IN UINT64       TimeStamp
1191   )
1192 {
1193   return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
1194 }
1195 
1196 /**
1197   Attempts to retrieve a performance measurement log entry from the performance measurement log.
1198   It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
1199   and then eliminate the Identifier.
1200 
1201   !!! Not Support!!!
1202 
1203   Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
1204   zero on entry, then an attempt is made to retrieve the first entry from the performance log,
1205   and the key for the second entry in the log is returned.  If the performance log is empty,
1206   then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
1207   log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
1208   returned.  If LogEntryKey is the key for the last entry in the log, then the last log entry is
1209   retrieved and an implementation specific non-zero key value that specifies the end of the performance
1210   log is returned.  If LogEntryKey is equal this implementation specific non-zero key value, then no entry
1211   is retrieved and zero is returned.  In the cases where a performance log entry can be returned,
1212   the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
1213   If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
1214   If Handle is NULL, then ASSERT().
1215   If Token is NULL, then ASSERT().
1216   If Module is NULL, then ASSERT().
1217   If StartTimeStamp is NULL, then ASSERT().
1218   If EndTimeStamp is NULL, then ASSERT().
1219 
1220   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
1221                                   0, then the first performance measurement log entry is retrieved.
1222                                   On exit, the key of the next performance log entry.
1223   @param  Handle                  Pointer to environment specific context used to identify the component
1224                                   being measured.
1225   @param  Token                   Pointer to a Null-terminated ASCII string that identifies the component
1226                                   being measured.
1227   @param  Module                  Pointer to a Null-terminated ASCII string that identifies the module
1228                                   being measured.
1229   @param  StartTimeStamp          Pointer to the 64-bit time stamp that was recorded when the measurement
1230                                   was started.
1231   @param  EndTimeStamp            Pointer to the 64-bit time stamp that was recorded when the measurement
1232                                   was ended.
1233 
1234   @return The key for the next performance log entry (in general case).
1235 
1236 **/
1237 UINTN
1238 EFIAPI
GetPerformanceMeasurement(IN UINTN LogEntryKey,OUT CONST VOID ** Handle,OUT CONST CHAR8 ** Token,OUT CONST CHAR8 ** Module,OUT UINT64 * StartTimeStamp,OUT UINT64 * EndTimeStamp)1239 GetPerformanceMeasurement (
1240   IN  UINTN       LogEntryKey,
1241   OUT CONST VOID  **Handle,
1242   OUT CONST CHAR8 **Token,
1243   OUT CONST CHAR8 **Module,
1244   OUT UINT64      *StartTimeStamp,
1245   OUT UINT64      *EndTimeStamp
1246   )
1247 {
1248   return 0;
1249 }
1250 
1251 /**
1252   Returns TRUE if the performance measurement macros are enabled.
1253 
1254   This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1255   PcdPerformanceLibraryPropertyMask is set.  Otherwise FALSE is returned.
1256 
1257   @retval TRUE                    The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1258                                   PcdPerformanceLibraryPropertyMask is set.
1259   @retval FALSE                   The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1260                                   PcdPerformanceLibraryPropertyMask is clear.
1261 
1262 **/
1263 BOOLEAN
1264 EFIAPI
PerformanceMeasurementEnabled(VOID)1265 PerformanceMeasurementEnabled (
1266   VOID
1267   )
1268 {
1269   return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
1270 }
1271 
1272 /**
1273   Create performance record with event description and a timestamp.
1274 
1275   @param CallerIdentifier  - Image handle or pointer to caller ID GUID
1276   @param Guid              - Pointer to a GUID
1277   @param String            - Pointer to a string describing the measurement
1278   @param Address           - Pointer to a location in memory relevant to the measurement
1279   @param Identifier        - Performance identifier describing the type of measurement
1280 
1281   @retval RETURN_SUCCESS           - Successfully created performance record
1282   @retval RETURN_OUT_OF_RESOURCES  - Ran out of space to store the records
1283   @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL
1284                                      pointer or invalid PerfId
1285 
1286 **/
1287 RETURN_STATUS
1288 EFIAPI
LogPerformanceMeasurement(IN CONST VOID * CallerIdentifier,IN CONST VOID * Guid,OPTIONAL IN CONST CHAR8 * String,OPTIONAL IN UINT64 Address,OPTIONAL IN UINT32 Identifier)1289 LogPerformanceMeasurement (
1290   IN CONST VOID   *CallerIdentifier,
1291   IN CONST VOID   *Guid,    OPTIONAL
1292   IN CONST CHAR8  *String,  OPTIONAL
1293   IN UINT64       Address, OPTIONAL
1294   IN UINT32       Identifier
1295   )
1296 {
1297   return (RETURN_STATUS)CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);
1298 }
1299 
1300 /**
1301   Check whether the specified performance measurement can be logged.
1302 
1303   This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set
1304   and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
1305 
1306   @param Type        - Type of the performance measurement entry.
1307 
1308   @retval TRUE         The performance measurement can be logged.
1309   @retval FALSE        The performance measurement can NOT be logged.
1310 
1311 **/
1312 BOOLEAN
1313 EFIAPI
LogPerformanceMeasurementEnabled(IN CONST UINTN Type)1314 LogPerformanceMeasurementEnabled (
1315   IN  CONST UINTN        Type
1316   )
1317 {
1318   //
1319   // When Performance measurement is enabled and the type is not filtered, the performance can be logged.
1320   //
1321   if (PerformanceMeasurementEnabled () && (PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
1322     return TRUE;
1323   }
1324   return FALSE;
1325 }
1326 
1327