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