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