• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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