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