blob: f4299fdedf2c80085d9e40397ce1e83a961195be [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:
Mathias Agopianca5e0bc2009-09-03 14:49:58 -070058 str r0, [r1]
59 bx lr;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080060
61/*
62 * ----------------------------------------------------------------------------
63 * android_atomic_inc
64 * input: r0 = address
65 * output: r0 = old value
66 */
67
68android_atomic_inc:
69 stmdb sp!, {r4, lr}
70 mov r2, r0
711: @ android_atomic_inc
72 ldr r0, [r2]
73 mov r3, #kernel_atomic_base
74#ifdef __ARM_HAVE_PC_INTERWORK
75 add lr, pc, #4
76 add r1, r0, #1
77 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
78#else
79 add r1, r0, #1
80 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
81 mov lr, pc
82 bx r3
83#endif
84 bcc 1b
85 sub r0, r1, #1
86 ldmia sp!, {r4, lr}
87 bx lr
88
89/*
90 * ----------------------------------------------------------------------------
91 * android_atomic_dec
92 * input: r0=address
93 * output: r0 = old value
94 */
95
96android_atomic_dec:
97 stmdb sp!, {r4, lr}
98 mov r2, r0
991: @ android_atomic_dec
100 ldr r0, [r2]
101 mov r3, #kernel_atomic_base
102#ifdef __ARM_HAVE_PC_INTERWORK
103 add lr, pc, #4
104 sub r1, r0, #1
105 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
106#else
107 sub r1, r0, #1
108 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
109 mov lr, pc
110 bx r3
111#endif
112 bcc 1b
113 add r0, r1, #1
114 ldmia sp!, {r4, lr}
115 bx lr
116
117/*
118 * ----------------------------------------------------------------------------
119 * android_atomic_add
120 * input: r0=value, r1=address
121 * output: r0 = old value
122 */
123
124android_atomic_add:
125 stmdb sp!, {r4, lr}
126 mov r2, r1
127 mov r4, r0
1281: @ android_atomic_add
129 ldr r0, [r2]
130 mov r3, #kernel_atomic_base
131#ifdef __ARM_HAVE_PC_INTERWORK
132 add lr, pc, #4
133 add r1, r0, r4
134 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
135#else
136 add r1, r0, r4
137 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
138 mov lr, pc
139 bx r3
140#endif
141 bcc 1b
142 sub r0, r1, r4
143 ldmia sp!, {r4, lr}
144 bx lr
145
146
147/*
148 * ----------------------------------------------------------------------------
149 * android_atomic_and
150 * input: r0=value, r1=address
151 * output: r0 = old value
152 */
153
154android_atomic_and:
155 stmdb sp!, {r4, r5, lr}
156 mov r2, r1 /* r2 = address */
157 mov r4, r0 /* r4 = the value */
1581: @ android_atomic_and
159 ldr r0, [r2] /* r0 = address[0] */
160 mov r3, #kernel_atomic_base
161#ifdef __ARM_HAVE_PC_INTERWORK
162 add lr, pc, #8
163 mov r5, r0 /* r5 = save address[0] */
164 and r1, r0, r4 /* r1 = new value */
165 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
166#else
167 mov r5, r0 /* r5 = save address[0] */
168 and r1, r0, r4 /* r1 = new value */
169 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
170 mov lr, pc
171 bx r3
172#endif
173 bcc 1b
174 mov r0, r5
175 ldmia sp!, {r4, r5, lr}
176 bx lr
177
178/*
179 * ----------------------------------------------------------------------------
180 * android_atomic_or
181 * input: r0=value, r1=address
182 * output: r0 = old value
183 */
184
185android_atomic_or:
186 stmdb sp!, {r4, r5, lr}
187 mov r2, r1 /* r2 = address */
188 mov r4, r0 /* r4 = the value */
1891: @ android_atomic_or
190 ldr r0, [r2] /* r0 = address[0] */
191 mov r3, #kernel_atomic_base
192#ifdef __ARM_HAVE_PC_INTERWORK
193 add lr, pc, #8
194 mov r5, r0 /* r5 = save address[0] */
195 orr r1, r0, r4 /* r1 = new value */
196 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
197#else
198 mov r5, r0 /* r5 = save address[0] */
199 orr r1, r0, r4 /* r1 = new value */
200 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
201 mov lr, pc
202 bx r3
203#endif
204 bcc 1b
205 mov r0, r5
206 ldmia sp!, {r4, r5, lr}
207 bx lr
208
209/*
210 * ----------------------------------------------------------------------------
211 * android_atomic_swap
212 * input: r0=value, r1=address
213 * output: r0 = old value
214 */
215
216/* FIXME: this is not safe on SMP systems
217 * a general way to do it is to use kernel_cmpxchg */
218
219android_atomic_swap:
220 swp r0, r0, [r1]
221 bx lr
222
223/*
224 * ----------------------------------------------------------------------------
225 * android_atomic_cmpxchg
226 * input: r0=oldvalue, r1=newvalue, r2=address
227 * output: r0 = 0 (xchg done) or non-zero (xchg not done)
228 */
229
230android_atomic_cmpxchg:
231 stmdb sp!, {r4, lr}
232 mov r4, r0 /* r4 = save oldvalue */
2331: @ android_atomic_cmpxchg
234 mov r3, #kernel_atomic_base
235#ifdef __ARM_HAVE_PC_INTERWORK
236 add lr, pc, #4
237 mov r0, r4 /* r0 = oldvalue */
238 add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
239#else
240 mov r0, r4 /* r0 = oldvalue */
241 add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
242 mov lr, pc
243 bx r3
244#endif
245 bcs 2f /* swap was made. we're good, return. */
246 ldr r3, [r2] /* swap not made, see if it's because *ptr!=oldvalue */
247 cmp r3, r4
248 beq 1b
2492: @ android_atomic_cmpxchg
250 ldmia sp!, {r4, lr}
251 bx lr
252
253/*
254 * ----------------------------------------------------------------------------
255 * android_atomic_cmpxchg_64
256 * input: r0-r1=oldvalue, r2-r3=newvalue, arg4 (on stack)=address
257 * output: r0 = 0 (xchg done) or non-zero (xchg not done)
258 */
259/* TODO: NEED IMPLEMENTATION FOR THIS ARCHITECTURE */