Home | History | Annotate | Download | only in UefiDpLib
      1 /** @file
      2   Utility functions used by the Dp application.
      3 
      4   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
      5   (C) Copyright 2015-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 #include <Library/HandleParsingLib.h>
     28 
     29 #include <Pi/PiFirmwareFile.h>
     30 #include <Library/DxeServicesLib.h>
     31 
     32 #include <Protocol/LoadedImage.h>
     33 #include <Protocol/DriverBinding.h>
     34 #include <Protocol/ComponentName2.h>
     35 #include <Protocol/DevicePath.h>
     36 
     37 #include <Guid/Performance.h>
     38 
     39 #include "Dp.h"
     40 #include "Literals.h"
     41 #include "DpInternal.h"
     42 
     43 /**
     44   Calculate an event's duration in timer ticks.
     45 
     46   Given the count direction and the event's start and end timer values,
     47   calculate the duration of the event in timer ticks.  Information for
     48   the current measurement is pointed to by the parameter.
     49 
     50   If the measurement's start time is 1, it indicates that the developer
     51   is indicating that the measurement began at the release of reset.
     52   The start time is adjusted to the timer's starting count before performing
     53   the elapsed time calculation.
     54 
     55   The calculated duration, in ticks, is the absolute difference between
     56   the measurement's ending and starting counts.
     57 
     58   @param Measurement   Pointer to a MEASUREMENT_RECORD structure containing
     59                        data for the current measurement.
     60 
     61   @return              The 64-bit duration of the event.
     62 **/
     63 UINT64
     64 GetDuration (
     65   IN OUT MEASUREMENT_RECORD   *Measurement
     66   )
     67 {
     68   UINT64    Duration;
     69   BOOLEAN   Error;
     70 
     71   if (Measurement->EndTimeStamp == 0) {
     72     return 0;
     73   }
     74 
     75   // PERF_START macros are called with a value of 1 to indicate
     76   // the beginning of time.  So, adjust the start ticker value
     77   // to the real beginning of time.
     78   // Assumes no wraparound.  Even then, there is a very low probability
     79   // of having a valid StartTicker value of 1.
     80   if (Measurement->StartTimeStamp == 1) {
     81     Measurement->StartTimeStamp = TimerInfo.StartCount;
     82   }
     83   if (TimerInfo.CountUp) {
     84     Duration = Measurement->EndTimeStamp - Measurement->StartTimeStamp;
     85     Error = (BOOLEAN)(Duration > Measurement->EndTimeStamp);
     86   }
     87   else {
     88     Duration = Measurement->StartTimeStamp - Measurement->EndTimeStamp;
     89     Error = (BOOLEAN)(Duration > Measurement->StartTimeStamp);
     90   }
     91 
     92   if (Error) {
     93     DEBUG ((EFI_D_ERROR, ALit_TimerLibError));
     94     Duration = 0;
     95   }
     96   return Duration;
     97 }
     98 
     99 /**
    100   Determine whether the Measurement record is for an EFI Phase.
    101 
    102   The Token and Module members of the measurement record are checked.
    103   Module must be empty and Token must be one of SEC, PEI, DXE, BDS, or SHELL.
    104 
    105   @param[in]  Measurement A pointer to the Measurement record to test.
    106 
    107   @retval     TRUE        The measurement record is for an EFI Phase.
    108   @retval     FALSE       The measurement record is NOT for an EFI Phase.
    109 **/
    110 BOOLEAN
    111 IsPhase(
    112   IN MEASUREMENT_RECORD        *Measurement
    113   )
    114 {
    115   BOOLEAN   RetVal;
    116 
    117   RetVal = (BOOLEAN)( ( *Measurement->Module == '\0')                               &&
    118             ((AsciiStrnCmp (Measurement->Token, ALit_SEC, PERF_TOKEN_LENGTH) == 0)    ||
    119              (AsciiStrnCmp (Measurement->Token, ALit_PEI, PERF_TOKEN_LENGTH) == 0)    ||
    120              (AsciiStrnCmp (Measurement->Token, ALit_DXE, PERF_TOKEN_LENGTH) == 0)    ||
    121              (AsciiStrnCmp (Measurement->Token, ALit_BDS, PERF_TOKEN_LENGTH) == 0))
    122             );
    123   return RetVal;
    124 }
    125 
    126 /**
    127   Get the file name portion of the Pdb File Name.
    128 
    129   The portion of the Pdb File Name between the last backslash and
    130   either a following period or the end of the string is converted
    131   to Unicode and copied into UnicodeBuffer.  The name is truncated,
    132   if necessary, to ensure that UnicodeBuffer is not overrun.
    133 
    134   @param[in]  PdbFileName     Pdb file name.
    135   @param[out] UnicodeBuffer   The resultant Unicode File Name.
    136 
    137 **/
    138 VOID
    139 DpGetShortPdbFileName (
    140   IN  CHAR8     *PdbFileName,
    141   OUT CHAR16    *UnicodeBuffer
    142   )
    143 {
    144   UINTN IndexA;     // Current work location within an ASCII string.
    145   UINTN IndexU;     // Current work location within a Unicode string.
    146   UINTN StartIndex;
    147   UINTN EndIndex;
    148 
    149   ZeroMem (UnicodeBuffer, (DP_GAUGE_STRING_LENGTH + 1) * sizeof (CHAR16));
    150 
    151   if (PdbFileName == NULL) {
    152     StrnCpyS (UnicodeBuffer, DP_GAUGE_STRING_LENGTH + 1, L" ", 1);
    153   } else {
    154     StartIndex = 0;
    155     for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
    156       ;
    157     for (IndexA = 0; PdbFileName[IndexA] != 0; IndexA++) {
    158       if (PdbFileName[IndexA] == '\\') {
    159         StartIndex = IndexA + 1;
    160       }
    161 
    162       if (PdbFileName[IndexA] == '.') {
    163         EndIndex = IndexA;
    164       }
    165     }
    166 
    167     IndexU = 0;
    168     for (IndexA = StartIndex; IndexA < EndIndex; IndexA++) {
    169       UnicodeBuffer[IndexU] = (CHAR16) PdbFileName[IndexA];
    170       IndexU++;
    171       if (IndexU >= DP_GAUGE_STRING_LENGTH) {
    172         UnicodeBuffer[DP_GAUGE_STRING_LENGTH] = 0;
    173         break;
    174       }
    175     }
    176   }
    177 }
    178 
    179 /**
    180   Get a human readable name for an image handle.
    181   The following methods will be tried orderly:
    182     1. Image PDB
    183     2. ComponentName2 protocol
    184     3. FFS UI section
    185     4. Image GUID
    186     5. Image DevicePath
    187     6. Unknown Driver Name
    188 
    189   @param[in]    Handle
    190 
    191   @post   The resulting Unicode name string is stored in the
    192           mGaugeString global array.
    193 
    194 **/
    195 VOID
    196 DpGetNameFromHandle (
    197   IN EFI_HANDLE   Handle
    198   )
    199 {
    200   EFI_STATUS                  Status;
    201   EFI_LOADED_IMAGE_PROTOCOL   *Image;
    202   CHAR8                       *PdbFileName;
    203   EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
    204   EFI_STRING                  StringPtr;
    205   EFI_DEVICE_PATH_PROTOCOL    *LoadedImageDevicePath;
    206   EFI_DEVICE_PATH_PROTOCOL    *DevicePath;
    207   EFI_GUID                    *NameGuid;
    208   CHAR16                      *NameString;
    209   UINTN                       StringSize;
    210   CHAR8                       *PlatformLanguage;
    211   EFI_COMPONENT_NAME2_PROTOCOL      *ComponentName2;
    212 
    213   Image = NULL;
    214   LoadedImageDevicePath = NULL;
    215   DevicePath = NULL;
    216 
    217   //
    218   // Method 1: Get the name string from image PDB
    219   //
    220   Status = gBS->HandleProtocol (
    221                   Handle,
    222                   &gEfiLoadedImageProtocolGuid,
    223                   (VOID **) &Image
    224                   );
    225 
    226   if (EFI_ERROR (Status)) {
    227     Status = gBS->OpenProtocol (
    228                     Handle,
    229                     &gEfiDriverBindingProtocolGuid,
    230                     (VOID **) &DriverBinding,
    231                     NULL,
    232                     NULL,
    233                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    234                     );
    235     if (!EFI_ERROR (Status)) {
    236       Status = gBS->HandleProtocol (
    237                       DriverBinding->ImageHandle,
    238                       &gEfiLoadedImageProtocolGuid,
    239                       (VOID **) &Image
    240                       );
    241     }
    242   }
    243 
    244   if (!EFI_ERROR (Status)) {
    245     PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
    246 
    247     if (PdbFileName != NULL) {
    248       DpGetShortPdbFileName (PdbFileName, mGaugeString);
    249       return;
    250     }
    251   }
    252 
    253   //
    254   // Method 2: Get the name string from ComponentName2 protocol
    255   //
    256   Status = gBS->HandleProtocol (
    257                   Handle,
    258                   &gEfiComponentName2ProtocolGuid,
    259                   (VOID **) &ComponentName2
    260                   );
    261   if (!EFI_ERROR (Status)) {
    262     //
    263     // Get the current platform language setting
    264     //
    265     PlatformLanguage = GetBestLanguageForDriver(ComponentName2->SupportedLanguages, NULL, FALSE);
    266     Status = ComponentName2->GetDriverName (
    267                                ComponentName2,
    268                                PlatformLanguage != NULL ? PlatformLanguage : "en-US",
    269                                &StringPtr
    270                                );
    271     if (!EFI_ERROR (Status)) {
    272       SHELL_FREE_NON_NULL (PlatformLanguage);
    273       StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, StringPtr, DP_GAUGE_STRING_LENGTH);
    274       mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
    275       return;
    276     }
    277   }
    278 
    279   Status = gBS->HandleProtocol (
    280                   Handle,
    281                   &gEfiLoadedImageDevicePathProtocolGuid,
    282                   (VOID **) &LoadedImageDevicePath
    283                   );
    284   if (!EFI_ERROR (Status) && (LoadedImageDevicePath != NULL)) {
    285     DevicePath = LoadedImageDevicePath;
    286   } else if (Image != NULL) {
    287     DevicePath = Image->FilePath;
    288   }
    289 
    290   if (DevicePath != NULL) {
    291     //
    292     // Try to get image GUID from image DevicePath
    293     //
    294     NameGuid = NULL;
    295     while (!IsDevicePathEndType (DevicePath)) {
    296       NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);
    297       if (NameGuid != NULL) {
    298         break;
    299       }
    300       DevicePath = NextDevicePathNode (DevicePath);
    301     }
    302 
    303     if (NameGuid != NULL) {
    304       //
    305       // Try to get the image's FFS UI section by image GUID
    306       //
    307       NameString = NULL;
    308       StringSize = 0;
    309       Status = GetSectionFromAnyFv (
    310                 NameGuid,
    311                 EFI_SECTION_USER_INTERFACE,
    312                 0,
    313                 (VOID **) &NameString,
    314                 &StringSize
    315                 );
    316 
    317       if (!EFI_ERROR (Status)) {
    318         //
    319         // Method 3. Get the name string from FFS UI section
    320         //
    321         StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, NameString, DP_GAUGE_STRING_LENGTH);
    322         mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
    323         FreePool (NameString);
    324       } else {
    325         //
    326         // Method 4: Get the name string from image GUID
    327         //
    328         UnicodeSPrint (mGaugeString, sizeof (mGaugeString), L"%g", NameGuid);
    329       }
    330       return;
    331     } else {
    332       //
    333       // Method 5: Get the name string from image DevicePath
    334       //
    335       NameString = ConvertDevicePathToText (DevicePath, TRUE, FALSE);
    336       if (NameString != NULL) {
    337         StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, NameString, DP_GAUGE_STRING_LENGTH);
    338         mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
    339         FreePool (NameString);
    340         return;
    341       }
    342     }
    343   }
    344 
    345   //
    346   // Method 6: Unknown Driver Name
    347   //
    348   StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_ERROR_NAME), NULL);
    349   ASSERT (StringPtr != NULL);
    350   StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, StringPtr, DP_GAUGE_STRING_LENGTH);
    351   FreePool (StringPtr);
    352 }
    353 
    354 /**
    355   Calculate the Duration in microseconds.
    356 
    357   Duration is multiplied by 1000, instead of Frequency being divided by 1000 or
    358   multiplying the result by 1000, in order to maintain precision.  Since Duration is
    359   a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow.
    360 
    361   The time is calculated as (Duration * 1000) / Timer_Frequency.
    362 
    363   @param[in]  Duration   The event duration in timer ticks.
    364 
    365   @return     A 64-bit value which is the Elapsed time in microseconds.
    366 **/
    367 UINT64
    368 DurationInMicroSeconds (
    369   IN UINT64 Duration
    370   )
    371 {
    372   UINT64 Temp;
    373 
    374   Temp = MultU64x32 (Duration, 1000);
    375   return DivU64x32 (Temp, TimerInfo.Frequency);
    376 }
    377 
    378 /**
    379   Get index of Measurement Record's match in the CumData array.
    380 
    381   If the Measurement's Token value matches a Token in one of the CumData
    382   records, the index of the matching record is returned.  The returned
    383   index is a signed value so that negative values can indicate that
    384   the Measurement didn't match any entry in the CumData array.
    385 
    386   @param[in]  Measurement A pointer to a Measurement Record to match against the CumData array.
    387 
    388   @retval     <0    Token is not in the CumData array.
    389   @retval     >=0   Return value is the index into CumData where Token is found.
    390 **/
    391 INTN
    392 GetCumulativeItem(
    393   IN MEASUREMENT_RECORD   *Measurement
    394   )
    395 {
    396   INTN    Index;
    397 
    398   for( Index = 0; Index < (INTN)NumCum; ++Index) {
    399     if (AsciiStrnCmp (Measurement->Token, CumData[Index].Name, PERF_TOKEN_LENGTH) == 0) {
    400       return Index;  // Exit, we found a match
    401     }
    402   }
    403   // If the for loop exits, Token was not found.
    404   return -1;   // Indicate failure
    405 }
    406