ShellPkg/Dp: make sure memory is freed before exit
[mirror_edk2.git] / ShellPkg / DynamicCommand / DpDynamicCommand / Dp.c
1 /** @file
2 Shell command for Displaying Performance Metrics.
3
4 The Dp command reads performance data and presents it in several
5 different formats depending upon the needs of the user. Both
6 Trace and Measured Profiling information is processed and presented.
7
8 Dp uses the "PerformanceLib" to read the measurement records.
9 The "TimerLib" provides information about the timer, such as frequency,
10 beginning, and ending counter values.
11 Measurement records contain identifying information (Handle, Token, Module)
12 and start and end time values.
13 Dp uses this information to group records in different ways. It also uses
14 timer information to calculate elapsed time for each measurement.
15
16 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
17 (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
18 This program and the accompanying materials
19 are licensed and made available under the terms and conditions of the BSD License
20 which accompanies this distribution. The full text of the license may be found at
21 http://opensource.org/licenses/bsd-license.php
22
23 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
24 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
25 **/
26
27 #include "Dp.h"
28 #include "Literals.h"
29 #include "DpInternal.h"
30
31 #pragma pack(1)
32
33 typedef struct {
34 EFI_ACPI_DESCRIPTION_HEADER Header;
35 UINT32 Entry;
36 } RSDT_TABLE;
37
38 typedef struct {
39 EFI_ACPI_DESCRIPTION_HEADER Header;
40 UINT64 Entry;
41 } XSDT_TABLE;
42
43 #pragma pack()
44
45 EFI_HANDLE mDpHiiHandle;
46
47 typedef struct {
48 EFI_HANDLE Handle;
49 EFI_GUID ModuleGuid;
50 } HANDLE_GUID_MAP;
51
52 HANDLE_GUID_MAP *mCacheHandleGuidTable;
53 UINTN mCachePairCount = 0;
54
55 //
56 /// Module-Global Variables
57 ///@{
58 CHAR16 mGaugeString[DP_GAUGE_STRING_LENGTH + 1];
59 CHAR16 mUnicodeToken[DXE_PERFORMANCE_STRING_SIZE];
60 UINT64 mInterestThreshold;
61 BOOLEAN mShowId = FALSE;
62 UINT8 *mBootPerformanceTable;
63 UINTN mBootPerformanceTableSize;
64 BOOLEAN mPeiPhase = FALSE;
65 BOOLEAN mDxePhase = FALSE;
66
67 PERF_SUMMARY_DATA SummaryData = { 0 }; ///< Create the SummaryData structure and init. to ZERO.
68 MEASUREMENT_RECORD *mMeasurementList = NULL;
69 UINTN mMeasurementNum = 0;
70
71 /// Items for which to gather cumulative statistics.
72 PERF_CUM_DATA CumData[] = {
73 PERF_INIT_CUM_DATA (LOAD_IMAGE_TOK),
74 PERF_INIT_CUM_DATA (START_IMAGE_TOK),
75 PERF_INIT_CUM_DATA (DRIVERBINDING_START_TOK),
76 PERF_INIT_CUM_DATA (DRIVERBINDING_SUPPORT_TOK)
77 };
78
79 /// Number of items for which we are gathering cumulative statistics.
80 UINT32 const NumCum = sizeof(CumData) / sizeof(PERF_CUM_DATA);
81
82 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
83 {L"-v", TypeFlag}, // -v Verbose Mode
84 {L"-A", TypeFlag}, // -A All, Cooked
85 {L"-R", TypeFlag}, // -R RAW All
86 {L"-s", TypeFlag}, // -s Summary
87 #if PROFILING_IMPLEMENTED
88 {L"-P", TypeFlag}, // -P Dump Profile Data
89 {L"-T", TypeFlag}, // -T Dump Trace Data
90 #endif // PROFILING_IMPLEMENTED
91 {L"-x", TypeFlag}, // -x eXclude Cumulative Items
92 {L"-i", TypeFlag}, // -i Display Identifier
93 {L"-c", TypeValue}, // -c Display cumulative data.
94 {L"-n", TypeValue}, // -n # Number of records to display for A and R
95 {L"-t", TypeValue}, // -t # Threshold of interest
96 {NULL, TypeMax}
97 };
98
99 ///@}
100
101 /**
102 Display the trailing Verbose information.
103 **/
104 VOID
105 DumpStatistics( void )
106 {
107 EFI_STRING StringPtr;
108 EFI_STRING StringPtrUnknown;
109 StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_STATISTICS), NULL);
110 StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
111 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), mDpHiiHandle,
112 (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
113 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMTRACE), mDpHiiHandle, SummaryData.NumTrace);
114 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMINCOMPLETE), mDpHiiHandle, SummaryData.NumIncomplete);
115 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPHASES), mDpHiiHandle, SummaryData.NumSummary);
116 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMHANDLES), mDpHiiHandle, SummaryData.NumHandles, SummaryData.NumTrace - SummaryData.NumHandles);
117 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPEIMS), mDpHiiHandle, SummaryData.NumPEIMs);
118 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMGLOBALS), mDpHiiHandle, SummaryData.NumGlobal);
119 #if PROFILING_IMPLEMENTED
120 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPROFILE), mDpHiiHandle, SummaryData.NumProfile);
121 #endif // PROFILING_IMPLEMENTED
122 SHELL_FREE_NON_NULL (StringPtr);
123 SHELL_FREE_NON_NULL (StringPtrUnknown);
124 }
125
126 /**
127 This function scan ACPI table in RSDT.
128
129 @param Rsdt ACPI RSDT
130 @param Signature ACPI table signature
131
132 @return ACPI table
133 **/
134 VOID *
135 ScanTableInRSDT (
136 IN RSDT_TABLE *Rsdt,
137 IN UINT32 Signature
138 )
139 {
140 UINTN Index;
141 UINT32 EntryCount;
142 UINT32 *EntryPtr;
143 EFI_ACPI_DESCRIPTION_HEADER *Table;
144
145 EntryCount = (Rsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
146
147 EntryPtr = &Rsdt->Entry;
148 for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
149 Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(*EntryPtr));
150 if (Table->Signature == Signature) {
151 return Table;
152 }
153 }
154
155 return NULL;
156 }
157
158 /**
159 This function scan ACPI table in XSDT.
160
161 @param Xsdt ACPI XSDT
162 @param Signature ACPI table signature
163
164 @return ACPI table
165 **/
166 VOID *
167 ScanTableInXSDT (
168 IN XSDT_TABLE *Xsdt,
169 IN UINT32 Signature
170 )
171 {
172 UINTN Index;
173 UINT32 EntryCount;
174 UINT64 EntryPtr;
175 UINTN BasePtr;
176 EFI_ACPI_DESCRIPTION_HEADER *Table;
177
178 EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
179
180 BasePtr = (UINTN)(&(Xsdt->Entry));
181 for (Index = 0; Index < EntryCount; Index ++) {
182 CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
183 Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(EntryPtr));
184 if (Table->Signature == Signature) {
185 return Table;
186 }
187 }
188
189 return NULL;
190 }
191
192 /**
193 This function scan ACPI table in RSDP.
194
195 @param Rsdp ACPI RSDP
196 @param Signature ACPI table signature
197
198 @return ACPI table
199 **/
200 VOID *
201 FindAcpiPtr (
202 IN EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp,
203 IN UINT32 Signature
204 )
205 {
206 EFI_ACPI_DESCRIPTION_HEADER *AcpiTable;
207 RSDT_TABLE *Rsdt;
208 XSDT_TABLE *Xsdt;
209
210 AcpiTable = NULL;
211
212 //
213 // Check ACPI2.0 table
214 //
215 Rsdt = (RSDT_TABLE *)(UINTN)Rsdp->RsdtAddress;
216 Xsdt = NULL;
217 if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) {
218 Xsdt = (XSDT_TABLE *)(UINTN)Rsdp->XsdtAddress;
219 }
220 //
221 // Check Xsdt
222 //
223 if (Xsdt != NULL) {
224 AcpiTable = ScanTableInXSDT (Xsdt, Signature);
225 }
226 //
227 // Check Rsdt
228 //
229 if ((AcpiTable == NULL) && (Rsdt != NULL)) {
230 AcpiTable = ScanTableInRSDT (Rsdt, Signature);
231 }
232
233 return AcpiTable;
234 }
235
236 /**
237 Get Boot performance table form Acpi table.
238
239 **/
240 EFI_STATUS
241 GetBootPerformanceTable (
242 )
243 {
244 EFI_STATUS Status;
245 VOID *AcpiTable;
246 FIRMWARE_PERFORMANCE_TABLE *FirmwarePerformanceTable;
247
248 AcpiTable = NULL;
249
250 Status = EfiGetSystemConfigurationTable (
251 &gEfiAcpi20TableGuid,
252 &AcpiTable
253 );
254 if (EFI_ERROR (Status)) {
255 Status = EfiGetSystemConfigurationTable (
256 &gEfiAcpi10TableGuid,
257 &AcpiTable
258 );
259 }
260 if (EFI_ERROR(Status) || AcpiTable == NULL) {
261 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GET_ACPI_TABLE_FAIL), mDpHiiHandle);
262 return Status;
263 }
264
265 FirmwarePerformanceTable = FindAcpiPtr (
266 (EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiTable,
267 EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE
268 );
269 if (FirmwarePerformanceTable == NULL) {
270 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GET_ACPI_FPDT_FAIL), mDpHiiHandle);
271 return EFI_NOT_FOUND;
272 }
273
274 mBootPerformanceTable = (UINT8*) (UINTN)FirmwarePerformanceTable->BootPointerRecord.BootPerformanceTablePointer;
275 mBootPerformanceTableSize = ((BOOT_PERFORMANCE_TABLE *) mBootPerformanceTable)->Header.Length;
276
277 return EFI_SUCCESS;
278 }
279
280 /**
281 Get Handle form Module Guid.
282
283 @param ModuleGuid Module Guid.
284 @param Handle The handle to be returned.
285
286 **/
287 VOID
288 GetHandleFormModuleGuid (
289 IN EFI_GUID *ModuleGuid,
290 IN OUT EFI_HANDLE *Handle
291 )
292 {
293 UINTN Index;
294
295 if (IsZeroGuid (ModuleGuid)) {
296 *Handle = NULL;
297 }
298 //
299 // Try to get the Handle form the caached array.
300 //
301 for (Index = 0; Index < mCachePairCount; Index++) {
302 if (CompareGuid (ModuleGuid, &mCacheHandleGuidTable[Index].ModuleGuid)) {
303 *Handle = mCacheHandleGuidTable[Index].Handle;
304 break;
305 }
306 }
307 if (Index >= mCachePairCount) {
308 *Handle = NULL;
309 }
310 }
311
312 /**
313 Cache the GUID and handle mapping pairs. In order to save time for searching.
314
315 **/
316 EFI_STATUS
317 BuildCachedGuidHandleTable (
318 VOID
319 )
320 {
321 EFI_STATUS Status;
322 EFI_HANDLE *HandleBuffer;
323 UINTN HandleCount;
324 UINTN Index;
325 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
326 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
327 EFI_GUID *TempGuid;
328 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
329
330 Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer);
331 if (EFI_ERROR (Status)) {
332 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), mDpHiiHandle, Status);
333 return Status;
334 }
335
336 mCacheHandleGuidTable = AllocateZeroPool (HandleCount * sizeof (HANDLE_GUID_MAP));
337 if (mCacheHandleGuidTable == NULL) {
338 return EFI_OUT_OF_RESOURCES;
339 }
340
341 for (Index = 0; Index < HandleCount; Index++) {
342 //
343 // Try Handle as ImageHandle.
344 //
345 Status = gBS->HandleProtocol (
346 HandleBuffer[Index],
347 &gEfiLoadedImageProtocolGuid,
348 (VOID**) &LoadedImage
349 );
350 if (EFI_ERROR (Status)) {
351 //
352 // Try Handle as Controller Handle
353 //
354 Status = gBS->OpenProtocol (
355 HandleBuffer[Index],
356 &gEfiDriverBindingProtocolGuid,
357 (VOID **) &DriverBinding,
358 NULL,
359 NULL,
360 EFI_OPEN_PROTOCOL_GET_PROTOCOL
361 );
362 if (!EFI_ERROR (Status)) {
363 //
364 // Get Image protocol from ImageHandle
365 //
366 Status = gBS->HandleProtocol (
367 DriverBinding->ImageHandle,
368 &gEfiLoadedImageProtocolGuid,
369 (VOID**) &LoadedImage
370 );
371 }
372 }
373
374 if (!EFI_ERROR (Status) && LoadedImage != NULL) {
375 //
376 // Get Module Guid from DevicePath.
377 //
378 if (LoadedImage->FilePath != NULL &&
379 LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH &&
380 LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP
381 ) {
382 FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath;
383 TempGuid = &FvFilePath->FvFileName;
384
385 mCacheHandleGuidTable[mCachePairCount].Handle = HandleBuffer[Index];
386 CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, TempGuid);
387 mCachePairCount ++;
388 }
389 }
390 }
391 if (HandleBuffer != NULL) {
392 FreePool (HandleBuffer);
393 HandleBuffer = NULL;
394 }
395 return EFI_SUCCESS;
396 }
397
398 /**
399 Get Measurement form Fpdt records.
400
401 @param RecordHeader Pointer to the start record.
402 @param IsStart Is start record or End record.
403 @param Measurement Pointer to the measurement which need to be filled.
404
405 **/
406 VOID
407 GetMeasurementInfo (
408 IN EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader,
409 IN BOOLEAN IsStart,
410 IN OUT MEASUREMENT_RECORD *Measurement
411 )
412 {
413 VOID *ModuleGuid;
414 EFI_HANDLE StartHandle;
415
416 switch (RecordHeader->Type) {
417 case FPDT_GUID_EVENT_TYPE:
418 ModuleGuid = &(((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Guid);
419 Measurement->Identifier = ((UINT32)((FPDT_GUID_EVENT_RECORD *)RecordHeader)->ProgressID);
420 if (IsStart) {
421 Measurement->StartTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp;
422 } else {
423 Measurement->EndTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp;
424 }
425 switch (Measurement->Identifier) {
426 case MODULE_START_ID:
427 case MODULE_END_ID:
428 if (mPeiPhase) {
429 Measurement->Token = ALit_PEIM;
430 Measurement->Module = ALit_PEIM;
431 } else if (mDxePhase) {
432 Measurement->Token = ALit_START_IMAGE;
433 Measurement->Module = ALit_START_IMAGE;
434 }
435 break;
436 default:
437 ASSERT(FALSE);
438 }
439
440 if (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) {
441 Measurement->Handle = &(((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Guid);
442 } else {
443 GetHandleFormModuleGuid(ModuleGuid, &StartHandle);
444 Measurement->Handle = StartHandle;
445 }
446 break;
447
448 case FPDT_DYNAMIC_STRING_EVENT_TYPE:
449 ModuleGuid = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);
450 Measurement->Identifier = ((UINT32)((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->ProgressID);
451 if (IsStart) {
452 Measurement->StartTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
453 } else {
454 Measurement->EndTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
455 }
456 switch (Measurement->Identifier) {
457 case MODULE_START_ID:
458 case MODULE_END_ID:
459 if (mPeiPhase) {
460 Measurement->Token = ALit_PEIM;
461 } else if (mDxePhase) {
462 Measurement->Token = ALit_START_IMAGE;
463 }
464 break;
465
466 case MODULE_LOADIMAGE_START_ID:
467 case MODULE_LOADIMAGE_END_ID:
468 Measurement->Token = ALit_LOAD_IMAGE;
469 break;
470
471 case MODULE_DB_START_ID:
472 case MODULE_DB_END_ID:
473 Measurement->Token = ALit_DB_START;
474 break;
475
476 case MODULE_DB_SUPPORT_START_ID:
477 case MODULE_DB_SUPPORT_END_ID:
478 Measurement->Token = ALit_DB_SUPPORT;
479 break;
480
481 case MODULE_DB_STOP_START_ID:
482 case MODULE_DB_STOP_END_ID:
483 Measurement->Token = ALit_DB_STOP;
484 break;
485
486 default:
487 Measurement->Token = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String;
488 break;
489 }
490
491 Measurement->Module = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String;
492
493 if (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) {
494 Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);
495 } else {
496 GetHandleFormModuleGuid(ModuleGuid, &StartHandle);
497 Measurement->Handle = StartHandle;
498 }
499 break;
500
501 case FPDT_GUID_QWORD_EVENT_TYPE:
502 ModuleGuid = &(((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Guid);
503 Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->ProgressID);
504 if (IsStart) {
505 Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp;
506 } else {
507 Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp;
508 }
509 switch (Measurement->Identifier) {
510 case MODULE_DB_START_ID:
511 Measurement->Token = ALit_DB_START;
512 Measurement->Module = ALit_DB_START;
513 break;
514
515 case MODULE_DB_SUPPORT_START_ID:
516 case MODULE_DB_SUPPORT_END_ID:
517 Measurement->Token = ALit_DB_SUPPORT;
518 Measurement->Module = ALit_DB_SUPPORT;
519 break;
520
521 case MODULE_DB_STOP_START_ID:
522 case MODULE_DB_STOP_END_ID:
523 Measurement->Token = ALit_DB_STOP;
524 Measurement->Module = ALit_DB_STOP;
525 break;
526
527 case MODULE_LOADIMAGE_START_ID:
528 case MODULE_LOADIMAGE_END_ID:
529 Measurement->Token = ALit_LOAD_IMAGE;
530 Measurement->Module = ALit_LOAD_IMAGE;
531 break;
532
533 default:
534 ASSERT(FALSE);
535 }
536 GetHandleFormModuleGuid(ModuleGuid, &StartHandle);
537 Measurement->Handle = StartHandle;
538 break;
539
540 case FPDT_GUID_QWORD_STRING_EVENT_TYPE:
541 ModuleGuid = &(((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Guid);
542 Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->ProgressID);
543 if (IsStart) {
544 Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD*)RecordHeader)->Timestamp;
545 } else {
546 Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
547 }
548 //
549 // Currently only "DB:Start:" end record with FPDT_GUID_QWORD_STRING_EVENT_TYPE.
550 //
551 switch (Measurement->Identifier) {
552 case MODULE_DB_END_ID:
553 Measurement->Token = ALit_DB_START;
554 Measurement->Module = ALit_DB_START;
555 break;
556 default:
557 ASSERT(FALSE);
558 }
559 GetHandleFormModuleGuid(ModuleGuid, &StartHandle);
560 Measurement->Handle = StartHandle;
561 break;
562
563 default:
564 break;
565 }
566 }
567
568 /**
569 Search the start measurement in the mMeasurementList for the end measurement.
570
571 @param EndMeasureMent Measurement for end record.
572
573 **/
574 VOID
575 SearchMeasurement (
576 IN MEASUREMENT_RECORD *EndMeasureMent
577 )
578 {
579 INTN Index;
580
581 for (Index = mMeasurementNum - 1; Index >= 0; Index--) {
582 if (AsciiStrCmp (EndMeasureMent->Token, ALit_PEIM) == 0) {
583 if (mMeasurementList[Index].EndTimeStamp == 0 && EndMeasureMent->Handle!= NULL && mMeasurementList[Index].Handle != NULL&&
584 CompareGuid(mMeasurementList[Index].Handle, EndMeasureMent->Handle) &&
585 (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) &&
586 (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0)) {
587 mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp;
588 break;
589 }
590 } else {
591 if (mMeasurementList[Index].EndTimeStamp == 0 && mMeasurementList[Index].Handle == EndMeasureMent->Handle &&
592 (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) &&
593 (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0)) {
594 mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp;
595 break;
596 }
597 }
598 }
599 }
600
601 /**
602 Generate the measure record array.
603
604 **/
605 EFI_STATUS
606 BuildMeasurementList (
607 )
608 {
609 EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader;
610 UINT8 *PerformanceTablePtr;
611 UINT16 StartProgressId;
612 UINTN TableLength;
613 UINT8 *StartRecordEvent;
614 MEASUREMENT_RECORD MeasureMent;
615
616 mMeasurementList = AllocateZeroPool (mBootPerformanceTableSize);
617 if (mMeasurementList == NULL) {
618 return EFI_OUT_OF_RESOURCES;
619 }
620
621 TableLength = sizeof (BOOT_PERFORMANCE_TABLE);
622 PerformanceTablePtr = (mBootPerformanceTable + TableLength);
623
624 while (TableLength < mBootPerformanceTableSize) {
625 RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER*) PerformanceTablePtr;
626 StartRecordEvent = (UINT8 *)RecordHeader;
627 StartProgressId = ((FPDT_GUID_EVENT_RECORD *)StartRecordEvent)->ProgressID;
628
629 //
630 // If the record is the start record, fill the info to the measurement in the mMeasurementList.
631 // If the record is the end record, find the related start measurement in the mMeasurementList and fill the EndTimeStamp.
632 //
633 if (((StartProgressId >= PERF_EVENTSIGNAL_START_ID && ((StartProgressId & 0x000F) == 0)) ||
634 (StartProgressId < PERF_EVENTSIGNAL_START_ID && ((StartProgressId & 0x0001) != 0)))) {
635 //
636 // Since PEIM and StartImage has same Type and ID when PCD PcdEdkiiFpdtStringRecordEnableOnly = FALSE
637 // So we need to identify these two kinds of record through different phase.
638 //
639 if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_PEI) == 0) {
640 mPeiPhase = TRUE;
641 } else if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_DXE) == 0) {
642 mDxePhase = TRUE;
643 mPeiPhase = FALSE;
644 }
645 // Get measurement info form the start record to the mMeasurementList.
646 GetMeasurementInfo (RecordHeader, TRUE, &(mMeasurementList[mMeasurementNum]));
647 mMeasurementNum ++;
648 } else {
649 GetMeasurementInfo (RecordHeader, FALSE, &MeasureMent);
650 SearchMeasurement (&MeasureMent);
651 }
652 TableLength += RecordHeader->Length;
653 PerformanceTablePtr += RecordHeader->Length;
654 }
655 return EFI_SUCCESS;
656 }
657
658 /**
659 Initialize the cumulative data.
660
661 **/
662 VOID
663 InitCumulativeData (
664 VOID
665 )
666 {
667 UINTN Index;
668
669 for (Index = 0; Index < NumCum; ++Index) {
670 CumData[Index].Count = 0;
671 CumData[Index].MinDur = PERF_MAXDUR;
672 CumData[Index].MaxDur = 0;
673 CumData[Index].Duration = 0;
674 }
675 }
676
677 /**
678 Dump performance data.
679
680 @param[in] ImageHandle The image handle.
681 @param[in] SystemTable The system table.
682
683 @retval SHELL_SUCCESS Command completed successfully.
684 @retval SHELL_INVALID_PARAMETER Command usage error.
685 @retval SHELL_ABORTED The user aborts the operation.
686 @retval value Unknown error.
687 **/
688 SHELL_STATUS
689 RunDp (
690 IN EFI_HANDLE ImageHandle,
691 IN EFI_SYSTEM_TABLE *SystemTable
692 )
693 {
694 LIST_ENTRY *ParamPackage;
695 CONST CHAR16 *CmdLineArg;
696 EFI_STATUS Status;
697
698 PERFORMANCE_PROPERTY *PerformanceProperty;
699 UINTN Number2Display;
700
701 EFI_STRING StringPtr;
702 BOOLEAN SummaryMode;
703 BOOLEAN VerboseMode;
704 BOOLEAN AllMode;
705 BOOLEAN RawMode;
706 BOOLEAN TraceMode;
707 BOOLEAN ProfileMode;
708 BOOLEAN ExcludeMode;
709 BOOLEAN CumulativeMode;
710 CONST CHAR16 *CustomCumulativeToken;
711 PERF_CUM_DATA *CustomCumulativeData;
712 UINTN NameSize;
713 SHELL_STATUS ShellStatus;
714 TIMER_INFO TimerInfo;
715
716 StringPtr = NULL;
717 SummaryMode = FALSE;
718 VerboseMode = FALSE;
719 AllMode = FALSE;
720 RawMode = FALSE;
721 TraceMode = FALSE;
722 ProfileMode = FALSE;
723 ExcludeMode = FALSE;
724 CumulativeMode = FALSE;
725 CustomCumulativeData = NULL;
726 ShellStatus = SHELL_SUCCESS;
727
728 //
729 // initialize the shell lib (we must be in non-auto-init...)
730 //
731 Status = ShellInitialize();
732 ASSERT_EFI_ERROR(Status);
733
734 //
735 // Process Command Line arguments
736 //
737 Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE);
738 if (EFI_ERROR(Status)) {
739 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_ARG), mDpHiiHandle);
740 return SHELL_INVALID_PARAMETER;
741 }
742
743 //
744 // Boolean options
745 //
746 VerboseMode = ShellCommandLineGetFlag (ParamPackage, L"-v");
747 SummaryMode = (BOOLEAN) (ShellCommandLineGetFlag (ParamPackage, L"-S") || ShellCommandLineGetFlag (ParamPackage, L"-s"));
748 AllMode = ShellCommandLineGetFlag (ParamPackage, L"-A");
749 RawMode = ShellCommandLineGetFlag (ParamPackage, L"-R");
750 #if PROFILING_IMPLEMENTED
751 TraceMode = ShellCommandLineGetFlag (ParamPackage, L"-T");
752 ProfileMode = ShellCommandLineGetFlag (ParamPackage, L"-P");
753 #endif // PROFILING_IMPLEMENTED
754 ExcludeMode = ShellCommandLineGetFlag (ParamPackage, L"-x");
755 mShowId = ShellCommandLineGetFlag (ParamPackage, L"-i");
756 CumulativeMode = ShellCommandLineGetFlag (ParamPackage, L"-c");
757
758 // Options with Values
759 CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-n");
760 if (CmdLineArg == NULL) {
761 Number2Display = DEFAULT_DISPLAYCOUNT;
762 } else {
763 Number2Display = StrDecimalToUintn(CmdLineArg);
764 if (Number2Display == 0) {
765 Number2Display = MAXIMUM_DISPLAYCOUNT;
766 }
767 }
768
769 CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-t");
770 if (CmdLineArg == NULL) {
771 mInterestThreshold = DEFAULT_THRESHOLD; // 1ms := 1,000 us
772 } else {
773 mInterestThreshold = StrDecimalToUint64(CmdLineArg);
774 }
775
776 // Handle Flag combinations and default behaviors
777 // If both TraceMode and ProfileMode are FALSE, set them both to TRUE
778 if ((! TraceMode) && (! ProfileMode)) {
779 TraceMode = TRUE;
780 #if PROFILING_IMPLEMENTED
781 ProfileMode = TRUE;
782 #endif // PROFILING_IMPLEMENTED
783 }
784
785 //
786 // DP dump performance data by parsing FPDT table in ACPI table.
787 // Folloing 3 steps are to get the measurement form the FPDT table.
788 //
789
790 //
791 //1. Get FPDT from ACPI table.
792 //
793 Status = GetBootPerformanceTable ();
794 if (EFI_ERROR (Status)) {
795 ShellStatus = Status;
796 goto Done;
797 }
798
799 //
800 //2. Cache the ModuleGuid and hanlde mapping table.
801 //
802 Status = BuildCachedGuidHandleTable();
803 if (EFI_ERROR (Status)) {
804 ShellStatus = Status;
805 goto Done;
806 }
807
808 //
809 //3. Build the measurement array form the FPDT records.
810 //
811 Status = BuildMeasurementList ();
812 if (EFI_ERROR (Status)) {
813 ShellStatus = SHELL_OUT_OF_RESOURCES;
814 goto Done;
815 }
816
817 //
818 // Initialize the pre-defined cumulative data.
819 //
820 InitCumulativeData ();
821
822 //
823 // Init the custom cumulative data.
824 //
825 CustomCumulativeToken = ShellCommandLineGetValue (ParamPackage, L"-c");
826 if (CustomCumulativeToken != NULL) {
827 CustomCumulativeData = AllocateZeroPool (sizeof (PERF_CUM_DATA));
828 if (CustomCumulativeData == NULL) {
829 ShellStatus = SHELL_OUT_OF_RESOURCES;
830 goto Done;
831 }
832 CustomCumulativeData->MinDur = PERF_MAXDUR;
833 CustomCumulativeData->MaxDur = 0;
834 CustomCumulativeData->Count = 0;
835 CustomCumulativeData->Duration = 0;
836 NameSize = StrLen (CustomCumulativeToken) + 1;
837 CustomCumulativeData->Name = AllocateZeroPool (NameSize);
838 if (CustomCumulativeData->Name == NULL) {
839 ShellStatus = SHELL_OUT_OF_RESOURCES;
840 goto Done;
841 }
842 UnicodeStrToAsciiStrS (CustomCumulativeToken, CustomCumulativeData->Name, NameSize);
843 }
844
845 //
846 // Timer specific processing
847 //
848 // Get the Performance counter characteristics:
849 // Freq = Frequency in Hz
850 // StartCount = Value loaded into the counter when it starts counting
851 // EndCount = Value counter counts to before it needs to be reset
852 //
853 Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);
854 if (EFI_ERROR (Status) || (PerformanceProperty == NULL)) {
855 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PERF_PROPERTY_NOT_FOUND), mDpHiiHandle);
856 goto Done;
857 }
858
859 TimerInfo.Frequency = (UINT32)DivU64x32 (PerformanceProperty->Frequency, 1000);
860 TimerInfo.StartCount = 0;
861 TimerInfo.EndCount = 0xFFFF;
862 TimerInfo.CountUp = TRUE;
863
864 //
865 // Print header
866 //
867 // print DP's build version
868 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_BUILD_REVISION), mDpHiiHandle, DP_MAJOR_VERSION, DP_MINOR_VERSION);
869
870 // print performance timer characteristics
871 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_KHZ), mDpHiiHandle, TimerInfo.Frequency);
872
873 if (VerboseMode && !RawMode) {
874 StringPtr = HiiGetString (mDpHiiHandle,
875 (EFI_STRING_ID) (TimerInfo.CountUp ? STRING_TOKEN (STR_DP_UP) : STRING_TOKEN (STR_DP_DOWN)), NULL);
876 ASSERT (StringPtr != NULL);
877 // Print Timer count range and direction
878 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TIMER_PROPERTIES), mDpHiiHandle,
879 StringPtr,
880 TimerInfo.StartCount,
881 TimerInfo.EndCount
882 );
883 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_VERBOSE_THRESHOLD), mDpHiiHandle, mInterestThreshold);
884 }
885
886 /****************************************************************************
887 **** Print Sections based on command line options
888 ****
889 **** Option modes have the following priority:
890 **** v Verbose -- Valid in combination with any other options
891 **** t Threshold -- Modifies All, Raw, and Cooked output
892 **** Default is 0 for All and Raw mode
893 **** Default is DEFAULT_THRESHOLD for "Cooked" mode
894 **** n Number2Display Used by All and Raw mode. Otherwise ignored.
895 **** A All -- R and S options are ignored
896 **** R Raw -- S option is ignored
897 **** s Summary -- Modifies "Cooked" output only
898 **** Cooked (Default)
899 ****
900 **** The All, Raw, and Cooked modes are modified by the Trace and Profile
901 **** options.
902 **** !T && !P := (0) Default, Both are displayed
903 **** T && !P := (1) Only Trace records are displayed
904 **** !T && P := (2) Only Profile records are displayed
905 **** T && P := (3) Same as Default, both are displayed
906 ****************************************************************************/
907 GatherStatistics (CustomCumulativeData);
908 if (CumulativeMode) {
909 ProcessCumulative (CustomCumulativeData);
910 } else if (AllMode) {
911 if (TraceMode) {
912 Status = DumpAllTrace( Number2Display, ExcludeMode);
913 if (Status == EFI_ABORTED) {
914 ShellStatus = SHELL_ABORTED;
915 goto Done;
916 }
917 }
918 if (ProfileMode) {
919 DumpAllProfile( Number2Display, ExcludeMode);
920 }
921 } else if (RawMode) {
922 if (TraceMode) {
923 Status = DumpRawTrace( Number2Display, ExcludeMode);
924 if (Status == EFI_ABORTED) {
925 ShellStatus = SHELL_ABORTED;
926 goto Done;
927 }
928 }
929 if (ProfileMode) {
930 DumpRawProfile( Number2Display, ExcludeMode);
931 }
932 } else {
933 //------------- Begin Cooked Mode Processing
934 if (TraceMode) {
935 ProcessPhases ();
936 if ( ! SummaryMode) {
937 Status = ProcessHandles ( ExcludeMode);
938 if (Status == EFI_ABORTED) {
939 ShellStatus = SHELL_ABORTED;
940 goto Done;
941 }
942
943 Status = ProcessPeims ();
944 if (Status == EFI_ABORTED) {
945 ShellStatus = SHELL_ABORTED;
946 goto Done;
947 }
948
949 Status = ProcessGlobal ();
950 if (Status == EFI_ABORTED) {
951 ShellStatus = SHELL_ABORTED;
952 goto Done;
953 }
954
955 ProcessCumulative (NULL);
956 }
957 }
958 if (ProfileMode) {
959 DumpAllProfile( Number2Display, ExcludeMode);
960 }
961 } //------------- End of Cooked Mode Processing
962 if ( VerboseMode || SummaryMode) {
963 DumpStatistics();
964 }
965
966 Done:
967 if (ParamPackage != NULL) {
968 ShellCommandLineFreeVarList (ParamPackage);
969 }
970 SHELL_FREE_NON_NULL (StringPtr);
971 if (CustomCumulativeData != NULL) {
972 SHELL_FREE_NON_NULL (CustomCumulativeData->Name);
973 }
974 SHELL_FREE_NON_NULL (CustomCumulativeData);
975
976 SHELL_FREE_NON_NULL (mMeasurementList);
977
978 SHELL_FREE_NON_NULL (mCacheHandleGuidTable);
979
980 mMeasurementNum = 0;
981 mCachePairCount = 0;
982 return ShellStatus;
983 }
984
985
986 /**
987 Retrive HII package list from ImageHandle and publish to HII database.
988
989 @param ImageHandle The image handle of the process.
990
991 @return HII handle.
992 **/
993 EFI_HANDLE
994 InitializeHiiPackage (
995 EFI_HANDLE ImageHandle
996 )
997 {
998 EFI_STATUS Status;
999 EFI_HII_PACKAGE_LIST_HEADER *PackageList;
1000 EFI_HANDLE HiiHandle;
1001
1002 //
1003 // Retrieve HII package list from ImageHandle
1004 //
1005 Status = gBS->OpenProtocol (
1006 ImageHandle,
1007 &gEfiHiiPackageListProtocolGuid,
1008 (VOID **)&PackageList,
1009 ImageHandle,
1010 NULL,
1011 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1012 );
1013 ASSERT_EFI_ERROR (Status);
1014 if (EFI_ERROR (Status)) {
1015 return NULL;
1016 }
1017
1018 //
1019 // Publish HII package list to HII Database.
1020 //
1021 Status = gHiiDatabase->NewPackageList (
1022 gHiiDatabase,
1023 PackageList,
1024 NULL,
1025 &HiiHandle
1026 );
1027 ASSERT_EFI_ERROR (Status);
1028 if (EFI_ERROR (Status)) {
1029 return NULL;
1030 }
1031 return HiiHandle;
1032 }