1 /** @file
2   Performance library instance used in DXE phase to dump both PEI/DXE and SMM performance data.
3 
4   This library instance allows a DXE driver or UEFI application to dump both PEI/DXE and SMM performance data.
5   StartPerformanceMeasurement(), EndPerformanceMeasurement(), StartPerformanceMeasurementEx()
6   and EndPerformanceMeasurementEx() are not implemented.
7 
8   Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution.  The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13 
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 
17 **/
18 
19 
20 #include <PiDxe.h>
21 
22 #include <Guid/Performance.h>
23 
24 #include <Library/PerformanceLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/UefiBootServicesTableLib.h>
27 #include <Library/UefiRuntimeServicesTableLib.h>
28 #include <Library/PcdLib.h>
29 #include <Library/BaseMemoryLib.h>
30 #include <Library/BaseLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 
33 #include <Protocol/SmmCommunication.h>
34 
35 #define SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)  + sizeof (SMM_PERF_COMMUNICATE))
36 
37 EFI_SMM_COMMUNICATION_PROTOCOL  *mSmmCommunication = NULL;
38 UINT8                           mSmmPerformanceBuffer[SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE];
39 GAUGE_DATA_ENTRY                *mGaugeData = NULL;
40 UINTN                           mGaugeNumberOfEntries = 0;
41 GAUGE_DATA_ENTRY_EX             *mGaugeDataEx = NULL;
42 UINTN                           mGaugeNumberOfEntriesEx = 0;
43 
44 BOOLEAN                         mNoSmmPerfHandler = FALSE;
45 BOOLEAN                         mNoSmmPerfExHandler = FALSE;
46 
47 //
48 // The cached Performance Protocol and PerformanceEx Protocol interface.
49 //
50 PERFORMANCE_PROTOCOL            *mPerformance = NULL;
51 PERFORMANCE_EX_PROTOCOL         *mPerformanceEx = NULL;
52 
53 /**
54   The function caches the pointer to SMM Communication protocol.
55 
56   The function locates SMM Communication protocol from protocol database.
57 
58   @retval EFI_SUCCESS     SMM Communication protocol is successfully located.
59   @retval Other           SMM Communication protocol is not located to log performance.
60 
61 **/
62 EFI_STATUS
GetCommunicationProtocol(VOID)63 GetCommunicationProtocol (
64   VOID
65   )
66 {
67   EFI_STATUS                      Status;
68   EFI_SMM_COMMUNICATION_PROTOCOL  *Communication;
69 
70   if (mSmmCommunication != NULL) {
71     return EFI_SUCCESS;
72   }
73 
74   Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication);
75   if (!EFI_ERROR (Status)) {
76     ASSERT (Communication != NULL);
77     //
78     // Cache SMM Communication protocol.
79     //
80     mSmmCommunication = Communication;
81   }
82 
83   return Status;
84 }
85 
86 /**
87   The function caches the pointers to PerformanceEx protocol and Performance Protocol.
88 
89   The function locates PerformanceEx protocol and Performance Protocol from protocol database.
90 
91   @retval EFI_SUCCESS     PerformanceEx protocol or Performance Protocol is successfully located.
92   @retval EFI_NOT_FOUND   Both PerformanceEx protocol and Performance Protocol are not located to log performance.
93 
94 **/
95 EFI_STATUS
GetPerformanceProtocol(VOID)96 GetPerformanceProtocol (
97   VOID
98   )
99 {
100   EFI_STATUS                Status;
101   PERFORMANCE_PROTOCOL      *Performance;
102   PERFORMANCE_EX_PROTOCOL   *PerformanceEx;
103 
104   if (mPerformanceEx != NULL || mPerformance != NULL) {
105     return EFI_SUCCESS;
106   }
107 
108   Status = gBS->LocateProtocol (&gPerformanceExProtocolGuid, NULL, (VOID **) &PerformanceEx);
109   if (!EFI_ERROR (Status)) {
110     ASSERT (PerformanceEx != NULL);
111     //
112     // Cache PerformanceEx Protocol.
113     //
114     mPerformanceEx = PerformanceEx;
115     return EFI_SUCCESS;
116   }
117 
118   Status = gBS->LocateProtocol (&gPerformanceProtocolGuid, NULL, (VOID **) &Performance);
119   if (!EFI_ERROR (Status)) {
120     ASSERT (Performance != NULL);
121     //
122     // Cache performance protocol.
123     //
124     mPerformance = Performance;
125     return EFI_SUCCESS;
126   }
127 
128   return EFI_NOT_FOUND;
129 }
130 
131 /**
132   Creates a record for the beginning of a performance measurement.
133 
134   Creates a record that contains the Handle, Token, Module and Identifier.
135   If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
136   If TimeStamp is zero, then this function reads the current time stamp
137   and adds that time stamp value to the record as the start time.
138 
139   @param  Handle                  Pointer to environment specific context used
140                                   to identify the component being measured.
141   @param  Token                   Pointer to a Null-terminated ASCII string
142                                   that identifies the component being measured.
143   @param  Module                  Pointer to a Null-terminated ASCII string
144                                   that identifies the module being measured.
145   @param  TimeStamp               64-bit time stamp.
146   @param  Identifier              32-bit identifier. If the value is 0, the created record
147                                   is same as the one created by StartPerformanceMeasurement.
148 
149   @retval RETURN_SUCCESS          The start of the measurement was recorded.
150   @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
151 
152 **/
153 RETURN_STATUS
154 EFIAPI
StartPerformanceMeasurementEx(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp,IN UINT32 Identifier)155 StartPerformanceMeasurementEx (
156   IN CONST VOID   *Handle,  OPTIONAL
157   IN CONST CHAR8  *Token,   OPTIONAL
158   IN CONST CHAR8  *Module,  OPTIONAL
159   IN UINT64       TimeStamp,
160   IN UINT32       Identifier
161   )
162 {
163   return RETURN_SUCCESS;
164 }
165 
166 /**
167   Fills in the end time of a performance measurement.
168 
169   Looks up the record that matches Handle, Token, Module and Identifier.
170   If the record can not be found then return RETURN_NOT_FOUND.
171   If the record is found and TimeStamp is not zero,
172   then TimeStamp is added to the record as the end time.
173   If the record is found and TimeStamp is zero, then this function reads
174   the current time stamp and adds that time stamp value to the record as the end time.
175 
176   @param  Handle                  Pointer to environment specific context used
177                                   to identify the component being measured.
178   @param  Token                   Pointer to a Null-terminated ASCII string
179                                   that identifies the component being measured.
180   @param  Module                  Pointer to a Null-terminated ASCII string
181                                   that identifies the module being measured.
182   @param  TimeStamp               64-bit time stamp.
183   @param  Identifier              32-bit identifier. If the value is 0, the found record
184                                   is same as the one found by EndPerformanceMeasurement.
185 
186   @retval RETURN_SUCCESS          The end of  the measurement was recorded.
187   @retval RETURN_NOT_FOUND        The specified measurement record could not be found.
188 
189 **/
190 RETURN_STATUS
191 EFIAPI
EndPerformanceMeasurementEx(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp,IN UINT32 Identifier)192 EndPerformanceMeasurementEx (
193   IN CONST VOID   *Handle,  OPTIONAL
194   IN CONST CHAR8  *Token,   OPTIONAL
195   IN CONST CHAR8  *Module,  OPTIONAL
196   IN UINT64       TimeStamp,
197   IN UINT32       Identifier
198   )
199 {
200   return RETURN_SUCCESS;
201 }
202 
203 /**
204   Creates a record for the beginning of a performance measurement.
205 
206   Creates a record that contains the Handle, Token, and Module.
207   If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
208   If TimeStamp is zero, then this function reads the current time stamp
209   and adds that time stamp value to the record as the start time.
210 
211   @param  Handle                  Pointer to environment specific context used
212                                   to identify the component being measured.
213   @param  Token                   Pointer to a Null-terminated ASCII string
214                                   that identifies the component being measured.
215   @param  Module                  Pointer to a Null-terminated ASCII string
216                                   that identifies the module being measured.
217   @param  TimeStamp               64-bit time stamp.
218 
219   @retval RETURN_SUCCESS          The start of the measurement was recorded.
220   @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
221 
222 **/
223 RETURN_STATUS
224 EFIAPI
StartPerformanceMeasurement(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp)225 StartPerformanceMeasurement (
226   IN CONST VOID   *Handle,  OPTIONAL
227   IN CONST CHAR8  *Token,   OPTIONAL
228   IN CONST CHAR8  *Module,  OPTIONAL
229   IN UINT64       TimeStamp
230   )
231 {
232   return RETURN_SUCCESS;
233 }
234 
235 /**
236   Fills in the end time of a performance measurement.
237 
238   Looks up the record that matches Handle, Token, and Module.
239   If the record can not be found then return RETURN_NOT_FOUND.
240   If the record is found and TimeStamp is not zero,
241   then TimeStamp is added to the record as the end time.
242   If the record is found and TimeStamp is zero, then this function reads
243   the current time stamp and adds that time stamp value to the record as the end time.
244 
245   @param  Handle                  Pointer to environment specific context used
246                                   to identify the component being measured.
247   @param  Token                   Pointer to a Null-terminated ASCII string
248                                   that identifies the component being measured.
249   @param  Module                  Pointer to a Null-terminated ASCII string
250                                   that identifies the module being measured.
251   @param  TimeStamp               64-bit time stamp.
252 
253   @retval RETURN_SUCCESS          The end of  the measurement was recorded.
254   @retval RETURN_NOT_FOUND        The specified measurement record could not be found.
255 
256 **/
257 RETURN_STATUS
258 EFIAPI
EndPerformanceMeasurement(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp)259 EndPerformanceMeasurement (
260   IN CONST VOID   *Handle,  OPTIONAL
261   IN CONST CHAR8  *Token,   OPTIONAL
262   IN CONST CHAR8  *Module,  OPTIONAL
263   IN UINT64       TimeStamp
264   )
265 {
266   return RETURN_SUCCESS;
267 }
268 
269 /**
270   Attempts to retrieve a performance measurement log entry from the performance measurement log.
271   It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
272   and then assign the Identifier with 0.
273 
274   Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
275   zero on entry, then an attempt is made to retrieve the first entry from the performance log,
276   and the key for the second entry in the log is returned.  If the performance log is empty,
277   then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
278   log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
279   returned.  If LogEntryKey is the key for the last entry in the log, then the last log entry is
280   retrieved and an implementation specific non-zero key value that specifies the end of the performance
281   log is returned.  If LogEntryKey is equal this implementation specific non-zero key value, then no entry
282   is retrieved and zero is returned.  In the cases where a performance log entry can be returned,
283   the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
284   If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
285   If Handle is NULL, then ASSERT().
286   If Token is NULL, then ASSERT().
287   If Module is NULL, then ASSERT().
288   If StartTimeStamp is NULL, then ASSERT().
289   If EndTimeStamp is NULL, then ASSERT().
290   If Identifier is NULL, then ASSERT().
291 
292   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
293                                   0, then the first performance measurement log entry is retrieved.
294                                   On exit, the key of the next performance log entry.
295   @param  Handle                  Pointer to environment specific context used to identify the component
296                                   being measured.
297   @param  Token                   Pointer to a Null-terminated ASCII string that identifies the component
298                                   being measured.
299   @param  Module                  Pointer to a Null-terminated ASCII string that identifies the module
300                                   being measured.
301   @param  StartTimeStamp          Pointer to the 64-bit time stamp that was recorded when the measurement
302                                   was started.
303   @param  EndTimeStamp            Pointer to the 64-bit time stamp that was recorded when the measurement
304                                   was ended.
305   @param  Identifier              Pointer to the 32-bit identifier that was recorded.
306 
307   @return The key for the next performance log entry (in general case).
308 
309 **/
310 UINTN
311 EFIAPI
GetByPerformanceProtocol(IN UINTN LogEntryKey,OUT CONST VOID ** Handle,OUT CONST CHAR8 ** Token,OUT CONST CHAR8 ** Module,OUT UINT64 * StartTimeStamp,OUT UINT64 * EndTimeStamp,OUT UINT32 * Identifier)312 GetByPerformanceProtocol (
313   IN  UINTN       LogEntryKey,
314   OUT CONST VOID  **Handle,
315   OUT CONST CHAR8 **Token,
316   OUT CONST CHAR8 **Module,
317   OUT UINT64      *StartTimeStamp,
318   OUT UINT64      *EndTimeStamp,
319   OUT UINT32      *Identifier
320   )
321 {
322   EFI_STATUS            Status;
323   GAUGE_DATA_ENTRY_EX   *GaugeData;
324 
325   Status = GetPerformanceProtocol ();
326   if (EFI_ERROR (Status)) {
327     return 0;
328   }
329 
330   if (mPerformanceEx != NULL) {
331     Status = mPerformanceEx->GetGaugeEx (LogEntryKey++, &GaugeData);
332   } else if (mPerformance != NULL) {
333     Status = mPerformance->GetGauge (LogEntryKey++, (GAUGE_DATA_ENTRY **) &GaugeData);
334   } else {
335     ASSERT (FALSE);
336     return 0;
337   }
338 
339   //
340   // Make sure that LogEntryKey is a valid log entry key,
341   //
342   ASSERT (Status != EFI_INVALID_PARAMETER);
343 
344   if (EFI_ERROR (Status)) {
345     //
346     // The LogEntryKey is the last entry (equals to the total entry number).
347     //
348     return 0;
349   }
350 
351   ASSERT (GaugeData != NULL);
352 
353   *Handle         = (VOID *) (UINTN) GaugeData->Handle;
354   *Token          = GaugeData->Token;
355   *Module         = GaugeData->Module;
356   *StartTimeStamp = GaugeData->StartTimeStamp;
357   *EndTimeStamp   = GaugeData->EndTimeStamp;
358   if (mPerformanceEx != NULL) {
359     *Identifier   = GaugeData->Identifier;
360   } else {
361     *Identifier   = 0;
362   }
363 
364   return LogEntryKey;
365 }
366 
367 
368 /**
369   Retrieves all previous logged performance measurement.
370   Function will use SMM communicate protocol to get all previous SMM performance measurement data.
371   If success, data buffer will be returned. If fail function will return NULL.
372 
373   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
374                                   0, then the first performance measurement log entry is retrieved.
375                                   On exit, the key of the next performance log entry.
376 
377   @retval !NULL           Get all gauge data success.
378   @retval NULL            Get all gauge data failed.
379 **/
380 GAUGE_DATA_ENTRY *
381 EFIAPI
GetAllSmmGaugeData(IN UINTN LogEntryKey)382 GetAllSmmGaugeData (
383   IN UINTN      LogEntryKey
384   )
385 {
386   EFI_STATUS                  Status;
387   EFI_SMM_COMMUNICATE_HEADER  *SmmCommBufferHeader;
388   SMM_PERF_COMMUNICATE        *SmmPerfCommData;
389   UINTN                       CommSize;
390   UINTN                       DataSize;
391 
392   if (mNoSmmPerfHandler) {
393     //
394     // Not try to get the SMM gauge data again
395     // if no SMM Performance handler found.
396     //
397     return NULL;
398   }
399 
400   if (LogEntryKey != 0) {
401     if (mGaugeData != NULL) {
402       return mGaugeData;
403     }
404   } else {
405     //
406     // Reget the SMM gauge data at the first entry get.
407     //
408     if (mGaugeData != NULL) {
409       FreePool (mGaugeData);
410       mGaugeData = NULL;
411       mGaugeNumberOfEntries = 0;
412     }
413   }
414 
415   Status = GetCommunicationProtocol ();
416   if (EFI_ERROR (Status)) {
417     return NULL;
418   }
419 
420   //
421   // Initialize communicate buffer
422   //
423   SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER *)mSmmPerformanceBuffer;
424   SmmPerfCommData = (SMM_PERF_COMMUNICATE *)SmmCommBufferHeader->Data;
425   ZeroMem((UINT8*)SmmPerfCommData, sizeof(SMM_PERF_COMMUNICATE));
426 
427   CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gSmmPerformanceProtocolGuid);
428   SmmCommBufferHeader->MessageLength = sizeof(SMM_PERF_COMMUNICATE);
429   CommSize = SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;
430 
431   //
432   // Get total number of SMM gauge entries
433   //
434   SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER;
435   Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
436   if (Status == EFI_NOT_FOUND) {
437     mNoSmmPerfHandler = TRUE;
438   }
439   if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus) || SmmPerfCommData->NumberOfEntries == 0) {
440     return NULL;
441   }
442 
443   mGaugeNumberOfEntries = SmmPerfCommData->NumberOfEntries;
444 
445   DataSize = mGaugeNumberOfEntries * sizeof(GAUGE_DATA_ENTRY);
446   mGaugeData = AllocateZeroPool(DataSize);
447   ASSERT (mGaugeData != NULL);
448 
449   //
450   // Get all SMM gauge data
451   //
452   SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_DATA;
453   SmmPerfCommData->LogEntryKey = 0;
454   SmmPerfCommData->NumberOfEntries = mGaugeNumberOfEntries;
455   SmmPerfCommData->GaugeData = mGaugeData;
456   Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
457   if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus)) {
458     FreePool (mGaugeData);
459     mGaugeData = NULL;
460     mGaugeNumberOfEntries = 0;
461   }
462 
463   return mGaugeData;
464 }
465 
466 /**
467   Retrieves all previous logged performance measurement.
468   Function will use SMM communicate protocol to get all previous SMM performance measurement data.
469   If success, data buffer will be returned. If fail function will return NULL.
470 
471   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
472                                   0, then the first performance measurement log entry is retrieved.
473                                   On exit, the key of the next performance log entry.
474 
475   @retval !NULL           Get all gauge data success.
476   @retval NULL            Get all gauge data failed.
477 **/
478 GAUGE_DATA_ENTRY_EX *
479 EFIAPI
GetAllSmmGaugeDataEx(IN UINTN LogEntryKey)480 GetAllSmmGaugeDataEx (
481   IN UINTN      LogEntryKey
482   )
483 {
484   EFI_STATUS                  Status;
485   EFI_SMM_COMMUNICATE_HEADER  *SmmCommBufferHeader;
486   SMM_PERF_COMMUNICATE_EX     *SmmPerfCommData;
487   UINTN                       CommSize;
488   UINTN                       DataSize;
489 
490   if (mNoSmmPerfExHandler) {
491     //
492     // Not try to get the SMM gauge data again
493     // if no SMM PerformanceEx handler found.
494     //
495     return NULL;
496   }
497 
498   if (LogEntryKey != 0) {
499     if (mGaugeDataEx != NULL) {
500       return mGaugeDataEx;
501     }
502   } else {
503     //
504     // Reget the SMM gauge data at the first entry get.
505     //
506     if (mGaugeDataEx != NULL) {
507       FreePool (mGaugeDataEx);
508       mGaugeDataEx = NULL;
509       mGaugeNumberOfEntriesEx = 0;
510     }
511   }
512 
513   Status = GetCommunicationProtocol ();
514   if (EFI_ERROR (Status)) {
515     return NULL;
516   }
517 
518   //
519   // Initialize communicate buffer
520   //
521   SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER *)mSmmPerformanceBuffer;
522   SmmPerfCommData = (SMM_PERF_COMMUNICATE_EX *)SmmCommBufferHeader->Data;
523   ZeroMem((UINT8*)SmmPerfCommData, sizeof(SMM_PERF_COMMUNICATE_EX));
524 
525   CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gSmmPerformanceExProtocolGuid);
526   SmmCommBufferHeader->MessageLength = sizeof(SMM_PERF_COMMUNICATE_EX);
527   CommSize = SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;
528 
529   //
530   // Get total number of SMM gauge entries
531   //
532   SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER;
533   Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
534   if (Status == EFI_NOT_FOUND) {
535     mNoSmmPerfExHandler = TRUE;
536   }
537   if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus) || SmmPerfCommData->NumberOfEntries == 0) {
538     return NULL;
539   }
540 
541   mGaugeNumberOfEntriesEx = SmmPerfCommData->NumberOfEntries;
542 
543   DataSize = mGaugeNumberOfEntriesEx * sizeof(GAUGE_DATA_ENTRY_EX);
544   mGaugeDataEx = AllocateZeroPool(DataSize);
545   ASSERT (mGaugeDataEx != NULL);
546 
547   //
548   // Get all SMM gauge data
549   //
550   SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_DATA;
551   SmmPerfCommData->LogEntryKey = 0;
552   SmmPerfCommData->NumberOfEntries = mGaugeNumberOfEntriesEx;
553   SmmPerfCommData->GaugeDataEx = mGaugeDataEx;
554   Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
555   if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus)) {
556     FreePool (mGaugeDataEx);
557     mGaugeDataEx = NULL;
558     mGaugeNumberOfEntriesEx = 0;
559   }
560 
561   return mGaugeDataEx;
562 }
563 
564 /**
565   Attempts to retrieve a performance measurement log entry from the performance measurement log.
566   It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
567   and then assign the Identifier with 0.
568 
569   Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
570   zero on entry, then an attempt is made to retrieve the first entry from the performance log,
571   and the key for the second entry in the log is returned.  If the performance log is empty,
572   then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
573   log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
574   returned.  If LogEntryKey is the key for the last entry in the log, then the last log entry is
575   retrieved and an implementation specific non-zero key value that specifies the end of the performance
576   log is returned.  If LogEntryKey is equal this implementation specific non-zero key value, then no entry
577   is retrieved and zero is returned.  In the cases where a performance log entry can be returned,
578   the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
579   If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
580   If Handle is NULL, then ASSERT().
581   If Token is NULL, then ASSERT().
582   If Module is NULL, then ASSERT().
583   If StartTimeStamp is NULL, then ASSERT().
584   If EndTimeStamp is NULL, then ASSERT().
585   If Identifier is NULL, then ASSERT().
586 
587   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
588                                   0, then the first performance measurement log entry is retrieved.
589                                   On exit, the key of the next performance log entry.
590   @param  Handle                  Pointer to environment specific context used to identify the component
591                                   being measured.
592   @param  Token                   Pointer to a Null-terminated ASCII string that identifies the component
593                                   being measured.
594   @param  Module                  Pointer to a Null-terminated ASCII string that identifies the module
595                                   being measured.
596   @param  StartTimeStamp          Pointer to the 64-bit time stamp that was recorded when the measurement
597                                   was started.
598   @param  EndTimeStamp            Pointer to the 64-bit time stamp that was recorded when the measurement
599                                   was ended.
600   @param  Identifier              Pointer to the 32-bit identifier that was recorded.
601 
602   @return The key for the next performance log entry (in general case).
603 
604 **/
605 UINTN
606 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)607 GetPerformanceMeasurementEx (
608   IN  UINTN       LogEntryKey,
609   OUT CONST VOID  **Handle,
610   OUT CONST CHAR8 **Token,
611   OUT CONST CHAR8 **Module,
612   OUT UINT64      *StartTimeStamp,
613   OUT UINT64      *EndTimeStamp,
614   OUT UINT32      *Identifier
615   )
616 {
617   GAUGE_DATA_ENTRY_EX   *GaugeData;
618 
619   GaugeData = NULL;
620 
621   ASSERT (Handle != NULL);
622   ASSERT (Token != NULL);
623   ASSERT (Module != NULL);
624   ASSERT (StartTimeStamp != NULL);
625   ASSERT (EndTimeStamp != NULL);
626   ASSERT (Identifier != NULL);
627 
628   mGaugeDataEx = GetAllSmmGaugeDataEx (LogEntryKey);
629   if (mGaugeDataEx != NULL) {
630     if (LogEntryKey >= mGaugeNumberOfEntriesEx) {
631       //
632       // Try to get the data by Performance Protocol.
633       //
634       LogEntryKey = LogEntryKey - mGaugeNumberOfEntriesEx;
635       LogEntryKey = GetByPerformanceProtocol (
636                       LogEntryKey,
637                       Handle,
638                       Token,
639                       Module,
640                       StartTimeStamp,
641                       EndTimeStamp,
642                       Identifier
643                       );
644       if (LogEntryKey == 0) {
645         //
646         // Last entry.
647         //
648         return LogEntryKey;
649       } else {
650         return (LogEntryKey + mGaugeNumberOfEntriesEx);
651       }
652     }
653 
654     GaugeData = &mGaugeDataEx[LogEntryKey++];
655     *Identifier = GaugeData->Identifier;
656   } else {
657     mGaugeData = GetAllSmmGaugeData (LogEntryKey);
658     if (mGaugeData != NULL) {
659       if (LogEntryKey >= mGaugeNumberOfEntries) {
660         //
661         // Try to get the data by Performance Protocol.
662         //
663         LogEntryKey = LogEntryKey - mGaugeNumberOfEntries;
664         LogEntryKey = GetByPerformanceProtocol (
665                         LogEntryKey,
666                         Handle,
667                         Token,
668                         Module,
669                         StartTimeStamp,
670                         EndTimeStamp,
671                         Identifier
672                         );
673         if (LogEntryKey == 0) {
674           //
675           // Last entry.
676           //
677           return LogEntryKey;
678         } else {
679           return (LogEntryKey + mGaugeNumberOfEntries);
680         }
681       }
682 
683       GaugeData = (GAUGE_DATA_ENTRY_EX *) &mGaugeData[LogEntryKey++];
684       *Identifier = 0;
685     } else {
686       return GetByPerformanceProtocol (
687                LogEntryKey,
688                Handle,
689                Token,
690                Module,
691                StartTimeStamp,
692                EndTimeStamp,
693                Identifier
694                );
695     }
696   }
697 
698   *Handle         = (VOID *) (UINTN) GaugeData->Handle;
699   *Token          = GaugeData->Token;
700   *Module         = GaugeData->Module;
701   *StartTimeStamp = GaugeData->StartTimeStamp;
702   *EndTimeStamp   = GaugeData->EndTimeStamp;
703 
704   return LogEntryKey;
705 }
706 
707 /**
708   Attempts to retrieve a performance measurement log entry from the performance measurement log.
709   It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
710   and then eliminate the Identifier.
711 
712   Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
713   zero on entry, then an attempt is made to retrieve the first entry from the performance log,
714   and the key for the second entry in the log is returned.  If the performance log is empty,
715   then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
716   log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
717   returned.  If LogEntryKey is the key for the last entry in the log, then the last log entry is
718   retrieved and an implementation specific non-zero key value that specifies the end of the performance
719   log is returned.  If LogEntryKey is equal this implementation specific non-zero key value, then no entry
720   is retrieved and zero is returned.  In the cases where a performance log entry can be returned,
721   the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
722   If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
723   If Handle is NULL, then ASSERT().
724   If Token is NULL, then ASSERT().
725   If Module is NULL, then ASSERT().
726   If StartTimeStamp is NULL, then ASSERT().
727   If EndTimeStamp is NULL, then ASSERT().
728 
729   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
730                                   0, then the first performance measurement log entry is retrieved.
731                                   On exit, the key of the next performance log entry.
732   @param  Handle                  Pointer to environment specific context used to identify the component
733                                   being measured.
734   @param  Token                   Pointer to a Null-terminated ASCII string that identifies the component
735                                   being measured.
736   @param  Module                  Pointer to a Null-terminated ASCII string that identifies the module
737                                   being measured.
738   @param  StartTimeStamp          Pointer to the 64-bit time stamp that was recorded when the measurement
739                                   was started.
740   @param  EndTimeStamp            Pointer to the 64-bit time stamp that was recorded when the measurement
741                                   was ended.
742 
743   @return The key for the next performance log entry (in general case).
744 
745 **/
746 UINTN
747 EFIAPI
GetPerformanceMeasurement(IN UINTN LogEntryKey,OUT CONST VOID ** Handle,OUT CONST CHAR8 ** Token,OUT CONST CHAR8 ** Module,OUT UINT64 * StartTimeStamp,OUT UINT64 * EndTimeStamp)748 GetPerformanceMeasurement (
749   IN  UINTN       LogEntryKey,
750   OUT CONST VOID  **Handle,
751   OUT CONST CHAR8 **Token,
752   OUT CONST CHAR8 **Module,
753   OUT UINT64      *StartTimeStamp,
754   OUT UINT64      *EndTimeStamp
755   )
756 {
757   UINT32 Identifier;
758   return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
759 }
760 
761 /**
762   Returns TRUE if the performance measurement macros are enabled.
763 
764   This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
765   PcdPerformanceLibraryPropertyMask is set.  Otherwise FALSE is returned.
766 
767   @retval TRUE                    The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
768                                   PcdPerformanceLibraryPropertyMask is set.
769   @retval FALSE                   The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
770                                   PcdPerformanceLibraryPropertyMask is clear.
771 
772 **/
773 BOOLEAN
774 EFIAPI
PerformanceMeasurementEnabled(VOID)775 PerformanceMeasurementEnabled (
776   VOID
777   )
778 {
779   return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
780 }
781