Home | History | Annotate | Download | only in Dp_App
      1 /** @file
      2   Utility functions used by the Dp application.
      3 
      4   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 **/
     13 
     14 #include <Library/BaseLib.h>
     15 #include <Library/BaseMemoryLib.h>
     16 #include <Library/MemoryAllocationLib.h>
     17 #include <Library/DebugLib.h>
     18 #include <Library/UefiBootServicesTableLib.h>
     19 #include <Library/TimerLib.h>
     20 #include <Library/PeCoffGetEntryPointLib.h>
     21 #include <Library/PrintLib.h>
     22 #include <Library/HiiLib.h>
     23 #include <Library/PcdLib.h>
     24 #include <Library/UefiLib.h>
     25 #include <Library/DevicePathLib.h>
     26 
     27 #include <Pi/PiFirmwareFile.h>
     28 #include <Library/DxeServicesLib.h>
     29 
     30 #include <Protocol/LoadedImage.h>
     31 #include <Protocol/DriverBinding.h>
     32 #include <Protocol/ComponentName2.h>
     33 #include <Protocol/DevicePath.h>
     34 
     35 #include <Guid/Performance.h>
     36 
     37 #include "Dp.h"
     38 #include "Literals.h"
     39 #include "DpInternal.h"
     40 
     41 /**
     42   Wrap original FreePool to check NULL pointer first.
     43 
     44   @param[in]    Buffer      The pointer to the buffer to free.
     45 
     46 **/
     47 VOID
     48 SafeFreePool (
     49   IN VOID   *Buffer
     50   )
     51 {
     52   if (Buffer != NULL) {
     53     FreePool (Buffer);
     54   }
     55 }
     56 
     57 /**
     58   Calculate an event's duration in timer ticks.
     59 
     60   Given the count direction and the event's start and end timer values,
     61   calculate the duration of the event in timer ticks.  Information for
     62   the current measurement is pointed to by the parameter.
     63 
     64   If the measurement's start time is 1, it indicates that the developer
     65   is indicating that the measurement began at the release of reset.
     66   The start time is adjusted to the timer's starting count before performing
     67   the elapsed time calculation.
     68 
     69   The calculated duration, in ticks, is the absolute difference between
     70   the measurement's ending and starting counts.
     71 
     72   @param Measurement   Pointer to a MEASUREMENT_RECORD structure containing
     73                        data for the current measurement.
     74 
     75   @return              The 64-bit duration of the event.
     76 **/
     77 UINT64
     78 GetDuration (
     79   IN OUT MEASUREMENT_RECORD   *Measurement
     80   )
     81 {
     82   UINT64    Duration;
     83   BOOLEAN   Error;
     84 
     85   // PERF_START macros are called with a value of 1 to indicate
     86   // the beginning of time.  So, adjust the start ticker value
     87   // to the real beginning of time.
     88   // Assumes no wraparound.  Even then, there is a very low probability
     89   // of having a valid StartTicker value of 1.
     90   if (Measurement->StartTimeStamp == 1) {
     91     Measurement->StartTimeStamp = TimerInfo.StartCount;
     92   }
     93   if (TimerInfo.CountUp) {
     94     Duration = Measurement->EndTimeStamp - Measurement->StartTimeStamp;
     95     Error = (BOOLEAN)(Duration > Measurement->EndTimeStamp);
     96   }
     97   else {
     98     Duration = Measurement->StartTimeStamp - Measurement->EndTimeStamp;
     99     Error = (BOOLEAN)(Duration > Measurement->StartTimeStamp);
    100   }
    101 
    102   if (Error) {
    103     DEBUG ((EFI_D_ERROR, ALit_TimerLibError));
    104     Duration = 0;
    105   }
    106   return Duration;
    107 }
    108 
    109 /**
    110   Determine whether the Measurement record is for an EFI Phase.
    111 
    112   The Token and Module members of the measurement record are checked.
    113   Module must be empty and Token must be one of SEC, PEI, DXE, BDS, or SHELL.
    114 
    115   @param[in]  Measurement A pointer to the Measurement record to test.
    116 
    117   @retval     TRUE        The measurement record is for an EFI Phase.
    118   @retval     FALSE       The measurement record is NOT for an EFI Phase.
    119 **/
    120 BOOLEAN
    121 IsPhase(
    122   IN MEASUREMENT_RECORD        *Measurement
    123   )
    124 {
    125   BOOLEAN   RetVal;
    126 
    127   RetVal = (BOOLEAN)( ( *Measurement->Module == '\0')                               &&
    128             ((AsciiStrnCmp (Measurement->Token, ALit_SEC, PERF_TOKEN_LENGTH) == 0)    ||
    129              (AsciiStrnCmp (Measurement->Token, ALit_PEI, PERF_TOKEN_LENGTH) == 0)    ||
    130              (AsciiStrnCmp (Measurement->Token, ALit_DXE, PERF_TOKEN_LENGTH) == 0)    ||
    131              (AsciiStrnCmp (Measurement->Token, ALit_BDS, PERF_TOKEN_LENGTH) == 0))
    132             );
    133   return RetVal;
    134 }
    135 
    136 /**
    137   Get the file name portion of the Pdb File Name.
    138 
    139   The portion of the Pdb File Name between the last backslash and
    140   either a following period or the end of the string is converted
    141   to Unicode and copied into UnicodeBuffer.  The name is truncated,
    142   if necessary, to ensure that UnicodeBuffer is not overrun.
    143 
    144   @param[in]  PdbFileName     Pdb file name.
    145   @param[out] UnicodeBuffer   The resultant Unicode File Name.
    146 
    147 **/
    148 VOID
    149 GetShortPdbFileName (
    150   IN  CHAR8     *PdbFileName,
    151   OUT CHAR16    *UnicodeBuffer
    152   )
    153 {
    154   UINTN IndexA;     // Current work location within an ASCII string.
    155   UINTN IndexU;     // Current work location within a Unicode string.
    156   UINTN StartIndex;
    157   UINTN EndIndex;
    158 
    159   ZeroMem (UnicodeBuffer, (DP_GAUGE_STRING_LENGTH + 1) * sizeof (CHAR16));
    160 
    161   if (PdbFileName == NULL) {
    162     StrCpyS (UnicodeBuffer, DP_GAUGE_STRING_LENGTH + 1, L" ");
    163   } else {
    164     StartIndex = 0;
    165     for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
    166       ;
    167     for (IndexA = 0; PdbFileName[IndexA] != 0; IndexA++) {
    168       if (PdbFileName[IndexA] == '\\') {
    169         StartIndex = IndexA + 1;
    170       }
    171 
    172       if (PdbFileName[IndexA] == '.') {
    173         EndIndex = IndexA;
    174       }
    175     }
    176 
    177     IndexU = 0;
    178     for (IndexA = StartIndex; IndexA < EndIndex; IndexA++) {
    179       UnicodeBuffer[IndexU] = (CHAR16) PdbFileName[IndexA];
    180       IndexU++;
    181       if (IndexU >= DP_GAUGE_STRING_LENGTH) {
    182         UnicodeBuffer[DP_GAUGE_STRING_LENGTH] = 0;
    183         break;
    184       }
    185     }
    186   }
    187 }
    188 
    189 /**
    190   Get a human readable name for an image handle.
    191   The following methods will be tried orderly:
    192     1. Image PDB
    193     2. ComponentName2 protocol
    194     3. FFS UI section
    195     4. Image GUID
    196     5. Image DevicePath
    197     6. Unknown Driver Name
    198 
    199   @param[in]    Handle
    200 
    201   @post   The resulting Unicode name string is stored in the
    202           mGaugeString global array.
    203 
    204 **/
    205 VOID
    206 GetNameFromHandle (
    207   IN EFI_HANDLE   Handle
    208   )
    209 {
    210   EFI_STATUS                  Status;
    211   EFI_LOADED_IMAGE_PROTOCOL   *Image;
    212   CHAR8                       *PdbFileName;
    213   EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
    214   EFI_STRING                  StringPtr;
    215   EFI_DEVICE_PATH_PROTOCOL    *LoadedImageDevicePath;
    216   EFI_DEVICE_PATH_PROTOCOL    *DevicePath;
    217   EFI_GUID                    *NameGuid;
    218   CHAR16                      *NameString;
    219   UINTN                       StringSize;
    220   CHAR8                       *PlatformLanguage;
    221   CHAR8                       *BestLanguage;
    222   EFI_COMPONENT_NAME2_PROTOCOL      *ComponentName2;
    223 
    224   BestLanguage     = NULL;
    225   PlatformLanguage = NULL;
    226 
    227   //
    228   // Method 1: Get the name string from image PDB
    229   //
    230   Status = gBS->HandleProtocol (
    231                   Handle,
    232                   &gEfiLoadedImageProtocolGuid,
    233                   (VOID **) &Image
    234                   );
    235 
    236   if (EFI_ERROR (Status)) {
    237     Status = gBS->OpenProtocol (
    238                     Handle,
    239                     &gEfiDriverBindingProtocolGuid,
    240                     (VOID **) &DriverBinding,
    241                     NULL,
    242                     NULL,
    243                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    244                     );
    245     if (!EFI_ERROR (Status)) {
    246       Status = gBS->HandleProtocol (
    247                       DriverBinding->ImageHandle,
    248                       &gEfiLoadedImageProtocolGuid,
    249                       (VOID **) &Image
    250                       );
    251     }
    252   }
    253 
    254   if (!EFI_ERROR (Status)) {
    255     PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
    256 
    257     if (PdbFileName != NULL) {
    258       GetShortPdbFileName (PdbFileName, mGaugeString);
    259       return;
    260     }
    261   }
    262 
    263   //
    264   // Method 2: Get the name string from ComponentName2 protocol
    265   //
    266   Status = gBS->HandleProtocol (
    267                   Handle,
    268                   &gEfiComponentName2ProtocolGuid,
    269                   (VOID **) &ComponentName2
    270                   );
    271   if (!EFI_ERROR (Status)) {
    272     //
    273     // Get the current platform language setting
    274     //
    275     GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
    276 
    277     BestLanguage = GetBestLanguage(
    278                      ComponentName2->SupportedLanguages,
    279                      FALSE,
    280                      PlatformLanguage,
    281                      ComponentName2->SupportedLanguages,
    282                      NULL
    283                      );
    284 
    285     SafeFreePool (PlatformLanguage);
    286     Status = ComponentName2->GetDriverName (
    287                                ComponentName2,
    288                                BestLanguage,
    289                                &StringPtr
    290                                );
    291     SafeFreePool (BestLanguage);
    292     if (!EFI_ERROR (Status)) {
    293       StrnCpyS (
    294         mGaugeString,
    295         DP_GAUGE_STRING_LENGTH + 1,
    296         StringPtr,
    297         DP_GAUGE_STRING_LENGTH
    298         );
    299       return;
    300     }
    301   }
    302 
    303   Status = gBS->HandleProtocol (
    304                   Handle,
    305                   &gEfiLoadedImageDevicePathProtocolGuid,
    306                   (VOID **) &LoadedImageDevicePath
    307                   );
    308   if (!EFI_ERROR (Status) && (LoadedImageDevicePath != NULL)) {
    309     DevicePath = LoadedImageDevicePath;
    310 
    311     //
    312     // Try to get image GUID from LoadedImageDevicePath protocol
    313     //
    314     NameGuid = NULL;
    315     while (!IsDevicePathEndType (DevicePath)) {
    316       NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);
    317       if (NameGuid != NULL) {
    318         break;
    319       }
    320       DevicePath = NextDevicePathNode (DevicePath);
    321     }
    322 
    323     if (NameGuid != NULL) {
    324       //
    325       // Try to get the image's FFS UI section by image GUID
    326       //
    327       NameString = NULL;
    328       StringSize = 0;
    329       Status = GetSectionFromAnyFv (
    330                 NameGuid,
    331                 EFI_SECTION_USER_INTERFACE,
    332                 0,
    333                 (VOID **) &NameString,
    334                 &StringSize
    335                 );
    336 
    337       if (!EFI_ERROR (Status)) {
    338         //
    339         // Method 3. Get the name string from FFS UI section
    340         //
    341         StrnCpyS (
    342           mGaugeString,
    343           DP_GAUGE_STRING_LENGTH + 1,
    344           NameString,
    345           DP_GAUGE_STRING_LENGTH
    346           );
    347         FreePool (NameString);
    348       } else {
    349         //
    350         // Method 4: Get the name string from image GUID
    351         //
    352         UnicodeSPrint (mGaugeString, sizeof (mGaugeString), L"%g", NameGuid);
    353       }
    354       return;
    355     } else {
    356       //
    357       // Method 5: Get the name string from image DevicePath
    358       //
    359       NameString = ConvertDevicePathToText (LoadedImageDevicePath, TRUE, FALSE);
    360       if (NameString != NULL) {
    361         StrnCpyS (
    362           mGaugeString,
    363           DP_GAUGE_STRING_LENGTH + 1,
    364           NameString,
    365           DP_GAUGE_STRING_LENGTH
    366           );
    367         FreePool (NameString);
    368         return;
    369       }
    370     }
    371   }
    372 
    373   //
    374   // Method 6: Unknown Driver Name
    375   //
    376   StringPtr = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_ERROR_NAME), NULL);
    377   ASSERT (StringPtr != NULL);
    378   StrCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, StringPtr);
    379   FreePool (StringPtr);
    380   return;
    381 }
    382 
    383 /**
    384   Calculate the Duration in microseconds.
    385 
    386   Duration is multiplied by 1000, instead of Frequency being divided by 1000 or
    387   multiplying the result by 1000, in order to maintain precision.  Since Duration is
    388   a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow.
    389 
    390   The time is calculated as (Duration * 1000) / Timer_Frequency.
    391 
    392   @param[in]  Duration   The event duration in timer ticks.
    393 
    394   @return     A 64-bit value which is the Elapsed time in microseconds.
    395 **/
    396 UINT64
    397 DurationInMicroSeconds (
    398   IN UINT64 Duration
    399   )
    400 {
    401   UINT64 Temp;
    402 
    403   Temp = MultU64x32 (Duration, 1000);
    404   return DivU64x32 (Temp, TimerInfo.Frequency);
    405 }
    406 
    407 /**
    408   Formatted Print using a Hii Token to reference the localized format string.
    409 
    410   @param[in]  Token   A HII token associated with a localized Unicode string.
    411   @param[in]  ...     The variable argument list.
    412 
    413   @return             The number of characters converted by UnicodeVSPrint().
    414 
    415 **/
    416 UINTN
    417 EFIAPI
    418 PrintToken (
    419   IN UINT16           Token,
    420   ...
    421   )
    422 {
    423   VA_LIST           Marker;
    424   EFI_STRING        StringPtr;
    425   UINTN             Return;
    426   UINTN             BufferSize;
    427 
    428   StringPtr = HiiGetString (gHiiHandle, Token, NULL);
    429   ASSERT (StringPtr != NULL);
    430 
    431   VA_START (Marker, Token);
    432 
    433   BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);
    434 
    435   if (mPrintTokenBuffer == NULL) {
    436     mPrintTokenBuffer = AllocatePool (BufferSize);
    437     ASSERT (mPrintTokenBuffer != NULL);
    438   }
    439   SetMem( mPrintTokenBuffer, BufferSize, 0);
    440 
    441   Return = UnicodeVSPrint (mPrintTokenBuffer, BufferSize, StringPtr, Marker);
    442   VA_END (Marker);
    443 
    444   if (Return > 0 && gST->ConOut != NULL) {
    445     gST->ConOut->OutputString (gST->ConOut, mPrintTokenBuffer);
    446   }
    447   FreePool (StringPtr);
    448   return Return;
    449 }
    450 
    451 /**
    452   Get index of Measurement Record's match in the CumData array.
    453 
    454   If the Measurement's Token value matches a Token in one of the CumData
    455   records, the index of the matching record is returned.  The returned
    456   index is a signed value so that negative values can indicate that
    457   the Measurement didn't match any entry in the CumData array.
    458 
    459   @param[in]  Measurement A pointer to a Measurement Record to match against the CumData array.
    460 
    461   @retval     <0    Token is not in the CumData array.
    462   @retval     >=0   Return value is the index into CumData where Token is found.
    463 **/
    464 INTN
    465 GetCumulativeItem(
    466   IN MEASUREMENT_RECORD   *Measurement
    467   )
    468 {
    469   INTN    Index;
    470 
    471   for( Index = 0; Index < (INTN)NumCum; ++Index) {
    472     if (AsciiStrnCmp (Measurement->Token, CumData[Index].Name, PERF_TOKEN_LENGTH) == 0) {
    473       return Index;  // Exit, we found a match
    474     }
    475   }
    476   // If the for loop exits, Token was not found.
    477   return -1;   // Indicate failure
    478 }
    479