MdeModulePkg-FPDT(4): Use fixed buffer for SMM_PERF_COMMUNICATE in PerfLib.
[mirror_edk2.git] / MdeModulePkg / Library / DxeSmmPerformanceLib / DxeSmmPerformanceLib.c
CommitLineData
d042c6e8 1/** @file\r
dccfb097 2 Performance library instance used in DXE phase to dump both PEI/DXE and SMM performance data.\r
d042c6e8 3\r
dccfb097 4 This library instance allows a DXE driver or UEFI application to dump both PEI/DXE and SMM performance data.\r
f0da4d7d
SZ
5 StartPerformanceMeasurement(), EndPerformanceMeasurement(), StartPerformanceMeasurementEx()\r
6 and EndPerformanceMeasurementEx() are not implemented.\r
d042c6e8 7\r
7a9395cd 8 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
d042c6e8 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
de2459d6
LG
35#include <Guid/PiSmmCommunicationRegionTable.h>\r
36#include <Library/UefiLib.h>\r
37\r
d042c6e8 38#define SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof (SMM_PERF_COMMUNICATE))\r
dccfb097 39\r
d042c6e8 40EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;\r
de2459d6 41UINT8 *mSmmPerformanceBuffer;\r
d042c6e8 42GAUGE_DATA_ENTRY *mGaugeData = NULL;\r
43UINTN mGaugeNumberOfEntries = 0;\r
f0da4d7d
SZ
44GAUGE_DATA_ENTRY_EX *mGaugeDataEx = NULL;\r
45UINTN mGaugeNumberOfEntriesEx = 0;\r
d042c6e8 46\r
11948471
SZ
47BOOLEAN mNoSmmPerfHandler = FALSE;\r
48BOOLEAN mNoSmmPerfExHandler = FALSE;\r
49\r
dccfb097
SZ
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
d042c6e8 56/**\r
f0da4d7d 57 The function caches the pointer to SMM Communication protocol.\r
d042c6e8 58\r
f0da4d7d 59 The function locates SMM Communication protocol from protocol database.\r
d042c6e8 60\r
f0da4d7d
SZ
61 @retval EFI_SUCCESS SMM Communication protocol is successfully located.\r
62 @retval Other SMM Communication protocol is not located to log performance.\r
d042c6e8 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
dccfb097
SZ
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
f0da4d7d
SZ
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
7a9395cd 172 Looks up the record that matches Handle, Token and Module.\r
f0da4d7d
SZ
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
d042c6e8 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
f0da4d7d 235 return RETURN_SUCCESS;\r
d042c6e8 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
d042c6e8 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
f0da4d7d 269 return RETURN_SUCCESS;\r
d042c6e8 270}\r
271\r
dccfb097
SZ
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
d042c6e8 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
dccfb097
SZ
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
d042c6e8 380 @retval !NULL Get all gauge data success.\r
11948471 381 @retval NULL Get all gauge data failed.\r
d042c6e8 382**/\r
f0da4d7d 383GAUGE_DATA_ENTRY *\r
d042c6e8 384EFIAPI\r
dccfb097
SZ
385GetAllSmmGaugeData (\r
386 IN UINTN LogEntryKey\r
387 )\r
d042c6e8 388{\r
de2459d6
LG
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
d042c6e8 401\r
11948471
SZ
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
dccfb097
SZ
410 if (LogEntryKey != 0) {\r
411 if (mGaugeData != NULL) {\r
412 return mGaugeData;\r
413 }\r
414 } else {\r
415 //\r
11948471 416 // Reget the SMM gauge data at the first entry get.\r
dccfb097
SZ
417 //\r
418 if (mGaugeData != NULL) {\r
419 FreePool (mGaugeData);\r
420 mGaugeData = NULL;\r
421 mGaugeNumberOfEntries = 0;\r
422 }\r
d042c6e8 423 }\r
424\r
425 Status = GetCommunicationProtocol ();\r
426 if (EFI_ERROR (Status)) {\r
427 return NULL;\r
428 }\r
429\r
de2459d6
LG
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
d042c6e8 452 //\r
453 // Initialize communicate buffer \r
454 //\r
f0da4d7d
SZ
455 SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER *)mSmmPerformanceBuffer;\r
456 SmmPerfCommData = (SMM_PERF_COMMUNICATE *)SmmCommBufferHeader->Data;\r
d042c6e8 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
f0da4d7d 461 CommSize = SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;\r
d042c6e8 462\r
463 //\r
11948471 464 // Get total number of SMM gauge entries\r
d042c6e8 465 //\r
466 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER;\r
467 Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);\r
11948471
SZ
468 if (Status == EFI_NOT_FOUND) {\r
469 mNoSmmPerfHandler = TRUE;\r
470 }\r
f0da4d7d 471 if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus) || SmmPerfCommData->NumberOfEntries == 0) {\r
d042c6e8 472 return NULL;\r
473 }\r
474\r
475 mGaugeNumberOfEntries = SmmPerfCommData->NumberOfEntries;\r
de2459d6
LG
476\r
477 Buffer = mSmmPerformanceBuffer + SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;\r
478 NumberOfEntries = (Size - SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE) / sizeof (GAUGE_DATA_ENTRY);\r
d042c6e8 479 DataSize = mGaugeNumberOfEntries * sizeof(GAUGE_DATA_ENTRY);\r
480 mGaugeData = AllocateZeroPool(DataSize);\r
f0da4d7d 481 ASSERT (mGaugeData != NULL);\r
de2459d6 482\r
d042c6e8 483 //\r
484 // Get all SMM gauge data\r
485 // \r
486 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_DATA;\r
de2459d6
LG
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
d042c6e8 507\r
f0da4d7d 508 return mGaugeData;\r
d042c6e8 509}\r
510\r
511/**\r
f0da4d7d
SZ
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
d042c6e8 515\r
dccfb097
SZ
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
f0da4d7d 520 @retval !NULL Get all gauge data success.\r
11948471 521 @retval NULL Get all gauge data failed.\r
d042c6e8 522**/\r
f0da4d7d 523GAUGE_DATA_ENTRY_EX *\r
d042c6e8 524EFIAPI\r
dccfb097
SZ
525GetAllSmmGaugeDataEx (\r
526 IN UINTN LogEntryKey\r
527 )\r
d042c6e8 528{\r
de2459d6
LG
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
f0da4d7d 541\r
11948471
SZ
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
dccfb097
SZ
550 if (LogEntryKey != 0) {\r
551 if (mGaugeDataEx != NULL) {\r
552 return mGaugeDataEx;\r
553 }\r
554 } else {\r
555 //\r
11948471 556 // Reget the SMM gauge data at the first entry get.\r
dccfb097
SZ
557 //\r
558 if (mGaugeDataEx != NULL) {\r
559 FreePool (mGaugeDataEx);\r
560 mGaugeDataEx = NULL;\r
561 mGaugeNumberOfEntriesEx = 0;\r
562 }\r
d042c6e8 563 }\r
f0da4d7d
SZ
564\r
565 Status = GetCommunicationProtocol ();\r
566 if (EFI_ERROR (Status)) {\r
567 return NULL;\r
d042c6e8 568 }\r
569\r
de2459d6
LG
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
f0da4d7d
SZ
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
11948471 603 // Get total number of SMM gauge entries\r
f0da4d7d
SZ
604 //\r
605 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER;\r
606 Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);\r
11948471
SZ
607 if (Status == EFI_NOT_FOUND) {\r
608 mNoSmmPerfExHandler = TRUE;\r
609 }\r
f0da4d7d
SZ
610 if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus) || SmmPerfCommData->NumberOfEntries == 0) {\r
611 return NULL;\r
d042c6e8 612 }\r
d042c6e8 613\r
f0da4d7d 614 mGaugeNumberOfEntriesEx = SmmPerfCommData->NumberOfEntries;\r
de2459d6
LG
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
f0da4d7d
SZ
618 DataSize = mGaugeNumberOfEntriesEx * sizeof(GAUGE_DATA_ENTRY_EX);\r
619 mGaugeDataEx = AllocateZeroPool(DataSize);\r
620 ASSERT (mGaugeDataEx != NULL);\r
de2459d6 621\r
f0da4d7d
SZ
622 //\r
623 // Get all SMM gauge data\r
624 // \r
625 SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_DATA;\r
de2459d6
LG
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
f0da4d7d 647 return mGaugeDataEx;\r
d042c6e8 648}\r
649\r
650/**\r
651 Attempts to retrieve a performance measurement log entry from the performance measurement log.\r
f0da4d7d
SZ
652 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,\r
653 and then assign the Identifier with 0.\r
d042c6e8 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
f0da4d7d 664 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.\r
d042c6e8 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
f0da4d7d 671 If Identifier is NULL, then ASSERT().\r
d042c6e8 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
f0da4d7d 686 @param Identifier Pointer to the 32-bit identifier that was recorded.\r
d042c6e8 687\r
688 @return The key for the next performance log entry (in general case).\r
689\r
690**/\r
691UINTN\r
692EFIAPI\r
f0da4d7d
SZ
693GetPerformanceMeasurementEx (\r
694 IN UINTN LogEntryKey, \r
d042c6e8 695 OUT CONST VOID **Handle,\r
696 OUT CONST CHAR8 **Token,\r
697 OUT CONST CHAR8 **Module,\r
698 OUT UINT64 *StartTimeStamp,\r
f0da4d7d
SZ
699 OUT UINT64 *EndTimeStamp,\r
700 OUT UINT32 *Identifier\r
d042c6e8 701 )\r
702{\r
f0da4d7d 703 GAUGE_DATA_ENTRY_EX *GaugeData;\r
d042c6e8 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
f0da4d7d 712 ASSERT (Identifier != NULL);\r
d042c6e8 713\r
dccfb097 714 mGaugeDataEx = GetAllSmmGaugeDataEx (LogEntryKey);\r
f0da4d7d 715 if (mGaugeDataEx != NULL) {\r
dccfb097
SZ
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
f0da4d7d
SZ
738 }\r
739\r
740 GaugeData = &mGaugeDataEx[LogEntryKey++];\r
741 *Identifier = GaugeData->Identifier;\r
742 } else {\r
dccfb097 743 mGaugeData = GetAllSmmGaugeData (LogEntryKey);\r
f0da4d7d 744 if (mGaugeData != NULL) {\r
dccfb097
SZ
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
f0da4d7d
SZ
767 }\r
768\r
769 GaugeData = (GAUGE_DATA_ENTRY_EX *) &mGaugeData[LogEntryKey++];\r
770 *Identifier = 0;\r
771 } else {\r
11948471
SZ
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
f0da4d7d 781 }\r
d042c6e8 782 }\r
783\r
d042c6e8 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
f0da4d7d
SZ
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
d042c6e8 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