1/* 2 * Copyright 2009-2016 Samy Al Bahra. 3 * Copyright 2016 Olivier Houchard. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: stable/11/sys/contrib/ck/include/gcc/arm/ck_pr_armv4.h 328515 2018-01-28 18:38:17Z cognet $ 28 */ 29 30#ifndef CK_PR_ARM_H 31#define CK_PR_ARM_H 32 33#ifndef CK_PR_H 34#error Do not include this file directly, use ck_pr.h 35#endif 36 37#include <ck_cc.h> 38#include <ck_md.h> 39 40#include <machine/armreg.h> 41 42/* 43 * armv4/v5 CPUs lack any instruction that would let us implement an atomic CAS 44 * so we have to give atomicity by disabling interrupts. This only works in 45 * the kernel, obviously. 46 */ 47#define __with_interrupts_disabled(expr) \ 48 do { \ 49 u_int cpsr_save, tmp; \ 50 \ 51 __asm __volatile( \ 52 "mrs %0, cpsr;" \ 53 "orr %1, %0, %2;" \ 54 "msr cpsr_fsxc, %1;" \ 55 : "=r" (cpsr_save), "=r" (tmp) \ 56 : "I" (PSR_I | PSR_F) \ 57 : "cc" ); \ 58 (expr); \ 59 __asm __volatile( \ 60 "msr cpsr_fsxc, %0" \ 61 : /* no output */ \ 62 : "r" (cpsr_save) \ 63 : "cc" ); \ 64 } while(0) 65/* 66 * The following represent supported atomic operations. 67 * These operations may be emulated. 68 */ 69#include "ck_f_pr.h" 70 71/* 72 * Minimum interface requirement met. 73 */ 74#define CK_F_PR 75 76CK_CC_INLINE static void 77ck_pr_stall(void) 78{ 79 80 __asm__ __volatile__("" ::: "memory"); 81 return; 82} 83 84#define CK_PR_FENCE(T, I) \ 85 CK_CC_INLINE static void \ 86 ck_pr_fence_strict_##T(void) \ 87 { \ 88 I; \ 89 } 90 91/* 92 * ARM CPUs prior to armv6 didn't reorder instructions, and we don't 93 * support any SMP system, so a compiler barrier should be enough for fences 94 */ 95CK_PR_FENCE(atomic, ck_pr_stall()) 96CK_PR_FENCE(atomic_store, ck_pr_stall()) 97CK_PR_FENCE(atomic_load, ck_pr_stall()) 98CK_PR_FENCE(store_atomic, ck_pr_stall()) 99CK_PR_FENCE(load_atomic, ck_pr_stall()) 100CK_PR_FENCE(store, ck_pr_stall()) 101CK_PR_FENCE(store_load, ck_pr_stall()) 102CK_PR_FENCE(load, ck_pr_stall()) 103CK_PR_FENCE(load_store, ck_pr_stall()) 104CK_PR_FENCE(memory, ck_pr_stall()) 105CK_PR_FENCE(acquire, ck_pr_stall()) 106CK_PR_FENCE(release, ck_pr_stall()) 107CK_PR_FENCE(acqrel, ck_pr_stall()) 108CK_PR_FENCE(lock, ck_pr_stall()) 109CK_PR_FENCE(unlock, ck_pr_stall()) 110 111#undef CK_PR_FENCE 112 113#define CK_PR_LOAD(S, M, T, C, I) \ 114 CK_CC_INLINE static T \ 115 ck_pr_md_load_##S(const M *target) \ 116 { \ 117 long r = 0; \ 118 __asm__ __volatile__(I " %0, [%1];" \ 119 : "=r" (r) \ 120 : "r" (target) \ 121 : "memory"); \ 122 return ((T)r); \ 123 } 124 125CK_PR_LOAD(ptr, void, void *, uint32_t, "ldr") 126 127#define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) 128 129CK_PR_LOAD_S(32, uint32_t, "ldr") 130CK_PR_LOAD_S(16, uint16_t, "ldrh") 131CK_PR_LOAD_S(8, uint8_t, "ldrb") 132CK_PR_LOAD_S(uint, unsigned int, "ldr") 133CK_PR_LOAD_S(int, int, "ldr") 134CK_PR_LOAD_S(short, short, "ldrh") 135CK_PR_LOAD_S(char, char, "ldrb") 136 137#undef CK_PR_LOAD_S 138#undef CK_PR_LOAD 139 140#define CK_PR_STORE(S, M, T, C, I) \ 141 CK_CC_INLINE static void \ 142 ck_pr_md_store_##S(M *target, T v) \ 143 { \ 144 __asm__ __volatile__(I " %1, [%0]" \ 145 : \ 146 : "r" (target), \ 147 "r" (v) \ 148 : "memory"); \ 149 return; \ 150 } 151 152CK_PR_STORE(ptr, void, const void *, uint32_t, "str") 153 154#define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) 155 156CK_PR_STORE_S(32, uint32_t, "str") 157CK_PR_STORE_S(16, uint16_t, "strh") 158CK_PR_STORE_S(8, uint8_t, "strb") 159CK_PR_STORE_S(uint, unsigned int, "str") 160CK_PR_STORE_S(int, int, "str") 161CK_PR_STORE_S(short, short, "strh") 162CK_PR_STORE_S(char, char, "strb") 163 164#undef CK_PR_STORE_S 165#undef CK_PR_STORE 166 167#define CK_PR_CAS(N, M, T) \ 168CK_CC_INLINE static bool \ 169ck_pr_cas_##N##_value(M *target, T compare, T set, M *value) \ 170{ \ 171 bool ret; \ 172 __with_interrupts_disabled( \ 173 { \ 174 *(T *)value = *(T *)target; \ 175 if (*(T *)target == compare) { \ 176 *(T *)target = set; \ 177 ret = true; \ 178 } else \ 179 ret = false; \ 180 } \ 181 ); \ 182 return ret; \ 183} \ 184CK_CC_INLINE static bool \ 185ck_pr_cas_##N(M *target, T compare, T set) \ 186{ \ 187 bool ret; \ 188 __with_interrupts_disabled( \ 189 { \ 190 if (*(T *)target == compare) { \ 191 *(T *)target = set; \ 192 ret = true; \ 193 } else \ 194 ret = false; \ 195 } \ 196 ); \ 197 return ret; \ 198} 199 200CK_PR_CAS(ptr, void, void *) 201 202#define CK_PR_CAS_S(N, T) CK_PR_CAS(N, T, T) 203CK_PR_CAS_S(32, uint32_t) 204CK_PR_CAS_S(uint, unsigned int) 205CK_PR_CAS_S(int, int) 206CK_PR_CAS_S(16, uint16_t) 207CK_PR_CAS_S(8, uint8_t) 208CK_PR_CAS_S(short, short) 209CK_PR_CAS_S(char, char) 210 211#undef CK_PR_CAS_S 212#undef CK_PR_CAS 213 214#define CK_PR_FAS(N, M, T, W) \ 215 CK_CC_INLINE static T \ 216 ck_pr_fas_##N(M *target, T v) \ 217 { \ 218 T previous = 0; \ 219 __with_interrupts_disabled( \ 220 { \ 221 previous = *(T *)target; \ 222 *(T *)target = v; \ 223 } \ 224 ); \ 225 return (previous); \ 226 } 227 228CK_PR_FAS(32, uint32_t, uint32_t, "") 229CK_PR_FAS(ptr, void, void *, "") 230CK_PR_FAS(int, int, int, "") 231CK_PR_FAS(uint, unsigned int, unsigned int, "") 232CK_PR_FAS(16, uint16_t, uint16_t, "h") 233CK_PR_FAS(8, uint8_t, uint8_t, "b") 234CK_PR_FAS(short, short, short, "h") 235CK_PR_FAS(char, char, char, "b") 236 237 238#undef CK_PR_FAS 239 240#define CK_PR_UNARY(O, N, M, T, I, W) \ 241 CK_CC_INLINE static void \ 242 ck_pr_##O##_##N(M *target) \ 243 { \ 244 __with_interrupts_disabled( \ 245 { \ 246 I; \ 247 } \ 248 ); \ 249 return; \ 250 } 251 252CK_PR_UNARY(inc, ptr, void, void *, (*(int *)target)++, "") 253CK_PR_UNARY(dec, ptr, void, void *, (*(int *)target)--, "") 254CK_PR_UNARY(not, ptr, void, void *, *(int *)target = !(*(int*)target), "") 255CK_PR_UNARY(neg, ptr, void, void *, *(int *)target = -(*(int *)target), "") 256 257#define CK_PR_UNARY_S(S, T, W) \ 258 CK_PR_UNARY(inc, S, T, T, *target++, W) \ 259 CK_PR_UNARY(dec, S, T, T, *target--, W) \ 260 CK_PR_UNARY(not, S, T, T, *target = !*target, W) \ 261 CK_PR_UNARY(neg, S, T, T, *target = -*target, W) \ 262 263CK_PR_UNARY_S(32, uint32_t, "") 264CK_PR_UNARY_S(uint, unsigned int, "") 265CK_PR_UNARY_S(int, int, "") 266CK_PR_UNARY_S(16, uint16_t, "h") 267CK_PR_UNARY_S(8, uint8_t, "b") 268CK_PR_UNARY_S(short, short, "h") 269CK_PR_UNARY_S(char, char, "b") 270 271#undef CK_PR_UNARY_S 272#undef CK_PR_UNARY 273 274#define CK_PR_BINARY(O, N, M, T, I, W) \ 275 CK_CC_INLINE static void \ 276 ck_pr_##O##_##N(M *target, T delta) \ 277 { \ 278 __with_interrupts_disabled( \ 279 { \ 280 I; \ 281 } \ 282 ); \ 283 return; \ 284 } 285 286CK_PR_BINARY(and, ptr, void, uintptr_t, *((uintptr_t *)target) &= delta, "") 287CK_PR_BINARY(add, ptr, void, uintptr_t, *((uintptr_t *)target) += delta, "") 288CK_PR_BINARY(or, ptr, void, uintptr_t, *((uintptr_t *)target) |= delta, "") 289CK_PR_BINARY(sub, ptr, void, uintptr_t, *((uintptr_t *)target) -= delta, "") 290CK_PR_BINARY(xor, ptr, void, uintptr_t, *((uintptr_t *)target) ^= delta, "") 291 292#define CK_PR_BINARY_S(S, T, W) \ 293 CK_PR_BINARY(and, S, T, T, *target &= delta, W) \ 294 CK_PR_BINARY(add, S, T, T, *target += delta, W) \ 295 CK_PR_BINARY(or, S, T, T, *target |= delta, W) \ 296 CK_PR_BINARY(sub, S, T, T, *target -= delta, W) \ 297 CK_PR_BINARY(xor, S, T, T, *target ^= delta, W) 298 299CK_PR_BINARY_S(32, uint32_t, "") 300CK_PR_BINARY_S(uint, unsigned int, "") 301CK_PR_BINARY_S(int, int, "") 302CK_PR_BINARY_S(16, uint16_t, "h") 303CK_PR_BINARY_S(8, uint8_t, "b") 304CK_PR_BINARY_S(short, short, "h") 305CK_PR_BINARY_S(char, char, "b") 306 307#undef CK_PR_BINARY_S 308#undef CK_PR_BINARY 309 310CK_CC_INLINE static void * 311ck_pr_faa_ptr(void *target, uintptr_t delta) 312{ 313 uintptr_t previous; 314 __with_interrupts_disabled( 315 { 316 previous = *(uintptr_t *)target; 317 *(uintptr_t *)target += delta; 318 } 319 ); 320 return (void *)(previous); 321} 322 323#define CK_PR_FAA(S, T, W) \ 324 CK_CC_INLINE static T \ 325 ck_pr_faa_##S(T *target, T delta) \ 326 { \ 327 T previous = 0; \ 328 __with_interrupts_disabled( \ 329 { \ 330 previous = *target; \ 331 *target += delta; \ 332 } \ 333 ); \ 334 return (previous); \ 335 } 336 337CK_PR_FAA(32, uint32_t, "") 338CK_PR_FAA(uint, unsigned int, "") 339CK_PR_FAA(int, int, "") 340CK_PR_FAA(16, uint16_t, "h") 341CK_PR_FAA(8, uint8_t, "b") 342CK_PR_FAA(short, short, "h") 343CK_PR_FAA(char, char, "b") 344 345#undef CK_PR_FAA 346 347#undef __with_interrupts_disabled 348 349#endif /* CK_PR_ARM_H */ 350 351