Home | History | Annotate | Download | only in DxeSmmPerformanceLib
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    861 PerformanceMeasurementEnabled (
    862   VOID
    863   )
    864 {
    865   return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
    866 }
    867