1/* 2 * Copyright (C) 2005 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <machine/cpu-features.h> 18 19/* 20 * NOTE: these atomic operations are SMP safe on all architectures, 21 * except swap(), see below. 22 */ 23 24 .text 25 .align 26 27 .global android_atomic_write 28 29 .global android_atomic_inc 30 .global android_atomic_dec 31 32 .global android_atomic_add 33 .global android_atomic_and 34 .global android_atomic_or 35 36 .global android_atomic_swap 37 38 .global android_atomic_cmpxchg 39 40/* 41 * ---------------------------------------------------------------------------- 42 * int __kernel_cmpxchg(int oldval, int newval, int *ptr) 43 * clobbered: r3, ip, flags 44 * return 0 if a swap was made, non-zero otherwise. 45 */ 46 47 .equ kernel_cmpxchg, 0xFFFF0FC0 48 .equ kernel_atomic_base, 0xFFFF0FFF 49 50/* 51 * ---------------------------------------------------------------------------- 52 * android_atomic_write 53 * input: r0=value, r1=address 54 * output: void 55 */ 56 57android_atomic_write: 58 str r0, [r1] 59 bx lr; 60 61/* 62 * ---------------------------------------------------------------------------- 63 * android_atomic_inc 64 * input: r0 = address 65 * output: r0 = old value 66 */ 67 68android_atomic_inc: 69 .fnstart 70 .save {r4, lr} 71 stmdb sp!, {r4, lr} 72 mov r2, r0 731: @ android_atomic_inc 74 ldr r0, [r2] 75 mov r3, #kernel_atomic_base 76#ifdef __ARM_HAVE_PC_INTERWORK 77 add lr, pc, #4 78 add r1, r0, #1 79 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) 80#else 81 add r1, r0, #1 82 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) 83 mov lr, pc 84 bx r3 85#endif 86 bcc 1b 87 sub r0, r1, #1 88 ldmia sp!, {r4, lr} 89 bx lr 90 .fnend 91 92/* 93 * ---------------------------------------------------------------------------- 94 * android_atomic_dec 95 * input: r0=address 96 * output: r0 = old value 97 */ 98 99android_atomic_dec: 100 .fnstart 101 .save {r4, lr} 102 stmdb sp!, {r4, lr} 103 mov r2, r0 1041: @ android_atomic_dec 105 ldr r0, [r2] 106 mov r3, #kernel_atomic_base 107#ifdef __ARM_HAVE_PC_INTERWORK 108 add lr, pc, #4 109 sub r1, r0, #1 110 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) 111#else 112 sub r1, r0, #1 113 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) 114 mov lr, pc 115 bx r3 116#endif 117 bcc 1b 118 add r0, r1, #1 119 ldmia sp!, {r4, lr} 120 bx lr 121 .fnend 122 123/* 124 * ---------------------------------------------------------------------------- 125 * android_atomic_add 126 * input: r0=value, r1=address 127 * output: r0 = old value 128 */ 129 130android_atomic_add: 131 .fnstart 132 .save {r4, lr} 133 stmdb sp!, {r4, lr} 134 mov r2, r1 135 mov r4, r0 1361: @ android_atomic_add 137 ldr r0, [r2] 138 mov r3, #kernel_atomic_base 139#ifdef __ARM_HAVE_PC_INTERWORK 140 add lr, pc, #4 141 add r1, r0, r4 142 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) 143#else 144 add r1, r0, r4 145 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) 146 mov lr, pc 147 bx r3 148#endif 149 bcc 1b 150 sub r0, r1, r4 151 ldmia sp!, {r4, lr} 152 bx lr 153 .fnend 154 155 156/* 157 * ---------------------------------------------------------------------------- 158 * android_atomic_and 159 * input: r0=value, r1=address 160 * output: r0 = old value 161 */ 162 163android_atomic_and: 164 .fnstart 165 .save {r4, r5, lr} 166 stmdb sp!, {r4, r5, lr} 167 mov r2, r1 /* r2 = address */ 168 mov r4, r0 /* r4 = the value */ 1691: @ android_atomic_and 170 ldr r0, [r2] /* r0 = address[0] */ 171 mov r3, #kernel_atomic_base 172#ifdef __ARM_HAVE_PC_INTERWORK 173 add lr, pc, #8 174 mov r5, r0 /* r5 = save address[0] */ 175 and r1, r0, r4 /* r1 = new value */ 176 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */ 177#else 178 mov r5, r0 /* r5 = save address[0] */ 179 and r1, r0, r4 /* r1 = new value */ 180 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */ 181 mov lr, pc 182 bx r3 183#endif 184 bcc 1b 185 mov r0, r5 186 ldmia sp!, {r4, r5, lr} 187 bx lr 188 .fnend 189 190/* 191 * ---------------------------------------------------------------------------- 192 * android_atomic_or 193 * input: r0=value, r1=address 194 * output: r0 = old value 195 */ 196 197android_atomic_or: 198 .fnstart 199 .save {r4, r5, lr} 200 stmdb sp!, {r4, r5, lr} 201 mov r2, r1 /* r2 = address */ 202 mov r4, r0 /* r4 = the value */ 2031: @ android_atomic_or 204 ldr r0, [r2] /* r0 = address[0] */ 205 mov r3, #kernel_atomic_base 206#ifdef __ARM_HAVE_PC_INTERWORK 207 add lr, pc, #8 208 mov r5, r0 /* r5 = save address[0] */ 209 orr r1, r0, r4 /* r1 = new value */ 210 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */ 211#else 212 mov r5, r0 /* r5 = save address[0] */ 213 orr r1, r0, r4 /* r1 = new value */ 214 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */ 215 mov lr, pc 216 bx r3 217#endif 218 bcc 1b 219 mov r0, r5 220 ldmia sp!, {r4, r5, lr} 221 bx lr 222 .fnend 223 224/* 225 * ---------------------------------------------------------------------------- 226 * android_atomic_swap 227 * input: r0=value, r1=address 228 * output: r0 = old value 229 */ 230 231/* FIXME: this is not safe on SMP systems 232 * a general way to do it is to use kernel_cmpxchg */ 233 234android_atomic_swap: 235 swp r0, r0, [r1] 236 bx lr 237 238/* 239 * ---------------------------------------------------------------------------- 240 * android_atomic_cmpxchg 241 * input: r0=oldvalue, r1=newvalue, r2=address 242 * output: r0 = 0 (xchg done) or non-zero (xchg not done) 243 */ 244 245android_atomic_cmpxchg: 246 .fnstart 247 .save {r4, lr} 248 stmdb sp!, {r4, lr} 249 mov r4, r0 /* r4 = save oldvalue */ 2501: @ android_atomic_cmpxchg 251 mov r3, #kernel_atomic_base 252#ifdef __ARM_HAVE_PC_INTERWORK 253 add lr, pc, #4 254 mov r0, r4 /* r0 = oldvalue */ 255 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) 256#else 257 mov r0, r4 /* r0 = oldvalue */ 258 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) 259 mov lr, pc 260 bx r3 261#endif 262 bcs 2f /* swap was made. we're good, return. */ 263 ldr r3, [r2] /* swap not made, see if it's because *ptr!=oldvalue */ 264 cmp r3, r4 265 beq 1b 2662: @ android_atomic_cmpxchg 267 ldmia sp!, {r4, lr} 268 bx lr 269 .fnend 270 271/* 272 * ---------------------------------------------------------------------------- 273 * android_atomic_cmpxchg_64 274 * input: r0-r1=oldvalue, r2-r3=newvalue, arg4 (on stack)=address 275 * output: r0 = 0 (xchg done) or non-zero (xchg not done) 276 */ 277/* TODO: NEED IMPLEMENTATION FOR THIS ARCHITECTURE */ 278