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