]> git.proxmox.com Git - mirror_edk2.git/blame - PerformancePkg/Dp_App/DpUtilities.c
Program SD Cards into 4-bit mode (support for this is required in the spec). This...
[mirror_edk2.git] / PerformancePkg / Dp_App / DpUtilities.c
CommitLineData
c06ad33e 1/** @file\r
2 * Utility functions used by the Dp application.\r
3 *\r
92ea1df8 4 * Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
c06ad33e 5 * This program and the accompanying materials\r
6 * are licensed and made available under the terms and conditions of the BSD License\r
7 * which accompanies this distribution. The full text of the license may be found at\r
8 * http://opensource.org/licenses/bsd-license.php\r
9 *\r
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12**/\r
13\r
14#include <Library/BaseLib.h>\r
15#include <Library/BaseMemoryLib.h>\r
16#include <Library/MemoryAllocationLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/UefiBootServicesTableLib.h>\r
19#include <Library/TimerLib.h>\r
20#include <Library/PeCoffGetEntryPointLib.h>\r
21#include <Library/PrintLib.h>\r
22#include <Library/HiiLib.h>\r
23#include <Library/PcdLib.h>\r
24\r
25#include <Protocol/LoadedImage.h>\r
26#include <Protocol/Driverbinding.h>\r
27\r
28#include <Guid/Performance.h>\r
29\r
30#include "Dp.h"\r
31#include "Literals.h"\r
32#include "DpInternal.h"\r
33\r
34/** Calculate an event's duration in timer ticks.\r
35 *\r
36 * Given the count direction and the event's start and end timer values,\r
37 * calculate the duration of the event in timer ticks. Information for\r
38 * the current measurement is pointed to by the parameter.\r
39 *\r
40 * If the measurement's start time is 1, it indicates that the developer\r
41 * is indicating that the measurement began at the release of reset.\r
42 * The start time is adjusted to the timer's starting count before performing\r
43 * the elapsed time calculation.\r
44 *\r
45 * The calculated duration, in ticks, is the absolute difference between\r
46 * the measurement's ending and starting counts.\r
47 *\r
48 * @pre The global TimerInfo structure must have already been initialized\r
49 * before this function is called.\r
50 *\r
51 * @param[in,out] Measurement Pointer to a MEASUREMENT_RECORD structure containing\r
52 * data for the current measurement.\r
53 *\r
54 * @return The 64-bit duration of the event.\r
55**/\r
56UINT64\r
57GetDuration (\r
58 IN OUT MEASUREMENT_RECORD *Measurement\r
59 )\r
60{\r
61 UINT64 Duration;\r
62 BOOLEAN Error;\r
63\r
64 // PERF_START macros are called with a value of 1 to indicate\r
65 // the beginning of time. So, adjust the start ticker value\r
66 // to the real beginning of time.\r
67 // Assumes no wraparound. Even then, there is a very low probability\r
68 // of having a valid StartTicker value of 1.\r
69 if (Measurement->StartTimeStamp == 1) {\r
70 Measurement->StartTimeStamp = TimerInfo.StartCount;\r
71 }\r
72 if (TimerInfo.CountUp) {\r
73 Duration = Measurement->EndTimeStamp - Measurement->StartTimeStamp;\r
74 Error = (BOOLEAN)(Duration > Measurement->EndTimeStamp);\r
75 }\r
76 else {\r
77 Duration = Measurement->StartTimeStamp - Measurement->EndTimeStamp;\r
78 Error = (BOOLEAN)(Duration > Measurement->StartTimeStamp);\r
79 }\r
80\r
81 if (Error) {\r
82 DEBUG ((EFI_D_ERROR, ALit_TimerLibError));\r
83 Duration = 0;\r
84 }\r
85 return Duration;\r
86}\r
87\r
88/** Determine whether the Measurement record is for an EFI Phase.\r
89 *\r
90 * The Token and Module members of the measurement record are checked.\r
91 * Module must be empty and Token must be one of SEC, PEI, DXE, BDS, or SHELL.\r
92 *\r
93 * @param[in] Measurement A pointer to the Measurement record to test.\r
94 *\r
95 * @retval TRUE The measurement record is for an EFI Phase.\r
96 * @retval FALSE The measurement record is NOT for an EFI Phase.\r
97**/\r
98BOOLEAN\r
99IsPhase(\r
100 IN MEASUREMENT_RECORD *Measurement\r
101 )\r
102{\r
103 BOOLEAN RetVal;\r
104\r
105 RetVal = (BOOLEAN)( ( *Measurement->Module == '\0') &&\r
106 ((AsciiStrnCmp (Measurement->Token, ALit_SEC, PERF_TOKEN_LENGTH) == 0) ||\r
107 (AsciiStrnCmp (Measurement->Token, ALit_PEI, PERF_TOKEN_LENGTH) == 0) ||\r
108 (AsciiStrnCmp (Measurement->Token, ALit_DXE, PERF_TOKEN_LENGTH) == 0) ||\r
109 (AsciiStrnCmp (Measurement->Token, ALit_BDS, PERF_TOKEN_LENGTH) == 0))\r
110 );\r
111 return RetVal;\r
112}\r
113\r
114/** Get the file name portion of the Pdb File Name.\r
115 *\r
116 * The portion of the Pdb File Name between the last backslash and\r
117 * either a following period or the end of the string is converted\r
118 * to Unicode and copied into UnicodeBuffer. The name is truncated,\r
119 * if necessary, to ensure that UnicodeBuffer is not overrun.\r
120 *\r
121 * @param[in] PdbFileName Pdb file name.\r
122 * @param[out] UnicodeBuffer The resultant Unicode File Name.\r
123 *\r
124**/\r
125VOID\r
126GetShortPdbFileName (\r
127 IN CHAR8 *PdbFileName,\r
128 OUT CHAR16 *UnicodeBuffer\r
129 )\r
130{\r
131 UINTN IndexA; // Current work location within an ASCII string.\r
132 UINTN IndexU; // Current work location within a Unicode string.\r
133 UINTN StartIndex;\r
134 UINTN EndIndex;\r
135\r
136 ZeroMem (UnicodeBuffer, DXE_PERFORMANCE_STRING_LENGTH * sizeof (CHAR16));\r
137\r
138 if (PdbFileName == NULL) {\r
139 StrCpy (UnicodeBuffer, L" ");\r
140 } else {\r
141 StartIndex = 0;\r
142 for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)\r
143 ;\r
144 for (IndexA = 0; PdbFileName[IndexA] != 0; IndexA++) {\r
145 if (PdbFileName[IndexA] == '\\') {\r
146 StartIndex = IndexA + 1;\r
147 }\r
148\r
149 if (PdbFileName[IndexA] == '.') {\r
150 EndIndex = IndexA;\r
151 }\r
152 }\r
153\r
154 IndexU = 0;\r
155 for (IndexA = StartIndex; IndexA < EndIndex; IndexA++) {\r
156 UnicodeBuffer[IndexU] = (CHAR16) PdbFileName[IndexA];\r
157 IndexU++;\r
158 if (IndexU >= DXE_PERFORMANCE_STRING_LENGTH) {\r
159 UnicodeBuffer[DXE_PERFORMANCE_STRING_LENGTH] = 0;\r
160 break;\r
161 }\r
162 }\r
163 }\r
164}\r
165\r
166/** Get a human readable name for an image handle.\r
167 *\r
168 * @param[in] Handle\r
169 *\r
170 * @post The resulting Unicode name string is stored in the\r
171 * mGaugeString global array.\r
172 *\r
173**/\r
174VOID\r
175GetNameFromHandle (\r
176 IN EFI_HANDLE Handle\r
177 )\r
178{\r
179 EFI_STATUS Status;\r
180 EFI_LOADED_IMAGE_PROTOCOL *Image;\r
181 CHAR8 *PdbFileName;\r
182 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
183 EFI_STRING StringPtr;\r
184\r
185 // Proactively get the error message so it will be ready if needed\r
186 StringPtr = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_ERROR_NAME), NULL);\r
187 ASSERT (StringPtr != NULL);\r
188\r
189 // Get handle name from image protocol\r
190 //\r
191 Status = gBS->HandleProtocol (\r
192 Handle,\r
193 &gEfiLoadedImageProtocolGuid,\r
194 &Image\r
195 );\r
196\r
197 if (EFI_ERROR (Status)) {\r
198 Status = gBS->OpenProtocol (\r
199 Handle,\r
200 &gEfiDriverBindingProtocolGuid,\r
201 (VOID **) &DriverBinding,\r
202 NULL,\r
203 NULL,\r
204 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
205 );\r
206 if (EFI_ERROR (Status)) {\r
207 StrCpy (mGaugeString, StringPtr);\r
208 return ;\r
209 }\r
210\r
211 // Get handle name from image protocol\r
212 //\r
213 Status = gBS->HandleProtocol (\r
214 DriverBinding->ImageHandle,\r
215 &gEfiLoadedImageProtocolGuid,\r
216 &Image\r
217 );\r
218 }\r
219\r
220 PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);\r
221\r
222 if (PdbFileName != NULL) {\r
223 GetShortPdbFileName (PdbFileName, mGaugeString);\r
224 } else {\r
225 StrCpy (mGaugeString, StringPtr);\r
226 }\r
227 return ;\r
228}\r
229\r
230/** Calculate the Duration in microseconds.\r
231 *\r
232 * Duration is multiplied by 1000, instead of Frequency being divided by 1000 or\r
233 * multiplying the result by 1000, in order to maintain precision. Since Duration is\r
234 * a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow.\r
235 *\r
236 * The time is calculated as (Duration * 1000) / Timer_Frequency.\r
237 *\r
238 * @param[in] Duration The event duration in timer ticks.\r
239 *\r
240 * @return A 64-bit value which is the Elapsed time in microseconds.\r
241**/\r
242UINT64\r
243DurationInMicroSeconds (\r
244 IN UINT64 Duration\r
245 )\r
246{\r
247 UINT64 Temp;\r
248\r
249 Temp = MultU64x32 (Duration, 1000);\r
250 return DivU64x32 (Temp, TimerInfo.Frequency);\r
251}\r
252\r
253/** Formatted Print using a Hii Token to reference the localized format string.\r
254 *\r
255 * @param[in] Token A HII token associated with a localized Unicode string.\r
256 *\r
257 * @return The number of characters converted by UnicodeVSPrint().\r
258 *\r
259**/\r
260UINTN\r
261PrintToken (\r
262 IN UINT16 Token,\r
263 ...\r
264 )\r
265{\r
266 VA_LIST Marker;\r
267 EFI_STRING StringPtr;\r
268 UINTN Return;\r
269 UINTN BufferSize;\r
270\r
271 StringPtr = HiiGetString (gHiiHandle, Token, NULL);\r
272 ASSERT (StringPtr != NULL);\r
273\r
274 VA_START (Marker, Token);\r
275\r
276 BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);\r
277\r
278 if (mPrintTokenBuffer == NULL) {\r
279 mPrintTokenBuffer = AllocatePool (BufferSize);\r
280 ASSERT (mPrintTokenBuffer != NULL);\r
281 }\r
282 SetMem( mPrintTokenBuffer, BufferSize, 0);\r
283\r
284 Return = UnicodeVSPrint (mPrintTokenBuffer, BufferSize, StringPtr, Marker);\r
285 if (Return > 0 && gST->ConOut != NULL) {\r
286 gST->ConOut->OutputString (gST->ConOut, mPrintTokenBuffer);\r
287 }\r
288 return Return;\r
289}\r
290\r
291/** Get index of Measurement Record's match in the CumData array.\r
292 *\r
293 * If the Measurement's Token value matches a Token in one of the CumData\r
294 * records, the index of the matching record is returned. The returned\r
295 * index is a signed value so that negative values can indicate that\r
296 * the Measurement didn't match any entry in the CumData array.\r
297 *\r
298 * @param[in] Measurement A pointer to a Measurement Record to match against the CumData array.\r
299 *\r
300 * @retval <0 Token is not in the CumData array.\r
301 * @retval >=0 Return value is the index into CumData where Token is found.\r
302**/\r
303INTN\r
304GetCumulativeItem(\r
305 IN MEASUREMENT_RECORD *Measurement\r
306 )\r
307{\r
308 INTN Index;\r
309\r
310 for( Index = 0; Index < (INTN)NumCum; ++Index) {\r
311 if (AsciiStrnCmp (Measurement->Token, CumData[Index].Name, PERF_TOKEN_LENGTH) == 0) {\r
312 return Index; // Exit, we found a match\r
313 }\r
314 }\r
315 // If the for loop exits, Token was not found.\r
316 return -1; // Indicate failure\r
317}\r