blob: c56ec5d0e3293600102e3487f873527cb5eec8c5 [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/*
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 stmdb sp!, {r4, lr}
59 mov r2, r1
60 mov r1, r0
611: @ android_atomic_write
62 ldr r0, [r2]
63 mov r3, #kernel_atomic_base
64#ifdef __ARM_HAVE_PC_INTERWORK
65 add lr, pc, #4
66 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
67#else
68 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
69 mov lr, pc
70 bx r3
71#endif
72 bcc 1b
73 ldmia sp!, {r4, lr}
74 bx lr
75
76/*
77 * ----------------------------------------------------------------------------
78 * android_atomic_inc
79 * input: r0 = address
80 * output: r0 = old value
81 */
82
83android_atomic_inc:
84 stmdb sp!, {r4, lr}
85 mov r2, r0
861: @ android_atomic_inc
87 ldr r0, [r2]
88 mov r3, #kernel_atomic_base
89#ifdef __ARM_HAVE_PC_INTERWORK
90 add lr, pc, #4
91 add r1, r0, #1
92 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
93#else
94 add r1, r0, #1
95 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
96 mov lr, pc
97 bx r3
98#endif
99 bcc 1b
100 sub r0, r1, #1
101 ldmia sp!, {r4, lr}
102 bx lr
103
104/*
105 * ----------------------------------------------------------------------------
106 * android_atomic_dec
107 * input: r0=address
108 * output: r0 = old value
109 */
110
111android_atomic_dec:
112 stmdb sp!, {r4, lr}
113 mov r2, r0
1141: @ android_atomic_dec
115 ldr r0, [r2]
116 mov r3, #kernel_atomic_base
117#ifdef __ARM_HAVE_PC_INTERWORK
118 add lr, pc, #4
119 sub r1, r0, #1
120 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
121#else
122 sub r1, r0, #1
123 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
124 mov lr, pc
125 bx r3
126#endif
127 bcc 1b
128 add r0, r1, #1
129 ldmia sp!, {r4, lr}
130 bx lr
131
132/*
133 * ----------------------------------------------------------------------------
134 * android_atomic_add
135 * input: r0=value, r1=address
136 * output: r0 = old value
137 */
138
139android_atomic_add:
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
161
162/*
163 * ----------------------------------------------------------------------------
164 * android_atomic_and
165 * input: r0=value, r1=address
166 * output: r0 = old value
167 */
168
169android_atomic_and:
170 stmdb sp!, {r4, r5, lr}
171 mov r2, r1 /* r2 = address */
172 mov r4, r0 /* r4 = the value */
1731: @ android_atomic_and
174 ldr r0, [r2] /* r0 = address[0] */
175 mov r3, #kernel_atomic_base
176#ifdef __ARM_HAVE_PC_INTERWORK
177 add lr, pc, #8
178 mov r5, r0 /* r5 = save address[0] */
179 and r1, r0, r4 /* r1 = new value */
180 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
181#else
182 mov r5, r0 /* r5 = save address[0] */
183 and r1, r0, r4 /* r1 = new value */
184 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
185 mov lr, pc
186 bx r3
187#endif
188 bcc 1b
189 mov r0, r5
190 ldmia sp!, {r4, r5, lr}
191 bx lr
192
193/*
194 * ----------------------------------------------------------------------------
195 * android_atomic_or
196 * input: r0=value, r1=address
197 * output: r0 = old value
198 */
199
200android_atomic_or:
201 stmdb sp!, {r4, r5, lr}
202 mov r2, r1 /* r2 = address */
203 mov r4, r0 /* r4 = the value */
2041: @ android_atomic_or
205 ldr r0, [r2] /* r0 = address[0] */
206 mov r3, #kernel_atomic_base
207#ifdef __ARM_HAVE_PC_INTERWORK
208 add lr, pc, #8
209 mov r5, r0 /* r5 = save address[0] */
210 orr r1, r0, r4 /* r1 = new value */
211 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
212#else
213 mov r5, r0 /* r5 = save address[0] */
214 orr r1, r0, r4 /* r1 = new value */
215 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
216 mov lr, pc
217 bx r3
218#endif
219 bcc 1b
220 mov r0, r5
221 ldmia sp!, {r4, r5, lr}
222 bx lr
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 stmdb sp!, {r4, lr}
247 mov r4, r0 /* r4 = save oldvalue */
2481: @ android_atomic_cmpxchg
249 mov r3, #kernel_atomic_base
250#ifdef __ARM_HAVE_PC_INTERWORK
251 add lr, pc, #4
252 mov r0, r4 /* r0 = oldvalue */
253 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
254#else
255 mov r0, r4 /* r0 = oldvalue */
256 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
257 mov lr, pc
258 bx r3
259#endif
260 bcs 2f /* swap was made. we're good, return. */
261 ldr r3, [r2] /* swap not made, see if it's because *ptr!=oldvalue */
262 cmp r3, r4
263 beq 1b
2642: @ android_atomic_cmpxchg
265 ldmia sp!, {r4, lr}
266 bx lr
267
268/*
269 * ----------------------------------------------------------------------------
270 * android_atomic_cmpxchg_64
271 * input: r0-r1=oldvalue, r2-r3=newvalue, arg4 (on stack)=address
272 * output: r0 = 0 (xchg done) or non-zero (xchg not done)
273 */
274/* TODO: NEED IMPLEMENTATION FOR THIS ARCHITECTURE */