2 Utility functions used by the Dp application.
4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 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
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.
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>
28 #include <Pi/PiFirmwareFile.h>
29 #include <Library/DxeServicesLib.h>
31 #include <Protocol/LoadedImage.h>
32 #include <Protocol/DriverBinding.h>
33 #include <Protocol/ComponentName2.h>
34 #include <Protocol/DevicePath.h>
36 #include <Guid/Performance.h>
40 #include "DpInternal.h"
43 Wrap original FreePool to check NULL pointer first.
45 @param[in] Buffer The pointer to the buffer to free.
59 Calculate an event's duration in timer ticks.
61 Given the count direction and the event's start and end timer values,
62 calculate the duration of the event in timer ticks. Information for
63 the current measurement is pointed to by the parameter.
65 If the measurement's start time is 1, it indicates that the developer
66 is indicating that the measurement began at the release of reset.
67 The start time is adjusted to the timer's starting count before performing
68 the elapsed time calculation.
70 The calculated duration, in ticks, is the absolute difference between
71 the measurement's ending and starting counts.
73 @param Measurement Pointer to a MEASUREMENT_RECORD structure containing
74 data for the current measurement.
76 @return The 64-bit duration of the event.
80 IN OUT MEASUREMENT_RECORD
*Measurement
86 if (Measurement
->EndTimeStamp
== 0) {
90 // PERF_START macros are called with a value of 1 to indicate
91 // the beginning of time. So, adjust the start ticker value
92 // to the real beginning of time.
93 // Assumes no wraparound. Even then, there is a very low probability
94 // of having a valid StartTicker value of 1.
95 if (Measurement
->StartTimeStamp
== 1) {
96 Measurement
->StartTimeStamp
= TimerInfo
.StartCount
;
98 if (TimerInfo
.CountUp
) {
99 Duration
= Measurement
->EndTimeStamp
- Measurement
->StartTimeStamp
;
100 Error
= (BOOLEAN
)(Duration
> Measurement
->EndTimeStamp
);
103 Duration
= Measurement
->StartTimeStamp
- Measurement
->EndTimeStamp
;
104 Error
= (BOOLEAN
)(Duration
> Measurement
->StartTimeStamp
);
108 DEBUG ((EFI_D_ERROR
, ALit_TimerLibError
));
115 Determine whether the Measurement record is for an EFI Phase.
117 The Token and Module members of the measurement record are checked.
118 Module must be empty and Token must be one of SEC, PEI, DXE, BDS, or SHELL.
120 @param[in] Measurement A pointer to the Measurement record to test.
122 @retval TRUE The measurement record is for an EFI Phase.
123 @retval FALSE The measurement record is NOT for an EFI Phase.
127 IN MEASUREMENT_RECORD
*Measurement
132 RetVal
= (BOOLEAN
)( ( *Measurement
->Module
== '\0') &&
133 ((AsciiStrnCmp (Measurement
->Token
, ALit_SEC
, PERF_TOKEN_LENGTH
) == 0) ||
134 (AsciiStrnCmp (Measurement
->Token
, ALit_PEI
, PERF_TOKEN_LENGTH
) == 0) ||
135 (AsciiStrnCmp (Measurement
->Token
, ALit_DXE
, PERF_TOKEN_LENGTH
) == 0) ||
136 (AsciiStrnCmp (Measurement
->Token
, ALit_BDS
, PERF_TOKEN_LENGTH
) == 0))
142 Get the file name portion of the Pdb File Name.
144 The portion of the Pdb File Name between the last backslash and
145 either a following period or the end of the string is converted
146 to Unicode and copied into UnicodeBuffer. The name is truncated,
147 if necessary, to ensure that UnicodeBuffer is not overrun.
149 @param[in] PdbFileName Pdb file name.
150 @param[out] UnicodeBuffer The resultant Unicode File Name.
154 GetShortPdbFileName (
155 IN CHAR8
*PdbFileName
,
156 OUT CHAR16
*UnicodeBuffer
159 UINTN IndexA
; // Current work location within an ASCII string.
160 UINTN IndexU
; // Current work location within a Unicode string.
164 ZeroMem (UnicodeBuffer
, (DP_GAUGE_STRING_LENGTH
+ 1) * sizeof (CHAR16
));
166 if (PdbFileName
== NULL
) {
167 StrCpyS (UnicodeBuffer
, DP_GAUGE_STRING_LENGTH
+ 1, L
" ");
170 for (EndIndex
= 0; PdbFileName
[EndIndex
] != 0; EndIndex
++)
172 for (IndexA
= 0; PdbFileName
[IndexA
] != 0; IndexA
++) {
173 if (PdbFileName
[IndexA
] == '\\') {
174 StartIndex
= IndexA
+ 1;
177 if (PdbFileName
[IndexA
] == '.') {
183 for (IndexA
= StartIndex
; IndexA
< EndIndex
; IndexA
++) {
184 UnicodeBuffer
[IndexU
] = (CHAR16
) PdbFileName
[IndexA
];
186 if (IndexU
>= DP_GAUGE_STRING_LENGTH
) {
187 UnicodeBuffer
[DP_GAUGE_STRING_LENGTH
] = 0;
195 Get a human readable name for an image handle.
196 The following methods will be tried orderly:
198 2. ComponentName2 protocol
202 6. Unknown Driver Name
206 @post The resulting Unicode name string is stored in the
207 mGaugeString global array.
216 EFI_LOADED_IMAGE_PROTOCOL
*Image
;
218 EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
;
219 EFI_STRING StringPtr
;
220 EFI_DEVICE_PATH_PROTOCOL
*LoadedImageDevicePath
;
221 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
225 CHAR8
*PlatformLanguage
;
227 EFI_COMPONENT_NAME2_PROTOCOL
*ComponentName2
;
230 LoadedImageDevicePath
= NULL
;
233 PlatformLanguage
= NULL
;
236 // Method 1: Get the name string from image PDB
238 Status
= gBS
->HandleProtocol (
240 &gEfiLoadedImageProtocolGuid
,
244 if (EFI_ERROR (Status
)) {
245 Status
= gBS
->OpenProtocol (
247 &gEfiDriverBindingProtocolGuid
,
248 (VOID
**) &DriverBinding
,
251 EFI_OPEN_PROTOCOL_GET_PROTOCOL
253 if (!EFI_ERROR (Status
)) {
254 Status
= gBS
->HandleProtocol (
255 DriverBinding
->ImageHandle
,
256 &gEfiLoadedImageProtocolGuid
,
262 if (!EFI_ERROR (Status
)) {
263 PdbFileName
= PeCoffLoaderGetPdbPointer (Image
->ImageBase
);
265 if (PdbFileName
!= NULL
) {
266 GetShortPdbFileName (PdbFileName
, mGaugeString
);
272 // Method 2: Get the name string from ComponentName2 protocol
274 Status
= gBS
->HandleProtocol (
276 &gEfiComponentName2ProtocolGuid
,
277 (VOID
**) &ComponentName2
279 if (!EFI_ERROR (Status
)) {
281 // Get the current platform language setting
283 GetEfiGlobalVariable2 (L
"PlatformLang", (VOID
**)&PlatformLanguage
, NULL
);
285 BestLanguage
= GetBestLanguage(
286 ComponentName2
->SupportedLanguages
,
289 ComponentName2
->SupportedLanguages
,
293 SafeFreePool (PlatformLanguage
);
294 Status
= ComponentName2
->GetDriverName (
299 SafeFreePool (BestLanguage
);
300 if (!EFI_ERROR (Status
)) {
303 DP_GAUGE_STRING_LENGTH
+ 1,
305 DP_GAUGE_STRING_LENGTH
311 Status
= gBS
->HandleProtocol (
313 &gEfiLoadedImageDevicePathProtocolGuid
,
314 (VOID
**) &LoadedImageDevicePath
316 if (!EFI_ERROR (Status
) && (LoadedImageDevicePath
!= NULL
)) {
317 DevicePath
= LoadedImageDevicePath
;
318 } else if (Image
!= NULL
) {
319 DevicePath
= Image
->FilePath
;
322 if (DevicePath
!= NULL
) {
324 // Try to get image GUID from image DevicePath
327 while (!IsDevicePathEndType (DevicePath
)) {
328 NameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) DevicePath
);
329 if (NameGuid
!= NULL
) {
332 DevicePath
= NextDevicePathNode (DevicePath
);
335 if (NameGuid
!= NULL
) {
337 // Try to get the image's FFS UI section by image GUID
341 Status
= GetSectionFromAnyFv (
343 EFI_SECTION_USER_INTERFACE
,
345 (VOID
**) &NameString
,
349 if (!EFI_ERROR (Status
)) {
351 // Method 3. Get the name string from FFS UI section
355 DP_GAUGE_STRING_LENGTH
+ 1,
357 DP_GAUGE_STRING_LENGTH
359 FreePool (NameString
);
362 // Method 4: Get the name string from image GUID
364 UnicodeSPrint (mGaugeString
, sizeof (mGaugeString
), L
"%g", NameGuid
);
369 // Method 5: Get the name string from image DevicePath
371 NameString
= ConvertDevicePathToText (DevicePath
, TRUE
, FALSE
);
372 if (NameString
!= NULL
) {
375 DP_GAUGE_STRING_LENGTH
+ 1,
377 DP_GAUGE_STRING_LENGTH
379 FreePool (NameString
);
386 // Method 6: Unknown Driver Name
388 StringPtr
= HiiGetString (gHiiHandle
, STRING_TOKEN (STR_DP_ERROR_NAME
), NULL
);
389 ASSERT (StringPtr
!= NULL
);
390 StrCpyS (mGaugeString
, DP_GAUGE_STRING_LENGTH
+ 1, StringPtr
);
391 FreePool (StringPtr
);
396 Calculate the Duration in microseconds.
398 Duration is multiplied by 1000, instead of Frequency being divided by 1000 or
399 multiplying the result by 1000, in order to maintain precision. Since Duration is
400 a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow.
402 The time is calculated as (Duration * 1000) / Timer_Frequency.
404 @param[in] Duration The event duration in timer ticks.
406 @return A 64-bit value which is the Elapsed time in microseconds.
409 DurationInMicroSeconds (
415 Temp
= MultU64x32 (Duration
, 1000);
416 return DivU64x32 (Temp
, TimerInfo
.Frequency
);
420 Formatted Print using a Hii Token to reference the localized format string.
422 @param[in] Token A HII token associated with a localized Unicode string.
423 @param[in] ... The variable argument list.
425 @return The number of characters converted by UnicodeVSPrint().
436 EFI_STRING StringPtr
;
440 StringPtr
= HiiGetString (gHiiHandle
, Token
, NULL
);
441 ASSERT (StringPtr
!= NULL
);
443 VA_START (Marker
, Token
);
445 BufferSize
= (PcdGet32 (PcdUefiLibMaxPrintBufferSize
) + 1) * sizeof (CHAR16
);
447 if (mPrintTokenBuffer
== NULL
) {
448 mPrintTokenBuffer
= AllocatePool (BufferSize
);
449 ASSERT (mPrintTokenBuffer
!= NULL
);
451 SetMem( mPrintTokenBuffer
, BufferSize
, 0);
453 Return
= UnicodeVSPrint (mPrintTokenBuffer
, BufferSize
, StringPtr
, Marker
);
456 if (Return
> 0 && gST
->ConOut
!= NULL
) {
457 gST
->ConOut
->OutputString (gST
->ConOut
, mPrintTokenBuffer
);
459 FreePool (StringPtr
);
464 Get index of Measurement Record's match in the CumData array.
466 If the Measurement's Token value matches a Token in one of the CumData
467 records, the index of the matching record is returned. The returned
468 index is a signed value so that negative values can indicate that
469 the Measurement didn't match any entry in the CumData array.
471 @param[in] Measurement A pointer to a Measurement Record to match against the CumData array.
473 @retval <0 Token is not in the CumData array.
474 @retval >=0 Return value is the index into CumData where Token is found.
478 IN MEASUREMENT_RECORD
*Measurement
483 for( Index
= 0; Index
< (INTN
)NumCum
; ++Index
) {
484 if (AsciiStrnCmp (Measurement
->Token
, CumData
[Index
].Name
, PERF_TOKEN_LENGTH
) == 0) {
485 return Index
; // Exit, we found a match
488 // If the for loop exits, Token was not found.
489 return -1; // Indicate failure