2 * Utility functions used by the Dp application.
4 * Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
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>
25 #include <Protocol/LoadedImage.h>
26 #include <Protocol/Driverbinding.h>
28 #include <Guid/Performance.h>
32 #include "DpInternal.h"
34 /** Calculate an event's duration in timer ticks.
36 * Given the count direction and the event's start and end timer values,
37 * calculate the duration of the event in timer ticks. Information for
38 * the current measurement is pointed to by the parameter.
40 * If the measurement's start time is 1, it indicates that the developer
41 * is indicating that the measurement began at the release of reset.
42 * The start time is adjusted to the timer's starting count before performing
43 * the elapsed time calculation.
45 * The calculated duration, in ticks, is the absolute difference between
46 * the measurement's ending and starting counts.
48 * @pre The global TimerInfo structure must have already been initialized
49 * before this function is called.
51 * @param[in,out] Measurement Pointer to a MEASUREMENT_RECORD structure containing
52 * data for the current measurement.
54 * @return The 64-bit duration of the event.
58 IN OUT MEASUREMENT_RECORD
*Measurement
64 // PERF_START macros are called with a value of 1 to indicate
65 // the beginning of time. So, adjust the start ticker value
66 // to the real beginning of time.
67 // Assumes no wraparound. Even then, there is a very low probability
68 // of having a valid StartTicker value of 1.
69 if (Measurement
->StartTimeStamp
== 1) {
70 Measurement
->StartTimeStamp
= TimerInfo
.StartCount
;
72 if (TimerInfo
.CountUp
) {
73 Duration
= Measurement
->EndTimeStamp
- Measurement
->StartTimeStamp
;
74 Error
= (BOOLEAN
)(Duration
> Measurement
->EndTimeStamp
);
77 Duration
= Measurement
->StartTimeStamp
- Measurement
->EndTimeStamp
;
78 Error
= (BOOLEAN
)(Duration
> Measurement
->StartTimeStamp
);
82 DEBUG ((EFI_D_ERROR
, ALit_TimerLibError
));
88 /** Determine whether the Measurement record is for an EFI Phase.
90 * The Token and Module members of the measurement record are checked.
91 * Module must be empty and Token must be one of SEC, PEI, DXE, BDS, or SHELL.
93 * @param[in] Measurement A pointer to the Measurement record to test.
95 * @retval TRUE The measurement record is for an EFI Phase.
96 * @retval FALSE The measurement record is NOT for an EFI Phase.
100 IN MEASUREMENT_RECORD
*Measurement
105 RetVal
= (BOOLEAN
)( ( *Measurement
->Module
== '\0') &&
106 ((AsciiStrnCmp (Measurement
->Token
, ALit_SEC
, PERF_TOKEN_LENGTH
) == 0) ||
107 (AsciiStrnCmp (Measurement
->Token
, ALit_PEI
, PERF_TOKEN_LENGTH
) == 0) ||
108 (AsciiStrnCmp (Measurement
->Token
, ALit_DXE
, PERF_TOKEN_LENGTH
) == 0) ||
109 (AsciiStrnCmp (Measurement
->Token
, ALit_BDS
, PERF_TOKEN_LENGTH
) == 0))
114 /** Get the file name portion of the Pdb File Name.
116 * The portion of the Pdb File Name between the last backslash and
117 * either a following period or the end of the string is converted
118 * to Unicode and copied into UnicodeBuffer. The name is truncated,
119 * if necessary, to ensure that UnicodeBuffer is not overrun.
121 * @param[in] PdbFileName Pdb file name.
122 * @param[out] UnicodeBuffer The resultant Unicode File Name.
126 GetShortPdbFileName (
127 IN CHAR8
*PdbFileName
,
128 OUT CHAR16
*UnicodeBuffer
131 UINTN IndexA
; // Current work location within an ASCII string.
132 UINTN IndexU
; // Current work location within a Unicode string.
136 ZeroMem (UnicodeBuffer
, DXE_PERFORMANCE_STRING_LENGTH
* sizeof (CHAR16
));
138 if (PdbFileName
== NULL
) {
139 StrCpy (UnicodeBuffer
, L
" ");
142 for (EndIndex
= 0; PdbFileName
[EndIndex
] != 0; EndIndex
++)
144 for (IndexA
= 0; PdbFileName
[IndexA
] != 0; IndexA
++) {
145 if (PdbFileName
[IndexA
] == '\\') {
146 StartIndex
= IndexA
+ 1;
149 if (PdbFileName
[IndexA
] == '.') {
155 for (IndexA
= StartIndex
; IndexA
< EndIndex
; IndexA
++) {
156 UnicodeBuffer
[IndexU
] = (CHAR16
) PdbFileName
[IndexA
];
158 if (IndexU
>= DXE_PERFORMANCE_STRING_LENGTH
) {
159 UnicodeBuffer
[DXE_PERFORMANCE_STRING_LENGTH
] = 0;
166 /** Get a human readable name for an image handle.
170 * @post The resulting Unicode name string is stored in the
171 * mGaugeString global array.
180 EFI_LOADED_IMAGE_PROTOCOL
*Image
;
182 EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
;
183 EFI_STRING StringPtr
;
185 // Proactively get the error message so it will be ready if needed
186 StringPtr
= HiiGetString (gHiiHandle
, STRING_TOKEN (STR_DP_ERROR_NAME
), NULL
);
187 ASSERT (StringPtr
!= NULL
);
189 // Get handle name from image protocol
191 Status
= gBS
->HandleProtocol (
193 &gEfiLoadedImageProtocolGuid
,
197 if (EFI_ERROR (Status
)) {
198 Status
= gBS
->OpenProtocol (
200 &gEfiDriverBindingProtocolGuid
,
201 (VOID
**) &DriverBinding
,
204 EFI_OPEN_PROTOCOL_GET_PROTOCOL
206 if (EFI_ERROR (Status
)) {
207 StrCpy (mGaugeString
, StringPtr
);
211 // Get handle name from image protocol
213 Status
= gBS
->HandleProtocol (
214 DriverBinding
->ImageHandle
,
215 &gEfiLoadedImageProtocolGuid
,
220 PdbFileName
= PeCoffLoaderGetPdbPointer (Image
->ImageBase
);
222 if (PdbFileName
!= NULL
) {
223 GetShortPdbFileName (PdbFileName
, mGaugeString
);
225 StrCpy (mGaugeString
, StringPtr
);
230 /** Calculate the Duration in microseconds.
232 * Duration is multiplied by 1000, instead of Frequency being divided by 1000 or
233 * multiplying the result by 1000, in order to maintain precision. Since Duration is
234 * a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow.
236 * The time is calculated as (Duration * 1000) / Timer_Frequency.
238 * @param[in] Duration The event duration in timer ticks.
240 * @return A 64-bit value which is the Elapsed time in microseconds.
243 DurationInMicroSeconds (
249 Temp
= MultU64x32 (Duration
, 1000);
250 return DivU64x32 (Temp
, TimerInfo
.Frequency
);
253 /** Formatted Print using a Hii Token to reference the localized format string.
255 * @param[in] Token A HII token associated with a localized Unicode string.
257 * @return The number of characters converted by UnicodeVSPrint().
267 EFI_STRING StringPtr
;
271 StringPtr
= HiiGetString (gHiiHandle
, Token
, NULL
);
272 ASSERT (StringPtr
!= NULL
);
274 VA_START (Marker
, Token
);
276 BufferSize
= (PcdGet32 (PcdUefiLibMaxPrintBufferSize
) + 1) * sizeof (CHAR16
);
278 if (mPrintTokenBuffer
== NULL
) {
279 mPrintTokenBuffer
= AllocatePool (BufferSize
);
280 ASSERT (mPrintTokenBuffer
!= NULL
);
282 SetMem( mPrintTokenBuffer
, BufferSize
, 0);
284 Return
= UnicodeVSPrint (mPrintTokenBuffer
, BufferSize
, StringPtr
, Marker
);
285 if (Return
> 0 && gST
->ConOut
!= NULL
) {
286 gST
->ConOut
->OutputString (gST
->ConOut
, mPrintTokenBuffer
);
291 /** Get index of Measurement Record's match in the CumData array.
293 * If the Measurement's Token value matches a Token in one of the CumData
294 * records, the index of the matching record is returned. The returned
295 * index is a signed value so that negative values can indicate that
296 * the Measurement didn't match any entry in the CumData array.
298 * @param[in] Measurement A pointer to a Measurement Record to match against the CumData array.
300 * @retval <0 Token is not in the CumData array.
301 * @retval >=0 Return value is the index into CumData where Token is found.
305 IN MEASUREMENT_RECORD
*Measurement
310 for( Index
= 0; Index
< (INTN
)NumCum
; ++Index
) {
311 if (AsciiStrnCmp (Measurement
->Token
, CumData
[Index
].Name
, PERF_TOKEN_LENGTH
) == 0) {
312 return Index
; // Exit, we found a match
315 // If the for loop exits, Token was not found.
316 return -1; // Indicate failure