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