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