]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Misc/Stall.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Misc / Stall.c
CommitLineData
23c98c94 1/** @file\r
504214c4 2 UEFI Miscellaneous boot Services Stall service implementation\r
28a00297 3\r
d1102dba 4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
28a00297 6\r
504214c4 7**/\r
28a00297 8\r
9//\r
10// Include statements\r
11//\r
12\r
9c4ac31c 13#include "DxeMain.h"\r
28a00297 14\r
a62da87e 15/**\r
d1102dba
LG
16 Internal worker function to call the Metronome Architectural Protocol for\r
17 the number of ticks specified by the UINT64 Counter value. WaitForTick()\r
a62da87e 18 service of the Metronome Architectural Protocol uses a UINT32 for the number\r
19 of ticks to wait, so this function loops when Counter is larger than 0xffffffff.\r
28a00297 20\r
a62da87e 21 @param Counter Number of ticks to wait.\r
22\r
23**/\r
24VOID\r
25CoreInternalWaitForTick (\r
26 IN UINT64 Counter\r
27 )\r
28{\r
769e4531 29 while (RShiftU64 (Counter, 32) > 0) {\r
a62da87e 30 gMetronome->WaitForTick (gMetronome, 0xffffffff);\r
31 Counter -= 0xffffffff;\r
32 }\r
1436aea4 33\r
a62da87e 34 gMetronome->WaitForTick (gMetronome, (UINT32)Counter);\r
35}\r
28a00297 36\r
162ed594 37/**\r
28a00297 38 Introduces a fine-grained stall.\r
39\r
162ed594 40 @param Microseconds The number of microseconds to stall execution.\r
28a00297 41\r
022c6d45 42 @retval EFI_SUCCESS Execution was stalled for at least the requested\r
43 amount of microseconds.\r
162ed594 44 @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet\r
28a00297 45\r
162ed594 46**/\r
47EFI_STATUS\r
48EFIAPI\r
49CoreStall (\r
1436aea4 50 IN UINTN Microseconds\r
162ed594 51 )\r
28a00297 52{\r
a62da87e 53 UINT64 Counter;\r
28a00297 54 UINT32 Remainder;\r
a62da87e 55 UINTN Index;\r
28a00297 56\r
57 if (gMetronome == NULL) {\r
58 return EFI_NOT_AVAILABLE_YET;\r
59 }\r
60\r
61 //\r
a62da87e 62 // Counter = Microseconds * 10 / gMetronome->TickPeriod\r
63 // 0x1999999999999999 = (2^64 - 1) / 10\r
28a00297 64 //\r
1436aea4 65 if ((UINT64)Microseconds > 0x1999999999999999ULL) {\r
a62da87e 66 //\r
d1102dba 67 // Microseconds is too large to multiple by 10 first. Perform the divide\r
a62da87e 68 // operation first and loop 10 times to avoid 64-bit math overflow.\r
69 //\r
70 Counter = DivU64x32Remainder (\r
71 Microseconds,\r
72 gMetronome->TickPeriod,\r
73 &Remainder\r
74 );\r
75 for (Index = 0; Index < 10; Index++) {\r
76 CoreInternalWaitForTick (Counter);\r
d1102dba 77 }\r
a62da87e 78\r
79 if (Remainder != 0) {\r
80 //\r
d1102dba 81 // If Remainder was not zero, then normally, Counter would be rounded\r
a62da87e 82 // up by 1 tick. In this case, since a loop for 10 counts was used\r
83 // to emulate the multiply by 10 operation, Counter needs to be rounded\r
84 // up by 10 counts.\r
85 //\r
86 CoreInternalWaitForTick (10);\r
87 }\r
88 } else {\r
89 //\r
90 // Calculate the number of ticks by dividing the number of microseconds by\r
91 // the TickPeriod. Calculation is based on 100ns unit.\r
92 //\r
93 Counter = DivU64x32Remainder (\r
94 MultU64x32 (Microseconds, 10),\r
95 gMetronome->TickPeriod,\r
96 &Remainder\r
97 );\r
98 if (Remainder != 0) {\r
99 //\r
100 // If Remainder is not zero, then round Counter up by one tick.\r
101 //\r
102 Counter++;\r
103 }\r
1436aea4 104\r
a62da87e 105 CoreInternalWaitForTick (Counter);\r
28a00297 106 }\r
107\r
28a00297 108 return EFI_SUCCESS;\r
109}\r