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