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