microsoft/mu_feature_ffa

Public

mirrored from https://github.com/microsoft/mu_feature_ffaAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
858d1559f5d2e1e97ccf62290e96060595aa2dfb

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

FfaFeaturePkg/Library/ArmArchTimerLibEx/ArmArchTimerLibEx.c

280lines · modecode

1/** @file
2 Generic ARM implementation of TimerLib.h
3
4 Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include <Base.h>
11#include <Library/ArmLib.h>
12#include <Library/BaseLib.h>
13#include <Library/TimerLib.h>
14#include <Library/DebugLib.h>
15#include <Library/PcdLib.h>
16#include <Library/ArmGenericTimerCounterLib.h>
17
18#define TICKS_PER_MICRO_SEC (PcdGet32 (PcdArmArchTimerFreqInHz)/1000000U)
19
20// Select appropriate multiply function for platform architecture.
21#ifdef MDE_CPU_ARM
22#define MULT_U64_X_N MultU64x32
23#else
24#define MULT_U64_X_N MultU64x64
25#endif
26
27RETURN_STATUS
28EFIAPI
29TimerConstructorEx (
30 VOID
31 )
32{
33 //
34 // Check if the ARM Generic Timer Extension is implemented.
35 //
36 if (ArmIsArchTimerImplemented ()) {
37 //
38 // Check if Architectural Timer frequency is pre-determined by the platform
39 // (ie. nonzero).
40 //
41 if (PcdGet32 (PcdArmArchTimerFreqInHz) != 0) {
42 //
43 // Check if ticks/uS is not 0. The Architectural timer runs at constant
44 // frequency, irrespective of CPU frequency. According to Generic Timer
45 // Ref manual, lower bound of the frequency is in the range of 1-10MHz.
46 //
47 ASSERT (TICKS_PER_MICRO_SEC);
48
49 #ifdef MDE_CPU_ARM
50 //
51 // Only set the frequency for ARMv7. We expect the secure firmware to
52 // have already done it.
53 // If the security extension is not implemented, set Timer Frequency
54 // here.
55 //
56 if (ArmHasSecurityExtensions ()) {
57 ArmGenericTimerSetTimerFreq (PcdGet32 (PcdArmArchTimerFreqInHz));
58 }
59
60 #endif
61 }
62
63 //
64 // Architectural Timer Frequency must be set in Secure privileged
65 // mode (if secure extension is supported).
66 // If the reset value (0) is returned, just ASSERT.
67 //
68 // ASSERT (ArmGenericTimerGetTimerFreq () != 0);
69 } else {
70 DEBUG ((DEBUG_ERROR, "ARM Architectural Timer is not available in the CPU, hence this library cannot be used.\n"));
71 ASSERT (0);
72 }
73
74 return RETURN_SUCCESS;
75}
76
77/**
78 A local utility function that returns the PCD value, if specified.
79 Otherwise it defaults to ArmGenericTimerGetTimerFreq.
80
81 @return The timer frequency.
82
83**/
84STATIC
85UINTN
86EFIAPI
87GetPlatformTimerFreq (
88 )
89{
90 UINTN TimerFreq;
91
92 TimerFreq = PcdGet32 (PcdArmArchTimerFreqInHz);
93 if (TimerFreq == 0) {
94 TimerFreq = ArmGenericTimerGetTimerFreq ();
95 }
96
97 return TimerFreq;
98}
99
100/**
101 Stalls the CPU for the number of microseconds specified by MicroSeconds.
102
103 @param MicroSeconds The minimum number of microseconds to delay.
104
105 @return The value of MicroSeconds input.
106
107**/
108UINTN
109EFIAPI
110MicroSecondDelay (
111 IN UINTN MicroSeconds
112 )
113{
114 UINT64 TimerTicks64;
115 UINT64 SystemCounterVal;
116
117 // Calculate counter ticks that represent requested delay:
118 // = MicroSeconds x TICKS_PER_MICRO_SEC
119 // = MicroSeconds x Frequency.10^-6
120 TimerTicks64 = DivU64x32 (
121 MULT_U64_X_N (
122 MicroSeconds,
123 GetPlatformTimerFreq ()
124 ),
125 1000000U
126 );
127
128 // Wait until delay count expires.
129 SystemCounterVal = 0;
130 while (SystemCounterVal < TimerTicks64) {
131 SystemCounterVal++;
132 }
133
134 return MicroSeconds;
135}
136
137/**
138 Stalls the CPU for at least the given number of nanoseconds.
139
140 Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
141
142 When the timer frequency is 1MHz, each tick corresponds to 1 microsecond.
143 Therefore, the nanosecond delay will be rounded up to the nearest 1 microsecond.
144
145 @param NanoSeconds The minimum number of nanoseconds to delay.
146
147 @return The value of NanoSeconds inputted.
148
149**/
150UINTN
151EFIAPI
152NanoSecondDelay (
153 IN UINTN NanoSeconds
154 )
155{
156 UINTN MicroSeconds;
157
158 // Round up to 1us Tick Number
159 MicroSeconds = NanoSeconds / 1000;
160 MicroSeconds += ((NanoSeconds % 1000) == 0) ? 0 : 1;
161
162 MicroSecondDelay (MicroSeconds);
163
164 return NanoSeconds;
165}
166
167/**
168 Retrieves the current value of a 64-bit free running performance counter.
169
170 The counter can either count up by 1 or count down by 1. If the physical
171 performance counter counts by a larger increment, then the counter values
172 must be translated. The properties of the counter can be retrieved from
173 GetPerformanceCounterProperties().
174
175 @return The current value of the free running performance counter.
176
177**/
178UINT64
179EFIAPI
180GetPerformanceCounter (
181 VOID
182 )
183{
184 // Just return the value of system count
185 return ArmGenericTimerGetSystemCount ();
186}
187
188/**
189 Retrieves the 64-bit frequency in Hz and the range of performance counter
190 values.
191
192 If StartValue is not NULL, then the value that the performance counter starts
193 with immediately after is it rolls over is returned in StartValue. If
194 EndValue is not NULL, then the value that the performance counter end with
195 immediately before it rolls over is returned in EndValue. The 64-bit
196 frequency of the performance counter in Hz is always returned. If StartValue
197 is less than EndValue, then the performance counter counts up. If StartValue
198 is greater than EndValue, then the performance counter counts down. For
199 example, a 64-bit free running counter that counts up would have a StartValue
200 of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
201 that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
202
203 @param StartValue The value the performance counter starts with when it
204 rolls over.
205 @param EndValue The value that the performance counter ends with before
206 it rolls over.
207
208 @return The frequency in Hz.
209
210**/
211UINT64
212EFIAPI
213GetPerformanceCounterProperties (
214 OUT UINT64 *StartValue OPTIONAL,
215 OUT UINT64 *EndValue OPTIONAL
216 )
217{
218 if (StartValue != NULL) {
219 // Timer starts at 0
220 *StartValue = (UINT64)0ULL;
221 }
222
223 if (EndValue != NULL) {
224 // Timer counts up.
225 *EndValue = 0xFFFFFFFFFFFFFFFFUL;
226 }
227
228 return (UINT64)ArmGenericTimerGetTimerFreq ();
229}
230
231/**
232 Converts elapsed ticks of performance counter to time in nanoseconds.
233
234 This function converts the elapsed ticks of running performance counter to
235 time value in unit of nanoseconds.
236
237 @param Ticks The number of elapsed ticks of running performance counter.
238
239 @return The elapsed time in nanoseconds.
240
241**/
242UINT64
243EFIAPI
244GetTimeInNanoSecond (
245 IN UINT64 Ticks
246 )
247{
248 UINT64 NanoSeconds;
249 UINT32 Remainder;
250 UINT32 TimerFreq;
251
252 TimerFreq = (UINT32)GetPlatformTimerFreq (); // MU_CHANGE - ARM64 VS change
253 //
254 // Ticks
255 // Time = --------- x 1,000,000,000
256 // Frequency
257 //
258 NanoSeconds = MULT_U64_X_N (
259 DivU64x32Remainder (
260 Ticks,
261 TimerFreq,
262 &Remainder
263 ),
264 1000000000U
265 );
266
267 //
268 // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)
269 // will not overflow 64-bit.
270 //
271 NanoSeconds += DivU64x32 (
272 MULT_U64_X_N (
273 (UINT64)Remainder,
274 1000000000U
275 ),
276 TimerFreq
277 );
278
279 return NanoSeconds;
280}
281