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