/** @file UEFI Miscellaneous boot Services Stall service implementation Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ // // Include statements // #include "DxeMain.h" /** Internal worker function to call the Metronome Architectural Protocol for the number of ticks specified by the UINT64 Counter value. WaitForTick() service of the Metronome Architectural Protocol uses a UINT32 for the number of ticks to wait, so this function loops when Counter is larger than 0xffffffff. @param Counter Number of ticks to wait. **/ VOID CoreInternalWaitForTick ( IN UINT64 Counter ) { while (RShiftU64 (Counter, 32) > 0) { gMetronome->WaitForTick (gMetronome, 0xffffffff); Counter -= 0xffffffff; } gMetronome->WaitForTick (gMetronome, (UINT32)Counter); } /** Introduces a fine-grained stall. @param Microseconds The number of microseconds to stall execution. @retval EFI_SUCCESS Execution was stalled for at least the requested amount of microseconds. @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet **/ EFI_STATUS EFIAPI CoreStall ( IN UINTN Microseconds ) { UINT64 Counter; UINT32 Remainder; UINTN Index; if (gMetronome == NULL) { return EFI_NOT_AVAILABLE_YET; } // // Counter = Microseconds * 10 / gMetronome->TickPeriod // 0x1999999999999999 = (2^64 - 1) / 10 // if ((UINT64) Microseconds > 0x1999999999999999ULL) { // // Microseconds is too large to multiple by 10 first. Perform the divide // operation first and loop 10 times to avoid 64-bit math overflow. // Counter = DivU64x32Remainder ( Microseconds, gMetronome->TickPeriod, &Remainder ); for (Index = 0; Index < 10; Index++) { CoreInternalWaitForTick (Counter); } if (Remainder != 0) { // // If Remainder was not zero, then normally, Counter would be rounded // up by 1 tick. In this case, since a loop for 10 counts was used // to emulate the multiply by 10 operation, Counter needs to be rounded // up by 10 counts. // CoreInternalWaitForTick (10); } } else { // // Calculate the number of ticks by dividing the number of microseconds by // the TickPeriod. Calculation is based on 100ns unit. // Counter = DivU64x32Remainder ( MultU64x32 (Microseconds, 10), gMetronome->TickPeriod, &Remainder ); if (Remainder != 0) { // // If Remainder is not zero, then round Counter up by one tick. // Counter++; } CoreInternalWaitForTick (Counter); } return EFI_SUCCESS; }