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 */ 22 23 .text 24 .align 25 26 .global android_atomic_write 27 .type android_atomic_write, %function 28 29 .global android_atomic_inc 30 .type android_atomic_inc, %function 31 .global android_atomic_dec 32 .type android_atomic_dec, %function 33 34 .global android_atomic_add 35 .type android_atomic_add, %function 36 .global android_atomic_and 37 .type android_atomic_and, %function 38 .global android_atomic_or 39 .type android_atomic_or, %function 40 41 .global android_atomic_swap 42 .type android_atomic_swap, %function 43 44 .global android_atomic_cmpxchg 45 .type android_atomic_cmpxchg, %function 46 47/* 48 * ---------------------------------------------------------------------------- 49 * int __kernel_cmpxchg(int oldval, int newval, int *ptr) 50 * clobbered: r3, ip, flags 51 * return 0 if a swap was made, non-zero otherwise. 52 */ 53 54 .equ kernel_cmpxchg, 0xFFFF0FC0 55 .equ kernel_atomic_base, 0xFFFF0FFF 56 57/* 58 * ---------------------------------------------------------------------------- 59 * android_atomic_write 60 * input: r0=value, r1=address 61 * output: void 62 */ 63 64android_atomic_write: 65 str r0, [r1] 66 bx lr; 67 68/* 69 * ---------------------------------------------------------------------------- 70 * android_atomic_inc 71 * input: r0 = address 72 * output: r0 = old value 73 */ 74 75android_atomic_inc: 76 .fnstart 77 .save {r4, lr} 78 stmdb sp!, {r4, lr} 79 mov r2, r0 801: @ android_atomic_inc 81 ldr r0, [r2] 82 mov r3, #kernel_atomic_base 83#ifdef __ARM_HAVE_PC_INTERWORK 84 add lr, pc, #4 85 add r1, r0, #1 86 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) 87#else 88 add r1, r0, #1 89 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) 90 mov lr, pc 91 bx r3 92#endif 93 bcc 1b 94 sub r0, r1, #1 95 ldmia sp!, {r4, lr} 96 bx lr 97 .fnend 98 99/* 100 * ---------------------------------------------------------------------------- 101 * android_atomic_dec 102 * input: r0=address 103 * output: r0 = old value 104 */ 105 106android_atomic_dec: 107 .fnstart 108 .save {r4, lr} 109 stmdb sp!, {r4, lr} 110 mov r2, r0 1111: @ android_atomic_dec 112 ldr r0, [r2] 113 mov r3, #kernel_atomic_base 114#ifdef __ARM_HAVE_PC_INTERWORK 115 add lr, pc, #4 116 sub r1, r0, #1 117 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) 118#else 119 sub r1, r0, #1 120 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) 121 mov lr, pc 122 bx r3 123#endif 124 bcc 1b 125 add r0, r1, #1 126 ldmia sp!, {r4, lr} 127 bx lr 128 .fnend 129 130/* 131 * ---------------------------------------------------------------------------- 132 * android_atomic_add 133 * input: r0=value, r1=address 134 * output: r0 = old value 135 */ 136 137android_atomic_add: 138 .fnstart 139 .save {r4, lr} 140 stmdb sp!, {r4, lr} 141 mov r2, r1 142 mov r4, r0 1431: @ android_atomic_add 144 ldr r0, [r2] 145 mov r3, #kernel_atomic_base 146#ifdef __ARM_HAVE_PC_INTERWORK 147 add lr, pc, #4 148 add r1, r0, r4 149 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) 150#else 151 add r1, r0, r4 152 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) 153 mov lr, pc 154 bx r3 155#endif 156 bcc 1b 157 sub r0, r1, r4 158 ldmia sp!, {r4, lr} 159 bx lr 160 .fnend 161 162 163/* 164 * ---------------------------------------------------------------------------- 165 * android_atomic_and 166 * input: r0=value, r1=address 167 * output: r0 = old value 168 */ 169 170android_atomic_and: 171 .fnstart 172 .save {r4, r5, lr} 173 stmdb sp!, {r4, r5, lr} 174 mov r2, r1 /* r2 = address */ 175 mov r4, r0 /* r4 = the value */ 1761: @ android_atomic_and 177 ldr r0, [r2] /* r0 = address[0] */ 178 mov r3, #kernel_atomic_base 179#ifdef __ARM_HAVE_PC_INTERWORK 180 add lr, pc, #8 181 mov r5, r0 /* r5 = save address[0] */ 182 and r1, r0, r4 /* r1 = new value */ 183 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */ 184#else 185 mov r5, r0 /* r5 = save address[0] */ 186 and r1, r0, r4 /* r1 = new value */ 187 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */ 188 mov lr, pc 189 bx r3 190#endif 191 bcc 1b 192 mov r0, r5 193 ldmia sp!, {r4, r5, lr} 194 bx lr 195 .fnend 196 197/* 198 * ---------------------------------------------------------------------------- 199 * android_atomic_or 200 * input: r0=value, r1=address 201 * output: r0 = old value 202 */ 203 204android_atomic_or: 205 .fnstart 206 .save {r4, r5, lr} 207 stmdb sp!, {r4, r5, lr} 208 mov r2, r1 /* r2 = address */ 209 mov r4, r0 /* r4 = the value */ 2101: @ android_atomic_or 211 ldr r0, [r2] /* r0 = address[0] */ 212 mov r3, #kernel_atomic_base 213#ifdef __ARM_HAVE_PC_INTERWORK 214 add lr, pc, #8 215 mov r5, r0 /* r5 = save address[0] */ 216 orr r1, r0, r4 /* r1 = new value */ 217 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */ 218#else 219 mov r5, r0 /* r5 = save address[0] */ 220 orr r1, r0, r4 /* r1 = new value */ 221 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */ 222 mov lr, pc 223 bx r3 224#endif 225 bcc 1b 226 mov r0, r5 227 ldmia sp!, {r4, r5, lr} 228 bx lr 229 .fnend 230 231/* 232 * ---------------------------------------------------------------------------- 233 * android_atomic_swap 234 * input: r0=value, r1=address 235 * output: r0 = old value 236 */ 237 238/* replaced swp instruction with ldrex/strex for ARMv6 & ARMv7 */ 239android_atomic_swap: 240#if defined (_ARM_HAVE_LDREX_STREX) 2411: ldrex r2, [r1] 242 strex r3, r0, [r1] 243 teq r3, #0 244 bne 1b 245 mov r0, r2 246 mcr p15, 0, r0, c7, c10, 5 /* or, use dmb */ 247#else 248 swp r0, r0, [r1] 249#endif 250 bx lr 251 252/* 253 * ---------------------------------------------------------------------------- 254 * android_atomic_cmpxchg 255 * input: r0=oldvalue, r1=newvalue, r2=address 256 * output: r0 = 0 (xchg done) or non-zero (xchg not done) 257 */ 258 259android_atomic_cmpxchg: 260 .fnstart 261 .save {r4, lr} 262 stmdb sp!, {r4, lr} 263 mov r4, r0 /* r4 = save oldvalue */ 2641: @ android_atomic_cmpxchg 265 mov r3, #kernel_atomic_base 266#ifdef __ARM_HAVE_PC_INTERWORK 267 add lr, pc, #4 268 mov r0, r4 /* r0 = oldvalue */ 269 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) 270#else 271 mov r0, r4 /* r0 = oldvalue */ 272 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) 273 mov lr, pc 274 bx r3 275#endif 276 bcs 2f /* swap was made. we're good, return. */ 277 ldr r3, [r2] /* swap not made, see if it's because *ptr!=oldvalue */ 278 cmp r3, r4 279 beq 1b 2802: @ android_atomic_cmpxchg 281 ldmia sp!, {r4, lr} 282 bx lr 283 .fnend 284 285/* 286 * ---------------------------------------------------------------------------- 287 * android_atomic_cmpxchg_64 288 * input: r0-r1=oldvalue, r2-r3=newvalue, arg4 (on stack)=address 289 * output: r0 = 0 (xchg done) or non-zero (xchg not done) 290 */ 291/* TODO: NEED IMPLEMENTATION FOR THIS ARCHITECTURE */ 292