]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.c
MdeModulePkg-FPDT(4): Use fixed buffer for SMM_PERF_COMMUNICATE in PerfLib.
[mirror_edk2.git] / MdeModulePkg / Library / DxeSmmPerformanceLib / DxeSmmPerformanceLib.c
... / ...
CommitLineData
1/** @file\r
2 Performance library instance used in DXE phase to dump both PEI/DXE and SMM performance data.\r
3\r
4 This library instance allows a DXE driver or UEFI application to dump both PEI/DXE and SMM performance data.\r
5 StartPerformanceMeasurement(), EndPerformanceMeasurement(), StartPerformanceMeasurementEx()\r
6 and EndPerformanceMeasurementEx() are not implemented.\r
7\r
8 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
9This program and the accompanying materials\r
10are licensed and made available under the terms and conditions of the BSD License\r
11which accompanies this distribution. The full text of the license may be found at\r
12http://opensource.org/licenses/bsd-license.php\r
13\r
14THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
17**/\r
18\r
19\r
20#include <PiDxe.h>\r
21\r
22#include <Guid/Performance.h>\r
23\r
24#include <Library/PerformanceLib.h>\r
25#include <Library/DebugLib.h>\r
26#include <Library/UefiBootServicesTableLib.h>\r
27#include <Library/UefiRuntimeServicesTableLib.h>\r
28#include <Library/PcdLib.h>\r
29#include <Library/BaseMemoryLib.h>\r
30#include <Library/BaseLib.h>\r
31#include <Library/MemoryAllocationLib.h>\r
32\r
33#include <Protocol/SmmCommunication.h>\r
34\r
35#include <Guid/PiSmmCommunicationRegionTable.h>\r
36#include <Library/UefiLib.h>\r
37\r
38#define SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof (SMM_PERF_COMMUNICATE))\r
39\r
40EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;\r
41UINT8 *mSmmPerformanceBuffer;\r
42GAUGE_DATA_ENTRY *mGaugeData = NULL;\r
43UINTN mGaugeNumberOfEntries = 0;\r
44GAUGE_DATA_ENTRY_EX *mGaugeDataEx = NULL;\r
45UINTN mGaugeNumberOfEntriesEx = 0;\r
46\r
47BOOLEAN mNoSmmPerfHandler = FALSE;\r
48BOOLEAN mNoSmmPerfExHandler = FALSE;\r
49\r
50//\r
51// The cached Performance Protocol and PerformanceEx Protocol interface.\r
52//\r
53PERFORMANCE_PROTOCOL *mPerformance = NULL;\r
54PERFORMANCE_EX_PROTOCOL *mPerformanceEx = NULL;\r
55\r
56/**\r
57 The function caches the pointer to SMM Communication protocol.\r
58\r
59 The function locates SMM Communication protocol from protocol database.\r
60\r
61 @retval EFI_SUCCESS SMM Communication protocol is successfully located.\r
62 @retval Other SMM Communication protocol is not located to log performance.\r
63\r
64**/\r
65EFI_STATUS\r
66GetCommunicationProtocol (\r
67 VOID\r
68 )\r
69{\r
70 EFI_STATUS Status;\r
71 EFI_SMM_COMMUNICATION_PROTOCOL *Communication;\r
72\r
73 if (mSmmCommunication != NULL) {\r
74 return EFI_SUCCESS;\r
75 }\r
76\r
77 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication);\r
78 if (!EFI_ERROR (Status)) {\r
79 ASSERT (Communication != NULL);\r
80 //\r
81 // Cache SMM Communication protocol.\r
82 //\r
83 mSmmCommunication = Communication;\r
84 }\r
85\r
86 return Status;\r
87}\r
88\r
89/**\r
90 The function caches the pointers to PerformanceEx protocol and Performance Protocol.\r
91\r
92 The function locates PerformanceEx protocol and Performance Protocol from protocol database.\r
93\r
94 @retval EFI_SUCCESS PerformanceEx protocol or Performance Protocol is successfully located.\r
95 @retval EFI_NOT_FOUND Both PerformanceEx protocol and Performance Protocol are not located to log performance.\r
96\r
97**/\r
98EFI_STATUS\r
99GetPerformanceProtocol (\r
100 VOID\r
101 )\r
102{\r
103 EFI_STATUS Status;\r
104 PERFORMANCE_PROTOCOL *Performance;\r
105 PERFORMANCE_EX_PROTOCOL *PerformanceEx;\r
106\r
107 if (mPerformanceEx != NULL || mPerformance != NULL) {\r
108 return EFI_SUCCESS;\r
109 }\r
110\r
111 Status = gBS->LocateProtocol (&gPerformanceExProtocolGuid, NULL, (VOID **) &PerformanceEx);\r
112 if (!EFI_ERROR (Status)) {\r
113 ASSERT (PerformanceEx != NULL);\r
114 //\r
115 // Cache PerformanceEx Protocol.\r
116 //\r
117 mPerformanceEx = PerformanceEx;\r
118 return EFI_SUCCESS;\r
119 }\r
120\r
121 Status = gBS->LocateProtocol (&gPerformanceProtocolGuid, NULL, (VOID **) &Performance);\r
122 if (!EFI_ERROR (Status)) {\r
123 ASSERT (Performance != NULL);\r
124 //\r
125 // Cache performance protocol.\r
126 //\r
127 mPerformance = Performance;\r
128 return EFI_SUCCESS;\r
129 }\r
130\r
131 return EFI_NOT_FOUND;\r
132}\r
133\r
134/**\r
135 Creates a record for the beginning of a performance measurement.\r
136\r
137 Creates a record that contains the Handle, Token, Module and Identifier.\r
138 If TimeStamp is not zero, then TimeStamp is added to the record as the start time.\r
139 If TimeStamp is zero, then this function reads the current time stamp\r
140 and adds that time stamp value to the record as the start time.\r
141\r
142 @param Handle Pointer to environment specific context used\r
143 to identify the component being measured.\r
144 @param Token Pointer to a Null-terminated ASCII string\r
145 that identifies the component being measured.\r
146 @param Module Pointer to a Null-terminated ASCII string\r
147 that identifies the module being measured.\r
148 @param TimeStamp 64-bit time stamp.\r
149 @param Identifier 32-bit identifier. If the value is 0, the created record\r
150 is same as the one created by StartPerformanceMeasurement.\r
151\r
152 @retval RETURN_SUCCESS The start of the measurement was recorded.\r
153 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.\r
154\r
155**/\r
156RETURN_STATUS\r
157EFIAPI\r
158StartPerformanceMeasurementEx (\r
159 IN CONST VOID *Handle, OPTIONAL\r
160 IN CONST CHAR8 *Token, OPTIONAL\r
161 IN CONST CHAR8 *Module, OPTIONAL\r
162 IN UINT64 TimeStamp,\r
163 IN UINT32 Identifier\r
164 )\r
165{\r
166 return RETURN_SUCCESS;\r
167}\r
168\r
169/**\r
170 Fills in the end time of a performance measurement.\r
171\r
172 Looks up the record that matches Handle, Token and Module.\r
173 If the record can not be found then return RETURN_NOT_FOUND.\r
174 If the record is found and TimeStamp is not zero,\r
175 then TimeStamp is added to the record as the end time.\r
176 If the record is found and TimeStamp is zero, then this function reads\r
177 the current time stamp and adds that time stamp value to the record as the end time.\r
178\r
179 @param Handle Pointer to environment specific context used\r
180 to identify the component being measured.\r
181 @param Token Pointer to a Null-terminated ASCII string\r
182 that identifies the component being measured.\r
183 @param Module Pointer to a Null-terminated ASCII string\r
184 that identifies the module being measured.\r
185 @param TimeStamp 64-bit time stamp.\r
186 @param Identifier 32-bit identifier. If the value is 0, the found record\r
187 is same as the one found by EndPerformanceMeasurement.\r
188\r
189 @retval RETURN_SUCCESS The end of the measurement was recorded.\r
190 @retval RETURN_NOT_FOUND The specified measurement record could not be found.\r
191\r
192**/\r
193RETURN_STATUS\r
194EFIAPI\r
195EndPerformanceMeasurementEx (\r
196 IN CONST VOID *Handle, OPTIONAL\r
197 IN CONST CHAR8 *Token, OPTIONAL\r
198 IN CONST CHAR8 *Module, OPTIONAL\r
199 IN UINT64 TimeStamp,\r
200 IN UINT32 Identifier\r
201 )\r
202{\r
203 return RETURN_SUCCESS;\r
204}\r
205\r
206/**\r
207 Creates a record for the beginning of a performance measurement.\r
208\r
209 Creates a record that contains the Handle, Token, and Module.\r
210 If TimeStamp is not zero, then TimeStamp is added to the record as the start time.\r
211 If TimeStamp is zero, then this function reads the current time stamp\r
212 and adds that time stamp value to the record as the start time.\r
213\r
214 @param Handle Pointer to environment specific context used\r
215 to identify the component being measured.\r
216 @param Token Pointer to a Null-terminated ASCII string\r
217 that identifies the component being measured.\r
218 @param Module Pointer to a Null-terminated ASCII string\r
219 that identifies the module being measured.\r
220 @param TimeStamp 64-bit time stamp.\r
221\r
222 @retval RETURN_SUCCESS The start of the measurement was recorded.\r
223 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.\r
224\r
225**/\r
226RETURN_STATUS\r
227EFIAPI\r
228StartPerformanceMeasurement (\r
229 IN CONST VOID *Handle, OPTIONAL\r
230 IN CONST CHAR8 *Token, OPTIONAL\r
231 IN CONST CHAR8 *Module, OPTIONAL\r
232 IN UINT64 TimeStamp\r
233 )\r
234{\r
235 return RETURN_SUCCESS;\r
236}\r
237\r
238/**\r
239 Fills in the end time of a performance measurement.\r
240\r
241 Looks up the record that matches Handle, Token, and Module.\r
242 If the record can not be found then return RETURN_NOT_FOUND.\r
243 If the record is found and TimeStamp is not zero,\r
244 then TimeStamp is added to the record as the end time.\r
245 If the record is found and TimeStamp is zero, then this function reads\r
246 the current time stamp and adds that time stamp value to the record as the end time.\r
247\r
248 @param Handle Pointer to environment specific context used\r
249 to identify the component being measured.\r
250 @param Token Pointer to a Null-terminated ASCII string\r
251 that identifies the component being measured.\r
252 @param Module Pointer to a Null-terminated ASCII string\r
253 that identifies the module being measured.\r
254 @param TimeStamp 64-bit time stamp.\r
255\r
256 @retval RETURN_SUCCESS The end of the measurement was recorded.\r
257 @retval RETURN_NOT_FOUND The specified measurement record could not be found.\r
258\r
259**/\r
260RETURN_STATUS\r
261EFIAPI\r
262EndPerformanceMeasurement (\r
263 IN CONST VOID *Handle, OPTIONAL\r
264 IN CONST CHAR8 *Token, OPTIONAL\r
265 IN CONST CHAR8 *Module, OPTIONAL\r
266 IN UINT64 TimeStamp\r
267 )\r
268{\r
269 return RETURN_SUCCESS;\r
270}\r
271\r
272/**\r
273 Attempts to retrieve a performance measurement log entry from the performance measurement log.\r
274 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,\r
275 and then assign the Identifier with 0.\r
276\r
277 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is\r
278 zero on entry, then an attempt is made to retrieve the first entry from the performance log,\r
279 and the key for the second entry in the log is returned. If the performance log is empty,\r
280 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance\r
281 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is\r
282 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is\r
283 retrieved and an implementation specific non-zero key value that specifies the end of the performance\r
284 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry\r
285 is retrieved and zero is returned. In the cases where a performance log entry can be returned,\r
286 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.\r
287 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().\r
288 If Handle is NULL, then ASSERT().\r
289 If Token is NULL, then ASSERT().\r
290 If Module is NULL, then ASSERT().\r
291 If StartTimeStamp is NULL, then ASSERT().\r
292 If EndTimeStamp is NULL, then ASSERT().\r
293 If Identifier is NULL, then ASSERT().\r
294\r
295 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.\r
296 0, then the first performance measurement log entry is retrieved.\r
297 On exit, the key of the next performance log entry.\r
298 @param Handle Pointer to environment specific context used to identify the component\r
299 being measured.\r
300 @param Token Pointer to a Null-terminated ASCII string that identifies the component\r
301 being measured.\r
302 @param Module Pointer to a Null-terminated ASCII string that identifies the module\r
303 being measured.\r
304 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement\r
305 was started.\r
306 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement\r
307 was ended.\r
308 @param Identifier Pointer to the 32-bit identifier that was recorded.\r
309\r
310 @return The key for the next performance log entry (in general case).\r
311\r
312**/\r
313UINTN\r
314EFIAPI\r
315GetByPerformanceProtocol (\r
316 IN UINTN LogEntryKey, \r
317 OUT CONST VOID **Handle,\r
318 OUT CONST CHAR8 **Token,\r
319 OUT CONST CHAR8 **Module,\r
320 OUT UINT64 *StartTimeStamp,\r
321 OUT UINT64 *EndTimeStamp,\r
322 OUT UINT32 *Identifier\r
323 )\r
324{\r
325 EFI_STATUS Status;\r
326 GAUGE_DATA_ENTRY_EX *GaugeData;\r
327\r
328 Status = GetPerformanceProtocol ();\r
329 if (EFI_ERROR (Status)) {\r
330 return 0;\r
331 }\r
332\r
333 if (mPerformanceEx != NULL) {\r
334 Status = mPerformanceEx->GetGaugeEx (LogEntryKey++, &GaugeData);\r
335 } else if (mPerformance != NULL) {\r
336 Status = mPerformance->GetGauge (LogEntryKey++, (GAUGE_DATA_ENTRY **) &GaugeData);\r
337 } else {\r
338 ASSERT (FALSE);\r
339 return 0;\r
340 }\r
341\r
342 //\r
343 // Make sure that LogEntryKey is a valid log entry key,\r
344 //\r
345 ASSERT (Status != EFI_INVALID_PARAMETER);\r
346\r
347 if (EFI_ERROR (Status)) {\r
348 //\r
349 // The LogEntryKey is the last entry (equals to the total entry number).\r
350 //\r
351 return 0;\r
352 }\r
353\r
354 ASSERT (GaugeData != NULL);\r
355\r
356 *Handle = (VOID *) (UINTN) GaugeData->Handle;\r
357 *Token = GaugeData->Token;\r
358 *Module = GaugeData->Module;\r
359 *StartTimeStamp = GaugeData->StartTimeStamp;\r
360 *EndTimeStamp = GaugeData->EndTimeStamp;\r
361 if (mPerformanceEx != NULL) {\r
362 *Identifier = GaugeData->Identifier;\r
363 } else {\r
364 *Identifier = 0;\r
365 }\r
366\r
367 return LogEntryKey;\r
368}\r
369\r
370\r
371/**\r
372 Retrieves all previous logged performance measurement.\r
373 Function will use SMM communicate protocol to get all previous SMM performance measurement data.\r
374 If success, data buffer will be returned. If fail function will return NULL.\r
375\r
376 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.\r
377 0, then the first performance measurement log entry is retrieved.\r
378 On exit, the key of the next performance log entry.\r
379\r
380 @retval !NULL Get all gauge data success.\r
381 @retval NULL Get all gauge data failed.\r
382**/\r
383GAUGE_DATA_ENTRY *\r
384EFIAPI\r
385GetAllSmmGaugeData (\r
386 IN UINTN LogEntryKey\r
387 )\r
388{\r
389 EFI_STATUS Status;\r
390 EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;\r
391 SMM_PERF_COMMUNICATE *SmmPerfCommData;\r
392 UINTN CommSize;\r
393 UINTN DataSize;\r
394 EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;\r
395 UINT32 Index;\r
396 EFI_MEMORY_DESCRIPTOR *Entry;\r
397 UINT8 *Buffer;\r
398 UINTN Size;\r
399 UINTN NumberOfEntries;\r
400 UINTN EntriesGot;\r
401\r
402 if (mNoSmmPerfHandler) {\r
403 //\r
404 // Not try to get the SMM gauge data again\r
405 // if no SMM Performance handler found.\r
406 //\r
407 return NULL;\r
408 }\r
409\r
410 if (LogEntryKey != 0) {\r
411 if (mGaugeData != NULL) {\r
412 return mGaugeData;\r
413 }\r
414 } else {\r
415 //\r
416 // Reget the SMM gauge data at the first entry get.\r
417 //\r
418 if (mGaugeData != NULL) {\r
419 FreePool (mGaugeData);\r
420 mGaugeData = NULL;\r
421 mGaugeNumberOfEntries = 0;\r
422 }\r
423 }\r
424\r
425 Status = GetCommunicationProtocol ();\r
426 if (EFI_ERROR (Status)) {\r
427 return NULL;\r
428 }\r
429\r
430 Status = EfiGetSystemConfigurationTable (\r
431 &gEdkiiPiSmmCommunicationRegionTableGuid,\r
432 (VOID **) &PiSmmCommunicationRegionTable\r
433 );\r
434 if (EFI_ERROR (Status)) {\r
435 return NULL;\r
436 }\r
437 ASSERT (PiSmmCommunicationRegionTable != NULL);\r
438 Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1);\r
439 Size = 0;\r
440 for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {\r
441 if (Entry->Type == EfiConventionalMemory) {\r
442 Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages);\r
443 if (Size >= (SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE + sizeof (GAUGE_DATA_ENTRY))) {\r
444 break;\r
445 }\r
446 }\r
447 Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize);\r
448 }\r
449 ASSERT (Index < PiSmmCommunicationRegionTable->NumberOfEntries);\r
450 mSmmPerformanceBuffer = (UINT8 *) (UINTN) Entry->PhysicalStart;\r
451\r
452 //\r
453 // Initialize communicate buffer \r
454 //\r
455 SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER *)mSmmPerformanceBuffer;\r
456 SmmPerfCommData = (SMM_PERF_COMMUNICATE *)SmmCommBufferHeader->Data;\r
457 ZeroMem((UINT8*)SmmPerfCommData, sizeof(SMM_PERF_COMMUNICATE));\r
458 \r
459 CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gSmmPerformanceProtocolGuid);\r
460 SmmCommBufferHeader->MessageLength = sizeof(SMM_PERF_COMMUNICATE);\r
461 CommSize = SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;\r
462\r
463 //\r
464 // Get total number of SMM gauge entries\r
465 //\r
466 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER;\r
467 Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);\r
468 if (Status == EFI_NOT_FOUND) {\r
469 mNoSmmPerfHandler = TRUE;\r
470 }\r
471 if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus) || SmmPerfCommData->NumberOfEntries == 0) {\r
472 return NULL;\r
473 }\r
474\r
475 mGaugeNumberOfEntries = SmmPerfCommData->NumberOfEntries;\r
476\r
477 Buffer = mSmmPerformanceBuffer + SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;\r
478 NumberOfEntries = (Size - SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE) / sizeof (GAUGE_DATA_ENTRY);\r
479 DataSize = mGaugeNumberOfEntries * sizeof(GAUGE_DATA_ENTRY);\r
480 mGaugeData = AllocateZeroPool(DataSize);\r
481 ASSERT (mGaugeData != NULL);\r
482\r
483 //\r
484 // Get all SMM gauge data\r
485 // \r
486 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_DATA;\r
487 SmmPerfCommData->GaugeData = (GAUGE_DATA_ENTRY *) Buffer;\r
488 EntriesGot = 0;\r
489 do {\r
490 SmmPerfCommData->LogEntryKey = EntriesGot;\r
491 if ((mGaugeNumberOfEntries - EntriesGot) >= NumberOfEntries) {\r
492 SmmPerfCommData->NumberOfEntries = NumberOfEntries;\r
493 } else {\r
494 SmmPerfCommData->NumberOfEntries = mGaugeNumberOfEntries - EntriesGot;\r
495 }\r
496 Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);\r
497 if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus)) {\r
498 FreePool (mGaugeData);\r
499 mGaugeData = NULL;\r
500 mGaugeNumberOfEntries = 0;\r
501 return NULL;\r
502 } else {\r
503 CopyMem (&mGaugeData[EntriesGot], Buffer, SmmPerfCommData->NumberOfEntries * sizeof (GAUGE_DATA_ENTRY));\r
504 }\r
505 EntriesGot += SmmPerfCommData->NumberOfEntries;\r
506 } while (EntriesGot < mGaugeNumberOfEntries);\r
507\r
508 return mGaugeData;\r
509}\r
510\r
511/**\r
512 Retrieves all previous logged performance measurement.\r
513 Function will use SMM communicate protocol to get all previous SMM performance measurement data.\r
514 If success, data buffer will be returned. If fail function will return NULL.\r
515\r
516 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.\r
517 0, then the first performance measurement log entry is retrieved.\r
518 On exit, the key of the next performance log entry.\r
519\r
520 @retval !NULL Get all gauge data success.\r
521 @retval NULL Get all gauge data failed.\r
522**/\r
523GAUGE_DATA_ENTRY_EX *\r
524EFIAPI\r
525GetAllSmmGaugeDataEx (\r
526 IN UINTN LogEntryKey\r
527 )\r
528{\r
529 EFI_STATUS Status;\r
530 EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;\r
531 SMM_PERF_COMMUNICATE_EX *SmmPerfCommData;\r
532 UINTN CommSize;\r
533 UINTN DataSize;\r
534 EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;\r
535 UINT32 Index;\r
536 EFI_MEMORY_DESCRIPTOR *Entry;\r
537 UINT8 *Buffer;\r
538 UINTN Size;\r
539 UINTN NumberOfEntries;\r
540 UINTN EntriesGot;\r
541\r
542 if (mNoSmmPerfExHandler) {\r
543 //\r
544 // Not try to get the SMM gauge data again\r
545 // if no SMM PerformanceEx handler found.\r
546 //\r
547 return NULL;\r
548 }\r
549\r
550 if (LogEntryKey != 0) {\r
551 if (mGaugeDataEx != NULL) {\r
552 return mGaugeDataEx;\r
553 }\r
554 } else {\r
555 //\r
556 // Reget the SMM gauge data at the first entry get.\r
557 //\r
558 if (mGaugeDataEx != NULL) {\r
559 FreePool (mGaugeDataEx);\r
560 mGaugeDataEx = NULL;\r
561 mGaugeNumberOfEntriesEx = 0;\r
562 }\r
563 }\r
564\r
565 Status = GetCommunicationProtocol ();\r
566 if (EFI_ERROR (Status)) {\r
567 return NULL;\r
568 }\r
569\r
570 Status = EfiGetSystemConfigurationTable (\r
571 &gEdkiiPiSmmCommunicationRegionTableGuid,\r
572 (VOID **) &PiSmmCommunicationRegionTable\r
573 );\r
574 if (EFI_ERROR (Status)) {\r
575 return NULL;\r
576 }\r
577 ASSERT (PiSmmCommunicationRegionTable != NULL);\r
578 Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1);\r
579 Size = 0;\r
580 for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {\r
581 if (Entry->Type == EfiConventionalMemory) {\r
582 Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages);\r
583 if (Size >= (SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE + sizeof (GAUGE_DATA_ENTRY_EX))) {\r
584 break;\r
585 }\r
586 }\r
587 Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize);\r
588 }\r
589 ASSERT (Index < PiSmmCommunicationRegionTable->NumberOfEntries);\r
590 mSmmPerformanceBuffer = (UINT8 *) (UINTN) Entry->PhysicalStart;\r
591 //\r
592 // Initialize communicate buffer \r
593 //\r
594 SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER *)mSmmPerformanceBuffer;\r
595 SmmPerfCommData = (SMM_PERF_COMMUNICATE_EX *)SmmCommBufferHeader->Data;\r
596 ZeroMem((UINT8*)SmmPerfCommData, sizeof(SMM_PERF_COMMUNICATE_EX));\r
597 \r
598 CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gSmmPerformanceExProtocolGuid);\r
599 SmmCommBufferHeader->MessageLength = sizeof(SMM_PERF_COMMUNICATE_EX);\r
600 CommSize = SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;\r
601\r
602 //\r
603 // Get total number of SMM gauge entries\r
604 //\r
605 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER;\r
606 Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);\r
607 if (Status == EFI_NOT_FOUND) {\r
608 mNoSmmPerfExHandler = TRUE;\r
609 }\r
610 if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus) || SmmPerfCommData->NumberOfEntries == 0) {\r
611 return NULL;\r
612 }\r
613\r
614 mGaugeNumberOfEntriesEx = SmmPerfCommData->NumberOfEntries;\r
615\r
616 Buffer = mSmmPerformanceBuffer + SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;\r
617 NumberOfEntries = (Size - SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE) / sizeof (GAUGE_DATA_ENTRY_EX);\r
618 DataSize = mGaugeNumberOfEntriesEx * sizeof(GAUGE_DATA_ENTRY_EX);\r
619 mGaugeDataEx = AllocateZeroPool(DataSize);\r
620 ASSERT (mGaugeDataEx != NULL);\r
621\r
622 //\r
623 // Get all SMM gauge data\r
624 // \r
625 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_DATA;\r
626 SmmPerfCommData->GaugeDataEx = (GAUGE_DATA_ENTRY_EX *) Buffer;\r
627 EntriesGot = 0;\r
628 do {\r
629 SmmPerfCommData->LogEntryKey = EntriesGot;\r
630 if ((mGaugeNumberOfEntriesEx - EntriesGot) >= NumberOfEntries) {\r
631 SmmPerfCommData->NumberOfEntries = NumberOfEntries;\r
632 } else {\r
633 SmmPerfCommData->NumberOfEntries = mGaugeNumberOfEntriesEx - EntriesGot;\r
634 }\r
635 Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);\r
636 if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus)) {\r
637 FreePool (mGaugeDataEx);\r
638 mGaugeDataEx = NULL;\r
639 mGaugeNumberOfEntriesEx = 0;\r
640 return NULL;\r
641 } else {\r
642 CopyMem (&mGaugeDataEx[EntriesGot], Buffer, SmmPerfCommData->NumberOfEntries * sizeof (GAUGE_DATA_ENTRY_EX));\r
643 }\r
644 EntriesGot += SmmPerfCommData->NumberOfEntries;\r
645 } while (EntriesGot < mGaugeNumberOfEntriesEx);\r
646\r
647 return mGaugeDataEx;\r
648}\r
649\r
650/**\r
651 Attempts to retrieve a performance measurement log entry from the performance measurement log.\r
652 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,\r
653 and then assign the Identifier with 0.\r
654\r
655 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is\r
656 zero on entry, then an attempt is made to retrieve the first entry from the performance log,\r
657 and the key for the second entry in the log is returned. If the performance log is empty,\r
658 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance\r
659 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is\r
660 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is\r
661 retrieved and an implementation specific non-zero key value that specifies the end of the performance\r
662 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry\r
663 is retrieved and zero is returned. In the cases where a performance log entry can be returned,\r
664 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.\r
665 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().\r
666 If Handle is NULL, then ASSERT().\r
667 If Token is NULL, then ASSERT().\r
668 If Module is NULL, then ASSERT().\r
669 If StartTimeStamp is NULL, then ASSERT().\r
670 If EndTimeStamp is NULL, then ASSERT().\r
671 If Identifier is NULL, then ASSERT().\r
672\r
673 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.\r
674 0, then the first performance measurement log entry is retrieved.\r
675 On exit, the key of the next performance log entry.\r
676 @param Handle Pointer to environment specific context used to identify the component\r
677 being measured.\r
678 @param Token Pointer to a Null-terminated ASCII string that identifies the component\r
679 being measured.\r
680 @param Module Pointer to a Null-terminated ASCII string that identifies the module\r
681 being measured.\r
682 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement\r
683 was started.\r
684 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement\r
685 was ended.\r
686 @param Identifier Pointer to the 32-bit identifier that was recorded.\r
687\r
688 @return The key for the next performance log entry (in general case).\r
689\r
690**/\r
691UINTN\r
692EFIAPI\r
693GetPerformanceMeasurementEx (\r
694 IN UINTN LogEntryKey, \r
695 OUT CONST VOID **Handle,\r
696 OUT CONST CHAR8 **Token,\r
697 OUT CONST CHAR8 **Module,\r
698 OUT UINT64 *StartTimeStamp,\r
699 OUT UINT64 *EndTimeStamp,\r
700 OUT UINT32 *Identifier\r
701 )\r
702{\r
703 GAUGE_DATA_ENTRY_EX *GaugeData;\r
704\r
705 GaugeData = NULL;\r
706\r
707 ASSERT (Handle != NULL);\r
708 ASSERT (Token != NULL);\r
709 ASSERT (Module != NULL);\r
710 ASSERT (StartTimeStamp != NULL);\r
711 ASSERT (EndTimeStamp != NULL);\r
712 ASSERT (Identifier != NULL);\r
713\r
714 mGaugeDataEx = GetAllSmmGaugeDataEx (LogEntryKey);\r
715 if (mGaugeDataEx != NULL) {\r
716 if (LogEntryKey >= mGaugeNumberOfEntriesEx) {\r
717 //\r
718 // Try to get the data by Performance Protocol.\r
719 //\r
720 LogEntryKey = LogEntryKey - mGaugeNumberOfEntriesEx;\r
721 LogEntryKey = GetByPerformanceProtocol (\r
722 LogEntryKey,\r
723 Handle,\r
724 Token,\r
725 Module,\r
726 StartTimeStamp,\r
727 EndTimeStamp,\r
728 Identifier\r
729 );\r
730 if (LogEntryKey == 0) {\r
731 //\r
732 // Last entry.\r
733 //\r
734 return LogEntryKey;\r
735 } else {\r
736 return (LogEntryKey + mGaugeNumberOfEntriesEx);\r
737 }\r
738 }\r
739\r
740 GaugeData = &mGaugeDataEx[LogEntryKey++];\r
741 *Identifier = GaugeData->Identifier;\r
742 } else {\r
743 mGaugeData = GetAllSmmGaugeData (LogEntryKey);\r
744 if (mGaugeData != NULL) {\r
745 if (LogEntryKey >= mGaugeNumberOfEntries) {\r
746 //\r
747 // Try to get the data by Performance Protocol.\r
748 //\r
749 LogEntryKey = LogEntryKey - mGaugeNumberOfEntries;\r
750 LogEntryKey = GetByPerformanceProtocol (\r
751 LogEntryKey,\r
752 Handle,\r
753 Token,\r
754 Module,\r
755 StartTimeStamp,\r
756 EndTimeStamp,\r
757 Identifier\r
758 );\r
759 if (LogEntryKey == 0) {\r
760 //\r
761 // Last entry.\r
762 //\r
763 return LogEntryKey;\r
764 } else {\r
765 return (LogEntryKey + mGaugeNumberOfEntries);\r
766 }\r
767 }\r
768\r
769 GaugeData = (GAUGE_DATA_ENTRY_EX *) &mGaugeData[LogEntryKey++];\r
770 *Identifier = 0;\r
771 } else {\r
772 return GetByPerformanceProtocol (\r
773 LogEntryKey,\r
774 Handle,\r
775 Token,\r
776 Module,\r
777 StartTimeStamp,\r
778 EndTimeStamp,\r
779 Identifier\r
780 );\r
781 }\r
782 }\r
783\r
784 *Handle = (VOID *) (UINTN) GaugeData->Handle;\r
785 *Token = GaugeData->Token;\r
786 *Module = GaugeData->Module;\r
787 *StartTimeStamp = GaugeData->StartTimeStamp;\r
788 *EndTimeStamp = GaugeData->EndTimeStamp;\r
789\r
790 return LogEntryKey;\r
791}\r
792\r
793/**\r
794 Attempts to retrieve a performance measurement log entry from the performance measurement log.\r
795 It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,\r
796 and then eliminate the Identifier.\r
797\r
798 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is\r
799 zero on entry, then an attempt is made to retrieve the first entry from the performance log,\r
800 and the key for the second entry in the log is returned. If the performance log is empty,\r
801 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance\r
802 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is\r
803 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is\r
804 retrieved and an implementation specific non-zero key value that specifies the end of the performance\r
805 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry\r
806 is retrieved and zero is returned. In the cases where a performance log entry can be returned,\r
807 the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.\r
808 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().\r
809 If Handle is NULL, then ASSERT().\r
810 If Token is NULL, then ASSERT().\r
811 If Module is NULL, then ASSERT().\r
812 If StartTimeStamp is NULL, then ASSERT().\r
813 If EndTimeStamp is NULL, then ASSERT().\r
814\r
815 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.\r
816 0, then the first performance measurement log entry is retrieved.\r
817 On exit, the key of the next performance log entry.\r
818 @param Handle Pointer to environment specific context used to identify the component\r
819 being measured.\r
820 @param Token Pointer to a Null-terminated ASCII string that identifies the component\r
821 being measured.\r
822 @param Module Pointer to a Null-terminated ASCII string that identifies the module\r
823 being measured.\r
824 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement\r
825 was started.\r
826 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement\r
827 was ended.\r
828\r
829 @return The key for the next performance log entry (in general case).\r
830\r
831**/\r
832UINTN\r
833EFIAPI\r
834GetPerformanceMeasurement (\r
835 IN UINTN LogEntryKey,\r
836 OUT CONST VOID **Handle,\r
837 OUT CONST CHAR8 **Token,\r
838 OUT CONST CHAR8 **Module,\r
839 OUT UINT64 *StartTimeStamp,\r
840 OUT UINT64 *EndTimeStamp\r
841 )\r
842{\r
843 UINT32 Identifier;\r
844 return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);\r
845}\r
846\r
847/**\r
848 Returns TRUE if the performance measurement macros are enabled.\r
849\r
850 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of\r
851 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.\r
852\r
853 @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of\r
854 PcdPerformanceLibraryPropertyMask is set.\r
855 @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of\r
856 PcdPerformanceLibraryPropertyMask is clear.\r
857\r
858**/\r
859BOOLEAN\r
860EFIAPI\r
861PerformanceMeasurementEnabled (\r
862 VOID\r
863 )\r
864{\r
865 return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);\r
866}\r