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