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