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