EFIAPI AcquireSpinLock ( IN OUT SPIN_LOCK *SpinLock ) { UINT64 Tick; UINT64 Start, End; UINT64 Timeout; Tick = 0; Start = 0; End = 0; if (PcdGet32 (PcdSpinLockTimeout) > 0) { Tick = GetPerformanceCounter (); Timeout = DivU64x32 ( MultU64x32 ( GetPerformanceCounterProperties (&Start, &End), PcdGet32 (PcdSpinLockTimeout) ), 1000000 ); if (Start < End) { Tick += Timeout; } else { Tick -= Timeout; } } while (!AcquireSpinLockOrFail (SpinLock)) { CpuPause (); ASSERT ((Start < End) ^ (Tick <= GetPerformanceCounter ())); } return SpinLock; }
/** Stalls the CPU for at least the given number of nanoseconds. Stalls the CPU for the number of nanoseconds specified by NanoSeconds. @param NanoSeconds The minimum number of nanoseconds to delay. @return The value of NanoSeconds inputted. **/ UINTN EFIAPI NanoSecondDelay ( IN UINTN NanoSeconds ) { InternalIpfDelay ( GetPerformanceCounterProperties (NULL, NULL) * NanoSeconds / 1000000000 ); return NanoSeconds; }
/** Entry point of the Timestamp Protocol driver. @param ImageHandle The image handle of this driver. @param SystemTable The pointer of EFI_SYSTEM_TABLE. @retval EFI_SUCCESS Watchdog Timer Architectural Protocol successfully installed. **/ EFI_STATUS EFIAPI TimestampDriverInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_HANDLE TimestampHandle; TimestampHandle = NULL; // // Get the start value, end value and frequency in Timerlib // mTimestampProperties.Frequency = GetPerformanceCounterProperties(&mTimerLibStartValue, &mTimerLibEndValue); // // Set the EndValue // if (mTimerLibEndValue > mTimerLibStartValue) { mTimestampProperties.EndValue = mTimerLibEndValue - mTimerLibStartValue; } else { mTimestampProperties.EndValue = mTimerLibStartValue - mTimerLibEndValue; } DEBUG ((EFI_D_INFO, "TimerFrequency:0x%lx, TimerLibStartTime:0x%lx, TimerLibEndtime:0x%lx\n", mTimestampProperties.Frequency, mTimerLibStartValue, mTimerLibEndValue)); // // Install the Timestamp Protocol onto a new handle // Status = gBS->InstallMultipleProtocolInterfaces ( &TimestampHandle, &gEfiTimestampProtocolGuid, &mTimestamp, NULL ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }
/** Initialize Timer for SMM AP Sync. **/ VOID InitializeSmmTimer ( VOID ) { UINT64 TimerFrequency; UINT64 Start; UINT64 End; TimerFrequency = GetPerformanceCounterProperties (&Start, &End); mTimeoutTicker = DivU64x32 ( MultU64x64(TimerFrequency, PcdGet64 (PcdCpuSmmApSyncTimeout)), 1000 * 1000 ); if (End < Start) { mCountDown = TRUE; mCycle = Start - End; } else { mCountDown = FALSE; mCycle = End - Start; } }
/** Writes performance data of booting into the allocated memory. OS can process these records. @param Event The triggered event. @param Context Context for this event. **/ VOID EFIAPI WriteBootToOsPerformanceData ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; UINT32 LimitCount; EFI_HANDLE *Handles; UINTN NoHandles; CHAR8 GaugeString[PERF_TOKEN_SIZE]; UINT8 *Ptr; UINT32 Index; UINT64 Ticker; UINT64 Freq; UINT32 Duration; UINTN LogEntryKey; CONST VOID *Handle; CONST CHAR8 *Token; CONST CHAR8 *Module; UINT64 StartTicker; UINT64 EndTicker; UINT64 StartValue; UINT64 EndValue; BOOLEAN CountUp; UINTN EntryIndex; UINTN NumPerfEntries; // // List of flags indicating PerfEntry contains DXE handle // BOOLEAN *PerfEntriesAsDxeHandle; UINTN VarSize; // // Record the performance data for End of BDS // PERF_END(NULL, "BDS", NULL, 0); // // Retrieve time stamp count as early as possible // Ticker = GetPerformanceCounter (); Freq = GetPerformanceCounterProperties (&StartValue, &EndValue); Freq = DivU64x32 (Freq, 1000); mPerfHeader.CpuFreq = Freq; // // Record BDS raw performance data // if (EndValue >= StartValue) { mPerfHeader.BDSRaw = Ticker - StartValue; CountUp = TRUE; } else { mPerfHeader.BDSRaw = StartValue - Ticker; CountUp = FALSE; } if (mAcpiLowMemoryBase == 0x0FFFFFFFF) { VarSize = sizeof (EFI_PHYSICAL_ADDRESS); Status = gRT->GetVariable ( L"PerfDataMemAddr", &gPerformanceProtocolGuid, NULL, &VarSize, &mAcpiLowMemoryBase ); if (EFI_ERROR (Status)) { // // Fail to get the variable, return. // return; } } // // Put Detailed performance data into memory // Handles = NULL; Status = gBS->LocateHandleBuffer ( AllHandles, NULL, NULL, &NoHandles, &Handles ); if (EFI_ERROR (Status)) { return ; } Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER)); LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); NumPerfEntries = 0; LogEntryKey = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { NumPerfEntries++; } PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN)); ASSERT (PerfEntriesAsDxeHandle != NULL); // // Get DXE drivers performance // for (Index = 0; Index < NoHandles; Index++) { Ticker = 0; LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) { PerfEntriesAsDxeHandle[EntryIndex] = TRUE; } EntryIndex++; if ((Handle == Handles[Index]) && (EndTicker != 0)) { if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); } } Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); if (Duration > 0) { GetNameFromHandle (Handles[Index], GaugeString); AsciiStrCpyS (mPerfData.Token, PERF_TOKEN_SIZE, GaugeString); mPerfData.Duration = Duration; CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } } // // Get inserted performance data // LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) { ZeroMem (&mPerfData, sizeof (PERF_DATA)); AsciiStrnCpyS (mPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH); if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } EntryIndex++; } Done: FreePool (Handles); FreePool (PerfEntriesAsDxeHandle); mPerfHeader.Signiture = PERFORMANCE_SIGNATURE; // // Put performance data to Reserved memory // CopyMem ( (UINTN *) (UINTN) mAcpiLowMemoryBase, &mPerfHeader, sizeof (PERF_HEADER) ); return ; }
EFIAPI AcquireSpinLock ( IN OUT SPIN_LOCK *SpinLock ) { UINT64 Current; UINT64 Previous; UINT64 Total; UINT64 Start; UINT64 End; UINT64 Timeout; INT64 Cycle; INT64 Delta; if (PcdGet32 (PcdSpinLockTimeout) > 0) { // // Get the current timer value // Current = GetPerformanceCounter(); // // Initialize local variables // Start = 0; End = 0; Total = 0; // // Retrieve the performance counter properties and compute the number of performance // counter ticks required to reach the timeout // Timeout = DivU64x32 ( MultU64x32 ( GetPerformanceCounterProperties (&Start, &End), PcdGet32 (PcdSpinLockTimeout) ), 1000000 ); Cycle = End - Start; if (Cycle < 0) { Cycle = -Cycle; } Cycle++; while (!AcquireSpinLockOrFail (SpinLock)) { CpuPause (); Previous = Current; Current = GetPerformanceCounter(); Delta = (INT64) (Current - Previous); if (Start > End) { Delta = -Delta; } if (Delta < 0) { Delta += Cycle; } Total += Delta; ASSERT (Total < Timeout); } } else { while (!AcquireSpinLockOrFail (SpinLock)) { CpuPause (); } } return SpinLock; }
/** Allocates a block of memory and writes performance data of booting into it. OS can processing these record. **/ VOID WriteBootToOsPerformanceData ( VOID ) { EFI_STATUS Status; UINT32 AcpiLowMemoryLength; UINT32 LimitCount; EFI_HANDLE *Handles; UINTN NoHandles; CHAR8 GaugeString[PERF_TOKEN_LENGTH]; UINT8 *Ptr; UINT32 Index; UINT64 Ticker; UINT64 Freq; UINT32 Duration; UINTN LogEntryKey; CONST VOID *Handle; CONST CHAR8 *Token; CONST CHAR8 *Module; UINT64 StartTicker; UINT64 EndTicker; UINT64 StartValue; UINT64 EndValue; BOOLEAN CountUp; UINTN EntryIndex; UINTN NumPerfEntries; // // List of flags indicating PerfEntry contains DXE handle // BOOLEAN *PerfEntriesAsDxeHandle; // // Retrieve time stamp count as early as possible // Ticker = GetPerformanceCounter (); Freq = GetPerformanceCounterProperties (&StartValue, &EndValue); Freq = DivU64x32 (Freq, 1000); mPerfHeader.CpuFreq = Freq; // // Record BDS raw performance data // if (EndValue >= StartValue) { mPerfHeader.BDSRaw = Ticker - StartValue; CountUp = TRUE; } else { mPerfHeader.BDSRaw = StartValue - Ticker; CountUp = FALSE; } // // Put Detailed performance data into memory // Handles = NULL; Status = gBS->LocateHandleBuffer ( AllHandles, NULL, NULL, &NoHandles, &Handles ); if (EFI_ERROR (Status)) { return ; } AcpiLowMemoryLength = 0x4000; if (mAcpiLowMemoryBase == 0x0FFFFFFFF) { // // Allocate a block of memory that contain performance data to OS // Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (AcpiLowMemoryLength), &mAcpiLowMemoryBase ); if (EFI_ERROR (Status)) { FreePool (Handles); return ; } } Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER)); LimitCount = (AcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); NumPerfEntries = 0; LogEntryKey = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { NumPerfEntries++; } PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN)); ASSERT (PerfEntriesAsDxeHandle != NULL); // // Get DXE drivers performance // for (Index = 0; Index < NoHandles; Index++) { Ticker = 0; LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) { PerfEntriesAsDxeHandle[EntryIndex] = TRUE; } EntryIndex++; if ((Handle == Handles[Index]) && (EndTicker != 0)) { if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); } } Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); if (Duration > 0) { GetNameFromHandle (Handles[Index], GaugeString); AsciiStrCpy (mPerfData.Token, GaugeString); mPerfData.Duration = Duration; CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } } // // Get inserted performance data // LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) { ZeroMem (&mPerfData, sizeof (PERF_DATA)); AsciiStrnCpy (mPerfData.Token, Token, PERF_TOKEN_LENGTH); if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } EntryIndex++; } Done: FreePool (Handles); FreePool (PerfEntriesAsDxeHandle); mPerfHeader.Signiture = PERFORMANCE_SIGNATURE; // // Put performance data to Reserved memory // CopyMem ( (UINTN *) (UINTN) mAcpiLowMemoryBase, &mPerfHeader, sizeof (PERF_HEADER) ); gRT->SetVariable ( L"PerfDataMemAddr", &gPerformanceProtocolGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof (EFI_PHYSICAL_ADDRESS), &mAcpiLowMemoryBase ); return ; }
/** Dump performance data. @param[in] ImageHandle The image handle. @param[in] SystemTable The system table. @retval EFI_SUCCESS Command completed successfully. @retval EFI_INVALID_PARAMETER Command usage error. @retval EFI_ABORTED The user aborts the operation. @retval value Unknown error. **/ EFI_STATUS EFIAPI InitializeDp ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { UINT64 Freq; UINT64 Ticker; UINT32 ListIndex; LIST_ENTRY *ParamPackage; CONST CHAR16 *CmdLineArg; EFI_STRING StringPtr; UINTN Number2Display; EFI_STATUS Status; BOOLEAN SummaryMode; BOOLEAN VerboseMode; BOOLEAN AllMode; BOOLEAN RawMode; BOOLEAN TraceMode; BOOLEAN ProfileMode; BOOLEAN ExcludeMode; BOOLEAN CumulativeMode; CONST CHAR16 *CustomCumulativeToken; PERF_CUM_DATA *CustomCumulativeData; EFI_STRING StringDpOptionQh; EFI_STRING StringDpOptionLh; EFI_STRING StringDpOptionUh; EFI_STRING StringDpOptionLv; EFI_STRING StringDpOptionUs; EFI_STRING StringDpOptionLs; EFI_STRING StringDpOptionUa; EFI_STRING StringDpOptionUr; EFI_STRING StringDpOptionUt; EFI_STRING StringDpOptionUp; EFI_STRING StringDpOptionLx; EFI_STRING StringDpOptionLn; EFI_STRING StringDpOptionLt; EFI_STRING StringDpOptionLi; EFI_STRING StringDpOptionLc; SummaryMode = FALSE; VerboseMode = FALSE; AllMode = FALSE; RawMode = FALSE; TraceMode = FALSE; ProfileMode = FALSE; ExcludeMode = FALSE; CumulativeMode = FALSE; CustomCumulativeData = NULL; StringDpOptionQh = NULL; StringDpOptionLh = NULL; StringDpOptionUh = NULL; StringDpOptionLv = NULL; StringDpOptionUs = NULL; StringDpOptionLs = NULL; StringDpOptionUa = NULL; StringDpOptionUr = NULL; StringDpOptionUt = NULL; StringDpOptionUp = NULL; StringDpOptionLx = NULL; StringDpOptionLn = NULL; StringDpOptionLt = NULL; StringDpOptionLi = NULL; StringDpOptionLc = NULL; StringPtr = NULL; // Get DP's entry time as soon as possible. // This is used as the Shell-Phase end time. // Ticker = GetPerformanceCounter (); // Register our string package with HII and return the handle to it. // gHiiHandle = HiiAddPackages (&gEfiCallerIdGuid, ImageHandle, DPStrings, NULL); ASSERT (gHiiHandle != NULL); // Initial the command list // InitialShellParamList (); /**************************************************************************** **** Process Command Line arguments **** ****************************************************************************/ Status = ShellCommandLineParse (DpParamList, &ParamPackage, NULL, TRUE); if (EFI_ERROR(Status)) { PrintToken (STRING_TOKEN (STR_DP_INVALID_ARG)); ShowHelp(); } else { StringDpOptionQh = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_QH), NULL); StringDpOptionLh = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_LH), NULL); StringDpOptionUh = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_UH), NULL); if (ShellCommandLineGetFlag (ParamPackage, StringDpOptionQh) || ShellCommandLineGetFlag (ParamPackage, StringDpOptionLh) || ShellCommandLineGetFlag (ParamPackage, StringDpOptionUh)) { ShowHelp(); } else { StringDpOptionLv = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_LV), NULL); StringDpOptionUs = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_US), NULL); StringDpOptionLs = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_LS), NULL); StringDpOptionUa = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_UA), NULL); StringDpOptionUr = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_UR), NULL); StringDpOptionUt = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_UT), NULL); StringDpOptionUp = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_UP), NULL); StringDpOptionLx = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_LX), NULL); StringDpOptionLn = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_LN), NULL); StringDpOptionLt = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_LT), NULL); StringDpOptionLi = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_LI), NULL); StringDpOptionLc = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_OPTION_LC), NULL); // Boolean Options // VerboseMode = ShellCommandLineGetFlag (ParamPackage, StringDpOptionLv); SummaryMode = (BOOLEAN) (ShellCommandLineGetFlag (ParamPackage, StringDpOptionUs) || ShellCommandLineGetFlag (ParamPackage, StringDpOptionLs)); AllMode = ShellCommandLineGetFlag (ParamPackage, StringDpOptionUa); RawMode = ShellCommandLineGetFlag (ParamPackage, StringDpOptionUr); #if PROFILING_IMPLEMENTED TraceMode = ShellCommandLineGetFlag (ParamPackage, StringDpOptionUt); ProfileMode = ShellCommandLineGetFlag (ParamPackage, StringDpOptionUp); #endif // PROFILING_IMPLEMENTED ExcludeMode = ShellCommandLineGetFlag (ParamPackage, StringDpOptionLx); mShowId = ShellCommandLineGetFlag (ParamPackage, StringDpOptionLi); CumulativeMode = ShellCommandLineGetFlag (ParamPackage, StringDpOptionLc); // Options with Values CmdLineArg = ShellCommandLineGetValue (ParamPackage, StringDpOptionLn); if (CmdLineArg == NULL) { Number2Display = DEFAULT_DISPLAYCOUNT; } else { Number2Display = StrDecimalToUintn(CmdLineArg); if (Number2Display == 0) { Number2Display = MAXIMUM_DISPLAYCOUNT; } } CmdLineArg = ShellCommandLineGetValue (ParamPackage, StringDpOptionLt); if (CmdLineArg == NULL) { mInterestThreshold = DEFAULT_THRESHOLD; // 1ms := 1,000 us } else { mInterestThreshold = StrDecimalToUint64(CmdLineArg); } // Handle Flag combinations and default behaviors // If both TraceMode and ProfileMode are FALSE, set them both to TRUE if ((! TraceMode) && (! ProfileMode)) { TraceMode = TRUE; #if PROFILING_IMPLEMENTED ProfileMode = TRUE; #endif // PROFILING_IMPLEMENTED } // // Init the custom cumulative data. // CustomCumulativeToken = ShellCommandLineGetValue (ParamPackage, StringDpOptionLc); if (CustomCumulativeToken != NULL) { CustomCumulativeData = AllocateZeroPool (sizeof (PERF_CUM_DATA)); ASSERT (CustomCumulativeData != NULL); CustomCumulativeData->MinDur = 0; CustomCumulativeData->MaxDur = 0; CustomCumulativeData->Count = 0; CustomCumulativeData->Duration = 0; CustomCumulativeData->Name = AllocateZeroPool (StrLen (CustomCumulativeToken) + 1); UnicodeStrToAsciiStr (CustomCumulativeToken, CustomCumulativeData->Name); } /**************************************************************************** **** Timer specific processing **** ****************************************************************************/ // Get the Performance counter characteristics: // Freq = Frequency in Hz // StartCount = Value loaded into the counter when it starts counting // EndCount = Value counter counts to before it needs to be reset // Freq = GetPerformanceCounterProperties (&TimerInfo.StartCount, &TimerInfo.EndCount); // Convert the Frequency from Hz to KHz TimerInfo.Frequency = (UINT32)DivU64x32 (Freq, 1000); // Determine in which direction the performance counter counts. TimerInfo.CountUp = (BOOLEAN) (TimerInfo.EndCount >= TimerInfo.StartCount); /**************************************************************************** **** Print heading **** ****************************************************************************/ // print DP's build version PrintToken (STRING_TOKEN (STR_DP_BUILD_REVISION), DP_MAJOR_VERSION, DP_MINOR_VERSION); // print performance timer characteristics PrintToken (STRING_TOKEN (STR_DP_KHZ), TimerInfo.Frequency); // Print Timer frequency in KHz if ((VerboseMode) && (! RawMode) ) { StringPtr = HiiGetString (gHiiHandle, (EFI_STRING_ID) (TimerInfo.CountUp ? STRING_TOKEN (STR_DP_UP) : STRING_TOKEN (STR_DP_DOWN)), NULL); ASSERT (StringPtr != NULL); PrintToken (STRING_TOKEN (STR_DP_TIMER_PROPERTIES), // Print Timer count range and direction StringPtr, TimerInfo.StartCount, TimerInfo.EndCount ); PrintToken (STRING_TOKEN (STR_DP_VERBOSE_THRESHOLD), mInterestThreshold); } /* ************************************************************************** **** Print Sections based on command line options **** **** Option modes have the following priority: **** v Verbose -- Valid in combination with any other options **** t Threshold -- Modifies All, Raw, and Cooked output **** Default is 0 for All and Raw mode **** Default is DEFAULT_THRESHOLD for "Cooked" mode **** n Number2Display Used by All and Raw mode. Otherwise ignored. **** A All -- R and S options are ignored **** R Raw -- S option is ignored **** s Summary -- Modifies "Cooked" output only **** Cooked (Default) **** **** The All, Raw, and Cooked modes are modified by the Trace and Profile **** options. **** !T && !P := (0) Default, Both are displayed **** T && !P := (1) Only Trace records are displayed **** !T && P := (2) Only Profile records are displayed **** T && P := (3) Same as Default, both are displayed ****************************************************************************/ GatherStatistics (CustomCumulativeData); if (CumulativeMode) { ProcessCumulative (CustomCumulativeData); } else if (AllMode) { if (TraceMode) { Status = DumpAllTrace( Number2Display, ExcludeMode); if (Status == EFI_ABORTED) { goto Done; } } if (ProfileMode) { DumpAllProfile( Number2Display, ExcludeMode); } } else if (RawMode) { if (TraceMode) { Status = DumpRawTrace( Number2Display, ExcludeMode); if (Status == EFI_ABORTED) { goto Done; } } if (ProfileMode) { DumpRawProfile( Number2Display, ExcludeMode); } } else { //------------- Begin Cooked Mode Processing if (TraceMode) { ProcessPhases ( Ticker ); if ( ! SummaryMode) { Status = ProcessHandles ( ExcludeMode); if (Status == EFI_ABORTED) { goto Done; } Status = ProcessPeims (); if (Status == EFI_ABORTED) { goto Done; } Status = ProcessGlobal (); if (Status == EFI_ABORTED) { goto Done; } ProcessCumulative (NULL); } } if (ProfileMode) { DumpAllProfile( Number2Display, ExcludeMode); } } //------------- End of Cooked Mode Processing if ( VerboseMode || SummaryMode) { DumpStatistics(); } } } Done: // // Free the memory allocate from HiiGetString // ListIndex = 0; while (DpParamList[ListIndex].Name != NULL) { FreePool (DpParamList[ListIndex].Name); ListIndex ++; } FreePool (DpParamList); SafeFreePool (StringDpOptionQh); SafeFreePool (StringDpOptionLh); SafeFreePool (StringDpOptionUh); SafeFreePool (StringDpOptionLv); SafeFreePool (StringDpOptionUs); SafeFreePool (StringDpOptionLs); SafeFreePool (StringDpOptionUa); SafeFreePool (StringDpOptionUr); SafeFreePool (StringDpOptionUt); SafeFreePool (StringDpOptionUp); SafeFreePool (StringDpOptionLx); SafeFreePool (StringDpOptionLn); SafeFreePool (StringDpOptionLt); SafeFreePool (StringDpOptionLi); SafeFreePool (StringDpOptionLc); SafeFreePool (StringPtr); SafeFreePool (mPrintTokenBuffer); if (CustomCumulativeData != NULL) { SafeFreePool (CustomCumulativeData->Name); } SafeFreePool (CustomCumulativeData); HiiRemovePackages (gHiiHandle); return Status; }
/** Initialize the debug port. If Function is not NULL, Debug Communication Libary will call this function by passing in the Context to be the first parameter. If needed, Debug Communication Library will create one debug port handle to be the second argument passing in calling the Function, otherwise it will pass NULL to be the second argument of Function. If Function is NULL, and Context is not NULL, the Debug Communication Library could a) Return the same handle as passed in (as Context parameter). b) Ignore the input Context parameter and create new hanlde to be returned. If parameter Function is NULL and Context is NULL, Debug Communication Library could created a new handle if needed and return it, otherwise it will return NULL. @param[in] Context Context needed by callback function; it was optional. @param[in] Function Continue function called by Debug Communication library; it was optional. @return The debug port handle created by Debug Communication Library if Function is not NULL. **/ DEBUG_PORT_HANDLE EFIAPI DebugPortInitialize ( IN VOID *Context, IN DEBUG_PORT_CONTINUE Function ) { RETURN_STATUS Status; USB_DEBUG_PORT_HANDLE Handle; USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle; UINT64 TimerStartValue; UINT64 TimerEndValue; // // Validate the PCD PcdDebugPortHandleBufferSize value // ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB_DEBUG_PORT_HANDLE)); if (Function == NULL && Context != NULL) { UsbDebugPortHandle = (USB_DEBUG_PORT_HANDLE *)Context; } else { ZeroMem(&Handle, sizeof (USB_DEBUG_PORT_HANDLE)); UsbDebugPortHandle = &Handle; } UsbDebugPortHandle->TimerFrequency = GetPerformanceCounterProperties ( &TimerStartValue, &TimerEndValue ); DEBUG ((EFI_D_INFO, "USB Debug Port: TimerFrequency = 0x%lx\n", UsbDebugPortHandle->TimerFrequency)); DEBUG ((EFI_D_INFO, "USB Debug Port: TimerStartValue = 0x%lx\n", TimerStartValue)); DEBUG ((EFI_D_INFO, "USB Debug Port: TimerEndValue = 0x%lx\n", TimerEndValue)); if (TimerEndValue < TimerStartValue) { UsbDebugPortHandle->TimerCountDown = TRUE; UsbDebugPortHandle->TimerCycle = TimerStartValue - TimerEndValue; } else { UsbDebugPortHandle->TimerCountDown = FALSE; UsbDebugPortHandle->TimerCycle = TimerEndValue - TimerStartValue; } if (Function == NULL && Context != NULL) { return (DEBUG_PORT_HANDLE *) Context; } Status = CalculateUsbDebugPortBar(&Handle.DebugPortOffset, &Handle.DebugPortBarNumber); if (RETURN_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "UsbDbg: the pci device pointed by PcdUsbEhciPciAddress is not EHCI host controller or does not support debug port capability!\n")); goto Exit; } Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET); if (Handle.EhciMemoryBase == 0) { // // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero // PciWrite32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, PcdGet32(PcdUsbEhciMemorySpaceBase)); Handle.EhciMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET); } Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4); if (Handle.UsbDebugPortMemoryBase == 0) { // // Usb Debug Port MMIO Space Is Not Enabled. Assumption here that DebugPortBase is zero // PciWrite32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4, PcdGet32(PcdUsbDebugPortMemorySpaceBase)); Handle.UsbDebugPortMemoryBase = 0xFFFFFC00 & PciRead32(PcdGet32(PcdUsbEhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + Handle.DebugPortBarNumber * 4); } Handle.Initialized = USBDBG_RESET; if (NeedReinitializeHardware(&Handle)) { DEBUG ((EFI_D_ERROR, "UsbDbg: Start EHCI debug port initialization!\n")); Status = InitializeUsbDebugHardware (&Handle); if (RETURN_ERROR(Status)) { DEBUG ((EFI_D_ERROR, "UsbDbg: Failed, please check if USB debug cable is plugged into EHCI debug port correctly!\n")); goto Exit; } } Exit: if (Function != NULL) { Function (Context, &Handle); } else { CopyMem(&mUsbDebugPortHandle, &Handle, sizeof (USB_DEBUG_PORT_HANDLE)); } return (DEBUG_PORT_HANDLE)(UINTN)&mUsbDebugPortHandle;
/** Simple arm disassembler via a library Argv[0] - disasm Argv[1] - Address to start disassembling from ARgv[2] - Number of instructions to disassembly (optional) @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EblPerformance ( IN UINTN Argc, IN CHAR8 **Argv ) { UINTN Key; CONST VOID *Handle; CONST CHAR8 *Token, *Module; UINT64 Start, Stop, TimeStamp; UINT64 Delta, TicksPerSecond, Milliseconds, Microseconds; UINTN Index; BOOLEAN CountUp; TicksPerSecond = GetPerformanceCounterProperties (&Start, &Stop); if (Start < Stop) { CountUp = TRUE; } else { CountUp = FALSE; } Key = 0; do { Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); if (Key != 0) { if (AsciiStriCmp ("StartImage:", Token) == 0) { if (Stop == 0) { // The entry for EBL is still running so the stop time will be zero. Skip it AsciiPrint (" running %a\n", ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); } else { Delta = CountUp?(Stop - Start):(Start - Stop); Microseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000000), TicksPerSecond, NULL); AsciiPrint ("%10ld us %a\n", Microseconds, ImageHandleToPdbFileName ((EFI_HANDLE)Handle)); } } } } while (Key != 0); AsciiPrint ("\n"); TimeStamp = 0; Key = 0; do { Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); if (Key != 0) { for (Index = 0; mTokenList[Index] != NULL; Index++) { if (AsciiStriCmp (mTokenList[Index], Token) == 0) { Delta = CountUp?(Stop - Start):(Start - Stop); TimeStamp += Delta; Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL); AsciiPrint ("%6a %6ld ms\n", Token, Milliseconds); break; } } } } while (Key != 0); AsciiPrint ("Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL)); return EFI_SUCCESS; }
/** This service enables the sending of commands to the TPM12. @param[in] InputParameterBlockSize Size of the TPM12 input parameter block. @param[in] InputParameterBlock Pointer to the TPM12 input parameter block. @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block. @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block. @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. **/ EFI_STATUS EFIAPI Tpm12SubmitCommand ( IN UINT32 InputParameterBlockSize, IN UINT8 *InputParameterBlock, IN OUT UINT32 *OutputParameterBlockSize, IN UINT8 *OutputParameterBlock ) { EFI_STATUS Status; UINT32 TpmOutSize; TPM_RSP_COMMAND_HDR *ResponseHeader; UINT64 Current; UINT64 Previous; UINT64 Total; UINT64 Start; UINT64 End; UINT64 Timeout; INT64 Cycle; INT64 Delta; // // Make sure response buffer is big enough to hold a response header // if (*OutputParameterBlockSize < sizeof (TPM_RSP_COMMAND_HDR)) { Status = EFI_BUFFER_TOO_SMALL; goto Done; } // // Get the current timer value // Current = GetPerformanceCounter(); // // Initialize local variables // Start = 0; End = 0; Total = 0; // // Retrieve the performance counter properties and compute the number of // performance counter ticks required to reach the maximum TIS timeout of // TIS_TIMEOUT_A. TIS_TIMEOUT_A is in microseconds. // Timeout = DivU64x32 ( MultU64x32 ( GetPerformanceCounterProperties (&Start, &End), TIS_TIMEOUT_A ), 1000000 ); Cycle = End - Start; if (Cycle < 0) { Cycle = -Cycle; } Cycle++; // // Send command // do { Status = WriteTpmBufferMultiple (InputParameterBlock, InputParameterBlockSize); Previous = Current; Current = GetPerformanceCounter(); Delta = (INT64) (Current - Previous); if (Start > End) { Delta = -Delta; } if (Delta < 0) { Delta += Cycle; } Total += Delta; if (Total >= Timeout) { Status = EFI_TIMEOUT; goto Done; } } while (EFI_ERROR (Status)); // // Receive response header // do { Status = ReadTpmBufferMultiple (OutputParameterBlock, sizeof (TPM_RSP_COMMAND_HDR)); Previous = Current; Current = GetPerformanceCounter(); Delta = (INT64) (Current - Previous); if (Start > End) { Delta = -Delta; } if (Delta < 0) { Delta += Cycle; } Total += Delta; if (Total >= Timeout) { Status = EFI_TIMEOUT; goto Done; } } while (EFI_ERROR (Status)); // // Check the response data header (tag, parasize and returncode) // ResponseHeader = (TPM_RSP_COMMAND_HDR *)OutputParameterBlock; if (SwapBytes16 (ReadUnaligned16 (&ResponseHeader->tag)) != TPM_TAG_RSP_COMMAND) { Status = EFI_DEVICE_ERROR; goto Done; } TpmOutSize = SwapBytes32 (ReadUnaligned32 (&ResponseHeader->paramSize)); if (TpmOutSize == sizeof (TPM_RSP_COMMAND_HDR)) { Status = EFI_SUCCESS; goto Done; } if (TpmOutSize < sizeof (TPM_RSP_COMMAND_HDR)) { Status = EFI_DEVICE_ERROR; goto Done; } if (*OutputParameterBlockSize < TpmOutSize) { Status = EFI_BUFFER_TOO_SMALL; goto Done; } *OutputParameterBlockSize = TpmOutSize; // // Receive the remaining data in the response header // do { Status = ReadTpmBufferMultiple ( OutputParameterBlock + sizeof (TPM_RSP_COMMAND_HDR), TpmOutSize - sizeof (TPM_RSP_COMMAND_HDR) ); Previous = Current; Current = GetPerformanceCounter(); Delta = (INT64) (Current - Previous); if (Start > End) { Delta = -Delta; } if (Delta < 0) { Delta += Cycle; } Total += Delta; if (Total >= Timeout) { Status = EFI_TIMEOUT; goto Done; } } while (EFI_ERROR (Status)); Done: DEBUG (( EFI_D_VERBOSE, "Tpm12SubmitCommand() Status = %r Time = %ld ms\n", Status, DivU64x64Remainder ( MultU64x32 (Total, 1000), GetPerformanceCounterProperties (NULL, NULL), NULL ) )); return Status; }
/** This service requests use TPM12. @retval EFI_SUCCESS Get the control of TPM12 chip. @retval EFI_NOT_FOUND TPM12 not found. @retval EFI_DEVICE_ERROR Unexpected device behavior. **/ EFI_STATUS EFIAPI Tpm12RequestUseTpm ( VOID ) { EFI_STATUS Status; UINT8 Data; UINT64 Current; UINT64 Previous; UINT64 Total; UINT64 Start; UINT64 End; UINT64 Timeout; INT64 Cycle; INT64 Delta; // // Get the current timer value // Current = GetPerformanceCounter(); // // Initialize local variables // Start = 0; End = 0; Total = 0; // // Retrieve the performance counter properties and compute the number of // performance counter ticks required to reach the maximum TIS timeout of // TIS_TIMEOUT_A. TIS_TIMEOUT_A is in microseconds. // Timeout = DivU64x32 ( MultU64x32 ( GetPerformanceCounterProperties (&Start, &End), TIS_TIMEOUT_A ), 1000000 ); Cycle = End - Start; if (Cycle < 0) { Cycle = -Cycle; } Cycle++; // // Attempt to read a byte from the Atmel I2C TPM // do { Status = ReadTpmBufferMultiple (&Data, sizeof(Data)); Previous = Current; Current = GetPerformanceCounter(); Delta = (INT64) (Current - Previous); if (Start > End) { Delta = -Delta; } if (Delta < 0) { Delta += Cycle; } Total += Delta; if (Total >= Timeout) { Status = EFI_TIMEOUT; DEBUG ((EFI_D_ERROR, "Atmel I2C TPM failed to read: %r\n", Status)); return Status; } } while (EFI_ERROR (Status)); // // Send Physical Presence Command to Atmel I2C TPM // Status = Tpm12PhysicalPresence (TPM_PHYSICAL_PRESENCE_PRESENT); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Atmel I2C TPM failed to submit physical presence command: %r\n", Status)); return Status; } return EFI_SUCCESS; }
/** Performance measure function to get S3 detailed performance data. This function will getS3 detailed performance data and saved in pre-reserved ACPI memory. **/ VOID WriteToOsS3PerformanceData ( VOID ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase; PERF_HEADER *PerfHeader; PERF_DATA *PerfData; UINT64 Ticker; UINTN Index; EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices; UINTN VarSize; UINTN LogEntryKey; CONST VOID *Handle; CONST CHAR8 *Token; CONST CHAR8 *Module; UINT64 StartTicker; UINT64 EndTicker; UINT64 StartValue; UINT64 EndValue; BOOLEAN CountUp; UINT64 Freq; // // Retrive time stamp count as early as possilbe // Ticker = GetPerformanceCounter (); Freq = GetPerformanceCounterProperties (&StartValue, &EndValue); Freq = DivU64x32 (Freq, 1000); Status = PeiServicesLocatePpi ( &gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariableServices ); ASSERT_EFI_ERROR (Status); VarSize = sizeof (EFI_PHYSICAL_ADDRESS); Status = VariableServices->GetVariable ( VariableServices, L"PerfDataMemAddr", &gPerformanceProtocolGuid, NULL, &VarSize, &mAcpiLowMemoryBase ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Fail to retrieve variable to log S3 performance data \n")); return; } PerfHeader = (PERF_HEADER *) (UINTN) mAcpiLowMemoryBase; if (PerfHeader->Signiture != PERFORMANCE_SIGNATURE) { DEBUG ((EFI_D_ERROR, "Performance data in ACPI memory get corrupted! \n")); return; } // // Record total S3 resume time. // if (EndValue >= StartValue) { PerfHeader->S3Resume = Ticker - StartValue; CountUp = TRUE; } else { PerfHeader->S3Resume = StartValue - Ticker; CountUp = FALSE; } // // Get S3 detailed performance data // Index = 0; LogEntryKey = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (EndTicker != 0) { PerfData = &PerfHeader->S3Entry[Index]; // // Use File Handle to specify the different performance log for PEIM. // File Handle is the base address of PEIM FFS file. // if ((AsciiStrnCmp (Token, "PEIM", PEI_PERFORMANCE_STRING_SIZE) == 0) && (Handle != NULL)) { AsciiSPrint (PerfData->Token, PERF_TOKEN_LENGTH, "0x%11p", Handle); } else { AsciiStrnCpy (PerfData->Token, Token, PERF_TOKEN_LENGTH); } if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker = CountUp? (EndTicker - StartTicker) : (StartTicker - EndTicker); PerfData->Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); // // Only Record > 1ms performance data so that more big performance can be recorded. // if ((Ticker > Freq) && (++Index >= PERF_PEI_ENTRY_MAX_NUM)) { // // Reach the maximum number of PEI performance log entries. // break; } } } PerfHeader->S3EntryNum = (UINT32) Index; }