/** @file\r
UEFI Miscellaneous boot Services Stall service implementation\r
\r
-Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
// Include statements\r
//\r
\r
-#include <DxeMain.h>\r
+#include "DxeMain.h"\r
+\r
+/**\r
+ Internal worker function to call the Metronome Architectural Protocol for\r
+ the number of ticks specified by the UINT64 Counter value. WaitForTick()\r
+ service of the Metronome Architectural Protocol uses a UINT32 for the number\r
+ of ticks to wait, so this function loops when Counter is larger than 0xffffffff.\r
\r
+ @param Counter Number of ticks to wait.\r
\r
+**/\r
+VOID\r
+CoreInternalWaitForTick (\r
+ IN UINT64 Counter\r
+ )\r
+{\r
+ while (RShiftU64 (Counter, 32) > 0) {\r
+ gMetronome->WaitForTick (gMetronome, 0xffffffff);\r
+ Counter -= 0xffffffff;\r
+ }\r
+ gMetronome->WaitForTick (gMetronome, (UINT32)Counter);\r
+}\r
\r
/**\r
Introduces a fine-grained stall.\r
IN UINTN Microseconds\r
)\r
{\r
- UINT32 Counter;\r
+ UINT64 Counter;\r
UINT32 Remainder;\r
+ UINTN Index;\r
\r
if (gMetronome == NULL) {\r
return EFI_NOT_AVAILABLE_YET;\r
}\r
\r
//\r
- // Calculate the number of ticks by dividing the number of microseconds by\r
- // the TickPeriod.\r
- // Calcullation is based on 100ns unit.\r
- //\r
- Counter = (UINT32) DivU64x32Remainder (\r
- Microseconds * 10,\r
- gMetronome->TickPeriod,\r
- &Remainder\r
- );\r
-\r
- //\r
- // Call WaitForTick for Counter + 1 ticks to try to guarantee Counter tick\r
- // periods, thus attempting to ensure Microseconds of stall time.\r
+ // Counter = Microseconds * 10 / gMetronome->TickPeriod\r
+ // 0x1999999999999999 = (2^64 - 1) / 10\r
//\r
- if (Remainder != 0) {\r
- Counter++;\r
+ if ((UINT64) Microseconds > 0x1999999999999999ULL) {\r
+ //\r
+ // Microseconds is too large to multiple by 10 first. Perform the divide\r
+ // operation first and loop 10 times to avoid 64-bit math overflow.\r
+ //\r
+ Counter = DivU64x32Remainder (\r
+ Microseconds,\r
+ gMetronome->TickPeriod,\r
+ &Remainder\r
+ );\r
+ for (Index = 0; Index < 10; Index++) {\r
+ CoreInternalWaitForTick (Counter);\r
+ }\r
+\r
+ if (Remainder != 0) {\r
+ //\r
+ // If Remainder was not zero, then normally, Counter would be rounded\r
+ // up by 1 tick. In this case, since a loop for 10 counts was used\r
+ // to emulate the multiply by 10 operation, Counter needs to be rounded\r
+ // up by 10 counts.\r
+ //\r
+ CoreInternalWaitForTick (10);\r
+ }\r
+ } else {\r
+ //\r
+ // Calculate the number of ticks by dividing the number of microseconds by\r
+ // the TickPeriod. Calculation is based on 100ns unit.\r
+ //\r
+ Counter = DivU64x32Remainder (\r
+ MultU64x32 (Microseconds, 10),\r
+ gMetronome->TickPeriod,\r
+ &Remainder\r
+ );\r
+ if (Remainder != 0) {\r
+ //\r
+ // If Remainder is not zero, then round Counter up by one tick.\r
+ //\r
+ Counter++;\r
+ }\r
+ CoreInternalWaitForTick (Counter);\r
}\r
\r
- gMetronome->WaitForTick (gMetronome, Counter);\r
-\r
return EFI_SUCCESS;\r
}\r