linux-atomic-64bit.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* 64bit Linux-specific atomic operations for ARM EABI.
  2. Copyright (C) 2008-2022 Free Software Foundation, Inc.
  3. Based on linux-atomic.c
  4. 64 bit additions david.gilbert@linaro.org
  5. This file is part of GCC.
  6. GCC is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU General Public License as published by the Free
  8. Software Foundation; either version 3, or (at your option) any later
  9. version.
  10. GCC is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. for more details.
  14. Under Section 7 of GPL version 3, you are granted additional
  15. permissions described in the GCC Runtime Library Exception, version
  16. 3.1, as published by the Free Software Foundation.
  17. You should have received a copy of the GNU General Public License and
  18. a copy of the GCC Runtime Library Exception along with this program;
  19. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  20. <http://www.gnu.org/licenses/>. */
  21. /* 64bit helper functions for atomic operations; the compiler will
  22. call these when the code is compiled for a CPU without ldrexd/strexd.
  23. (If the CPU had those then the compiler inlines the operation).
  24. These helpers require a kernel helper that's only present on newer
  25. kernels; we check for that in an init section and bail out rather
  26. unceremoneously. */
  27. extern int write (int fd, const void *buf, unsigned int count);
  28. extern void abort (void);
  29. /* Kernel helper for compare-and-exchange. */
  30. typedef int (__kernel_cmpxchg64_t) (const long long* oldval,
  31. const long long* newval,
  32. long long *ptr);
  33. #define __kernel_cmpxchg64 (*(__kernel_cmpxchg64_t *) 0xffff0f60)
  34. /* Kernel helper page version number. */
  35. #define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
  36. /* Check that the kernel has a new enough version at load. */
  37. static void __check_for_sync8_kernelhelper (void)
  38. {
  39. if (__kernel_helper_version < 5)
  40. {
  41. const char err[] = "A newer kernel is required to run this binary. "
  42. "(__kernel_cmpxchg64 helper)\n";
  43. /* At this point we need a way to crash with some information
  44. for the user - I'm not sure I can rely on much else being
  45. available at this point, so do the same as generic-morestack.c
  46. write () and abort (). */
  47. write (2 /* stderr. */, err, sizeof (err));
  48. abort ();
  49. }
  50. };
  51. static void (*__sync8_kernelhelper_inithook[]) (void)
  52. __attribute__ ((used, section (".init_array"))) = {
  53. &__check_for_sync8_kernelhelper
  54. };
  55. #define HIDDEN __attribute__ ((visibility ("hidden")))
  56. #define FETCH_AND_OP_WORD64(OP, PFX_OP, INF_OP) \
  57. long long HIDDEN \
  58. __sync_fetch_and_##OP##_8 (long long *ptr, long long val) \
  59. { \
  60. int failure; \
  61. long long tmp,tmp2; \
  62. \
  63. do { \
  64. tmp = *ptr; \
  65. tmp2 = PFX_OP (tmp INF_OP val); \
  66. failure = __kernel_cmpxchg64 (&tmp, &tmp2, ptr); \
  67. } while (failure != 0); \
  68. \
  69. return tmp; \
  70. }
  71. FETCH_AND_OP_WORD64 (add, , +)
  72. FETCH_AND_OP_WORD64 (sub, , -)
  73. FETCH_AND_OP_WORD64 (or, , |)
  74. FETCH_AND_OP_WORD64 (and, , &)
  75. FETCH_AND_OP_WORD64 (xor, , ^)
  76. FETCH_AND_OP_WORD64 (nand, ~, &)
  77. #define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
  78. #define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
  79. /* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
  80. subword-sized quantities. */
  81. #define OP_AND_FETCH_WORD64(OP, PFX_OP, INF_OP) \
  82. long long HIDDEN \
  83. __sync_##OP##_and_fetch_8 (long long *ptr, long long val) \
  84. { \
  85. int failure; \
  86. long long tmp,tmp2; \
  87. \
  88. do { \
  89. tmp = *ptr; \
  90. tmp2 = PFX_OP (tmp INF_OP val); \
  91. failure = __kernel_cmpxchg64 (&tmp, &tmp2, ptr); \
  92. } while (failure != 0); \
  93. \
  94. return tmp2; \
  95. }
  96. OP_AND_FETCH_WORD64 (add, , +)
  97. OP_AND_FETCH_WORD64 (sub, , -)
  98. OP_AND_FETCH_WORD64 (or, , |)
  99. OP_AND_FETCH_WORD64 (and, , &)
  100. OP_AND_FETCH_WORD64 (xor, , ^)
  101. OP_AND_FETCH_WORD64 (nand, ~, &)
  102. long long HIDDEN
  103. __sync_val_compare_and_swap_8 (long long *ptr, long long oldval,
  104. long long newval)
  105. {
  106. int failure;
  107. long long actual_oldval;
  108. while (1)
  109. {
  110. actual_oldval = *ptr;
  111. if (__builtin_expect (oldval != actual_oldval, 0))
  112. return actual_oldval;
  113. failure = __kernel_cmpxchg64 (&actual_oldval, &newval, ptr);
  114. if (__builtin_expect (!failure, 1))
  115. return oldval;
  116. }
  117. }
  118. typedef unsigned char bool;
  119. bool HIDDEN
  120. __sync_bool_compare_and_swap_8 (long long *ptr, long long oldval,
  121. long long newval)
  122. {
  123. int failure = __kernel_cmpxchg64 (&oldval, &newval, ptr);
  124. return (failure == 0);
  125. }
  126. long long HIDDEN
  127. __sync_lock_test_and_set_8 (long long *ptr, long long val)
  128. {
  129. int failure;
  130. long long oldval;
  131. do {
  132. oldval = *ptr;
  133. failure = __kernel_cmpxchg64 (&oldval, &val, ptr);
  134. } while (failure != 0);
  135. return oldval;
  136. }