]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BaseSynchronizationLib/SynchronizationGcc.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdePkg / Library / BaseSynchronizationLib / SynchronizationGcc.c
1 /** @file
2 Implementation of synchronization functions.
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "BaseSynchronizationLibInternals.h"
11
12 //
13 // GCC inline assembly for Read Write Barrier
14 //
15 #define _ReadWriteBarrier() do { __asm__ __volatile__ ("": : : "memory"); } while(0)
16
17 #define SPIN_LOCK_RELEASED ((UINTN) 1)
18 #define SPIN_LOCK_ACQUIRED ((UINTN) 2)
19
20 /**
21 Retrieves the architecture specific spin lock alignment requirements for
22 optimal spin lock performance.
23
24 This function retrieves the spin lock alignment requirements for optimal
25 performance on a given CPU architecture. The spin lock alignment is byte alignment.
26 It must be a power of two and is returned by this function. If there are no alignment
27 requirements, then 1 must be returned. The spin lock synchronization
28 functions must function correctly if the spin lock size and alignment values
29 returned by this function are not used at all. These values are hints to the
30 consumers of the spin lock synchronization functions to obtain optimal spin
31 lock performance.
32
33 @return The architecture specific spin lock alignment.
34
35 **/
36 UINTN
37 EFIAPI
38 GetSpinLockProperties (
39 VOID
40 )
41 {
42 return InternalGetSpinLockProperties ();
43 }
44
45 /**
46 Initializes a spin lock to the released state and returns the spin lock.
47
48 This function initializes the spin lock specified by SpinLock to the released
49 state, and returns SpinLock. Optimal performance can be achieved by calling
50 GetSpinLockProperties() to determine the size and alignment requirements for
51 SpinLock.
52
53 If SpinLock is NULL, then ASSERT().
54
55 @param SpinLock A pointer to the spin lock to initialize to the released
56 state.
57
58 @return SpinLock is in release state.
59
60 **/
61 SPIN_LOCK *
62 EFIAPI
63 InitializeSpinLock (
64 OUT SPIN_LOCK *SpinLock
65 )
66 {
67 ASSERT (SpinLock != NULL);
68
69 _ReadWriteBarrier ();
70 *SpinLock = SPIN_LOCK_RELEASED;
71 _ReadWriteBarrier ();
72
73 return SpinLock;
74 }
75
76 /**
77 Waits until a spin lock can be placed in the acquired state.
78
79 This function checks the state of the spin lock specified by SpinLock. If
80 SpinLock is in the released state, then this function places SpinLock in the
81 acquired state and returns SpinLock. Otherwise, this function waits
82 indefinitely for the spin lock to be released, and then places it in the
83 acquired state and returns SpinLock. All state transitions of SpinLock must
84 be performed using MP safe mechanisms.
85
86 If SpinLock is NULL, then ASSERT().
87 If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
88 If PcdSpinLockTimeout is not zero, and SpinLock is can not be acquired in
89 PcdSpinLockTimeout microseconds, then ASSERT().
90
91 @param SpinLock A pointer to the spin lock to place in the acquired state.
92
93 @return SpinLock acquired the lock.
94
95 **/
96 SPIN_LOCK *
97 EFIAPI
98 AcquireSpinLock (
99 IN OUT SPIN_LOCK *SpinLock
100 )
101 {
102 UINT64 Current;
103 UINT64 Previous;
104 UINT64 Total;
105 UINT64 Start;
106 UINT64 End;
107 UINT64 Timeout;
108 INT64 Cycle;
109 INT64 Delta;
110
111 if (PcdGet32 (PcdSpinLockTimeout) == 0) {
112 while (!AcquireSpinLockOrFail (SpinLock)) {
113 CpuPause ();
114 }
115 } else if (!AcquireSpinLockOrFail (SpinLock)) {
116 //
117 // Get the current timer value
118 //
119 Current = GetPerformanceCounter ();
120
121 //
122 // Initialize local variables
123 //
124 Start = 0;
125 End = 0;
126 Total = 0;
127
128 //
129 // Retrieve the performance counter properties and compute the number of performance
130 // counter ticks required to reach the timeout
131 //
132 Timeout = DivU64x32 (
133 MultU64x32 (
134 GetPerformanceCounterProperties (&Start, &End),
135 PcdGet32 (PcdSpinLockTimeout)
136 ),
137 1000000
138 );
139 Cycle = End - Start;
140 if (Cycle < 0) {
141 Cycle = -Cycle;
142 }
143
144 Cycle++;
145
146 while (!AcquireSpinLockOrFail (SpinLock)) {
147 CpuPause ();
148 Previous = Current;
149 Current = GetPerformanceCounter ();
150 Delta = (INT64)(Current - Previous);
151 if (Start > End) {
152 Delta = -Delta;
153 }
154
155 if (Delta < 0) {
156 Delta += Cycle;
157 }
158
159 Total += Delta;
160 ASSERT (Total < Timeout);
161 }
162 }
163
164 return SpinLock;
165 }
166
167 /**
168 Attempts to place a spin lock in the acquired state.
169
170 This function checks the state of the spin lock specified by SpinLock. If
171 SpinLock is in the released state, then this function places SpinLock in the
172 acquired state and returns TRUE. Otherwise, FALSE is returned. All state
173 transitions of SpinLock must be performed using MP safe mechanisms.
174
175 If SpinLock is NULL, then ASSERT().
176 If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
177
178 @param SpinLock A pointer to the spin lock to place in the acquired state.
179
180 @retval TRUE SpinLock was placed in the acquired state.
181 @retval FALSE SpinLock could not be acquired.
182
183 **/
184 BOOLEAN
185 EFIAPI
186 AcquireSpinLockOrFail (
187 IN OUT SPIN_LOCK *SpinLock
188 )
189 {
190 SPIN_LOCK LockValue;
191 VOID *Result;
192
193 ASSERT (SpinLock != NULL);
194
195 LockValue = *SpinLock;
196 ASSERT (LockValue == SPIN_LOCK_ACQUIRED || LockValue == SPIN_LOCK_RELEASED);
197
198 _ReadWriteBarrier ();
199 Result = InterlockedCompareExchangePointer (
200 (VOID **)SpinLock,
201 (VOID *)SPIN_LOCK_RELEASED,
202 (VOID *)SPIN_LOCK_ACQUIRED
203 );
204
205 _ReadWriteBarrier ();
206 return (BOOLEAN)(Result == (VOID *)SPIN_LOCK_RELEASED);
207 }
208
209 /**
210 Releases a spin lock.
211
212 This function places the spin lock specified by SpinLock in the release state
213 and returns SpinLock.
214
215 If SpinLock is NULL, then ASSERT().
216 If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
217
218 @param SpinLock A pointer to the spin lock to release.
219
220 @return SpinLock released the lock.
221
222 **/
223 SPIN_LOCK *
224 EFIAPI
225 ReleaseSpinLock (
226 IN OUT SPIN_LOCK *SpinLock
227 )
228 {
229 SPIN_LOCK LockValue;
230
231 ASSERT (SpinLock != NULL);
232
233 LockValue = *SpinLock;
234 ASSERT (LockValue == SPIN_LOCK_ACQUIRED || LockValue == SPIN_LOCK_RELEASED);
235
236 _ReadWriteBarrier ();
237 *SpinLock = SPIN_LOCK_RELEASED;
238 _ReadWriteBarrier ();
239
240 return SpinLock;
241 }
242
243 /**
244 Performs an atomic increment of an 32-bit unsigned integer.
245
246 Performs an atomic increment of the 32-bit unsigned integer specified by
247 Value and returns the incremented value. The increment operation must be
248 performed using MP safe mechanisms.
249
250 If Value is NULL, then ASSERT().
251
252 @param Value A pointer to the 32-bit value to increment.
253
254 @return The incremented value.
255
256 **/
257 UINT32
258 EFIAPI
259 InterlockedIncrement (
260 IN volatile UINT32 *Value
261 )
262 {
263 ASSERT (Value != NULL);
264 return InternalSyncIncrement (Value);
265 }
266
267 /**
268 Performs an atomic decrement of an 32-bit unsigned integer.
269
270 Performs an atomic decrement of the 32-bit unsigned integer specified by
271 Value and returns the decremented value. The decrement operation must be
272 performed using MP safe mechanisms.
273
274 If Value is NULL, then ASSERT().
275
276 @param Value A pointer to the 32-bit value to decrement.
277
278 @return The decremented value.
279
280 **/
281 UINT32
282 EFIAPI
283 InterlockedDecrement (
284 IN volatile UINT32 *Value
285 )
286 {
287 ASSERT (Value != NULL);
288 return InternalSyncDecrement (Value);
289 }
290
291 /**
292 Performs an atomic compare exchange operation on a 16-bit unsigned integer.
293
294 Performs an atomic compare exchange operation on the 16-bit unsigned integer
295 specified by Value. If Value is equal to CompareValue, then Value is set to
296 ExchangeValue and CompareValue is returned. If Value is not equal to CompareValue,
297 then Value is returned. The compare exchange operation must be performed using
298 MP safe mechanisms.
299
300 If Value is NULL, then ASSERT().
301
302 @param Value A pointer to the 16-bit value for the compare exchange
303 operation.
304 @param CompareValue A 16-bit value used in compare operation.
305 @param ExchangeValue A 16-bit value used in exchange operation.
306
307 @return The original *Value before exchange.
308
309 **/
310 UINT16
311 EFIAPI
312 InterlockedCompareExchange16 (
313 IN OUT volatile UINT16 *Value,
314 IN UINT16 CompareValue,
315 IN UINT16 ExchangeValue
316 )
317 {
318 ASSERT (Value != NULL);
319 return InternalSyncCompareExchange16 (Value, CompareValue, ExchangeValue);
320 }
321
322 /**
323 Performs an atomic compare exchange operation on a 32-bit unsigned integer.
324
325 Performs an atomic compare exchange operation on the 32-bit unsigned integer
326 specified by Value. If Value is equal to CompareValue, then Value is set to
327 ExchangeValue and CompareValue is returned. If Value is not equal to CompareValue,
328 then Value is returned. The compare exchange operation must be performed using
329 MP safe mechanisms.
330
331 If Value is NULL, then ASSERT().
332
333 @param Value A pointer to the 32-bit value for the compare exchange
334 operation.
335 @param CompareValue A 32-bit value used in compare operation.
336 @param ExchangeValue A 32-bit value used in exchange operation.
337
338 @return The original *Value before exchange.
339
340 **/
341 UINT32
342 EFIAPI
343 InterlockedCompareExchange32 (
344 IN OUT volatile UINT32 *Value,
345 IN UINT32 CompareValue,
346 IN UINT32 ExchangeValue
347 )
348 {
349 ASSERT (Value != NULL);
350 return InternalSyncCompareExchange32 (Value, CompareValue, ExchangeValue);
351 }
352
353 /**
354 Performs an atomic compare exchange operation on a 64-bit unsigned integer.
355
356 Performs an atomic compare exchange operation on the 64-bit unsigned integer specified
357 by Value. If Value is equal to CompareValue, then Value is set to ExchangeValue and
358 CompareValue is returned. If Value is not equal to CompareValue, then Value is returned.
359 The compare exchange operation must be performed using MP safe mechanisms.
360
361 If Value is NULL, then ASSERT().
362
363 @param Value A pointer to the 64-bit value for the compare exchange
364 operation.
365 @param CompareValue A 64-bit value used in a compare operation.
366 @param ExchangeValue A 64-bit value used in an exchange operation.
367
368 @return The original *Value before exchange.
369
370 **/
371 UINT64
372 EFIAPI
373 InterlockedCompareExchange64 (
374 IN OUT volatile UINT64 *Value,
375 IN UINT64 CompareValue,
376 IN UINT64 ExchangeValue
377 )
378 {
379 ASSERT (Value != NULL);
380 return InternalSyncCompareExchange64 (Value, CompareValue, ExchangeValue);
381 }
382
383 /**
384 Performs an atomic compare exchange operation on a pointer value.
385
386 Performs an atomic compare exchange operation on the pointer value specified
387 by Value. If Value is equal to CompareValue, then Value is set to
388 ExchangeValue and CompareValue is returned. If Value is not equal to
389 CompareValue, then Value is returned. The compare exchange operation must be
390 performed using MP safe mechanisms.
391
392 If Value is NULL, then ASSERT().
393
394 @param Value A pointer to the pointer value for the compare exchange
395 operation.
396 @param CompareValue A pointer value used in a compare operation.
397 @param ExchangeValue A pointer value used in an exchange operation.
398
399 @return The original *Value before exchange.
400 **/
401 VOID *
402 EFIAPI
403 InterlockedCompareExchangePointer (
404 IN OUT VOID *volatile *Value,
405 IN VOID *CompareValue,
406 IN VOID *ExchangeValue
407 )
408 {
409 UINT8 SizeOfValue;
410
411 SizeOfValue = sizeof (*Value);
412
413 switch (SizeOfValue) {
414 case sizeof (UINT32):
415 return (VOID *)(UINTN)InterlockedCompareExchange32 (
416 (volatile UINT32 *)Value,
417 (UINT32)(UINTN)CompareValue,
418 (UINT32)(UINTN)ExchangeValue
419 );
420 case sizeof (UINT64):
421 return (VOID *)(UINTN)InterlockedCompareExchange64 (
422 (volatile UINT64 *)Value,
423 (UINT64)(UINTN)CompareValue,
424 (UINT64)(UINTN)ExchangeValue
425 );
426 default:
427 ASSERT (FALSE);
428 return NULL;
429 }
430 }