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