blob: da5c26b06d25ac1afd97b6794557ed31d456f3a1 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
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/*
Vinay HARUGOP02608472009-09-10 00:31:12 +053020 * NOTE: these atomic operations are SMP safe on all architectures.
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080021 */
22
23 .text
24 .align
25
26 .global android_atomic_write
27
28 .global android_atomic_inc
29 .global android_atomic_dec
30
31 .global android_atomic_add
32 .global android_atomic_and
33 .global android_atomic_or
34
35 .global android_atomic_swap
36
37 .global android_atomic_cmpxchg
38
39/*
40 * ----------------------------------------------------------------------------
41 * int __kernel_cmpxchg(int oldval, int newval, int *ptr)
42 * clobbered: r3, ip, flags
43 * return 0 if a swap was made, non-zero otherwise.
44 */
45
46 .equ kernel_cmpxchg, 0xFFFF0FC0
47 .equ kernel_atomic_base, 0xFFFF0FFF
48
49/*
50 * ----------------------------------------------------------------------------
51 * android_atomic_write
52 * input: r0=value, r1=address
53 * output: void
54 */
55
56android_atomic_write:
Mathias Agopianca5e0bc2009-09-03 14:49:58 -070057 str r0, [r1]
58 bx lr;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080059
60/*
61 * ----------------------------------------------------------------------------
62 * android_atomic_inc
63 * input: r0 = address
64 * output: r0 = old value
65 */
66
67android_atomic_inc:
Ben Cheng21ec7792009-10-12 16:51:23 -070068 .fnstart
69 .save {r4, lr}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080070 stmdb sp!, {r4, lr}
71 mov r2, r0
721: @ android_atomic_inc
73 ldr r0, [r2]
74 mov r3, #kernel_atomic_base
75#ifdef __ARM_HAVE_PC_INTERWORK
76 add lr, pc, #4
77 add r1, r0, #1
78 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
79#else
80 add r1, r0, #1
81 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
82 mov lr, pc
83 bx r3
84#endif
85 bcc 1b
86 sub r0, r1, #1
87 ldmia sp!, {r4, lr}
88 bx lr
Ben Cheng21ec7792009-10-12 16:51:23 -070089 .fnend
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080090
91/*
92 * ----------------------------------------------------------------------------
93 * android_atomic_dec
94 * input: r0=address
95 * output: r0 = old value
96 */
97
98android_atomic_dec:
Ben Cheng21ec7792009-10-12 16:51:23 -070099 .fnstart
100 .save {r4, lr}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800101 stmdb sp!, {r4, lr}
102 mov r2, r0
1031: @ android_atomic_dec
104 ldr r0, [r2]
105 mov r3, #kernel_atomic_base
106#ifdef __ARM_HAVE_PC_INTERWORK
107 add lr, pc, #4
108 sub r1, r0, #1
109 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
110#else
111 sub r1, r0, #1
112 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
113 mov lr, pc
114 bx r3
115#endif
116 bcc 1b
117 add r0, r1, #1
118 ldmia sp!, {r4, lr}
119 bx lr
Ben Cheng21ec7792009-10-12 16:51:23 -0700120 .fnend
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800121
122/*
123 * ----------------------------------------------------------------------------
124 * android_atomic_add
125 * input: r0=value, r1=address
126 * output: r0 = old value
127 */
128
129android_atomic_add:
Ben Cheng21ec7792009-10-12 16:51:23 -0700130 .fnstart
131 .save {r4, lr}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800132 stmdb sp!, {r4, lr}
133 mov r2, r1
134 mov r4, r0
1351: @ android_atomic_add
136 ldr r0, [r2]
137 mov r3, #kernel_atomic_base
138#ifdef __ARM_HAVE_PC_INTERWORK
139 add lr, pc, #4
140 add r1, r0, r4
141 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
142#else
143 add r1, r0, r4
144 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
145 mov lr, pc
146 bx r3
147#endif
148 bcc 1b
149 sub r0, r1, r4
150 ldmia sp!, {r4, lr}
151 bx lr
Ben Cheng21ec7792009-10-12 16:51:23 -0700152 .fnend
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800153
154
155/*
156 * ----------------------------------------------------------------------------
157 * android_atomic_and
158 * input: r0=value, r1=address
159 * output: r0 = old value
160 */
161
162android_atomic_and:
Ben Cheng21ec7792009-10-12 16:51:23 -0700163 .fnstart
164 .save {r4, r5, lr}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800165 stmdb sp!, {r4, r5, lr}
166 mov r2, r1 /* r2 = address */
167 mov r4, r0 /* r4 = the value */
1681: @ android_atomic_and
169 ldr r0, [r2] /* r0 = address[0] */
170 mov r3, #kernel_atomic_base
171#ifdef __ARM_HAVE_PC_INTERWORK
172 add lr, pc, #8
173 mov r5, r0 /* r5 = save address[0] */
174 and r1, r0, r4 /* r1 = new value */
175 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
176#else
177 mov r5, r0 /* r5 = save address[0] */
178 and r1, r0, r4 /* r1 = new value */
179 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
180 mov lr, pc
181 bx r3
182#endif
183 bcc 1b
184 mov r0, r5
185 ldmia sp!, {r4, r5, lr}
186 bx lr
Ben Cheng21ec7792009-10-12 16:51:23 -0700187 .fnend
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800188
189/*
190 * ----------------------------------------------------------------------------
191 * android_atomic_or
192 * input: r0=value, r1=address
193 * output: r0 = old value
194 */
195
196android_atomic_or:
Ben Cheng21ec7792009-10-12 16:51:23 -0700197 .fnstart
198 .save {r4, r5, lr}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800199 stmdb sp!, {r4, r5, lr}
200 mov r2, r1 /* r2 = address */
201 mov r4, r0 /* r4 = the value */
2021: @ android_atomic_or
203 ldr r0, [r2] /* r0 = address[0] */
204 mov r3, #kernel_atomic_base
205#ifdef __ARM_HAVE_PC_INTERWORK
206 add lr, pc, #8
207 mov r5, r0 /* r5 = save address[0] */
208 orr r1, r0, r4 /* r1 = new value */
209 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
210#else
211 mov r5, r0 /* r5 = save address[0] */
212 orr r1, r0, r4 /* r1 = new value */
213 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
214 mov lr, pc
215 bx r3
216#endif
217 bcc 1b
218 mov r0, r5
219 ldmia sp!, {r4, r5, lr}
220 bx lr
Ben Cheng21ec7792009-10-12 16:51:23 -0700221 .fnend
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800222
223/*
224 * ----------------------------------------------------------------------------
225 * android_atomic_swap
226 * input: r0=value, r1=address
227 * output: r0 = old value
228 */
229
Vinay HARUGOP02608472009-09-10 00:31:12 +0530230/* replaced swp instruction with ldrex/strex for ARMv6 & ARMv7 */
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800231android_atomic_swap:
Vinay HARUGOP02608472009-09-10 00:31:12 +0530232#if defined (_ARM_HAVE_LDREX_STREX)
2331: ldrex r2, [r1]
234 strex r3, r0, [r1]
235 teq r3, #0
236 bne 1b
237 mov r0, r2
238 mcr p15, 0, r0, c7, c10, 5 /* or, use dmb */
239#else
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800240 swp r0, r0, [r1]
Vinay HARUGOP02608472009-09-10 00:31:12 +0530241#endif
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800242 bx lr
243
244/*
245 * ----------------------------------------------------------------------------
246 * android_atomic_cmpxchg
247 * input: r0=oldvalue, r1=newvalue, r2=address
248 * output: r0 = 0 (xchg done) or non-zero (xchg not done)
249 */
250
251android_atomic_cmpxchg:
Ben Cheng21ec7792009-10-12 16:51:23 -0700252 .fnstart
253 .save {r4, lr}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800254 stmdb sp!, {r4, lr}
255 mov r4, r0 /* r4 = save oldvalue */
2561: @ android_atomic_cmpxchg
257 mov r3, #kernel_atomic_base
258#ifdef __ARM_HAVE_PC_INTERWORK
259 add lr, pc, #4
260 mov r0, r4 /* r0 = oldvalue */
261 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
262#else
263 mov r0, r4 /* r0 = oldvalue */
264 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
265 mov lr, pc
266 bx r3
267#endif
268 bcs 2f /* swap was made. we're good, return. */
269 ldr r3, [r2] /* swap not made, see if it's because *ptr!=oldvalue */
270 cmp r3, r4
271 beq 1b
2722: @ android_atomic_cmpxchg
273 ldmia sp!, {r4, lr}
274 bx lr
Ben Cheng21ec7792009-10-12 16:51:23 -0700275 .fnend
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800276
277/*
278 * ----------------------------------------------------------------------------
279 * android_atomic_cmpxchg_64
280 * input: r0-r1=oldvalue, r2-r3=newvalue, arg4 (on stack)=address
281 * output: r0 = 0 (xchg done) or non-zero (xchg not done)
282 */
283/* TODO: NEED IMPLEMENTATION FOR THIS ARCHITECTURE */