]> git.proxmox.com Git - mirror_edk2.git/blame - EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c
Bug fix for "Tiano BIOS needs to implement an automatic reboot when BIOS settings...
[mirror_edk2.git] / EdkNt32Pkg / Library / EdkGenericBdsLib / Performance.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 Performance.c\r
15\r
16Abstract:\r
17\r
18 This file include the file which can help to get the system\r
19 performance, all the function will only include if the performance\r
20 switch is set.\r
21\r
22--*/\r
23\r
24#include "Performance.h"\r
25\r
26VOID\r
27ClearDebugRegisters (\r
28 VOID\r
29 )\r
30{\r
2ce31132 31 //\r
32 // BugBug: We should not need to do this. We need to root cause this bug!!!!\r
33 //\r
878ddf1f 34 AsmWriteDr0 (0);\r
35 AsmWriteDr1 (0);\r
36}\r
37\r
38STATIC\r
39VOID\r
40GetShortPdbFileName (\r
41 CHAR8 *PdbFileName,\r
42 CHAR8 *GaugeString\r
43 )\r
44/*++\r
45\r
46Routine Description:\r
47 \r
48Arguments:\r
49\r
50Returns:\r
51\r
52--*/\r
53{\r
54 UINTN Index;\r
55 UINTN Index1;\r
56 UINTN StartIndex;\r
57 UINTN EndIndex;\r
58\r
59 if (PdbFileName == NULL) {\r
60 AsciiStrCpy (GaugeString, " ");\r
61 } else {\r
62 StartIndex = 0;\r
63 for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)\r
64 ;\r
65\r
66 for (Index = 0; PdbFileName[Index] != 0; Index++) {\r
67 if (PdbFileName[Index] == '\\') {\r
68 StartIndex = Index + 1;\r
69 }\r
70\r
71 if (PdbFileName[Index] == '.') {\r
72 EndIndex = Index;\r
73 }\r
74 }\r
75\r
76 Index1 = 0;\r
77 for (Index = StartIndex; Index < EndIndex; Index++) {\r
78 GaugeString[Index1] = PdbFileName[Index];\r
79 Index1++;\r
80 if (Index1 == PERF_TOKEN_LENGTH - 1) {\r
81 break;\r
82 }\r
83 }\r
84\r
85 GaugeString[Index1] = 0;\r
86 }\r
87\r
88 return ;\r
89}\r
90\r
2ce31132 91\r
92\r
878ddf1f 93STATIC\r
94CHAR8 *\r
95GetPdbPath (\r
96 VOID *ImageBase\r
97 )\r
98/*++\r
99\r
100Routine Description:\r
101\r
102 Located PDB path name in PE image\r
103\r
104Arguments:\r
105\r
106 ImageBase - base of PE to search\r
107\r
108Returns:\r
109\r
110 Pointer into image at offset of PDB file name if PDB file name is found,\r
111 Otherwise a pointer to an empty string.\r
112\r
113--*/\r
114{\r
2ce31132 115 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
116\r
117 ZeroMem (&ImageContext, sizeof (ImageContext));\r
118 ImageContext.Handle = ImageBase;\r
119 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
878ddf1f 120\r
2ce31132 121 PeCoffLoaderGetImageInfo (&ImageContext);\r
122\r
123 return ImageContext.PdbPointer;\r
878ddf1f 124}\r
125\r
2ce31132 126\r
878ddf1f 127STATIC\r
128VOID\r
129GetNameFromHandle (\r
130 IN EFI_HANDLE Handle,\r
131 OUT CHAR8 *GaugeString\r
132 )\r
133{\r
134 EFI_STATUS Status;\r
135 EFI_LOADED_IMAGE_PROTOCOL *Image;\r
136 CHAR8 *PdbFileName;\r
137 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
138\r
139 AsciiStrCpy (GaugeString, " ");\r
140\r
141 //\r
142 // Get handle name from image protocol\r
143 //\r
144 Status = gBS->HandleProtocol (\r
145 Handle,\r
146 &gEfiLoadedImageProtocolGuid,\r
147 &Image\r
148 );\r
149\r
150 if (EFI_ERROR (Status)) {\r
151 Status = gBS->OpenProtocol (\r
152 Handle,\r
153 &gEfiDriverBindingProtocolGuid,\r
154 (VOID **) &DriverBinding,\r
155 NULL,\r
156 NULL,\r
157 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
158 );\r
159 if (EFI_ERROR (Status)) {\r
160 return ;\r
161 }\r
162 //\r
163 // Get handle name from image protocol\r
164 //\r
165 Status = gBS->HandleProtocol (\r
166 DriverBinding->ImageHandle,\r
167 &gEfiLoadedImageProtocolGuid,\r
168 &Image\r
169 );\r
170 }\r
171\r
172 PdbFileName = GetPdbPath (Image->ImageBase);\r
173\r
174 if (PdbFileName != NULL) {\r
175 GetShortPdbFileName (PdbFileName, GaugeString);\r
176 }\r
177\r
178 return ;\r
179}\r
180\r
181\r
182\r
183VOID\r
184WriteBootToOsPerformanceData (\r
185 VOID\r
186 )\r
187/*++\r
188\r
189Routine Description:\r
190 \r
191 Allocates a block of memory and writes performance data of booting to OS into it.\r
192\r
193Arguments:\r
194 \r
195 None\r
196 \r
197Returns:\r
198\r
199 None\r
200\r
201--*/\r
202{\r
203 EFI_STATUS Status;\r
204 EFI_CPU_ARCH_PROTOCOL *Cpu;\r
205 EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase;\r
206 UINT32 mAcpiLowMemoryLength;\r
207 UINT32 LimitCount;\r
208 PERF_HEADER mPerfHeader;\r
209 PERF_DATA mPerfData;\r
210 EFI_HANDLE *Handles;\r
211 UINTN NoHandles;\r
212 CHAR8 GaugeString[PERF_TOKEN_LENGTH];\r
213 UINT8 *Ptr;\r
214 UINT32 mIndex;\r
215 UINT64 Ticker;\r
216 UINT64 Freq;\r
217 UINT32 Duration;\r
218 UINT64 CurrentTicker;\r
219 UINT64 TimerPeriod;\r
220 UINTN LogEntryKey;\r
221 CONST VOID *Handle;\r
222 CONST CHAR8 *Token;\r
223 CONST CHAR8 *Module;\r
224 UINT64 StartTicker;\r
225 UINT64 EndTicker;\r
226\r
227 //\r
228 // Retrive time stamp count as early as possilbe\r
229 //\r
230 Ticker = AsmReadTsc ();\r
231\r
232 //\r
233 // Allocate a block of memory that contain performance data to OS\r
234 //\r
cb44bbdb 235 mAcpiLowMemoryBase = 0xFFFFFFFF;\r
878ddf1f 236 Status = gBS->AllocatePages (\r
cb44bbdb 237 AllocateMaxAddress,\r
238 EfiReservedMemoryType,\r
878ddf1f 239 4,\r
240 &mAcpiLowMemoryBase\r
241 );\r
242 if (EFI_ERROR (Status)) {\r
243 return ;\r
244 }\r
245\r
cb44bbdb 246 mAcpiLowMemoryLength = EFI_PAGES_TO_SIZE(4);\r
878ddf1f 247\r
248 Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));\r
249 LimitCount = (mAcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);\r
250\r
251 //\r
252 // Initialize performance data structure\r
253 //\r
254 ZeroMem (&mPerfHeader, sizeof (PERF_HEADER));\r
255\r
256 //\r
257 // Get CPU frequency\r
258 //\r
259 Status = gBS->LocateProtocol (\r
260 &gEfiCpuArchProtocolGuid,\r
261 NULL,\r
262 &Cpu\r
263 );\r
264 if (EFI_ERROR (Status)) {\r
cb44bbdb 265 gBS->FreePages (mAcpiLowMemoryBase, 4);\r
878ddf1f 266 return ;\r
267 }\r
268 //\r
269 // Get Cpu Frequency\r
270 //\r
271 Status = Cpu->GetTimerValue (Cpu, 0, &(CurrentTicker), &TimerPeriod);\r
272 if (EFI_ERROR (Status)) {\r
cb44bbdb 273 gBS->FreePages (mAcpiLowMemoryBase, 4);\r
878ddf1f 274 return ;\r
275 }\r
276\r
277 Freq = DivU64x32 (1000000000000, (UINTN) TimerPeriod);\r
278\r
279 mPerfHeader.CpuFreq = Freq;\r
280\r
281 //\r
282 // Record BDS raw performance data\r
283 //\r
284 mPerfHeader.BDSRaw = Ticker;\r
285\r
286 //\r
287 // Put Detailed performance data into memory\r
288 //\r
289 Handles = NULL;\r
290 Status = gBS->LocateHandleBuffer (\r
291 AllHandles,\r
292 NULL,\r
293 NULL,\r
294 &NoHandles,\r
295 &Handles\r
296 );\r
297 if (EFI_ERROR (Status)) {\r
cb44bbdb 298 gBS->FreePages (mAcpiLowMemoryBase, 4);\r
878ddf1f 299 return ;\r
300 }\r
301 //\r
302 // Get DXE drivers performance\r
303 //\r
304 for (mIndex = 0; mIndex < NoHandles; mIndex++) {\r
305 Ticker = 0;\r
306 LogEntryKey = 0;\r
307 while ((LogEntryKey = GetPerformanceMeasurement (\r
308 LogEntryKey,\r
309 &Handle,\r
310 &Token,\r
311 &Module,\r
312 &StartTicker,\r
313 &EndTicker)) != 0) {\r
314 if ((Handle == Handles[mIndex]) && (StartTicker < EndTicker)) {\r
315 Ticker += (EndTicker - StartTicker);\r
316 }\r
317 }\r
318\r
319 Duration = (UINT32) DivU64x32 (\r
320 Ticker,\r
321 (UINT32) Freq\r
322 );\r
323\r
324 if (Duration > 0) {\r
325 ZeroMem (&mPerfData, sizeof (PERF_DATA));\r
326\r
327 GetNameFromHandle (Handles[mIndex], GaugeString);\r
328\r
329 AsciiStrCpy (mPerfData.Token, GaugeString);\r
330 mPerfData.Duration = Duration;\r
331\r
332 CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));\r
333 Ptr += sizeof (PERF_DATA);\r
334\r
335 mPerfHeader.Count++;\r
336 if (mPerfHeader.Count == LimitCount) {\r
337 goto Done;\r
338 }\r
339 }\r
340 }\r
341\r
342 gBS->FreePool (Handles);\r
343\r
344 //\r
345 // Get inserted performance data\r
346 //\r
347 LogEntryKey = 0;\r
348 while ((LogEntryKey = GetPerformanceMeasurement (\r
349 LogEntryKey,\r
350 &Handle,\r
351 &Token,\r
352 &Module,\r
353 &StartTicker,\r
354 &EndTicker)) != 0) {\r
355 if ((Handle == NULL) && (StartTicker <= EndTicker)) {\r
356\r
357 ZeroMem (&mPerfData, sizeof (PERF_DATA));\r
358\r
359 AsciiStrnCpy (mPerfData.Token, Token, DXE_PERFORMANCE_STRING_SIZE);\r
360 mPerfData.Duration = (UINT32) DivU64x32 (\r
361 EndTicker - StartTicker,\r
362 (UINT32) Freq\r
363 );\r
364\r
365 CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));\r
366 Ptr += sizeof (PERF_DATA);\r
367\r
368 mPerfHeader.Count++;\r
369 if (mPerfHeader.Count == LimitCount) {\r
370 goto Done;\r
371 }\r
372 }\r
373 }\r
374\r
375Done:\r
376\r
377 ClearDebugRegisters ();\r
378\r
379 mPerfHeader.Signiture = 0x66726550;\r
380\r
381 //\r
382 // Put performance data to memory\r
383 //\r
384 CopyMem (\r
385 (UINT32 *) (UINT32) mAcpiLowMemoryBase,\r
386 &mPerfHeader,\r
387 sizeof (PERF_HEADER)\r
388 );\r
389\r
390 gRT->SetVariable (\r
391 L"PerfDataMemAddr",\r
392 &gEfiGlobalVariableGuid,\r
393 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
394 sizeof (UINT32),\r
395 (VOID *) &mAcpiLowMemoryBase\r
396 );\r
397\r
398 return ;\r
399}\r