]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - 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
1/** @file\r
2 UEFI Miscellaneous boot Services Stall service implementation\r
3\r
4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9//\r
10// Include statements\r
11//\r
12\r
13#include "DxeMain.h"\r
14\r
15/**\r
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
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
20\r
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
29 while (RShiftU64 (Counter, 32) > 0) {\r
30 gMetronome->WaitForTick (gMetronome, 0xffffffff);\r
31 Counter -= 0xffffffff;\r
32 }\r
33\r
34 gMetronome->WaitForTick (gMetronome, (UINT32)Counter);\r
35}\r
36\r
37/**\r
38 Introduces a fine-grained stall.\r
39\r
40 @param Microseconds The number of microseconds to stall execution.\r
41\r
42 @retval EFI_SUCCESS Execution was stalled for at least the requested\r
43 amount of microseconds.\r
44 @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet\r
45\r
46**/\r
47EFI_STATUS\r
48EFIAPI\r
49CoreStall (\r
50 IN UINTN Microseconds\r
51 )\r
52{\r
53 UINT64 Counter;\r
54 UINT32 Remainder;\r
55 UINTN Index;\r
56\r
57 if (gMetronome == NULL) {\r
58 return EFI_NOT_AVAILABLE_YET;\r
59 }\r
60\r
61 //\r
62 // Counter = Microseconds * 10 / gMetronome->TickPeriod\r
63 // 0x1999999999999999 = (2^64 - 1) / 10\r
64 //\r
65 if ((UINT64)Microseconds > 0x1999999999999999ULL) {\r
66 //\r
67 // Microseconds is too large to multiple by 10 first. Perform the divide\r
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
77 }\r
78\r
79 if (Remainder != 0) {\r
80 //\r
81 // If Remainder was not zero, then normally, Counter would be rounded\r
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
104\r
105 CoreInternalWaitForTick (Counter);\r
106 }\r
107\r
108 return EFI_SUCCESS;\r
109}\r