]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
MdeModulePkg/PerfLib: Add NULL pointer check for "Token"
[mirror_edk2.git] / MdeModulePkg / Library / DxeCorePerformanceLib / DxeCorePerformanceLib.c
1 /** @file
2 Performance library instance mainly used by DxeCore.
3
4 This library provides the performance measurement interfaces and initializes performance
5 logging for DXE phase. It first initializes its private global data structure for
6 performance logging and saves the performance GUIDed HOB passed from PEI phase.
7 It initializes DXE phase performance logging by publishing the Performance and PerformanceEx Protocol,
8 which are consumed by DxePerformanceLib to logging performance data in DXE phase.
9
10 This library is mainly used by DxeCore to start performance logging to ensure that
11 Performance Protocol is installed at the very beginning of DXE phase.
12
13 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
14 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
15 This program and the accompanying materials
16 are licensed and made available under the terms and conditions of the BSD License
17 which accompanies this distribution. The full text of the license may be found at
18 http://opensource.org/licenses/bsd-license.php
19
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
22
23 **/
24
25
26 #include "DxeCorePerformanceLibInternal.h"
27
28 //
29 // Data for FPDT performance records.
30 //
31 #define SMM_BOOT_RECORD_COMM_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE))
32 #define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
33 #define FIRMWARE_RECORD_BUFFER 0x10000
34 #define CACHE_HANDLE_GUID_COUNT 0x800
35
36 BOOT_PERFORMANCE_TABLE *mAcpiBootPerformanceTable = NULL;
37 BOOT_PERFORMANCE_TABLE mBootPerformanceTableTemplate = {
38 {
39 EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE,
40 sizeof (BOOT_PERFORMANCE_TABLE)
41 },
42 {
43 {
44 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT, // Type
45 sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD), // Length
46 EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT // Revision
47 },
48 0, // Reserved
49 //
50 // These values will be updated at runtime.
51 //
52 0, // ResetEnd
53 0, // OsLoaderLoadImageStart
54 0, // OsLoaderStartImageStart
55 0, // ExitBootServicesEntry
56 0 // ExitBootServicesExit
57 }
58 };
59
60 typedef struct {
61 EFI_HANDLE Handle;
62 CHAR8 NameString[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
63 EFI_GUID ModuleGuid;
64 } HANDLE_GUID_MAP;
65
66 HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];
67 UINTN mCachePairCount = 0;
68
69 UINT32 mLoadImageCount = 0;
70 UINT32 mPerformanceLength = 0;
71 UINT32 mMaxPerformanceLength = 0;
72 UINT32 mBootRecordSize = 0;
73 UINT32 mBootRecordMaxSize = 0;
74
75 BOOLEAN mFpdtBufferIsReported = FALSE;
76 BOOLEAN mLackSpaceIsReported = FALSE;
77 CHAR8 *mPlatformLanguage = NULL;
78 UINT8 *mPerformancePointer = NULL;
79 UINT8 *mBootRecordBuffer = NULL;
80 BOOLEAN mLockInsertRecord = FALSE;
81
82 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *mDevicePathToText = NULL;
83
84 //
85 // Interfaces for Performance Protocol.
86 //
87 PERFORMANCE_PROTOCOL mPerformanceInterface = {
88 StartGauge,
89 EndGauge,
90 GetGauge
91 };
92
93 //
94 // Interfaces for PerformanceEx Protocol.
95 //
96 PERFORMANCE_EX_PROTOCOL mPerformanceExInterface = {
97 StartGaugeEx,
98 EndGaugeEx,
99 GetGaugeEx
100 };
101
102 PERFORMANCE_PROPERTY mPerformanceProperty;
103
104 /**
105 Check whether the Token is a known one which is uesed by core.
106
107 @param Token Pointer to a Null-terminated ASCII string
108
109 @retval TRUE Is a known one used by core.
110 @retval FALSE Not a known one.
111
112 **/
113 BOOLEAN
114 IsKnownTokens (
115 IN CONST CHAR8 *Token
116 )
117 {
118 if (Token == NULL) {
119 return FALSE;
120 }
121
122 if (AsciiStrCmp (Token, SEC_TOK) == 0 ||
123 AsciiStrCmp (Token, PEI_TOK) == 0 ||
124 AsciiStrCmp (Token, DXE_TOK) == 0 ||
125 AsciiStrCmp (Token, BDS_TOK) == 0 ||
126 AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0 ||
127 AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0 ||
128 AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0 ||
129 AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0 ||
130 AsciiStrCmp (Token, START_IMAGE_TOK) == 0 ||
131 AsciiStrCmp (Token, PEIM_TOK) == 0) {
132 return TRUE;
133 } else {
134 return FALSE;
135 }
136 }
137
138 /**
139 Check whether the ID is a known one which map to the known Token.
140
141 @param Identifier 32-bit identifier.
142
143 @retval TRUE Is a known one used by core.
144 @retval FALSE Not a known one.
145
146 **/
147 BOOLEAN
148 IsKnownID (
149 IN UINT32 Identifier
150 )
151 {
152 if (Identifier == MODULE_START_ID ||
153 Identifier == MODULE_END_ID ||
154 Identifier == MODULE_LOADIMAGE_START_ID ||
155 Identifier == MODULE_LOADIMAGE_END_ID ||
156 Identifier == MODULE_DB_START_ID ||
157 Identifier == MODULE_DB_END_ID ||
158 Identifier == MODULE_DB_SUPPORT_START_ID ||
159 Identifier == MODULE_DB_SUPPORT_END_ID ||
160 Identifier == MODULE_DB_STOP_START_ID ||
161 Identifier == MODULE_DB_STOP_END_ID) {
162 return TRUE;
163 } else {
164 return FALSE;
165 }
166 }
167
168 /**
169 Allocate EfiReservedMemoryType below 4G memory address.
170
171 This function allocates EfiReservedMemoryType below 4G memory address.
172
173 @param[in] Size Size of memory to allocate.
174
175 @return Allocated address for output.
176
177 **/
178 VOID *
179 FpdtAllocateReservedMemoryBelow4G (
180 IN UINTN Size
181 )
182 {
183 UINTN Pages;
184 EFI_PHYSICAL_ADDRESS Address;
185 EFI_STATUS Status;
186 VOID *Buffer;
187
188 Buffer = NULL;
189 Pages = EFI_SIZE_TO_PAGES (Size);
190 Address = 0xffffffff;
191
192 Status = gBS->AllocatePages (
193 AllocateMaxAddress,
194 EfiReservedMemoryType,
195 Pages,
196 &Address
197 );
198 ASSERT_EFI_ERROR (Status);
199
200 if (!EFI_ERROR (Status)) {
201 Buffer = (VOID *) (UINTN) Address;
202 ZeroMem (Buffer, Size);
203 }
204
205 return Buffer;
206 }
207
208 /**
209 Allocate buffer for Boot Performance table.
210
211 @return Status code.
212
213 **/
214 EFI_STATUS
215 AllocateBootPerformanceTable (
216 )
217 {
218 EFI_STATUS Status;
219 UINTN Size;
220 UINT8 *SmmBootRecordCommBuffer;
221 EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;
222 SMM_BOOT_RECORD_COMMUNICATE *SmmCommData;
223 UINTN CommSize;
224 UINTN BootPerformanceDataSize;
225 UINT8 *BootPerformanceData;
226 EFI_SMM_COMMUNICATION_PROTOCOL *Communication;
227 FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;
228 EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *SmmCommRegionTable;
229 EFI_MEMORY_DESCRIPTOR *SmmCommMemRegion;
230 UINTN Index;
231 VOID *SmmBootRecordData;
232 UINTN SmmBootRecordDataSize;
233 UINTN ReservedMemSize;
234
235 //
236 // Collect boot records from SMM drivers.
237 //
238 SmmBootRecordCommBuffer = NULL;
239 SmmCommData = NULL;
240 SmmBootRecordData = NULL;
241 SmmBootRecordDataSize = 0;
242 ReservedMemSize = 0;
243 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication);
244 if (!EFI_ERROR (Status)) {
245 //
246 // Initialize communicate buffer
247 // Get the prepared Reserved Memory Range
248 //
249 Status = EfiGetSystemConfigurationTable (
250 &gEdkiiPiSmmCommunicationRegionTableGuid,
251 (VOID **) &SmmCommRegionTable
252 );
253 if (!EFI_ERROR (Status)) {
254 ASSERT (SmmCommRegionTable != NULL);
255 SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) (SmmCommRegionTable + 1);
256 for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries; Index ++) {
257 if (SmmCommMemRegion->Type == EfiConventionalMemory) {
258 break;
259 }
260 SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);
261 }
262 ASSERT (Index < SmmCommRegionTable->NumberOfEntries);
263 ASSERT (SmmCommMemRegion->PhysicalStart > 0);
264 ASSERT (SmmCommMemRegion->NumberOfPages > 0);
265 ReservedMemSize = (UINTN) SmmCommMemRegion->NumberOfPages * EFI_PAGE_SIZE;
266
267 //
268 // Check enough reserved memory space
269 //
270 if (ReservedMemSize > SMM_BOOT_RECORD_COMM_SIZE) {
271 SmmBootRecordCommBuffer = (VOID *) (UINTN) SmmCommMemRegion->PhysicalStart;
272 SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER*)SmmBootRecordCommBuffer;
273 SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)SmmCommBufferHeader->Data;
274 ZeroMem((UINT8*)SmmCommData, sizeof(SMM_BOOT_RECORD_COMMUNICATE));
275
276 CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gEfiFirmwarePerformanceGuid);
277 SmmCommBufferHeader->MessageLength = sizeof(SMM_BOOT_RECORD_COMMUNICATE);
278 CommSize = SMM_BOOT_RECORD_COMM_SIZE;
279
280 //
281 // Get the size of boot records.
282 //
283 SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE;
284 SmmCommData->BootRecordData = NULL;
285 Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
286 ASSERT_EFI_ERROR (Status);
287
288 if (!EFI_ERROR (SmmCommData->ReturnStatus) && SmmCommData->BootRecordSize != 0) {
289 //
290 // Get all boot records
291 //
292 SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET;
293 SmmBootRecordDataSize = SmmCommData->BootRecordSize;
294 SmmBootRecordData = AllocateZeroPool(SmmBootRecordDataSize);
295 ASSERT (SmmBootRecordData != NULL);
296 SmmCommData->BootRecordOffset = 0;
297 SmmCommData->BootRecordData = (VOID *) ((UINTN) SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE);
298 SmmCommData->BootRecordSize = ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE;
299 while (SmmCommData->BootRecordOffset < SmmBootRecordDataSize) {
300 Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
301 ASSERT_EFI_ERROR (Status);
302 ASSERT_EFI_ERROR(SmmCommData->ReturnStatus);
303 if (SmmCommData->BootRecordOffset + SmmCommData->BootRecordSize > SmmBootRecordDataSize) {
304 CopyMem ((UINT8 *) SmmBootRecordData + SmmCommData->BootRecordOffset, SmmCommData->BootRecordData, SmmBootRecordDataSize - SmmCommData->BootRecordOffset);
305 } else {
306 CopyMem ((UINT8 *) SmmBootRecordData + SmmCommData->BootRecordOffset, SmmCommData->BootRecordData, SmmCommData->BootRecordSize);
307 }
308 SmmCommData->BootRecordOffset = SmmCommData->BootRecordOffset + SmmCommData->BootRecordSize;
309 }
310 }
311 }
312 }
313 }
314
315 //
316 // Prepare memory for Boot Performance table.
317 // Boot Performance table includes BasicBoot record, and one or more appended Boot Records.
318 //
319 BootPerformanceDataSize = sizeof (BOOT_PERFORMANCE_TABLE) + mPerformanceLength + PcdGet32 (PcdExtFpdtBootRecordPadSize);
320 if (SmmCommData != NULL) {
321 BootPerformanceDataSize += SmmBootRecordDataSize;
322 }
323
324 //
325 // Try to allocate the same runtime buffer as last time boot.
326 //
327 ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));
328 Size = sizeof (PerformanceVariable);
329 Status = gRT->GetVariable (
330 EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
331 &gEfiFirmwarePerformanceGuid,
332 NULL,
333 &Size,
334 &PerformanceVariable
335 );
336 if (!EFI_ERROR (Status)) {
337 Status = gBS->AllocatePages (
338 AllocateAddress,
339 EfiReservedMemoryType,
340 EFI_SIZE_TO_PAGES (BootPerformanceDataSize),
341 &PerformanceVariable.BootPerformanceTablePointer
342 );
343 if (!EFI_ERROR (Status)) {
344 mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.BootPerformanceTablePointer;
345 }
346 }
347
348 if (mAcpiBootPerformanceTable == NULL) {
349 //
350 // Fail to allocate at specified address, continue to allocate at any address.
351 //
352 mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) FpdtAllocateReservedMemoryBelow4G (BootPerformanceDataSize);
353 }
354 DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable));
355
356 if (mAcpiBootPerformanceTable == NULL) {
357 if (SmmCommData != NULL && SmmBootRecordData != NULL) {
358 FreePool (SmmBootRecordData);
359 }
360 return EFI_OUT_OF_RESOURCES;
361 }
362
363 //
364 // Prepare Boot Performance Table.
365 //
366 BootPerformanceData = (UINT8 *) mAcpiBootPerformanceTable;
367 //
368 // Fill Basic Boot record to Boot Performance Table.
369 //
370 CopyMem (mAcpiBootPerformanceTable, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate));
371 BootPerformanceData = BootPerformanceData + mAcpiBootPerformanceTable->Header.Length;
372 //
373 // Fill Boot records from boot drivers.
374 //
375 if (mPerformancePointer != NULL) {
376 CopyMem (BootPerformanceData, mPerformancePointer, mPerformanceLength);
377 mAcpiBootPerformanceTable->Header.Length += mPerformanceLength;
378 BootPerformanceData = BootPerformanceData + mPerformanceLength;
379 FreePool (mPerformancePointer);
380 mPerformancePointer = NULL;
381 mPerformanceLength = 0;
382 mMaxPerformanceLength = 0;
383 }
384 if (SmmCommData != NULL && SmmBootRecordData != NULL) {
385 //
386 // Fill Boot records from SMM drivers.
387 //
388 CopyMem (BootPerformanceData, SmmBootRecordData, SmmBootRecordDataSize);
389 FreePool (SmmBootRecordData);
390 mAcpiBootPerformanceTable->Header.Length = (UINT32) (mAcpiBootPerformanceTable->Header.Length + SmmBootRecordDataSize);
391 BootPerformanceData = BootPerformanceData + SmmBootRecordDataSize;
392 }
393
394 mBootRecordBuffer = (UINT8 *) mAcpiBootPerformanceTable;
395 mBootRecordSize = mAcpiBootPerformanceTable->Header.Length;
396 mBootRecordMaxSize = mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);
397
398 return EFI_SUCCESS;
399 }
400
401 /**
402 Get a human readable module name and module guid for the given image handle.
403 If module name can't be found, "" string will return.
404 If module guid can't be found, Zero Guid will return.
405
406 @param Handle Image handle or Controller handle.
407 @param NameString The ascii string will be filled into it. If not found, null string will return.
408 @param BufferSize Size of the input NameString buffer.
409 @param ModuleGuid Point to the guid buffer to store the got module guid value.
410
411 @retval EFI_SUCCESS Successfully get module name and guid.
412 @retval EFI_INVALID_PARAMETER The input parameter NameString is NULL.
413 @retval other value Module Name can't be got.
414 **/
415 EFI_STATUS
416 GetModuleInfoFromHandle (
417 IN EFI_HANDLE Handle,
418 OUT CHAR8 *NameString,
419 IN UINTN BufferSize,
420 OUT EFI_GUID *ModuleGuid OPTIONAL
421 )
422 {
423 EFI_STATUS Status;
424 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
425 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
426 CHAR8 *PdbFileName;
427 EFI_GUID *TempGuid;
428 UINTN StartIndex;
429 UINTN Index;
430 INTN Count;
431 BOOLEAN ModuleGuidIsGet;
432 UINTN StringSize;
433 CHAR16 *StringPtr;
434 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
435 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
436
437 if (NameString == NULL || BufferSize == 0) {
438 return EFI_INVALID_PARAMETER;
439 }
440 //
441 // Try to get the ModuleGuid and name string form the caached array.
442 //
443 if (mCachePairCount > 0) {
444 for (Count = mCachePairCount -1; Count >= 0; Count--) {
445 if (Handle == mCacheHandleGuidTable[Count].Handle) {
446 CopyGuid (ModuleGuid, &mCacheHandleGuidTable[Count].ModuleGuid);
447 AsciiStrCpyS (NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, mCacheHandleGuidTable[Count].NameString);
448 return EFI_SUCCESS;
449 }
450 }
451 }
452
453 Status = EFI_INVALID_PARAMETER;
454 LoadedImage = NULL;
455 ModuleGuidIsGet = FALSE;
456
457 //
458 // Initialize GUID as zero value.
459 //
460 TempGuid = &gZeroGuid;
461 //
462 // Initialize it as "" string.
463 //
464 NameString[0] = 0;
465
466 if (Handle != NULL) {
467 //
468 // Try Handle as ImageHandle.
469 //
470 Status = gBS->HandleProtocol (
471 Handle,
472 &gEfiLoadedImageProtocolGuid,
473 (VOID**) &LoadedImage
474 );
475
476 if (EFI_ERROR (Status)) {
477 //
478 // Try Handle as Controller Handle
479 //
480 Status = gBS->OpenProtocol (
481 Handle,
482 &gEfiDriverBindingProtocolGuid,
483 (VOID **) &DriverBinding,
484 NULL,
485 NULL,
486 EFI_OPEN_PROTOCOL_GET_PROTOCOL
487 );
488 if (!EFI_ERROR (Status)) {
489 //
490 // Get Image protocol from ImageHandle
491 //
492 Status = gBS->HandleProtocol (
493 DriverBinding->ImageHandle,
494 &gEfiLoadedImageProtocolGuid,
495 (VOID**) &LoadedImage
496 );
497 }
498 }
499 }
500
501 if (!EFI_ERROR (Status) && LoadedImage != NULL) {
502 //
503 // Get Module Guid from DevicePath.
504 //
505 if (LoadedImage->FilePath != NULL &&
506 LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH &&
507 LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP
508 ) {
509 //
510 // Determine GUID associated with module logging performance
511 //
512 ModuleGuidIsGet = TRUE;
513 FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath;
514 TempGuid = &FvFilePath->FvFileName;
515 }
516
517 //
518 // Method 1 Get Module Name from PDB string.
519 //
520 PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);
521 if (PdbFileName != NULL && BufferSize > 0) {
522 StartIndex = 0;
523 for (Index = 0; PdbFileName[Index] != 0; Index++) {
524 if ((PdbFileName[Index] == '\\') || (PdbFileName[Index] == '/')) {
525 StartIndex = Index + 1;
526 }
527 }
528 //
529 // Copy the PDB file name to our temporary string.
530 // If the length is bigger than BufferSize, trim the redudant characters to avoid overflow in array boundary.
531 //
532 for (Index = 0; Index < BufferSize - 1; Index++) {
533 NameString[Index] = PdbFileName[Index + StartIndex];
534 if (NameString[Index] == 0 || NameString[Index] == '.') {
535 NameString[Index] = 0;
536 break;
537 }
538 }
539
540 if (Index == BufferSize - 1) {
541 NameString[Index] = 0;
542 }
543 //
544 // Module Name is got.
545 //
546 goto Done;
547 }
548 }
549
550 //
551 // Method 2: Get the name string from ComponentName2 protocol
552 //
553 Status = gBS->HandleProtocol (
554 Handle,
555 &gEfiComponentName2ProtocolGuid,
556 (VOID **) &ComponentName2
557 );
558 if (!EFI_ERROR (Status)) {
559 //
560 // Get the current platform language setting
561 //
562 if (mPlatformLanguage == NULL) {
563 GetEfiGlobalVariable2 (L"PlatformLang", (VOID **) &mPlatformLanguage, NULL);
564 }
565 if (mPlatformLanguage != NULL) {
566 Status = ComponentName2->GetDriverName (
567 ComponentName2,
568 mPlatformLanguage != NULL ? mPlatformLanguage : "en-US",
569 &StringPtr
570 );
571 if (!EFI_ERROR (Status)) {
572 for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
573 NameString[Index] = (CHAR8) StringPtr[Index];
574 }
575 NameString[Index] = 0;
576 //
577 // Module Name is got.
578 //
579 goto Done;
580 }
581 }
582 }
583
584 if (ModuleGuidIsGet) {
585 //
586 // Method 3 Try to get the image's FFS UI section by image GUID
587 //
588 StringPtr = NULL;
589 StringSize = 0;
590 Status = GetSectionFromAnyFv (
591 TempGuid,
592 EFI_SECTION_USER_INTERFACE,
593 0,
594 (VOID **) &StringPtr,
595 &StringSize
596 );
597
598 if (!EFI_ERROR (Status)) {
599 //
600 // Method 3. Get the name string from FFS UI section
601 //
602 for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
603 NameString[Index] = (CHAR8) StringPtr[Index];
604 }
605 NameString[Index] = 0;
606 FreePool (StringPtr);
607 }
608 }
609
610 Done:
611 //
612 // Copy Module Guid
613 //
614 if (ModuleGuid != NULL) {
615 CopyGuid (ModuleGuid, TempGuid);
616 if (IsZeroGuid(TempGuid) && (Handle != NULL) && !ModuleGuidIsGet) {
617 // Handle is GUID
618 CopyGuid (ModuleGuid, (EFI_GUID *) Handle);
619 }
620 }
621
622 //
623 // Cache the Handle and Guid pairs.
624 //
625 if (mCachePairCount < CACHE_HANDLE_GUID_COUNT) {
626 mCacheHandleGuidTable[mCachePairCount].Handle = Handle;
627 CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, ModuleGuid);
628 AsciiStrCpyS (mCacheHandleGuidTable[mCachePairCount].NameString, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, NameString);
629 mCachePairCount ++;
630 }
631
632 return Status;
633 }
634
635 /**
636 Get the FPDT record info.
637
638 @param IsStart TRUE if the performance log is start log.
639 @param Handle Pointer to environment specific context used
640 to identify the component being measured.
641 @param Token Pointer to a Null-terminated ASCII string
642 that identifies the component being measured.
643 @param Module Pointer to a Null-terminated ASCII string
644 that identifies the module being measured.
645 @param RecordInfo On return, pointer to the info of the record.
646 @param UseModuleName Only useful for FPDT_DYNAMIC_STRING_EVENT_TYPE, indicate that whether need use
647 Module name to fill the string field in the FPDT_DYNAMIC_STRING_EVENT_RECORD.
648
649 @retval EFI_SUCCESS Get record info successfully.
650 @retval EFI_UNSUPPORTED No matched FPDT record.
651
652 **/
653 EFI_STATUS
654 GetFpdtRecordInfo (
655 IN BOOLEAN IsStart,
656 IN CONST VOID *Handle,
657 IN CONST CHAR8 *Token,
658 IN CONST CHAR8 *Module,
659 OUT FPDT_BASIC_RECORD_INFO *RecordInfo,
660 IN OUT BOOLEAN *UseModuleName
661 )
662 {
663 UINT16 RecordType;
664 UINTN StringSize;
665
666 RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE;
667
668 //
669 // Token to Type and Id.
670 //
671 if (Token != NULL) {
672 if (AsciiStrCmp (Token, START_IMAGE_TOK) == 0) { // "StartImage:"
673 *UseModuleName = TRUE;
674 RecordType = FPDT_GUID_EVENT_TYPE;
675 if (IsStart) {
676 RecordInfo->ProgressID = MODULE_START_ID;
677 } else {
678 RecordInfo->ProgressID = MODULE_END_ID;
679 }
680 } else if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) { // "LoadImage:"
681 *UseModuleName = TRUE;
682 RecordType = FPDT_GUID_QWORD_EVENT_TYPE;
683 if (IsStart) {
684 RecordInfo->ProgressID = MODULE_LOADIMAGE_START_ID;
685 } else {
686 RecordInfo->ProgressID = MODULE_LOADIMAGE_END_ID;
687 }
688 } else if (AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0) { // "DB:Start:"
689 *UseModuleName = TRUE;
690 if (IsStart) {
691 RecordInfo->ProgressID = MODULE_DB_START_ID;
692 RecordType = FPDT_GUID_QWORD_EVENT_TYPE;
693 } else {
694 RecordInfo->ProgressID = MODULE_DB_END_ID;
695 RecordType = FPDT_GUID_QWORD_STRING_EVENT_TYPE;
696 }
697 } else if (AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0) { // "DB:Support:"
698 *UseModuleName = TRUE;
699 if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
700 return RETURN_UNSUPPORTED;
701 }
702 RecordType = FPDT_GUID_QWORD_EVENT_TYPE;
703 if (IsStart) {
704 RecordInfo->ProgressID = MODULE_DB_SUPPORT_START_ID;
705 } else {
706 RecordInfo->ProgressID = MODULE_DB_SUPPORT_END_ID;
707 }
708 } else if (AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0) { // "DB:Stop:"
709 *UseModuleName = TRUE;
710 if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
711 return RETURN_UNSUPPORTED;
712 }
713 RecordType = FPDT_GUID_QWORD_EVENT_TYPE;
714 if (IsStart) {
715 RecordInfo->ProgressID = MODULE_DB_STOP_START_ID;
716 } else {
717 RecordInfo->ProgressID = MODULE_DB_STOP_END_ID;
718 }
719 } else if (AsciiStrCmp (Token, PEI_TOK) == 0 || // "PEI"
720 AsciiStrCmp (Token, DXE_TOK) == 0 || // "DXE"
721 AsciiStrCmp (Token, BDS_TOK) == 0) { // "BDS"
722 if (IsStart) {
723 RecordInfo->ProgressID = PERF_CROSSMODULE_START_ID;
724 } else {
725 RecordInfo->ProgressID = PERF_CROSSMODULE_END_ID;
726 }
727 } else { // Pref used in Modules.
728 if (IsStart) {
729 RecordInfo->ProgressID = PERF_INMODULE_START_ID;
730 } else {
731 RecordInfo->ProgressID = PERF_INMODULE_END_ID;
732 }
733 }
734 } else if (Handle!= NULL || Module != NULL) { // Pref used in Modules.
735 if (IsStart) {
736 RecordInfo->ProgressID = PERF_INMODULE_START_ID;
737 } else {
738 RecordInfo->ProgressID = PERF_INMODULE_END_ID;
739 }
740 } else {
741 return EFI_UNSUPPORTED;
742 }
743
744 //
745 // Get Record size baesed on the record type.
746 // When PcdEdkiiFpdtStringRecordEnableOnly is TRUE, all records are with type of FPDT_DYNAMIC_STRING_EVENT_TYPE.
747 //
748 if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
749 RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE;
750 RecordInfo->RecordSize = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE;
751 } else {
752 switch (RecordType) {
753 case FPDT_GUID_EVENT_TYPE:
754 RecordInfo->RecordSize = sizeof (FPDT_GUID_EVENT_RECORD);
755 break;
756
757 case FPDT_DYNAMIC_STRING_EVENT_TYPE:
758 if (*UseModuleName) {
759 StringSize = STRING_SIZE;
760 } else if (Token != NULL) {
761 StringSize = AsciiStrSize (Token);
762 } else if (Module != NULL) {
763 StringSize = AsciiStrSize (Module);
764 } else {
765 StringSize = STRING_SIZE;
766 }
767 if (StringSize > STRING_SIZE) {
768 StringSize = STRING_SIZE;
769 }
770 RecordInfo->RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize);
771 break;
772
773 case FPDT_GUID_QWORD_EVENT_TYPE:
774 RecordInfo->RecordSize = (UINT8)sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
775 break;
776
777 case FPDT_GUID_QWORD_STRING_EVENT_TYPE:
778 RecordInfo->RecordSize = (UINT8)sizeof (FPDT_GUID_QWORD_STRING_EVENT_RECORD);
779 break;
780
781 default:
782 //
783 // Record is unsupported yet, return EFI_UNSUPPORTED
784 //
785 return EFI_UNSUPPORTED;
786 }
787 }
788
789 RecordInfo->Type = RecordType;
790 return EFI_SUCCESS;
791 }
792
793 /**
794 Add performance log to FPDT boot record table.
795
796 @param IsStart TRUE if the performance log is start log.
797 @param Handle Pointer to environment specific context used
798 to identify the component being measured.
799 @param Token Pointer to a Null-terminated ASCII string
800 that identifies the component being measured.
801 @param Module Pointer to a Null-terminated ASCII string
802 that identifies the module being measured.
803 @param Ticker 64-bit time stamp.
804 @param Identifier 32-bit identifier. If the value is 0, the created record
805 is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
806
807 @retval EFI_SUCCESS Add FPDT boot record.
808 @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
809 @retval EFI_UNSUPPORTED No matched FPDT record.
810
811 **/
812 EFI_STATUS
813 InsertFpdtMeasurement (
814 IN BOOLEAN IsStart,
815 IN CONST VOID *Handle, OPTIONAL
816 IN CONST CHAR8 *Token, OPTIONAL
817 IN CONST CHAR8 *Module, OPTIONAL
818 IN UINT64 Ticker,
819 IN UINT32 Identifier
820 )
821 {
822 EFI_GUID ModuleGuid;
823 CHAR8 ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
824 EFI_STATUS Status;
825 FPDT_RECORD_PTR FpdtRecordPtr;
826 FPDT_BASIC_RECORD_INFO RecordInfo;
827 UINT64 TimeStamp;
828 UINTN DestMax;
829 UINTN StrLength;
830 CONST CHAR8 *StringPtr;
831 BOOLEAN UseModuleName;
832
833 StringPtr = NULL;
834 UseModuleName = FALSE;
835 ZeroMem (ModuleName, sizeof (ModuleName));
836
837 if (mLockInsertRecord) {
838 return EFI_UNSUPPORTED;
839 }
840
841 mLockInsertRecord = TRUE;
842
843 //
844 // Get record info (type, size, ProgressID and Module Guid).
845 //
846 Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo, &UseModuleName);
847 if (EFI_ERROR (Status)) {
848 mLockInsertRecord = FALSE;
849 return Status;
850 }
851
852 //
853 // If PERF_START()/PERF_END() have specified the ProgressID,it has high priority.
854 // !!! Note: If the Perf is not the known Token used in the core but have same
855 // ID with the core Token, this case will not be supported.
856 // And in currtnt usage mode, for the unkown ID, there is a general rule:
857 // If it is start pref: the lower 4 bits of the ID should be 0.
858 // If it is end pref: the lower 4 bits of the ID should not be 0.
859 // If input ID doesn't follow the rule, we will adjust it.
860 //
861 if ((Identifier != 0) && (IsKnownID (Identifier)) && (!IsKnownTokens (Token))) {
862 mLockInsertRecord = FALSE;
863 return EFI_UNSUPPORTED;
864 } else if ((Identifier != 0) && (!IsKnownID (Identifier)) && (!IsKnownTokens (Token))) {
865 if (IsStart && ((Identifier & 0x000F) != 0)) {
866 Identifier &= 0xFFF0;
867 } else if ((!IsStart) && ((Identifier & 0x000F) == 0)) {
868 Identifier += 1;
869 }
870 RecordInfo.ProgressID = (UINT16)Identifier;
871 }
872
873 if (mFpdtBufferIsReported) {
874 //
875 // Append Boot records to the boot performance table.
876 //
877 if (mBootRecordSize + RecordInfo.RecordSize > mBootRecordMaxSize) {
878 if (!mLackSpaceIsReported) {
879 DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: No enough space to save boot records\n"));
880 mLackSpaceIsReported = TRUE;
881 }
882 mLockInsertRecord = FALSE;
883 return EFI_OUT_OF_RESOURCES;
884 } else {
885 //
886 // Save boot record into BootPerformance table
887 //
888 FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + mBootRecordSize);
889 mBootRecordSize += RecordInfo.RecordSize;
890 mAcpiBootPerformanceTable->Header.Length += RecordInfo.RecordSize;
891 }
892 } else {
893 //
894 // Check if pre-allocated buffer is full
895 //
896 if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength) {
897 mPerformancePointer = ReallocatePool (
898 mPerformanceLength,
899 mPerformanceLength + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER,
900 mPerformancePointer
901 );
902
903 if (mPerformancePointer == NULL) {
904 mLockInsertRecord = FALSE;
905 return EFI_OUT_OF_RESOURCES;
906 }
907 mMaxPerformanceLength = mPerformanceLength + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER;
908 }
909 //
910 // Covert buffer to FPDT Ptr Union type.
911 //
912 FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mPerformanceLength);
913 mPerformanceLength += RecordInfo.RecordSize;
914 }
915
916 //
917 // Get the TimeStamp.
918 //
919 if (Ticker == 0) {
920 Ticker = GetPerformanceCounter ();
921 TimeStamp = GetTimeInNanoSecond (Ticker);
922 } else if (Ticker == 1) {
923 TimeStamp = 0;
924 } else {
925 TimeStamp = GetTimeInNanoSecond (Ticker);
926 }
927
928 //
929 // Get the ModuleName and ModuleGuid form the handle.
930 //
931 GetModuleInfoFromHandle ((EFI_HANDLE *)Handle, ModuleName, sizeof (ModuleName), &ModuleGuid);
932
933 //
934 // Fill in the record information.
935 //
936 switch (RecordInfo.Type) {
937 case FPDT_GUID_EVENT_TYPE:
938 FpdtRecordPtr.GuidEvent->Header.Type = FPDT_GUID_EVENT_TYPE;
939 FpdtRecordPtr.GuidEvent->Header.Length = RecordInfo.RecordSize;
940 FpdtRecordPtr.GuidEvent->Header.Revision = FPDT_RECORD_REVISION_1;
941 FpdtRecordPtr.GuidEvent->ProgressID = RecordInfo.ProgressID;
942 FpdtRecordPtr.GuidEvent->Timestamp = TimeStamp;
943 CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
944 break;
945
946 case FPDT_DYNAMIC_STRING_EVENT_TYPE:
947 FpdtRecordPtr.DynamicStringEvent->Header.Type = FPDT_DYNAMIC_STRING_EVENT_TYPE;
948 FpdtRecordPtr.DynamicStringEvent->Header.Length = RecordInfo.RecordSize;
949 FpdtRecordPtr.DynamicStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
950 FpdtRecordPtr.DynamicStringEvent->ProgressID = RecordInfo.ProgressID;
951 FpdtRecordPtr.DynamicStringEvent->Timestamp = TimeStamp;
952 CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
953
954 if (UseModuleName) {
955 StringPtr = ModuleName;
956 } else if (Token != NULL) {
957 StringPtr = Token;
958 } else if (Module != NULL) {
959 StringPtr = Module;
960 } else if (ModuleName != NULL) {
961 StringPtr = ModuleName;
962 }
963 if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) {
964 StrLength = AsciiStrLen (StringPtr);
965 DestMax = (RecordInfo.RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8);
966 if (StrLength >= DestMax) {
967 StrLength = DestMax -1;
968 }
969 AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StrLength);
970 } else {
971 AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name");
972 }
973 break;
974
975 case FPDT_GUID_QWORD_EVENT_TYPE:
976 FpdtRecordPtr.GuidQwordEvent->Header.Type = FPDT_GUID_QWORD_EVENT_TYPE;
977 FpdtRecordPtr.GuidQwordEvent->Header.Length = RecordInfo.RecordSize;
978 FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
979 FpdtRecordPtr.GuidQwordEvent->ProgressID = RecordInfo.ProgressID;
980 FpdtRecordPtr.GuidQwordEvent->Timestamp = TimeStamp;
981 CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));
982 if ((MODULE_LOADIMAGE_START_ID == RecordInfo.ProgressID) && AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) {
983 mLoadImageCount++;
984 FpdtRecordPtr.GuidQwordEvent->Qword = mLoadImageCount;
985 }
986 break;
987
988 case FPDT_GUID_QWORD_STRING_EVENT_TYPE:
989 FpdtRecordPtr.GuidQwordStringEvent->Header.Type = FPDT_GUID_QWORD_STRING_EVENT_TYPE;
990 FpdtRecordPtr.GuidQwordStringEvent->Header.Length = RecordInfo.RecordSize;
991 FpdtRecordPtr.GuidQwordStringEvent->Header.Revision = FPDT_RECORD_REVISION_1;
992 FpdtRecordPtr.GuidQwordStringEvent->ProgressID = RecordInfo.ProgressID;
993 FpdtRecordPtr.GuidQwordStringEvent->Timestamp = TimeStamp;
994 CopyMem (&FpdtRecordPtr.GuidQwordStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordStringEvent->Guid));
995 break;
996
997 default:
998 //
999 // Record is not supported in current DXE phase, return EFI_ABORTED
1000 //
1001 mLockInsertRecord = FALSE;
1002 return EFI_UNSUPPORTED;
1003 }
1004
1005 mLockInsertRecord = FALSE;
1006 return EFI_SUCCESS;
1007 }
1008
1009 /**
1010 Dumps all the PEI performance.
1011
1012 @param HobStart A pointer to a Guid.
1013
1014 This internal function dumps all the PEI performance log to the DXE performance gauge array.
1015 It retrieves the optional GUID HOB for PEI performance and then saves the performance data
1016 to DXE performance data structures.
1017
1018 **/
1019 VOID
1020 InternalGetPeiPerformance (
1021 VOID *HobStart
1022 )
1023 {
1024 UINT8 *FirmwarePerformanceHob;
1025 FPDT_PEI_EXT_PERF_HEADER *PeiPerformanceLogHeader;
1026 UINT8 *EventRec;
1027 EFI_HOB_GUID_TYPE *GuidHob;
1028
1029 GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, HobStart);
1030 while (GuidHob != NULL) {
1031 FirmwarePerformanceHob = GET_GUID_HOB_DATA (GuidHob);
1032 PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)FirmwarePerformanceHob;
1033
1034 if (mPerformanceLength + PeiPerformanceLogHeader->SizeOfAllEntries > mMaxPerformanceLength) {
1035 mPerformancePointer = ReallocatePool (
1036 mPerformanceLength,
1037 mPerformanceLength +
1038 (UINTN)PeiPerformanceLogHeader->SizeOfAllEntries +
1039 FIRMWARE_RECORD_BUFFER,
1040 mPerformancePointer
1041 );
1042 ASSERT (mPerformancePointer != NULL);
1043 mMaxPerformanceLength = mPerformanceLength +
1044 (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries) +
1045 FIRMWARE_RECORD_BUFFER;
1046 }
1047
1048 EventRec = mPerformancePointer + mPerformanceLength;
1049 CopyMem (EventRec, FirmwarePerformanceHob + sizeof (FPDT_PEI_EXT_PERF_HEADER), (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries));
1050 //
1051 // Update the used buffer size.
1052 //
1053 mPerformanceLength += (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries);
1054 mLoadImageCount += PeiPerformanceLogHeader->LoadImageCount;
1055
1056 //
1057 // Get next performance guid hob
1058 //
1059 GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob));
1060 }
1061 }
1062
1063 /**
1064 Report Boot Perforamnce table address as report status code.
1065
1066 @param Event The event of notify protocol.
1067 @param Context Notify event context.
1068
1069 **/
1070 VOID
1071 EFIAPI
1072 ReportFpdtRecordBuffer (
1073 IN EFI_EVENT Event,
1074 IN VOID *Context
1075 )
1076 {
1077 EFI_STATUS Status;
1078 UINT64 BPDTAddr;
1079
1080 if (!mFpdtBufferIsReported) {
1081 Status = AllocateBootPerformanceTable ();
1082 if (!EFI_ERROR(Status)) {
1083 BPDTAddr = (UINT64)(UINTN)mAcpiBootPerformanceTable;
1084 REPORT_STATUS_CODE_EX (
1085 EFI_PROGRESS_CODE,
1086 EFI_SOFTWARE_DXE_BS_DRIVER,
1087 0,
1088 NULL,
1089 &gEdkiiFpdtExtendedFirmwarePerformanceGuid,
1090 &BPDTAddr,
1091 sizeof (UINT64)
1092 );
1093 }
1094 //
1095 // Set FPDT report state to TRUE.
1096 //
1097 mFpdtBufferIsReported = TRUE;
1098 }
1099 }
1100
1101 /**
1102 Adds a record at the end of the performance measurement log
1103 that records the start time of a performance measurement.
1104
1105 Adds a record to the end of the performance measurement log
1106 that contains the Handle, Token, Module and Identifier.
1107 The end time of the new record must be set to zero.
1108 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
1109 If TimeStamp is zero, the start time in the record is filled in with the value
1110 read from the current time stamp.
1111
1112 @param Handle Pointer to environment specific context used
1113 to identify the component being measured.
1114 @param Token Pointer to a Null-terminated ASCII string
1115 that identifies the component being measured.
1116 @param Module Pointer to a Null-terminated ASCII string
1117 that identifies the module being measured.
1118 @param TimeStamp 64-bit time stamp.
1119 @param Identifier 32-bit identifier. If the value is 0, the created record
1120 is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
1121
1122 @retval EFI_SUCCESS The data was read correctly from the device.
1123 @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
1124
1125 **/
1126 EFI_STATUS
1127 EFIAPI
1128 StartGaugeEx (
1129 IN CONST VOID *Handle, OPTIONAL
1130 IN CONST CHAR8 *Token, OPTIONAL
1131 IN CONST CHAR8 *Module, OPTIONAL
1132 IN UINT64 TimeStamp,
1133 IN UINT32 Identifier
1134 )
1135 {
1136 return InsertFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, Identifier);
1137 }
1138
1139 /**
1140 Searches the performance measurement log from the beginning of the log
1141 for the first matching record that contains a zero end time and fills in a valid end time.
1142
1143 Searches the performance measurement log from the beginning of the log
1144 for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
1145 If the record can not be found then return EFI_NOT_FOUND.
1146 If the record is found and TimeStamp is not zero,
1147 then the end time in the record is filled in with the value specified by TimeStamp.
1148 If the record is found and TimeStamp is zero, then the end time in the matching record
1149 is filled in with the current time stamp value.
1150
1151 @param Handle Pointer to environment specific context used
1152 to identify the component being measured.
1153 @param Token Pointer to a Null-terminated ASCII string
1154 that identifies the component being measured.
1155 @param Module Pointer to a Null-terminated ASCII string
1156 that identifies the module being measured.
1157 @param TimeStamp 64-bit time stamp.
1158 @param Identifier 32-bit identifier. If the value is 0, the found record
1159 is same as the one found by EndGauge of PERFORMANCE_PROTOCOL.
1160
1161 @retval EFI_SUCCESS The end of the measurement was recorded.
1162 @retval EFI_NOT_FOUND The specified measurement record could not be found.
1163
1164 **/
1165 EFI_STATUS
1166 EFIAPI
1167 EndGaugeEx (
1168 IN CONST VOID *Handle, OPTIONAL
1169 IN CONST CHAR8 *Token, OPTIONAL
1170 IN CONST CHAR8 *Module, OPTIONAL
1171 IN UINT64 TimeStamp,
1172 IN UINT32 Identifier
1173 )
1174 {
1175 return InsertFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, Identifier);
1176 }
1177
1178 /**
1179 Retrieves a previously logged performance measurement.
1180 It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,
1181 and then assign the Identifier with 0.
1182
1183 !!! Not support!!!
1184
1185 Retrieves the performance log entry from the performance log specified by LogEntryKey.
1186 If it stands for a valid entry, then EFI_SUCCESS is returned and
1187 GaugeDataEntryEx stores the pointer to that entry.
1188
1189 @param LogEntryKey The key for the previous performance measurement log entry.
1190 If 0, then the first performance measurement log entry is retrieved.
1191 @param GaugeDataEntryEx The indirect pointer to the extended gauge data entry specified by LogEntryKey
1192 if the retrieval is successful.
1193
1194 @retval EFI_SUCCESS The GuageDataEntryEx is successfully found based on LogEntryKey.
1195 @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
1196 @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
1197 @retval EFI_INVALIDE_PARAMETER GaugeDataEntryEx is NULL.
1198
1199 **/
1200 EFI_STATUS
1201 EFIAPI
1202 GetGaugeEx (
1203 IN UINTN LogEntryKey,
1204 OUT GAUGE_DATA_ENTRY_EX **GaugeDataEntryEx
1205 )
1206 {
1207 return EFI_UNSUPPORTED;
1208 }
1209
1210 /**
1211 Adds a record at the end of the performance measurement log
1212 that records the start time of a performance measurement.
1213
1214 Adds a record to the end of the performance measurement log
1215 that contains the Handle, Token, and Module.
1216 The end time of the new record must be set to zero.
1217 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
1218 If TimeStamp is zero, the start time in the record is filled in with the value
1219 read from the current time stamp.
1220
1221 @param Handle Pointer to environment specific context used
1222 to identify the component being measured.
1223 @param Token Pointer to a Null-terminated ASCII string
1224 that identifies the component being measured.
1225 @param Module Pointer to a Null-terminated ASCII string
1226 that identifies the module being measured.
1227 @param TimeStamp 64-bit time stamp.
1228
1229 @retval EFI_SUCCESS The data was read correctly from the device.
1230 @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
1231
1232 **/
1233 EFI_STATUS
1234 EFIAPI
1235 StartGauge (
1236 IN CONST VOID *Handle, OPTIONAL
1237 IN CONST CHAR8 *Token, OPTIONAL
1238 IN CONST CHAR8 *Module, OPTIONAL
1239 IN UINT64 TimeStamp
1240 )
1241 {
1242 return StartGaugeEx (Handle, Token, Module, TimeStamp, 0);
1243 }
1244
1245 /**
1246 Searches the performance measurement log from the beginning of the log
1247 for the first matching record that contains a zero end time and fills in a valid end time.
1248
1249 Searches the performance measurement log from the beginning of the log
1250 for the first record that matches Handle, Token, and Module and has an end time value of zero.
1251 If the record can not be found then return EFI_NOT_FOUND.
1252 If the record is found and TimeStamp is not zero,
1253 then the end time in the record is filled in with the value specified by TimeStamp.
1254 If the record is found and TimeStamp is zero, then the end time in the matching record
1255 is filled in with the current time stamp value.
1256
1257 @param Handle Pointer to environment specific context used
1258 to identify the component being measured.
1259 @param Token Pointer to a Null-terminated ASCII string
1260 that identifies the component being measured.
1261 @param Module Pointer to a Null-terminated ASCII string
1262 that identifies the module being measured.
1263 @param TimeStamp 64-bit time stamp.
1264
1265 @retval EFI_SUCCESS The end of the measurement was recorded.
1266 @retval EFI_NOT_FOUND The specified measurement record could not be found.
1267
1268 **/
1269 EFI_STATUS
1270 EFIAPI
1271 EndGauge (
1272 IN CONST VOID *Handle, OPTIONAL
1273 IN CONST CHAR8 *Token, OPTIONAL
1274 IN CONST CHAR8 *Module, OPTIONAL
1275 IN UINT64 TimeStamp
1276 )
1277 {
1278 return EndGaugeEx (Handle, Token, Module, TimeStamp, 0);
1279 }
1280
1281 /**
1282 Retrieves a previously logged performance measurement.
1283 It can also retrieve the log created by StartGaugeEx and EndGaugeEx of PERFORMANCE_EX_PROTOCOL,
1284 and then eliminate the Identifier.
1285
1286 !!! Not support!!!
1287
1288 Retrieves the performance log entry from the performance log specified by LogEntryKey.
1289 If it stands for a valid entry, then EFI_SUCCESS is returned and
1290 GaugeDataEntry stores the pointer to that entry.
1291
1292 @param LogEntryKey The key for the previous performance measurement log entry.
1293 If 0, then the first performance measurement log entry is retrieved.
1294 @param GaugeDataEntry The indirect pointer to the gauge data entry specified by LogEntryKey
1295 if the retrieval is successful.
1296
1297 @retval EFI_SUCCESS The GuageDataEntry is successfully found based on LogEntryKey.
1298 @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
1299 @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
1300 @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL.
1301
1302 **/
1303 EFI_STATUS
1304 EFIAPI
1305 GetGauge (
1306 IN UINTN LogEntryKey,
1307 OUT GAUGE_DATA_ENTRY **GaugeDataEntry
1308 )
1309 {
1310 return EFI_UNSUPPORTED;
1311 }
1312
1313
1314 /**
1315 The constructor function initializes Performance infrastructure for DXE phase.
1316
1317 The constructor function publishes Performance and PerformanceEx protocol, allocates memory to log DXE performance
1318 and merges PEI performance data to DXE performance log.
1319 It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
1320
1321 @param ImageHandle The firmware allocated handle for the EFI image.
1322 @param SystemTable A pointer to the EFI System Table.
1323
1324 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
1325
1326 **/
1327 EFI_STATUS
1328 EFIAPI
1329 DxeCorePerformanceLibConstructor (
1330 IN EFI_HANDLE ImageHandle,
1331 IN EFI_SYSTEM_TABLE *SystemTable
1332 )
1333 {
1334 EFI_STATUS Status;
1335 EFI_HANDLE Handle;
1336 EFI_EVENT ReadyToBootEvent;
1337 PERFORMANCE_PROPERTY *PerformanceProperty;
1338
1339 if (!PerformanceMeasurementEnabled ()) {
1340 //
1341 // Do not initialize performance infrastructure if not required.
1342 //
1343 return EFI_SUCCESS;
1344 }
1345
1346 //
1347 // Dump normal PEI performance records
1348 //
1349 InternalGetPeiPerformance (GetHobList());
1350
1351 //
1352 // Install the protocol interfaces for DXE performance library instance.
1353 //
1354 Handle = NULL;
1355 Status = gBS->InstallMultipleProtocolInterfaces (
1356 &Handle,
1357 &gPerformanceProtocolGuid,
1358 &mPerformanceInterface,
1359 &gPerformanceExProtocolGuid,
1360 &mPerformanceExInterface,
1361 NULL
1362 );
1363 ASSERT_EFI_ERROR (Status);
1364
1365 //
1366 // Register ReadyToBoot event to report StatusCode data
1367 //
1368 Status = gBS->CreateEventEx (
1369 EVT_NOTIFY_SIGNAL,
1370 TPL_CALLBACK,
1371 ReportFpdtRecordBuffer,
1372 NULL,
1373 &gEfiEventReadyToBootGuid,
1374 &ReadyToBootEvent
1375 );
1376
1377 ASSERT_EFI_ERROR (Status);
1378
1379 Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);
1380 if (EFI_ERROR (Status)) {
1381 //
1382 // Install configuration table for performance property.
1383 //
1384 mPerformanceProperty.Revision = PERFORMANCE_PROPERTY_REVISION;
1385 mPerformanceProperty.Reserved = 0;
1386 mPerformanceProperty.Frequency = GetPerformanceCounterProperties (
1387 &mPerformanceProperty.TimerStartValue,
1388 &mPerformanceProperty.TimerEndValue
1389 );
1390 Status = gBS->InstallConfigurationTable (&gPerformanceProtocolGuid, &mPerformanceProperty);
1391 ASSERT_EFI_ERROR (Status);
1392 }
1393
1394 return EFI_SUCCESS;
1395 }
1396
1397 /**
1398 Adds a record at the end of the performance measurement log
1399 that records the start time of a performance measurement.
1400
1401 Adds a record to the end of the performance measurement log
1402 that contains the Handle, Token, Module and Identifier.
1403 The end time of the new record must be set to zero.
1404 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
1405 If TimeStamp is zero, the start time in the record is filled in with the value
1406 read from the current time stamp.
1407
1408 @param Handle Pointer to environment specific context used
1409 to identify the component being measured.
1410 @param Token Pointer to a Null-terminated ASCII string
1411 that identifies the component being measured.
1412 @param Module Pointer to a Null-terminated ASCII string
1413 that identifies the module being measured.
1414 @param TimeStamp 64-bit time stamp.
1415 @param Identifier 32-bit identifier. If the value is 0, the created record
1416 is same as the one created by StartPerformanceMeasurement.
1417
1418 @retval RETURN_SUCCESS The start of the measurement was recorded.
1419 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
1420
1421 **/
1422 RETURN_STATUS
1423 EFIAPI
1424 StartPerformanceMeasurementEx (
1425 IN CONST VOID *Handle, OPTIONAL
1426 IN CONST CHAR8 *Token, OPTIONAL
1427 IN CONST CHAR8 *Module, OPTIONAL
1428 IN UINT64 TimeStamp,
1429 IN UINT32 Identifier
1430 )
1431 {
1432 return InsertFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, Identifier);
1433 }
1434
1435 /**
1436 Searches the performance measurement log from the beginning of the log
1437 for the first matching record that contains a zero end time and fills in a valid end time.
1438
1439 Searches the performance measurement log from the beginning of the log
1440 for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
1441 If the record can not be found then return RETURN_NOT_FOUND.
1442 If the record is found and TimeStamp is not zero,
1443 then the end time in the record is filled in with the value specified by TimeStamp.
1444 If the record is found and TimeStamp is zero, then the end time in the matching record
1445 is filled in with the current time stamp value.
1446
1447 @param Handle Pointer to environment specific context used
1448 to identify the component being measured.
1449 @param Token Pointer to a Null-terminated ASCII string
1450 that identifies the component being measured.
1451 @param Module Pointer to a Null-terminated ASCII string
1452 that identifies the module being measured.
1453 @param TimeStamp 64-bit time stamp.
1454 @param Identifier 32-bit identifier. If the value is 0, the found record
1455 is same as the one found by EndPerformanceMeasurement.
1456
1457 @retval RETURN_SUCCESS The end of the measurement was recorded.
1458 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
1459
1460 **/
1461 RETURN_STATUS
1462 EFIAPI
1463 EndPerformanceMeasurementEx (
1464 IN CONST VOID *Handle, OPTIONAL
1465 IN CONST CHAR8 *Token, OPTIONAL
1466 IN CONST CHAR8 *Module, OPTIONAL
1467 IN UINT64 TimeStamp,
1468 IN UINT32 Identifier
1469 )
1470 {
1471 return InsertFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, Identifier);
1472 }
1473
1474 /**
1475 Attempts to retrieve a performance measurement log entry from the performance measurement log.
1476 It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
1477 and then assign the Identifier with 0.
1478
1479 !!! Not support!!!
1480
1481 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
1482 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
1483 and the key for the second entry in the log is returned. If the performance log is empty,
1484 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
1485 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
1486 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
1487 retrieved and an implementation specific non-zero key value that specifies the end of the performance
1488 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
1489 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
1490 the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
1491 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
1492 If Handle is NULL, then ASSERT().
1493 If Token is NULL, then ASSERT().
1494 If Module is NULL, then ASSERT().
1495 If StartTimeStamp is NULL, then ASSERT().
1496 If EndTimeStamp is NULL, then ASSERT().
1497 If Identifier is NULL, then ASSERT().
1498
1499 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
1500 0, then the first performance measurement log entry is retrieved.
1501 On exit, the key of the next performance log entry.
1502 @param Handle Pointer to environment specific context used to identify the component
1503 being measured.
1504 @param Token Pointer to a Null-terminated ASCII string that identifies the component
1505 being measured.
1506 @param Module Pointer to a Null-terminated ASCII string that identifies the module
1507 being measured.
1508 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1509 was started.
1510 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1511 was ended.
1512 @param Identifier Pointer to the 32-bit identifier that was recorded when the measurement
1513 was ended.
1514
1515 @return The key for the next performance log entry (in general case).
1516
1517 **/
1518 UINTN
1519 EFIAPI
1520 GetPerformanceMeasurementEx (
1521 IN UINTN LogEntryKey,
1522 OUT CONST VOID **Handle,
1523 OUT CONST CHAR8 **Token,
1524 OUT CONST CHAR8 **Module,
1525 OUT UINT64 *StartTimeStamp,
1526 OUT UINT64 *EndTimeStamp,
1527 OUT UINT32 *Identifier
1528 )
1529 {
1530 return 0;
1531 }
1532
1533 /**
1534 Adds a record at the end of the performance measurement log
1535 that records the start time of a performance measurement.
1536
1537 Adds a record to the end of the performance measurement log
1538 that contains the Handle, Token, and Module.
1539 The end time of the new record must be set to zero.
1540 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
1541 If TimeStamp is zero, the start time in the record is filled in with the value
1542 read from the current time stamp.
1543
1544 @param Handle Pointer to environment specific context used
1545 to identify the component being measured.
1546 @param Token Pointer to a Null-terminated ASCII string
1547 that identifies the component being measured.
1548 @param Module Pointer to a Null-terminated ASCII string
1549 that identifies the module being measured.
1550 @param TimeStamp 64-bit time stamp.
1551
1552 @retval RETURN_SUCCESS The start of the measurement was recorded.
1553 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
1554
1555 **/
1556 RETURN_STATUS
1557 EFIAPI
1558 StartPerformanceMeasurement (
1559 IN CONST VOID *Handle, OPTIONAL
1560 IN CONST CHAR8 *Token, OPTIONAL
1561 IN CONST CHAR8 *Module, OPTIONAL
1562 IN UINT64 TimeStamp
1563 )
1564 {
1565 return InsertFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, 0);
1566 }
1567
1568 /**
1569 Searches the performance measurement log from the beginning of the log
1570 for the first matching record that contains a zero end time and fills in a valid end time.
1571
1572 Searches the performance measurement log from the beginning of the log
1573 for the first record that matches Handle, Token, and Module and has an end time value of zero.
1574 If the record can not be found then return RETURN_NOT_FOUND.
1575 If the record is found and TimeStamp is not zero,
1576 then the end time in the record is filled in with the value specified by TimeStamp.
1577 If the record is found and TimeStamp is zero, then the end time in the matching record
1578 is filled in with the current time stamp value.
1579
1580 @param Handle Pointer to environment specific context used
1581 to identify the component being measured.
1582 @param Token Pointer to a Null-terminated ASCII string
1583 that identifies the component being measured.
1584 @param Module Pointer to a Null-terminated ASCII string
1585 that identifies the module being measured.
1586 @param TimeStamp 64-bit time stamp.
1587
1588 @retval RETURN_SUCCESS The end of the measurement was recorded.
1589 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
1590
1591 **/
1592 RETURN_STATUS
1593 EFIAPI
1594 EndPerformanceMeasurement (
1595 IN CONST VOID *Handle, OPTIONAL
1596 IN CONST CHAR8 *Token, OPTIONAL
1597 IN CONST CHAR8 *Module, OPTIONAL
1598 IN UINT64 TimeStamp
1599 )
1600 {
1601 return InsertFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, 0);
1602 }
1603
1604 /**
1605 Attempts to retrieve a performance measurement log entry from the performance measurement log.
1606 It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
1607 and then eliminate the Identifier.
1608
1609 !!! Not support!!!
1610
1611 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
1612 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
1613 and the key for the second entry in the log is returned. If the performance log is empty,
1614 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
1615 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
1616 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
1617 retrieved and an implementation specific non-zero key value that specifies the end of the performance
1618 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
1619 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
1620 the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
1621 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
1622 If Handle is NULL, then ASSERT().
1623 If Token is NULL, then ASSERT().
1624 If Module is NULL, then ASSERT().
1625 If StartTimeStamp is NULL, then ASSERT().
1626 If EndTimeStamp is NULL, then ASSERT().
1627
1628 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
1629 0, then the first performance measurement log entry is retrieved.
1630 On exit, the key of the next performance log entry.
1631 @param Handle Pointer to environment specific context used to identify the component
1632 being measured.
1633 @param Token Pointer to a Null-terminated ASCII string that identifies the component
1634 being measured.
1635 @param Module Pointer to a Null-terminated ASCII string that identifies the module
1636 being measured.
1637 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1638 was started.
1639 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
1640 was ended.
1641
1642 @return The key for the next performance log entry (in general case).
1643
1644 **/
1645 UINTN
1646 EFIAPI
1647 GetPerformanceMeasurement (
1648 IN UINTN LogEntryKey,
1649 OUT CONST VOID **Handle,
1650 OUT CONST CHAR8 **Token,
1651 OUT CONST CHAR8 **Module,
1652 OUT UINT64 *StartTimeStamp,
1653 OUT UINT64 *EndTimeStamp
1654 )
1655 {
1656 return 0;
1657 }
1658
1659 /**
1660 Returns TRUE if the performance measurement macros are enabled.
1661
1662 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1663 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
1664
1665 @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1666 PcdPerformanceLibraryPropertyMask is set.
1667 @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
1668 PcdPerformanceLibraryPropertyMask is clear.
1669
1670 **/
1671 BOOLEAN
1672 EFIAPI
1673 PerformanceMeasurementEnabled (
1674 VOID
1675 )
1676 {
1677 return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
1678 }