]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiDpLib/DpUtilities.c
fbdd938bc3bfbd1388515f909c7d4645000817a8
[mirror_edk2.git] / ShellPkg / Library / UefiDpLib / DpUtilities.c
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 }