]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Library / SmmCorePerformanceLib / SmmCorePerformanceLib.c
CommitLineData
d042c6e8 1/** @file\r
2 Performance library instance used by SMM Core.\r
3\r
4 This library provides the performance measurement interfaces and initializes performance\r
5 logging for the SMM phase.\r
f0da4d7d 6 It initializes SMM phase performance logging by publishing the SMM Performance and PerformanceEx Protocol,\r
d042c6e8 7 which is consumed by SmmPerformanceLib to logging performance data in SMM phase.\r
8\r
9 This library is mainly used by SMM Core to start performance logging to ensure that\r
f0da4d7d 10 SMM Performance and PerformanceEx Protocol are installed at the very beginning of SMM phase.\r
d042c6e8 11\r
ccd2f6b0 12 Caution: This module requires additional review when modified.\r
13 This driver will have external input - performance data and communicate buffer in SMM mode.\r
14 This external input must be validated carefully to avoid security issue like\r
15 buffer overflow, integer overflow.\r
16\r
17 SmmPerformanceHandlerEx(), SmmPerformanceHandler() will receive untrusted input and do basic validation.\r
18\r
2001f84e 19Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 20SPDX-License-Identifier: BSD-2-Clause-Patent\r
d042c6e8 21\r
22**/\r
23\r
24\r
25#include "SmmCorePerformanceLibInternal.h"\r
26\r
2001f84e
DB
27#define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))\r
28#define FIRMWARE_RECORD_BUFFER 0x1000\r
29#define CACHE_HANDLE_GUID_COUNT 0x100\r
d042c6e8 30\r
2001f84e 31SMM_BOOT_PERFORMANCE_TABLE *mSmmBootPerformanceTable = NULL;\r
d042c6e8 32\r
2001f84e
DB
33typedef struct {\r
34 EFI_HANDLE Handle;\r
35 CHAR8 NameString[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];\r
36 EFI_GUID ModuleGuid;\r
37} HANDLE_GUID_MAP;\r
d042c6e8 38\r
2001f84e
DB
39HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];\r
40UINTN mCachePairCount = 0;\r
d042c6e8 41\r
dd3907f2 42UINT32 mPerformanceLength = sizeof (SMM_BOOT_PERFORMANCE_TABLE);\r
2001f84e 43UINT32 mMaxPerformanceLength = 0;\r
6b4d58a1 44UINT32 mLoadImageCount = 0;\r
2001f84e
DB
45BOOLEAN mFpdtDataIsReported = FALSE;\r
46BOOLEAN mLackSpaceIsReport = FALSE;\r
47CHAR8 *mPlatformLanguage = NULL;\r
48SPIN_LOCK mSmmFpdtLock;\r
49PERFORMANCE_PROPERTY mPerformanceProperty;\r
6b4d58a1 50UINT32 mCachedLength = 0;\r
d042c6e8 51\r
d042c6e8 52//\r
137fb13d 53// Interfaces for SMM PerformanceMeasurement Protocol.\r
d042c6e8 54//\r
137fb13d
BD
55EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = {\r
56 CreatePerformanceMeasurement,\r
f0da4d7d
SZ
57};\r
58\r
6b4d58a1
BD
59/**\r
60 Return the pointer to the FPDT record in the allocated memory.\r
61\r
62 @param RecordSize The size of FPDT record.\r
63 @param FpdtRecordPtr Pointer the FPDT record in the allocated memory.\r
64\r
65 @retval EFI_SUCCESS Successfully get the pointer to the FPDT record.\r
66 @retval EFI_OUT_OF_RESOURCES Ran out of space to store the records.\r
67**/\r
68EFI_STATUS\r
69GetFpdtRecordPtr (\r
70 IN UINT8 RecordSize,\r
71 IN OUT FPDT_RECORD_PTR *FpdtRecordPtr\r
72)\r
73{\r
74 if (mFpdtDataIsReported) {\r
75 //\r
76 // Append Boot records after Smm boot performance records have been reported.\r
77 //\r
78 if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {\r
79 if (!mLackSpaceIsReport) {\r
80 DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to save boot records\n"));\r
81 mLackSpaceIsReport = TRUE;\r
82 }\r
83 return EFI_OUT_OF_RESOURCES;\r
84 } else {\r
85 //\r
86 // Covert buffer to FPDT Ptr Union type.\r
87 //\r
88 FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);\r
89 }\r
90 } else {\r
91 //\r
92 // Check if pre-allocated buffer is full\r
93 //\r
94 if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {\r
95 mSmmBootPerformanceTable = ReallocatePool (\r
96 mPerformanceLength,\r
dd3907f2 97 mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER,\r
6b4d58a1
BD
98 mSmmBootPerformanceTable\r
99 );\r
100\r
101 if (mSmmBootPerformanceTable == NULL) {\r
102 return EFI_OUT_OF_RESOURCES;\r
103 }\r
dd3907f2
DB
104 mSmmBootPerformanceTable->Header.Length = mPerformanceLength;\r
105 mMaxPerformanceLength = mPerformanceLength + RecordSize + FIRMWARE_RECORD_BUFFER;\r
6b4d58a1
BD
106 }\r
107 //\r
108 // Covert buffer to FPDT Ptr Union type.\r
109 //\r
110 FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);\r
111 }\r
112 FpdtRecordPtr->RecordHeader->Length = 0;\r
113 return EFI_SUCCESS;\r
114}\r
115\r
116\r
2001f84e
DB
117/**\r
118Check whether the Token is a known one which is uesed by core.\r
119\r
120@param Token Pointer to a Null-terminated ASCII string\r
121\r
122@retval TRUE Is a known one used by core.\r
123@retval FALSE Not a known one.\r
124\r
125**/\r
126BOOLEAN\r
127IsKnownTokens (\r
128 IN CONST CHAR8 *Token\r
129 )\r
130{\r
c9faac27
DB
131 if (Token == NULL) {\r
132 return FALSE;\r
133 }\r
134\r
2001f84e
DB
135 if (AsciiStrCmp (Token, SEC_TOK) == 0 ||\r
136 AsciiStrCmp (Token, PEI_TOK) == 0 ||\r
137 AsciiStrCmp (Token, DXE_TOK) == 0 ||\r
138 AsciiStrCmp (Token, BDS_TOK) == 0 ||\r
139 AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0 ||\r
140 AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0 ||\r
141 AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0 ||\r
142 AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0 ||\r
143 AsciiStrCmp (Token, START_IMAGE_TOK) == 0 ||\r
144 AsciiStrCmp (Token, PEIM_TOK) == 0) {\r
145 return TRUE;\r
146 } else {\r
147 return FALSE;\r
148 }\r
149}\r
cfb0aba7 150\r
d042c6e8 151/**\r
2001f84e 152Check whether the ID is a known one which map to the known Token.\r
d042c6e8 153\r
2001f84e 154@param Identifier 32-bit identifier.\r
d042c6e8 155\r
2001f84e
DB
156@retval TRUE Is a known one used by core.\r
157@retval FALSE Not a known one.\r
158\r
159**/\r
160BOOLEAN\r
161IsKnownID (\r
162 IN UINT32 Identifier\r
163 )\r
164{\r
165 if (Identifier == MODULE_START_ID ||\r
166 Identifier == MODULE_END_ID ||\r
167 Identifier == MODULE_LOADIMAGE_START_ID ||\r
168 Identifier == MODULE_LOADIMAGE_END_ID ||\r
169 Identifier == MODULE_DB_START_ID ||\r
170 Identifier == MODULE_DB_END_ID ||\r
171 Identifier == MODULE_DB_SUPPORT_START_ID ||\r
172 Identifier == MODULE_DB_SUPPORT_END_ID ||\r
173 Identifier == MODULE_DB_STOP_START_ID ||\r
174 Identifier == MODULE_DB_STOP_END_ID) {\r
175 return TRUE;\r
176 } else {\r
177 return FALSE;\r
178 }\r
179}\r
180\r
181/**\r
6b4d58a1 182 Get the FPDT record identifier.\r
2001f84e 183\r
6b4d58a1
BD
184 @param Attribute The attribute of the Record.\r
185 PerfStartEntry: Start Record.\r
186 PerfEndEntry: End Record.\r
187 @param Handle Pointer to environment specific context used to identify the component being measured.\r
188 @param String Pointer to a Null-terminated ASCII string that identifies the component being measured.\r
189 @param ProgressID On return, pointer to the ProgressID.\r
d042c6e8 190\r
6b4d58a1
BD
191 @retval EFI_SUCCESS Get record info successfully.\r
192 @retval EFI_INVALID_PARAMETER No matched FPDT record.\r
d042c6e8 193\r
194**/\r
2001f84e 195EFI_STATUS\r
6b4d58a1
BD
196GetFpdtRecordId (\r
197 IN PERF_MEASUREMENT_ATTRIBUTE Attribute,\r
198 IN CONST VOID *Handle,\r
199 IN CONST CHAR8 *String,\r
200 OUT UINT16 *ProgressID\r
d042c6e8 201 )\r
202{\r
2001f84e 203 //\r
6b4d58a1 204 // Token to Id.\r
2001f84e 205 //\r
6b4d58a1
BD
206 if (String != NULL) {\r
207 if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) { // "StartImage:"\r
208 if (Attribute == PerfStartEntry) {\r
209 *ProgressID = MODULE_START_ID;\r
2001f84e 210 } else {\r
6b4d58a1 211 *ProgressID = MODULE_END_ID;\r
2001f84e 212 }\r
6b4d58a1
BD
213 } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) { // "LoadImage:"\r
214 if (Attribute == PerfStartEntry) {\r
215 *ProgressID = MODULE_LOADIMAGE_START_ID;\r
2001f84e 216 } else {\r
6b4d58a1 217 *ProgressID = MODULE_LOADIMAGE_END_ID;\r
2001f84e
DB
218 }\r
219 } else { // Pref used in Modules\r
6b4d58a1
BD
220 if (Attribute == PerfStartEntry) {\r
221 *ProgressID = PERF_INMODULE_START_ID;\r
2001f84e 222 } else {\r
6b4d58a1 223 *ProgressID = PERF_INMODULE_END_ID;\r
2001f84e
DB
224 }\r
225 }\r
6b4d58a1
BD
226 } else if (Handle != NULL) { // Pref used in Modules\r
227 if (Attribute == PerfStartEntry) {\r
228 *ProgressID = PERF_INMODULE_START_ID;\r
2001f84e 229 } else {\r
6b4d58a1 230 *ProgressID = PERF_INMODULE_END_ID;\r
2001f84e
DB
231 }\r
232 } else {\r
233 return EFI_UNSUPPORTED;\r
d042c6e8 234 }\r
2001f84e 235 return EFI_SUCCESS;\r
d042c6e8 236}\r
237\r
238/**\r
2001f84e
DB
239 Get a human readable module name and module guid for the given image handle.\r
240 If module name can't be found, "" string will return.\r
241 If module guid can't be found, Zero Guid will return.\r
242\r
243 @param Handle Image handle or Controller handle.\r
244 @param NameString The ascii string will be filled into it. If not found, null string will return.\r
245 @param BufferSize Size of the input NameString buffer.\r
246 @param ModuleGuid Point to the guid buffer to store the got module guid value.\r
247\r
248 @retval EFI_SUCCESS Successfully get module name and guid.\r
249 @retval EFI_INVALID_PARAMETER The input parameter NameString is NULL.\r
250 @retval other value Module Name can't be got.\r
251**/\r
252EFI_STATUS\r
253EFIAPI\r
254GetModuleInfoFromHandle (\r
255 IN EFI_HANDLE Handle,\r
256 OUT CHAR8 *NameString,\r
257 IN UINTN BufferSize,\r
258 OUT EFI_GUID *ModuleGuid OPTIONAL\r
259 )\r
260{\r
261 EFI_STATUS Status;\r
262 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
263 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
264 CHAR8 *PdbFileName;\r
265 EFI_GUID *TempGuid;\r
266 UINTN StartIndex;\r
267 UINTN Index;\r
268 INTN Count;\r
269 BOOLEAN ModuleGuidIsGet;\r
270 UINTN StringSize;\r
271 CHAR16 *StringPtr;\r
272 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;\r
273\r
274 if (NameString == NULL || BufferSize == 0) {\r
275 return EFI_INVALID_PARAMETER;\r
276 }\r
d042c6e8 277\r
2001f84e
DB
278 //\r
279 // Try to get the ModuleGuid and name string form the caached array.\r
280 //\r
281 if (mCachePairCount > 0) {\r
282 for (Count = mCachePairCount - 1; Count >= 0; Count--) {\r
283 if (Handle == mCacheHandleGuidTable[Count].Handle) {\r
284 CopyGuid (ModuleGuid, &mCacheHandleGuidTable[Count].ModuleGuid);\r
285 AsciiStrCpyS (NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, mCacheHandleGuidTable[Count].NameString);\r
286 return EFI_SUCCESS;\r
287 }\r
288 }\r
289 }\r
290\r
291 Status = EFI_INVALID_PARAMETER;\r
292 LoadedImage = NULL;\r
293 ModuleGuidIsGet = FALSE;\r
d042c6e8 294\r
2001f84e
DB
295 //\r
296 // Initialize GUID as zero value.\r
297 //\r
298 TempGuid = &gZeroGuid;\r
299 //\r
300 // Initialize it as "" string.\r
301 //\r
302 NameString[0] = 0;\r
303\r
304 if (Handle != NULL) {\r
305 //\r
306 // Try Handle as ImageHandle.\r
307 //\r
308 Status = gBS->HandleProtocol (\r
309 Handle,\r
310 &gEfiLoadedImageProtocolGuid,\r
311 (VOID**) &LoadedImage\r
312 );\r
313\r
314 if (EFI_ERROR (Status)) {\r
315 //\r
316 // Try Handle as Controller Handle\r
317 //\r
318 Status = gBS->OpenProtocol (\r
319 Handle,\r
320 &gEfiDriverBindingProtocolGuid,\r
321 (VOID **) &DriverBinding,\r
322 NULL,\r
323 NULL,\r
324 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
325 );\r
326 if (!EFI_ERROR (Status)) {\r
327 //\r
328 // Get Image protocol from ImageHandle\r
329 //\r
330 Status = gBS->HandleProtocol (\r
331 DriverBinding->ImageHandle,\r
332 &gEfiLoadedImageProtocolGuid,\r
333 (VOID**) &LoadedImage\r
334 );\r
335 }\r
336 }\r
337 }\r
338\r
339 if (!EFI_ERROR (Status) && LoadedImage != NULL) {\r
340 //\r
341 // Get Module Guid from DevicePath.\r
342 //\r
343 if (LoadedImage->FilePath != NULL &&\r
344 LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH &&\r
345 LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP\r
346 ) {\r
347 //\r
348 // Determine GUID associated with module logging performance\r
349 //\r
350 ModuleGuidIsGet = TRUE;\r
351 FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath;\r
352 TempGuid = &FvFilePath->FvFileName;\r
353 }\r
354\r
355 //\r
356 // Method 1 Get Module Name from PDB string.\r
357 //\r
358 PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);\r
359 if (PdbFileName != NULL && BufferSize > 0) {\r
360 StartIndex = 0;\r
361 for (Index = 0; PdbFileName[Index] != 0; Index++) {\r
362 if ((PdbFileName[Index] == '\\') || (PdbFileName[Index] == '/')) {\r
363 StartIndex = Index + 1;\r
364 }\r
365 }\r
366 //\r
367 // Copy the PDB file name to our temporary string.\r
368 // If the length is bigger than BufferSize, trim the redudant characters to avoid overflow in array boundary.\r
369 //\r
370 for (Index = 0; Index < BufferSize - 1; Index++) {\r
371 NameString[Index] = PdbFileName[Index + StartIndex];\r
372 if (NameString[Index] == 0 || NameString[Index] == '.') {\r
373 NameString[Index] = 0;\r
374 break;\r
375 }\r
376 }\r
377\r
378 if (Index == BufferSize - 1) {\r
379 NameString[Index] = 0;\r
380 }\r
381 //\r
382 // Module Name is got.\r
383 //\r
384 goto Done;\r
385 }\r
386 }\r
387\r
388 if (ModuleGuidIsGet) {\r
389 //\r
390 // Method 2 Try to get the image's FFS UI section by image GUID\r
391 //\r
392 StringPtr = NULL;\r
393 StringSize = 0;\r
394 Status = GetSectionFromAnyFv (\r
395 TempGuid,\r
396 EFI_SECTION_USER_INTERFACE,\r
397 0,\r
398 (VOID **) &StringPtr,\r
399 &StringSize\r
400 );\r
401\r
402 if (!EFI_ERROR (Status)) {\r
403 //\r
404 // Method 3. Get the name string from FFS UI section\r
405 //\r
406 for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {\r
407 NameString[Index] = (CHAR8) StringPtr[Index];\r
408 }\r
409 NameString[Index] = 0;\r
410 FreePool (StringPtr);\r
411 }\r
412 }\r
413\r
414Done:\r
415 //\r
416 // Copy Module Guid\r
417 //\r
418 if (ModuleGuid != NULL) {\r
419 CopyGuid (ModuleGuid, TempGuid);\r
420 if (IsZeroGuid(TempGuid) && (Handle != NULL) && !ModuleGuidIsGet) {\r
421 // Handle is GUID\r
422 CopyGuid (ModuleGuid, (EFI_GUID *) Handle);\r
423 }\r
424 }\r
425\r
426 //\r
427 // Cache the Handle and Guid pairs.\r
428 //\r
429 if (mCachePairCount < CACHE_HANDLE_GUID_COUNT) {\r
430 mCacheHandleGuidTable[mCachePairCount].Handle = Handle;\r
431 CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, ModuleGuid);\r
432 AsciiStrCpyS (mCacheHandleGuidTable[mCachePairCount].NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, NameString);\r
433 mCachePairCount ++;\r
434 }\r
435\r
436 return Status;\r
437}\r
438\r
439/**\r
6b4d58a1
BD
440 Copies the string from Source into Destination and updates Length with the\r
441 size of the string.\r
2001f84e 442\r
6b4d58a1
BD
443 @param Destination - destination of the string copy\r
444 @param Source - pointer to the source string which will get copied\r
445 @param Length - pointer to a length variable to be updated\r
446\r
447**/\r
448VOID\r
449CopyStringIntoPerfRecordAndUpdateLength (\r
450 IN OUT CHAR8 *Destination,\r
451 IN CONST CHAR8 *Source,\r
452 IN OUT UINT8 *Length\r
453 )\r
454{\r
455 UINTN StringLen;\r
456 UINTN DestMax;\r
457\r
458 ASSERT (Source != NULL);\r
459\r
460 if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
461 DestMax = STRING_SIZE;\r
462 } else {\r
463 DestMax = AsciiStrSize (Source);\r
464 if (DestMax > STRING_SIZE) {\r
465 DestMax = STRING_SIZE;\r
466 }\r
467 }\r
468 StringLen = AsciiStrLen (Source);\r
469 if (StringLen >= DestMax) {\r
470 StringLen = DestMax -1;\r
471 }\r
d042c6e8 472\r
6b4d58a1
BD
473 AsciiStrnCpyS(Destination, DestMax, Source, StringLen);\r
474 *Length += (UINT8)DestMax;\r
475\r
476 return;\r
477}\r
478\r
479/**\r
480 Create performance record with event description and a timestamp.\r
481\r
482 @param CallerIdentifier - Image handle or pointer to caller ID GUID.\r
483 @param Guid - Pointer to a GUID.\r
484 @param String - Pointer to a string describing the measurement.\r
485 @param Ticker - 64-bit time stamp.\r
486 @param Address - Pointer to a location in memory relevant to the measurement.\r
487 @param PerfId - Performance identifier describing the type of measurement.\r
488 @param Attribute - The attribute of the measurement. According to attribute can create a start\r
489 record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,\r
490 or a general record for other Perf macros.\r
491\r
492 @retval EFI_SUCCESS - Successfully created performance record.\r
493 @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.\r
494 @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL\r
495 pointer or invalid PerfId.\r
496\r
497 @retval EFI_SUCCESS - Successfully created performance record\r
498 @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records\r
499 @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL\r
500 pointer or invalid PerfId\r
d042c6e8 501\r
502**/\r
503EFI_STATUS\r
6b4d58a1
BD
504InsertFpdtRecord (\r
505 IN CONST VOID *CallerIdentifier, OPTIONAL\r
506 IN CONST VOID *Guid, OPTIONAL\r
507 IN CONST CHAR8 *String, OPTIONAL\r
508 IN UINT64 Ticker,\r
509 IN UINT64 Address, OPTIONAL\r
510 IN UINT16 PerfId,\r
511 IN PERF_MEASUREMENT_ATTRIBUTE Attribute\r
d042c6e8 512 )\r
6b4d58a1 513\r
d042c6e8 514{\r
6b4d58a1 515 EFI_STATUS Status;\r
2001f84e
DB
516 EFI_GUID ModuleGuid;\r
517 CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];\r
2001f84e 518 FPDT_RECORD_PTR FpdtRecordPtr;\r
6b4d58a1 519 FPDT_RECORD_PTR CachedFpdtRecordPtr;\r
2001f84e 520 UINT64 TimeStamp;\r
2001f84e 521 CONST CHAR8 *StringPtr;\r
6b4d58a1
BD
522 UINTN DestMax;\r
523 UINTN StringLen;\r
524 UINT16 ProgressId;\r
2001f84e
DB
525\r
526 StringPtr = NULL;\r
2001f84e 527 ZeroMem (ModuleName, sizeof (ModuleName));\r
d042c6e8 528\r
2001f84e 529 //\r
6b4d58a1
BD
530 // 1. Get the Perf Id for records from PERF_START/PERF_END, PERF_START_EX/PERF_END_EX.\r
531 // notes: For other Perf macros (Attribute == PerfEntry), their Id is known.\r
2001f84e 532 //\r
6b4d58a1 533 if (Attribute != PerfEntry) {\r
d042c6e8 534 //\r
6b4d58a1
BD
535 // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has high priority.\r
536 // !!! Note: If the Perf is not the known Token used in the core but have same\r
537 // ID with the core Token, this case will not be supported.\r
538 // And in currtnt usage mode, for the unkown ID, there is a general rule:\r
539 // If it is start pref: the lower 4 bits of the ID should be 0.\r
540 // If it is end pref: the lower 4 bits of the ID should not be 0.\r
541 // If input ID doesn't follow the rule, we will adjust it.\r
d042c6e8 542 //\r
6b4d58a1
BD
543 if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {\r
544 return EFI_INVALID_PARAMETER;\r
545 } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens (String))) {\r
546 if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) {\r
547 PerfId &= 0xFFF0;\r
548 } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {\r
549 PerfId += 1;\r
2001f84e 550 }\r
6b4d58a1
BD
551 }\r
552 if (PerfId == 0) {\r
2001f84e 553 //\r
6b4d58a1 554 // Get ProgressID form the String Token.\r
2001f84e 555 //\r
6b4d58a1
BD
556 Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &ProgressId);\r
557 if (EFI_ERROR (Status)) {\r
558 return Status;\r
2001f84e 559 }\r
6b4d58a1 560 PerfId = ProgressId;\r
d042c6e8 561 }\r
2001f84e 562 }\r
d042c6e8 563\r
2001f84e 564 //\r
6b4d58a1
BD
565 // 2. Get the buffer to store the FPDT record.\r
566 //\r
567 Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr);\r
568 if (EFI_ERROR (Status)) {\r
569 return Status;\r
570 }\r
571\r
572 //\r
573 // 3. Get the TimeStamp.\r
2001f84e
DB
574 //\r
575 if (Ticker == 0) {\r
576 Ticker = GetPerformanceCounter ();\r
577 TimeStamp = GetTimeInNanoSecond (Ticker);\r
578 } else if (Ticker == 1) {\r
579 TimeStamp = 0;\r
580 } else {\r
581 TimeStamp = GetTimeInNanoSecond (Ticker);\r
d042c6e8 582 }\r
583\r
2001f84e 584 //\r
6b4d58a1 585 // 4. Fill in the FPDT record according to different Performance Identifier.\r
2001f84e 586 //\r
6b4d58a1
BD
587 switch (PerfId) {\r
588 case MODULE_START_ID:\r
589 case MODULE_END_ID:\r
590 GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);\r
591 StringPtr = ModuleName;\r
592 //\r
593 // Cache the offset of start image start record and use to update the start image end record if needed.\r
594 //\r
595 if (PerfId == MODULE_START_ID && Attribute == PerfEntry) {\r
596 mCachedLength = mSmmBootPerformanceTable->Header.Length;\r
597 }\r
598 if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
599 FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE;\r
600 FpdtRecordPtr.GuidEvent->Header.Length = sizeof (FPDT_GUID_EVENT_RECORD);\r
601 FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1;\r
602 FpdtRecordPtr.GuidEvent->ProgressID = PerfId;\r
603 FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp;\r
604 CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));\r
605 if (CallerIdentifier == NULL && PerfId == MODULE_END_ID && mCachedLength != 0) {\r
606 CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);\r
607 CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid));\r
608 mCachedLength = 0;\r
609 }\r
610 }\r
611 break;\r
d042c6e8 612\r
6b4d58a1
BD
613 case MODULE_LOADIMAGE_START_ID:\r
614 case MODULE_LOADIMAGE_END_ID:\r
615 GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);\r
616 StringPtr = ModuleName;\r
617 if (PerfId == MODULE_LOADIMAGE_START_ID) {\r
618 mLoadImageCount++;\r
619 //\r
620 // Cache the offset of load image start record and use to be updated by the load image end record if needed.\r
621 //\r
622 if (CallerIdentifier == NULL && Attribute == PerfEntry) {\r
623 mCachedLength = mSmmBootPerformanceTable->Header.Length;\r
624 }\r
625 }\r
626 if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
627 FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE;\r
628 FpdtRecordPtr.GuidQwordEvent->Header.Length = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);\r
629 FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;\r
630 FpdtRecordPtr.GuidQwordEvent->ProgressID = PerfId;\r
631 FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp;\r
632 FpdtRecordPtr.GuidQwordEvent->Qword = mLoadImageCount;\r
633 CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));\r
634 if (PerfId == MODULE_LOADIMAGE_END_ID && mCachedLength != 0) {\r
635 CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);\r
636 CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid));\r
637 mCachedLength = 0;\r
638 }\r
639 }\r
2001f84e
DB
640 break;\r
641\r
6b4d58a1
BD
642 case PERF_EVENTSIGNAL_START_ID:\r
643 case PERF_EVENTSIGNAL_END_ID:\r
644 case PERF_CALLBACK_START_ID:\r
645 case PERF_CALLBACK_END_ID:\r
981b7edc 646 if (String == NULL || Guid == NULL) {\r
6b4d58a1
BD
647 return EFI_INVALID_PARAMETER;\r
648 }\r
6b4d58a1 649 StringPtr = String;\r
981b7edc
DB
650 if (AsciiStrLen (String) == 0) {\r
651 StringPtr = "unknown name";\r
652 }\r
6b4d58a1
BD
653 if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
654 FpdtRecordPtr.DualGuidStringEvent->Header.Type = FPDT_DUAL_GUID_STRING_EVENT_TYPE;\r
655 FpdtRecordPtr.DualGuidStringEvent->Header.Length = sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD);\r
656 FpdtRecordPtr.DualGuidStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;\r
657 FpdtRecordPtr.DualGuidStringEvent->ProgressID = PerfId;\r
658 FpdtRecordPtr.DualGuidStringEvent->Timestamp = TimeStamp;\r
659 CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));\r
660 CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid2));\r
661 CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, &FpdtRecordPtr.DualGuidStringEvent->Header.Length);\r
662 }\r
663 break;\r
2001f84e 664\r
6b4d58a1
BD
665 case PERF_EVENT_ID:\r
666 case PERF_FUNCTION_START_ID:\r
667 case PERF_FUNCTION_END_ID:\r
668 case PERF_INMODULE_START_ID:\r
669 case PERF_INMODULE_END_ID:\r
670 case PERF_CROSSMODULE_START_ID:\r
671 case PERF_CROSSMODULE_END_ID:\r
672 GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);\r
673 if (String != NULL) {\r
674 StringPtr = String;\r
675 } else {\r
676 StringPtr = ModuleName;\r
677 }\r
678 if (AsciiStrLen (StringPtr) == 0) {\r
679 StringPtr = "unknown name";\r
2001f84e 680 }\r
6b4d58a1
BD
681 if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
682 FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;\r
683 FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);\r
684 FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;\r
685 FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;\r
686 FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;\r
687 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));\r
688 CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);\r
689 }\r
690 break;\r
691\r
692 default:\r
693 if (Attribute != PerfEntry) {\r
694 GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, sizeof (ModuleName), &ModuleGuid);\r
695 if (String != NULL) {\r
696 StringPtr = String;\r
697 } else {\r
698 StringPtr = ModuleName;\r
699 }\r
700 if (AsciiStrLen (StringPtr) == 0) {\r
701 StringPtr = "unknown name";\r
702 }\r
703 if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
704 FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;\r
705 FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);\r
706 FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;\r
707 FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;\r
708 FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;\r
709 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));\r
710 CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);\r
2001f84e 711 }\r
2001f84e 712 } else {\r
6b4d58a1 713 return EFI_INVALID_PARAMETER;\r
2001f84e
DB
714 }\r
715 break;\r
6b4d58a1 716 }\r
2001f84e 717\r
6b4d58a1
BD
718 //\r
719 // 4.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record for all Perf entries.\r
720 //\r
721 if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {\r
722 if (StringPtr == NULL) {\r
723 return EFI_INVALID_PARAMETER;\r
724 }\r
725 FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;\r
726 FpdtRecordPtr.DynamicStringEvent->Header.Length = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);\r
727 FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;\r
728 FpdtRecordPtr.DynamicStringEvent->ProgressID = PerfId;\r
729 FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;\r
981b7edc
DB
730 if (Guid != NULL) {\r
731 //\r
732 // Cache the event guid in string event record.\r
733 //\r
734 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));\r
735 } else {\r
736 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));\r
737 }\r
6b4d58a1
BD
738 if (AsciiStrLen (StringPtr) == 0) {\r
739 StringPtr = "unknown name";\r
740 }\r
741 CopyStringIntoPerfRecordAndUpdateLength (FpdtRecordPtr.DynamicStringEvent->String, StringPtr, &FpdtRecordPtr.DynamicStringEvent->Header.Length);\r
2001f84e 742\r
6b4d58a1
BD
743 if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) {\r
744 FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE);\r
745 }\r
746 if ((PerfId == MODULE_LOADIMAGE_END_ID || PerfId == MODULE_END_ID) && mCachedLength != 0) {\r
747 CachedFpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)((UINT8*)mSmmBootPerformanceTable + mCachedLength);\r
748 if (PerfId == MODULE_LOADIMAGE_END_ID) {\r
749 DestMax = CachedFpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);\r
750 StringLen = AsciiStrLen (StringPtr);\r
751 if (StringLen >= DestMax) {\r
752 StringLen = DestMax -1;\r
753 }\r
754 CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));\r
755 AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StringLen);\r
756 } else if (PerfId == MODULE_END_ID) {\r
757 DestMax = FpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);\r
758 StringLen = AsciiStrLen (CachedFpdtRecordPtr.DynamicStringEvent->String);\r
759 if (StringLen >= DestMax) {\r
760 StringLen = DestMax -1;\r
761 }\r
762 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &CachedFpdtRecordPtr.DynamicStringEvent->Guid, sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));\r
763 AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, CachedFpdtRecordPtr.DynamicStringEvent->String, StringLen);\r
764 }\r
765 mCachedLength = 0;\r
766 }\r
d042c6e8 767 }\r
768\r
2001f84e 769 //\r
6b4d58a1 770 // 5. Update the length of the used buffer after fill in the record.\r
2001f84e
DB
771 //\r
772 mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;\r
773 mSmmBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length;\r
f0da4d7d 774\r
2001f84e
DB
775 return EFI_SUCCESS;\r
776}\r
d042c6e8 777\r
2001f84e
DB
778/**\r
779 SmmReadyToBoot protocol notification event handler.\r
f0da4d7d 780\r
2001f84e
DB
781 @param Protocol Points to the protocol's unique identifier\r
782 @param Interface Points to the interface instance\r
783 @param Handle The handle on which the interface was installed\r
ccd2f6b0 784\r
2001f84e 785 @retval EFI_SUCCESS SmmReadyToBootCallback runs successfully\r
f0da4d7d 786\r
d042c6e8 787**/\r
788EFI_STATUS\r
789EFIAPI\r
2001f84e
DB
790SmmReportFpdtRecordData (\r
791 IN CONST EFI_GUID *Protocol,\r
792 IN VOID *Interface,\r
793 IN EFI_HANDLE Handle\r
d042c6e8 794 )\r
795{\r
2001f84e
DB
796 UINT64 SmmBPDTddr;\r
797\r
798 if (!mFpdtDataIsReported && mSmmBootPerformanceTable != NULL) {\r
799 SmmBPDTddr = (UINT64)(UINTN)mSmmBootPerformanceTable;\r
800 REPORT_STATUS_CODE_EX (\r
801 EFI_PROGRESS_CODE,\r
802 EFI_SOFTWARE_SMM_DRIVER,\r
803 0,\r
804 NULL,\r
805 &gEdkiiFpdtExtendedFirmwarePerformanceGuid,\r
806 &SmmBPDTddr,\r
807 sizeof (UINT64)\r
808 );\r
809 //\r
810 // Set FPDT report state to TRUE.\r
811 //\r
812 mFpdtDataIsReported = TRUE;\r
f0da4d7d 813 }\r
d042c6e8 814 return EFI_SUCCESS;\r
815}\r
816\r
817/**\r
2001f84e
DB
818 SmmBase2 protocol notify callback function, when SMST and SMM memory service get initialized\r
819 this function is callbacked to initialize the Smm Performance Lib\r
d042c6e8 820\r
821 @param Event The event of notify protocol.\r
822 @param Context Notify event context.\r
823\r
824**/\r
825VOID\r
826EFIAPI\r
827InitializeSmmCorePerformanceLib (\r
828 IN EFI_EVENT Event,\r
829 IN VOID *Context\r
830 )\r
831{\r
d042c6e8 832 EFI_HANDLE Handle;\r
2001f84e
DB
833 EFI_STATUS Status;\r
834 VOID *SmmReadyToBootRegistration;\r
cfb0aba7 835 PERFORMANCE_PROPERTY *PerformanceProperty;\r
d042c6e8 836\r
837 //\r
838 // Initialize spin lock\r
839 //\r
2001f84e 840 InitializeSpinLock (&mSmmFpdtLock);\r
d042c6e8 841\r
d042c6e8 842 //\r
2001f84e 843 // Install the protocol interfaces for SMM performance library instance.\r
d042c6e8 844 //\r
2001f84e 845 Handle = NULL;\r
d042c6e8 846 Status = gSmst->SmmInstallProtocolInterface (\r
2001f84e 847 &Handle,\r
137fb13d 848 &gEdkiiSmmPerformanceMeasurementProtocolGuid,\r
f0da4d7d 849 EFI_NATIVE_INTERFACE,\r
137fb13d 850 &mPerformanceMeasurementInterface\r
f0da4d7d
SZ
851 );\r
852 ASSERT_EFI_ERROR (Status);\r
853\r
2001f84e
DB
854 Status = gSmst->SmmRegisterProtocolNotify (\r
855 &gEdkiiSmmReadyToBootProtocolGuid,\r
856 SmmReportFpdtRecordData,\r
857 &SmmReadyToBootRegistration\r
858 );\r
9802d6d5 859 Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);\r
cfb0aba7
SZ
860 if (EFI_ERROR (Status)) {\r
861 //\r
862 // Install configuration table for performance property.\r
863 //\r
864 mPerformanceProperty.Revision = PERFORMANCE_PROPERTY_REVISION;\r
865 mPerformanceProperty.Reserved = 0;\r
866 mPerformanceProperty.Frequency = GetPerformanceCounterProperties (\r
867 &mPerformanceProperty.TimerStartValue,\r
868 &mPerformanceProperty.TimerEndValue\r
869 );\r
870 Status = gBS->InstallConfigurationTable (&gPerformanceProtocolGuid, &mPerformanceProperty);\r
871 ASSERT_EFI_ERROR (Status);\r
872 }\r
d042c6e8 873}\r
874\r
875/**\r
2001f84e 876 The constructor function initializes the Performance Measurement Enable flag and\r
f0da4d7d 877 registers SmmBase2 protocol notify callback.\r
d042c6e8 878 It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.\r
879\r
880 @param ImageHandle The firmware allocated handle for the EFI image.\r
881 @param SystemTable A pointer to the EFI System Table.\r
882\r
883 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
884\r
885**/\r
886EFI_STATUS\r
887EFIAPI\r
888SmmCorePerformanceLibConstructor (\r
889 IN EFI_HANDLE ImageHandle,\r
890 IN EFI_SYSTEM_TABLE *SystemTable\r
891 )\r
892{\r
893 EFI_STATUS Status;\r
894 EFI_EVENT Event;\r
895 VOID *Registration;\r
896\r
2001f84e 897 if (!PerformanceMeasurementEnabled ()) {\r
d042c6e8 898 //\r
899 // Do not initialize performance infrastructure if not required.\r
900 //\r
901 return EFI_SUCCESS;\r
902 }\r
903\r
904 //\r
905 // Create the events to do the library init.\r
906 //\r
907 Status = gBS->CreateEvent (\r
908 EVT_NOTIFY_SIGNAL,\r
909 TPL_CALLBACK,\r
910 InitializeSmmCorePerformanceLib,\r
911 NULL,\r
912 &Event\r
913 );\r
914 ASSERT_EFI_ERROR (Status);\r
915\r
916 //\r
917 // Register for protocol notifications on this event\r
918 //\r
919 Status = gBS->RegisterProtocolNotify (\r
920 &gEfiSmmBase2ProtocolGuid,\r
921 Event,\r
922 &Registration\r
923 );\r
924\r
925 ASSERT_EFI_ERROR (Status);\r
926\r
927 return EFI_SUCCESS;\r
928}\r
929\r
137fb13d
BD
930/**\r
931 Create performance record with event description and a timestamp.\r
932\r
933 @param CallerIdentifier - Image handle or pointer to caller ID GUID.\r
934 @param Guid - Pointer to a GUID.\r
935 @param String - Pointer to a string describing the measurement.\r
936 @param TimeStamp - 64-bit time stamp.\r
937 @param Address - Pointer to a location in memory relevant to the measurement.\r
938 @param Identifier - Performance identifier describing the type of measurement.\r
939 @param Attribute - The attribute of the measurement. According to attribute can create a start\r
940 record for PERF_START/PERF_START_EX, or a end record for PERF_END/PERF_END_EX,\r
941 or a general record for other Perf macros.\r
942\r
943 @retval EFI_SUCCESS - Successfully created performance record.\r
944 @retval EFI_OUT_OF_RESOURCES - Ran out of space to store the records.\r
945 @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL\r
946 pointer or invalid PerfId.\r
947**/\r
948EFI_STATUS\r
949EFIAPI\r
950CreatePerformanceMeasurement(\r
951 IN CONST VOID *CallerIdentifier, OPTIONAL\r
952 IN CONST VOID *Guid, OPTIONAL\r
953 IN CONST CHAR8 *String, OPTIONAL\r
954 IN UINT64 TimeStamp, OPTIONAL\r
955 IN UINT64 Address, OPTIONAL\r
956 IN UINT32 Identifier,\r
957 IN PERF_MEASUREMENT_ATTRIBUTE Attribute\r
958 )\r
959{\r
960 EFI_STATUS Status;\r
961\r
6b4d58a1
BD
962 Status = EFI_SUCCESS;\r
963\r
137fb13d 964 AcquireSpinLock (&mSmmFpdtLock);\r
6b4d58a1 965 Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, Address, (UINT16)Identifier, Attribute);\r
137fb13d
BD
966 ReleaseSpinLock (&mSmmFpdtLock);\r
967 return Status;\r
968}\r
969\r
d042c6e8 970/**\r
971 Adds a record at the end of the performance measurement log\r
972 that records the start time of a performance measurement.\r
973\r
974 Adds a record to the end of the performance measurement log\r
f0da4d7d 975 that contains the Handle, Token, Module and Identifier.\r
d042c6e8 976 The end time of the new record must be set to zero.\r
977 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.\r
978 If TimeStamp is zero, the start time in the record is filled in with the value\r
979 read from the current time stamp.\r
980\r
981 @param Handle Pointer to environment specific context used\r
982 to identify the component being measured.\r
983 @param Token Pointer to a Null-terminated ASCII string\r
984 that identifies the component being measured.\r
985 @param Module Pointer to a Null-terminated ASCII string\r
986 that identifies the module being measured.\r
987 @param TimeStamp 64-bit time stamp.\r
f0da4d7d
SZ
988 @param Identifier 32-bit identifier. If the value is 0, the created record\r
989 is same as the one created by StartPerformanceMeasurement.\r
d042c6e8 990\r
991 @retval RETURN_SUCCESS The start of the measurement was recorded.\r
992 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.\r
993\r
994**/\r
995RETURN_STATUS\r
996EFIAPI\r
f0da4d7d 997StartPerformanceMeasurementEx (\r
d042c6e8 998 IN CONST VOID *Handle, OPTIONAL\r
999 IN CONST CHAR8 *Token, OPTIONAL\r
1000 IN CONST CHAR8 *Module, OPTIONAL\r
f0da4d7d
SZ
1001 IN UINT64 TimeStamp,\r
1002 IN UINT32 Identifier\r
d042c6e8 1003 )\r
1004{\r
137fb13d
BD
1005 CONST CHAR8 *String;\r
1006\r
1007 if (Token != NULL) {\r
1008 String = Token;\r
1009 } else if (Module != NULL) {\r
1010 String = Module;\r
1011 } else {\r
1012 String = NULL;\r
1013 }\r
1014\r
1015 return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfStartEntry);\r
d042c6e8 1016}\r
1017\r
1018/**\r
1019 Searches the performance measurement log from the beginning of the log\r
1020 for the first matching record that contains a zero end time and fills in a valid end time.\r
1021\r
1022 Searches the performance measurement log from the beginning of the log\r
2001f84e 1023 for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.\r
d042c6e8 1024 If the record can not be found then return RETURN_NOT_FOUND.\r
1025 If the record is found and TimeStamp is not zero,\r
1026 then the end time in the record is filled in with the value specified by TimeStamp.\r
1027 If the record is found and TimeStamp is zero, then the end time in the matching record\r
1028 is filled in with the current time stamp value.\r
1029\r
1030 @param Handle Pointer to environment specific context used\r
1031 to identify the component being measured.\r
1032 @param Token Pointer to a Null-terminated ASCII string\r
1033 that identifies the component being measured.\r
1034 @param Module Pointer to a Null-terminated ASCII string\r
1035 that identifies the module being measured.\r
1036 @param TimeStamp 64-bit time stamp.\r
f0da4d7d
SZ
1037 @param Identifier 32-bit identifier. If the value is 0, the found record\r
1038 is same as the one found by EndPerformanceMeasurement.\r
d042c6e8 1039\r
1040 @retval RETURN_SUCCESS The end of the measurement was recorded.\r
1041 @retval RETURN_NOT_FOUND The specified measurement record could not be found.\r
1042\r
1043**/\r
1044RETURN_STATUS\r
1045EFIAPI\r
f0da4d7d 1046EndPerformanceMeasurementEx (\r
d042c6e8 1047 IN CONST VOID *Handle, OPTIONAL\r
1048 IN CONST CHAR8 *Token, OPTIONAL\r
1049 IN CONST CHAR8 *Module, OPTIONAL\r
f0da4d7d
SZ
1050 IN UINT64 TimeStamp,\r
1051 IN UINT32 Identifier\r
d042c6e8 1052 )\r
1053{\r
137fb13d
BD
1054 CONST CHAR8 *String;\r
1055\r
1056 if (Token != NULL) {\r
1057 String = Token;\r
1058 } else if (Module != NULL) {\r
1059 String = Module;\r
1060 } else {\r
1061 String = NULL;\r
1062 }\r
1063\r
1064 return (RETURN_STATUS)CreatePerformanceMeasurement (Handle, NULL, String, TimeStamp, 0, Identifier, PerfEndEntry);\r
d042c6e8 1065}\r
1066\r
1067/**\r
1068 Attempts to retrieve a performance measurement log entry from the performance measurement log.\r
f0da4d7d
SZ
1069 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,\r
1070 and then assign the Identifier with 0.\r
d042c6e8 1071\r
2001f84e
DB
1072 !!! Not Support!!!\r
1073\r
d042c6e8 1074 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is\r
1075 zero on entry, then an attempt is made to retrieve the first entry from the performance log,\r
1076 and the key for the second entry in the log is returned. If the performance log is empty,\r
1077 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance\r
1078 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is\r
1079 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is\r
1080 retrieved and an implementation specific non-zero key value that specifies the end of the performance\r
1081 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry\r
1082 is retrieved and zero is returned. In the cases where a performance log entry can be returned,\r
f0da4d7d 1083 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.\r
d042c6e8 1084 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().\r
1085 If Handle is NULL, then ASSERT().\r
1086 If Token is NULL, then ASSERT().\r
1087 If Module is NULL, then ASSERT().\r
1088 If StartTimeStamp is NULL, then ASSERT().\r
1089 If EndTimeStamp is NULL, then ASSERT().\r
f0da4d7d 1090 If Identifier is NULL, then ASSERT().\r
d042c6e8 1091\r
1092 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.\r
1093 0, then the first performance measurement log entry is retrieved.\r
1094 On exit, the key of the next performance log entry.\r
1095 @param Handle Pointer to environment specific context used to identify the component\r
1096 being measured.\r
1097 @param Token Pointer to a Null-terminated ASCII string that identifies the component\r
1098 being measured.\r
1099 @param Module Pointer to a Null-terminated ASCII string that identifies the module\r
1100 being measured.\r
1101 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement\r
1102 was started.\r
1103 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement\r
1104 was ended.\r
f0da4d7d 1105 @param Identifier Pointer to the 32-bit identifier that was recorded.\r
d042c6e8 1106\r
1107 @return The key for the next performance log entry (in general case).\r
1108\r
1109**/\r
1110UINTN\r
1111EFIAPI\r
f0da4d7d 1112GetPerformanceMeasurementEx (\r
2001f84e 1113 IN UINTN LogEntryKey,\r
d042c6e8 1114 OUT CONST VOID **Handle,\r
1115 OUT CONST CHAR8 **Token,\r
1116 OUT CONST CHAR8 **Module,\r
1117 OUT UINT64 *StartTimeStamp,\r
f0da4d7d
SZ
1118 OUT UINT64 *EndTimeStamp,\r
1119 OUT UINT32 *Identifier\r
d042c6e8 1120 )\r
1121{\r
2001f84e 1122 return 0;\r
d042c6e8 1123}\r
1124\r
f0da4d7d
SZ
1125/**\r
1126 Adds a record at the end of the performance measurement log\r
1127 that records the start time of a performance measurement.\r
1128\r
1129 Adds a record to the end of the performance measurement log\r
1130 that contains the Handle, Token, and Module.\r
1131 The end time of the new record must be set to zero.\r
1132 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.\r
1133 If TimeStamp is zero, the start time in the record is filled in with the value\r
1134 read from the current time stamp.\r
1135\r
1136 @param Handle Pointer to environment specific context used\r
1137 to identify the component being measured.\r
1138 @param Token Pointer to a Null-terminated ASCII string\r
1139 that identifies the component being measured.\r
1140 @param Module Pointer to a Null-terminated ASCII string\r
1141 that identifies the module being measured.\r
1142 @param TimeStamp 64-bit time stamp.\r
1143\r
1144 @retval RETURN_SUCCESS The start of the measurement was recorded.\r
1145 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.\r
1146\r
1147**/\r
1148RETURN_STATUS\r
1149EFIAPI\r
1150StartPerformanceMeasurement (\r
1151 IN CONST VOID *Handle, OPTIONAL\r
1152 IN CONST CHAR8 *Token, OPTIONAL\r
1153 IN CONST CHAR8 *Module, OPTIONAL\r
1154 IN UINT64 TimeStamp\r
1155 )\r
1156{\r
137fb13d 1157 return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);\r
f0da4d7d
SZ
1158}\r
1159\r
1160/**\r
1161 Searches the performance measurement log from the beginning of the log\r
1162 for the first matching record that contains a zero end time and fills in a valid end time.\r
1163\r
1164 Searches the performance measurement log from the beginning of the log\r
1165 for the first record that matches Handle, Token, and Module and has an end time value of zero.\r
1166 If the record can not be found then return RETURN_NOT_FOUND.\r
1167 If the record is found and TimeStamp is not zero,\r
1168 then the end time in the record is filled in with the value specified by TimeStamp.\r
1169 If the record is found and TimeStamp is zero, then the end time in the matching record\r
1170 is filled in with the current time stamp value.\r
1171\r
1172 @param Handle Pointer to environment specific context used\r
1173 to identify the component being measured.\r
1174 @param Token Pointer to a Null-terminated ASCII string\r
1175 that identifies the component being measured.\r
1176 @param Module Pointer to a Null-terminated ASCII string\r
1177 that identifies the module being measured.\r
1178 @param TimeStamp 64-bit time stamp.\r
1179\r
1180 @retval RETURN_SUCCESS The end of the measurement was recorded.\r
1181 @retval RETURN_NOT_FOUND The specified measurement record could not be found.\r
1182\r
1183**/\r
1184RETURN_STATUS\r
1185EFIAPI\r
1186EndPerformanceMeasurement (\r
1187 IN CONST VOID *Handle, OPTIONAL\r
1188 IN CONST CHAR8 *Token, OPTIONAL\r
1189 IN CONST CHAR8 *Module, OPTIONAL\r
1190 IN UINT64 TimeStamp\r
1191 )\r
1192{\r
137fb13d 1193 return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);\r
f0da4d7d
SZ
1194}\r
1195\r
1196/**\r
1197 Attempts to retrieve a performance measurement log entry from the performance measurement log.\r
1198 It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,\r
1199 and then eliminate the Identifier.\r
1200\r
2001f84e
DB
1201 !!! Not Support!!!\r
1202\r
f0da4d7d
SZ
1203 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is\r
1204 zero on entry, then an attempt is made to retrieve the first entry from the performance log,\r
1205 and the key for the second entry in the log is returned. If the performance log is empty,\r
1206 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance\r
1207 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is\r
1208 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is\r
1209 retrieved and an implementation specific non-zero key value that specifies the end of the performance\r
1210 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry\r
1211 is retrieved and zero is returned. In the cases where a performance log entry can be returned,\r
1212 the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.\r
1213 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().\r
1214 If Handle is NULL, then ASSERT().\r
1215 If Token is NULL, then ASSERT().\r
1216 If Module is NULL, then ASSERT().\r
1217 If StartTimeStamp is NULL, then ASSERT().\r
1218 If EndTimeStamp is NULL, then ASSERT().\r
1219\r
1220 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.\r
1221 0, then the first performance measurement log entry is retrieved.\r
1222 On exit, the key of the next performance log entry.\r
1223 @param Handle Pointer to environment specific context used to identify the component\r
1224 being measured.\r
1225 @param Token Pointer to a Null-terminated ASCII string that identifies the component\r
1226 being measured.\r
1227 @param Module Pointer to a Null-terminated ASCII string that identifies the module\r
1228 being measured.\r
1229 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement\r
1230 was started.\r
1231 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement\r
1232 was ended.\r
1233\r
1234 @return The key for the next performance log entry (in general case).\r
1235\r
1236**/\r
1237UINTN\r
1238EFIAPI\r
1239GetPerformanceMeasurement (\r
1240 IN UINTN LogEntryKey,\r
1241 OUT CONST VOID **Handle,\r
1242 OUT CONST CHAR8 **Token,\r
1243 OUT CONST CHAR8 **Module,\r
1244 OUT UINT64 *StartTimeStamp,\r
1245 OUT UINT64 *EndTimeStamp\r
1246 )\r
1247{\r
2001f84e 1248 return 0;\r
f0da4d7d
SZ
1249}\r
1250\r
d042c6e8 1251/**\r
1252 Returns TRUE if the performance measurement macros are enabled.\r
1253\r
1254 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of\r
1255 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.\r
1256\r
1257 @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of\r
1258 PcdPerformanceLibraryPropertyMask is set.\r
1259 @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of\r
1260 PcdPerformanceLibraryPropertyMask is clear.\r
1261\r
1262**/\r
1263BOOLEAN\r
1264EFIAPI\r
1265PerformanceMeasurementEnabled (\r
1266 VOID\r
1267 )\r
1268{\r
2001f84e 1269 return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);\r
d042c6e8 1270}\r
6b4d58a1
BD
1271\r
1272/**\r
1273 Create performance record with event description and a timestamp.\r
1274\r
1275 @param CallerIdentifier - Image handle or pointer to caller ID GUID\r
1276 @param Guid - Pointer to a GUID\r
1277 @param String - Pointer to a string describing the measurement\r
1278 @param Address - Pointer to a location in memory relevant to the measurement\r
1279 @param Identifier - Performance identifier describing the type of measurement\r
1280\r
1281 @retval RETURN_SUCCESS - Successfully created performance record\r
1282 @retval RETURN_OUT_OF_RESOURCES - Ran out of space to store the records\r
1283 @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - NULL\r
1284 pointer or invalid PerfId\r
1285\r
1286**/\r
1287RETURN_STATUS\r
1288EFIAPI\r
1289LogPerformanceMeasurement (\r
1290 IN CONST VOID *CallerIdentifier,\r
1291 IN CONST VOID *Guid, OPTIONAL\r
1292 IN CONST CHAR8 *String, OPTIONAL\r
1293 IN UINT64 Address, OPTIONAL\r
1294 IN UINT32 Identifier\r
1295 )\r
1296{\r
1297 return (RETURN_STATUS)CreatePerformanceMeasurement (CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);\r
1298}\r
1299\r
1300/**\r
1301 Check whether the specified performance measurement can be logged.\r
1302\r
1303 This function returns TRUE when the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of PcdPerformanceLibraryPropertyMask is set\r
1304 and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.\r
1305\r
1306 @param Type - Type of the performance measurement entry.\r
1307\r
1308 @retval TRUE The performance measurement can be logged.\r
1309 @retval FALSE The performance measurement can NOT be logged.\r
1310\r
1311**/\r
1312BOOLEAN\r
1313EFIAPI\r
1314LogPerformanceMeasurementEnabled (\r
1315 IN CONST UINTN Type\r
1316 )\r
1317{\r
1318 //\r
1319 // When Performance measurement is enabled and the type is not filtered, the performance can be logged.\r
1320 //\r
1321 if (PerformanceMeasurementEnabled () && (PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {\r
1322 return TRUE;\r
1323 }\r
1324 return FALSE;\r
1325}\r
1326\r