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