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