2 Utility functions used by the Dp application.
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
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.
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>
27 #include <Pi/PiFirmwareFile.h>
28 #include <Library/DxeServicesLib.h>
30 #include <Protocol/LoadedImage.h>
31 #include <Protocol/DriverBinding.h>
32 #include <Protocol/ComponentName2.h>
33 #include <Protocol/DevicePath.h>
35 #include <Guid/Performance.h>
39 #include "DpInternal.h"
42 Calculate an event's duration in timer ticks.
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.
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.
53 The calculated duration, in ticks, is the absolute difference between
54 the measurement's ending and starting counts.
56 @param Measurement Pointer to a MEASUREMENT_RECORD structure containing
57 data for the current measurement.
59 @return The 64-bit duration of the event.
63 IN OUT MEASUREMENT_RECORD
*Measurement
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
;
77 if (TimerInfo
.CountUp
) {
78 Duration
= Measurement
->EndTimeStamp
- Measurement
->StartTimeStamp
;
79 Error
= (BOOLEAN
)(Duration
> Measurement
->EndTimeStamp
);
82 Duration
= Measurement
->StartTimeStamp
- Measurement
->EndTimeStamp
;
83 Error
= (BOOLEAN
)(Duration
> Measurement
->StartTimeStamp
);
87 DEBUG ((EFI_D_ERROR
, ALit_TimerLibError
));
94 Determine whether the Measurement record is for an EFI Phase.
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.
99 @param[in] Measurement A pointer to the Measurement record to test.
101 @retval TRUE The measurement record is for an EFI Phase.
102 @retval FALSE The measurement record is NOT for an EFI Phase.
106 IN MEASUREMENT_RECORD
*Measurement
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))
121 Get the file name portion of the Pdb File Name.
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.
128 @param[in] PdbFileName Pdb file name.
129 @param[out] UnicodeBuffer The resultant Unicode File Name.
133 GetShortPdbFileName (
134 IN CHAR8
*PdbFileName
,
135 OUT CHAR16
*UnicodeBuffer
138 UINTN IndexA
; // Current work location within an ASCII string.
139 UINTN IndexU
; // Current work location within a Unicode string.
143 ZeroMem (UnicodeBuffer
, DXE_PERFORMANCE_STRING_LENGTH
* sizeof (CHAR16
));
145 if (PdbFileName
== NULL
) {
146 StrCpy (UnicodeBuffer
, L
" ");
149 for (EndIndex
= 0; PdbFileName
[EndIndex
] != 0; EndIndex
++)
151 for (IndexA
= 0; PdbFileName
[IndexA
] != 0; IndexA
++) {
152 if (PdbFileName
[IndexA
] == '\\') {
153 StartIndex
= IndexA
+ 1;
156 if (PdbFileName
[IndexA
] == '.') {
162 for (IndexA
= StartIndex
; IndexA
< EndIndex
; IndexA
++) {
163 UnicodeBuffer
[IndexU
] = (CHAR16
) PdbFileName
[IndexA
];
165 if (IndexU
>= DXE_PERFORMANCE_STRING_LENGTH
) {
166 UnicodeBuffer
[DXE_PERFORMANCE_STRING_LENGTH
] = 0;
174 Get a human readable name for an image handle.
175 The following methods will be tried orderly:
177 2. ComponentName2 protocol
181 6. Unknown Driver Name
185 @post The resulting Unicode name string is stored in the
186 mGaugeString global array.
195 EFI_LOADED_IMAGE_PROTOCOL
*Image
;
197 EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
;
198 EFI_STRING StringPtr
;
199 EFI_DEVICE_PATH_PROTOCOL
*LoadedImageDevicePath
;
200 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
204 CHAR8
*PlatformLanguage
;
205 EFI_COMPONENT_NAME2_PROTOCOL
*ComponentName2
;
208 // Method 1: Get the name string from image PDB
210 Status
= gBS
->HandleProtocol (
212 &gEfiLoadedImageProtocolGuid
,
216 if (EFI_ERROR (Status
)) {
217 Status
= gBS
->OpenProtocol (
219 &gEfiDriverBindingProtocolGuid
,
220 (VOID
**) &DriverBinding
,
223 EFI_OPEN_PROTOCOL_GET_PROTOCOL
225 if (!EFI_ERROR (Status
)) {
226 Status
= gBS
->HandleProtocol (
227 DriverBinding
->ImageHandle
,
228 &gEfiLoadedImageProtocolGuid
,
234 if (!EFI_ERROR (Status
)) {
235 PdbFileName
= PeCoffLoaderGetPdbPointer (Image
->ImageBase
);
237 if (PdbFileName
!= NULL
) {
238 GetShortPdbFileName (PdbFileName
, mGaugeString
);
244 // Method 2: Get the name string from ComponentName2 protocol
246 Status
= gBS
->HandleProtocol (
248 &gEfiComponentName2ProtocolGuid
,
249 (VOID
**) &ComponentName2
251 if (!EFI_ERROR (Status
)) {
253 // Get the current platform language setting
255 GetEfiGlobalVariable2 (L
"PlatformLang", (VOID
**)&PlatformLanguage
, NULL
);
256 Status
= ComponentName2
->GetDriverName (
258 PlatformLanguage
!= NULL
? PlatformLanguage
: "en-US",
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;
269 Status
= gBS
->HandleProtocol (
271 &gEfiLoadedImageDevicePathProtocolGuid
,
272 (VOID
**) &LoadedImageDevicePath
274 if (!EFI_ERROR (Status
) && (LoadedImageDevicePath
!= NULL
)) {
275 DevicePath
= LoadedImageDevicePath
;
278 // Try to get image GUID from LoadedImageDevicePath protocol
281 while (!IsDevicePathEndType (DevicePath
)) {
282 NameGuid
= EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH
*) DevicePath
);
283 if (NameGuid
!= NULL
) {
286 DevicePath
= NextDevicePathNode (DevicePath
);
289 if (NameGuid
!= NULL
) {
291 // Try to get the image's FFS UI section by image GUID
295 Status
= GetSectionFromAnyFv (
297 EFI_SECTION_USER_INTERFACE
,
299 (VOID
**) &NameString
,
303 if (!EFI_ERROR (Status
)) {
305 // Method 3. Get the name string from FFS UI section
307 StrnCpy (mGaugeString
, NameString
, DP_GAUGE_STRING_LENGTH
);
308 mGaugeString
[DP_GAUGE_STRING_LENGTH
] = 0;
309 FreePool (NameString
);
312 // Method 4: Get the name string from image GUID
314 UnicodeSPrint (mGaugeString
, sizeof (mGaugeString
), L
"%g", NameGuid
);
319 // Method 5: Get the name string from image DevicePath
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
);
332 // Method 6: Unknown Driver Name
334 StringPtr
= HiiGetString (gDpHiiHandle
, STRING_TOKEN (STR_DP_ERROR_NAME
), NULL
);
335 ASSERT (StringPtr
!= NULL
);
336 StrCpy (mGaugeString
, StringPtr
);
337 FreePool (StringPtr
);
341 Calculate the Duration in microseconds.
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.
347 The time is calculated as (Duration * 1000) / Timer_Frequency.
349 @param[in] Duration The event duration in timer ticks.
351 @return A 64-bit value which is the Elapsed time in microseconds.
354 DurationInMicroSeconds (
360 Temp
= MultU64x32 (Duration
, 1000);
361 return DivU64x32 (Temp
, TimerInfo
.Frequency
);
365 Get index of Measurement Record's match in the CumData array.
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.
372 @param[in] Measurement A pointer to a Measurement Record to match against the CumData array.
374 @retval <0 Token is not in the CumData array.
375 @retval >=0 Return value is the index into CumData where Token is found.
379 IN MEASUREMENT_RECORD
*Measurement
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
389 // If the for loop exits, Token was not found.
390 return -1; // Indicate failure