cmpxchg_32.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /* Copyright (C) 2014 OSCAR lab, Stony Brook University
  2. This file is part of Graphene Library OS.
  3. Graphene Library OS is free software: you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. Graphene Library OS is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /*
  14. * cmpxchg_32.h
  15. */
  16. #ifndef _ASM_X86_CMPXCHG_32_H
  17. #define _ASM_X86_CMPXCHG_32_H
  18. #define LOCK_PREFIX "\n\tlock; "
  19. /*
  20. * Note: if you use set64_bit(), __cmpxchg64(), or their variants, you
  21. * you need to test for the feature in boot_cpu_data.
  22. */
  23. extern void __xchg_wrong_size(void);
  24. /*
  25. * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
  26. * Note 2: xchg has side effect, so that attribute volatile is necessary,
  27. * but generally the primitive is invalid, *ptr is output argument. --ANK
  28. */
  29. struct __xchg_dummy {
  30. unsigned long a[100];
  31. };
  32. #define __xg(x) ((struct __xchg_dummy *)(x))
  33. #define __xchg(x, ptr, size) \
  34. ({ \
  35. __typeof(*(ptr)) __x = (x); \
  36. switch (size) { \
  37. case 1: \
  38. asm volatile("lock; xchgb %b0,%1" \
  39. : "=q" (__x), "+m" (*__xg(ptr)) \
  40. : "0" (__x) \
  41. : "memory"); \
  42. break; \
  43. case 2: \
  44. asm volatile("lock; xchgw %w0,%1" \
  45. : "=r" (__x), "+m" (*__xg(ptr)) \
  46. : "0" (__x) \
  47. : "memory"); \
  48. break; \
  49. case 4: \
  50. asm volatile("lock; xchgl %0,%1" \
  51. : "=r" (__x), "+m" (*__xg(ptr)) \
  52. : "0" (__x) \
  53. : "memory"); \
  54. break; \
  55. default: \
  56. __xchg_wrong_size(); \
  57. } \
  58. __x; \
  59. })
  60. #define xchg(ptr, v) \
  61. __xchg((v), (ptr), sizeof(*ptr))
  62. /*
  63. * CMPXCHG8B only writes to the target if we had the previous
  64. * value in registers, otherwise it acts as a read and gives us the
  65. * "new previous" value. That is why there is a loop. Preloading
  66. * EDX:EAX is a performance optimization: in the common case it means
  67. * we need only one locked operation.
  68. *
  69. * A SIMD/3DNOW!/MMX/FPU 64-bit store here would require at the very
  70. * least an FPU save and/or %cr0.ts manipulation.
  71. *
  72. * cmpxchg8b must be used with the lock prefix here to allow the
  73. * instruction to be executed atomically. We need to have the reader
  74. * side to see the coherent 64bit value.
  75. */
  76. static inline void set_64bit(volatile u64 *ptr, u64 value)
  77. {
  78. u32 low = value;
  79. u32 high = value >> 32;
  80. u64 prev = *ptr;
  81. asm volatile("\n1:\t"
  82. LOCK_PREFIX "cmpxchg8b %0\n\t"
  83. "jnz 1b"
  84. : "=m" (*ptr), "+A" (prev)
  85. : "b" (low), "c" (high)
  86. : "memory");
  87. }
  88. extern void __cmpxchg_wrong_size(void);
  89. /*
  90. * Atomic compare and exchange. Compare OLD with MEM, if identical,
  91. * store NEW in MEM. Return the initial value in MEM. Success is
  92. * indicated by comparing RETURN with OLD.
  93. */
  94. #define __raw_cmpxchg(ptr, old, new, size, lock) \
  95. ({ \
  96. __typeof__(*(ptr)) __ret; \
  97. __typeof__(*(ptr)) __old = (old); \
  98. __typeof__(*(ptr)) __new = (new); \
  99. switch (size) { \
  100. case 1: \
  101. asm volatile(lock "cmpxchgb %b2,%1" \
  102. : "=a" (__ret), "+m" (*__xg(ptr)) \
  103. : "q" (__new), "0" (__old) \
  104. : "memory"); \
  105. break; \
  106. case 2: \
  107. asm volatile(lock "cmpxchgw %w2,%1" \
  108. : "=a" (__ret), "+m" (*__xg(ptr)) \
  109. : "r" (__new), "0" (__old) \
  110. : "memory"); \
  111. break; \
  112. case 4: \
  113. asm volatile(lock "cmpxchgl %2,%1" \
  114. : "=a" (__ret), "+m" (*__xg(ptr)) \
  115. : "r" (__new), "0" (__old) \
  116. : "memory"); \
  117. break; \
  118. default: \
  119. __cmpxchg_wrong_size(); \
  120. } \
  121. __ret; \
  122. })
  123. #define __cmpxchg(ptr, old, new, size) \
  124. __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
  125. #define __sync_cmpxchg(ptr, old, new, size) \
  126. __raw_cmpxchg((ptr), (old), (new), (size), "lock; ")
  127. #define __cmpxchg_local(ptr, old, new, size) \
  128. __raw_cmpxchg((ptr), (old), (new), (size), "")
  129. #ifdef CONFIG_X86_CMPXCHG
  130. #define __HAVE_ARCH_CMPXCHG 1
  131. #define cmpxchg(ptr, old, new) \
  132. __cmpxchg((ptr), (old), (new), sizeof(*ptr))
  133. #define sync_cmpxchg(ptr, old, new) \
  134. __sync_cmpxchg((ptr), (old), (new), sizeof(*ptr))
  135. #define cmpxchg_local(ptr, old, new) \
  136. __cmpxchg_local((ptr), (old), (new), sizeof(*ptr))
  137. #endif
  138. #ifdef CONFIG_X86_CMPXCHG64
  139. #define cmpxchg64(ptr, o, n) \
  140. ((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \
  141. (unsigned long long)(n)))
  142. #define cmpxchg64_local(ptr, o, n) \
  143. ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \
  144. (unsigned long long)(n)))
  145. #endif
  146. static inline unsigned long long __cmpxchg64(volatile void *ptr,
  147. unsigned long long old,
  148. unsigned long long new)
  149. {
  150. unsigned long long prev;
  151. asm volatile(LOCK_PREFIX "cmpxchg8b %1"
  152. : "=A" (prev),
  153. "+m" (*__xg(ptr))
  154. : "b" ((unsigned long)new),
  155. "c" ((unsigned long)(new >> 32)),
  156. "0" (old)
  157. : "memory");
  158. return prev;
  159. }
  160. static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
  161. unsigned long long old,
  162. unsigned long long new)
  163. {
  164. unsigned long long prev;
  165. asm volatile("cmpxchg8b %1"
  166. : "=A" (prev),
  167. "+m" (*__xg(ptr))
  168. : "b" ((unsigned long)new),
  169. "c" ((unsigned long)(new >> 32)),
  170. "0" (old)
  171. : "memory");
  172. return prev;
  173. }
  174. #ifndef CONFIG_X86_CMPXCHG
  175. /*
  176. * Building a kernel capable running on 80386. It may be necessary to
  177. * simulate the cmpxchg on the 80386 CPU. For that purpose we define
  178. * a function for each of the sizes we support.
  179. */
  180. extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);
  181. extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);
  182. extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);
  183. static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
  184. unsigned long new, int size)
  185. {
  186. switch (size) {
  187. case 1:
  188. return cmpxchg_386_u8(ptr, old, new);
  189. case 2:
  190. return cmpxchg_386_u16(ptr, old, new);
  191. case 4:
  192. return cmpxchg_386_u32(ptr, old, new);
  193. }
  194. return old;
  195. }
  196. #define cmpxchg(ptr, o, n) \
  197. ({ \
  198. __typeof__(*(ptr)) __ret; \
  199. if (likely(boot_cpu_data.x86 > 3)) \
  200. __ret = (__typeof__(*(ptr)))__cmpxchg((ptr), \
  201. (unsigned long)(o), (unsigned long)(n), \
  202. sizeof(*(ptr))); \
  203. else \
  204. __ret = (__typeof__(*(ptr)))cmpxchg_386((ptr), \
  205. (unsigned long)(o), (unsigned long)(n), \
  206. sizeof(*(ptr))); \
  207. __ret; \
  208. })
  209. #define cmpxchg_local(ptr, o, n) \
  210. ({ \
  211. __typeof__(*(ptr)) __ret; \
  212. if (likely(boot_cpu_data.x86 > 3)) \
  213. __ret = (__typeof__(*(ptr)))__cmpxchg_local((ptr), \
  214. (unsigned long)(o), (unsigned long)(n), \
  215. sizeof(*(ptr))); \
  216. else \
  217. __ret = (__typeof__(*(ptr)))cmpxchg_386((ptr), \
  218. (unsigned long)(o), (unsigned long)(n), \
  219. sizeof(*(ptr))); \
  220. __ret; \
  221. })
  222. #endif
  223. #ifndef CONFIG_X86_CMPXCHG64
  224. /*
  225. * Building a kernel capable running on 80386 and 80486. It may be necessary
  226. * to simulate the cmpxchg8b on the 80386 and 80486 CPU.
  227. */
  228. extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64);
  229. #define cmpxchg64(ptr, o, n) \
  230. ({ \
  231. __typeof__(*(ptr)) __ret; \
  232. __typeof__(*(ptr)) __old = (o); \
  233. __typeof__(*(ptr)) __new = (n); \
  234. alternative_io(LOCK_PREFIX_HERE \
  235. "call cmpxchg8b_emu", \
  236. "lock; cmpxchg8b (%%esi)" , \
  237. X86_FEATURE_CX8, \
  238. "=A" (__ret), \
  239. "S" ((ptr)), "0" (__old), \
  240. "b" ((unsigned int)__new), \
  241. "c" ((unsigned int)(__new>>32)) \
  242. : "memory"); \
  243. __ret; })
  244. #define cmpxchg64_local(ptr, o, n) \
  245. ({ \
  246. __typeof__(*(ptr)) __ret; \
  247. if (likely(boot_cpu_data.x86 > 4)) \
  248. __ret = (__typeof__(*(ptr)))__cmpxchg64_local((ptr), \
  249. (unsigned long long)(o), \
  250. (unsigned long long)(n)); \
  251. else \
  252. __ret = (__typeof__(*(ptr)))cmpxchg_486_u64((ptr), \
  253. (unsigned long long)(o), \
  254. (unsigned long long)(n)); \
  255. __ret; \
  256. })
  257. #endif
  258. #endif /* _ASM_X86_CMPXCHG_32_H */