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