summaryrefslogtreecommitdiffstats
path: root/libcutils/atomic-android-arm.S
diff options
context:
space:
mode:
Diffstat (limited to 'libcutils/atomic-android-arm.S')
-rw-r--r--libcutils/atomic-android-arm.S274
1 files changed, 274 insertions, 0 deletions
diff --git a/libcutils/atomic-android-arm.S b/libcutils/atomic-android-arm.S
new file mode 100644
index 0000000..c56ec5d
--- /dev/null
+++ b/libcutils/atomic-android-arm.S
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <machine/cpu-features.h>
+
+/*
+ * NOTE: these atomic operations are SMP safe on all architectures,
+ * except swap(), see below.
+ */
+
+ .text
+ .align
+
+ .global android_atomic_write
+
+ .global android_atomic_inc
+ .global android_atomic_dec
+
+ .global android_atomic_add
+ .global android_atomic_and
+ .global android_atomic_or
+
+ .global android_atomic_swap
+
+ .global android_atomic_cmpxchg
+
+/*
+ * ----------------------------------------------------------------------------
+ * int __kernel_cmpxchg(int oldval, int newval, int *ptr)
+ * clobbered: r3, ip, flags
+ * return 0 if a swap was made, non-zero otherwise.
+ */
+
+ .equ kernel_cmpxchg, 0xFFFF0FC0
+ .equ kernel_atomic_base, 0xFFFF0FFF
+
+/*
+ * ----------------------------------------------------------------------------
+ * android_atomic_write
+ * input: r0=value, r1=address
+ * output: void
+ */
+
+android_atomic_write:
+ stmdb sp!, {r4, lr}
+ mov r2, r1
+ mov r1, r0
+1: @ android_atomic_write
+ ldr r0, [r2]
+ mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
+ add lr, pc, #4
+ add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+ mov lr, pc
+ bx r3
+#endif
+ bcc 1b
+ ldmia sp!, {r4, lr}
+ bx lr
+
+/*
+ * ----------------------------------------------------------------------------
+ * android_atomic_inc
+ * input: r0 = address
+ * output: r0 = old value
+ */
+
+android_atomic_inc:
+ stmdb sp!, {r4, lr}
+ mov r2, r0
+1: @ android_atomic_inc
+ ldr r0, [r2]
+ mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
+ add lr, pc, #4
+ add r1, r0, #1
+ add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+ add r1, r0, #1
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+ mov lr, pc
+ bx r3
+#endif
+ bcc 1b
+ sub r0, r1, #1
+ ldmia sp!, {r4, lr}
+ bx lr
+
+/*
+ * ----------------------------------------------------------------------------
+ * android_atomic_dec
+ * input: r0=address
+ * output: r0 = old value
+ */
+
+android_atomic_dec:
+ stmdb sp!, {r4, lr}
+ mov r2, r0
+1: @ android_atomic_dec
+ ldr r0, [r2]
+ mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
+ add lr, pc, #4
+ sub r1, r0, #1
+ add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+ sub r1, r0, #1
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+ mov lr, pc
+ bx r3
+#endif
+ bcc 1b
+ add r0, r1, #1
+ ldmia sp!, {r4, lr}
+ bx lr
+
+/*
+ * ----------------------------------------------------------------------------
+ * android_atomic_add
+ * input: r0=value, r1=address
+ * output: r0 = old value
+ */
+
+android_atomic_add:
+ stmdb sp!, {r4, lr}
+ mov r2, r1
+ mov r4, r0
+1: @ android_atomic_add
+ ldr r0, [r2]
+ mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
+ add lr, pc, #4
+ add r1, r0, r4
+ add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+ add r1, r0, r4
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+ mov lr, pc
+ bx r3
+#endif
+ bcc 1b
+ sub r0, r1, r4
+ ldmia sp!, {r4, lr}
+ bx lr
+
+
+/*
+ * ----------------------------------------------------------------------------
+ * android_atomic_and
+ * input: r0=value, r1=address
+ * output: r0 = old value
+ */
+
+android_atomic_and:
+ stmdb sp!, {r4, r5, lr}
+ mov r2, r1 /* r2 = address */
+ mov r4, r0 /* r4 = the value */
+1: @ android_atomic_and
+ ldr r0, [r2] /* r0 = address[0] */
+ mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
+ add lr, pc, #8
+ mov r5, r0 /* r5 = save address[0] */
+ and r1, r0, r4 /* r1 = new value */
+ add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
+#else
+ mov r5, r0 /* r5 = save address[0] */
+ and r1, r0, r4 /* r1 = new value */
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
+ mov lr, pc
+ bx r3
+#endif
+ bcc 1b
+ mov r0, r5
+ ldmia sp!, {r4, r5, lr}
+ bx lr
+
+/*
+ * ----------------------------------------------------------------------------
+ * android_atomic_or
+ * input: r0=value, r1=address
+ * output: r0 = old value
+ */
+
+android_atomic_or:
+ stmdb sp!, {r4, r5, lr}
+ mov r2, r1 /* r2 = address */
+ mov r4, r0 /* r4 = the value */
+1: @ android_atomic_or
+ ldr r0, [r2] /* r0 = address[0] */
+ mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
+ add lr, pc, #8
+ mov r5, r0 /* r5 = save address[0] */
+ orr r1, r0, r4 /* r1 = new value */
+ add pc, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
+#else
+ mov r5, r0 /* r5 = save address[0] */
+ orr r1, r0, r4 /* r1 = new value */
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base) /* call cmpxchg() */
+ mov lr, pc
+ bx r3
+#endif
+ bcc 1b
+ mov r0, r5
+ ldmia sp!, {r4, r5, lr}
+ bx lr
+
+/*
+ * ----------------------------------------------------------------------------
+ * android_atomic_swap
+ * input: r0=value, r1=address
+ * output: r0 = old value
+ */
+
+/* FIXME: this is not safe on SMP systems
+ * a general way to do it is to use kernel_cmpxchg */
+
+android_atomic_swap:
+ swp r0, r0, [r1]
+ bx lr
+
+/*
+ * ----------------------------------------------------------------------------
+ * android_atomic_cmpxchg
+ * input: r0=oldvalue, r1=newvalue, r2=address
+ * output: r0 = 0 (xchg done) or non-zero (xchg not done)
+ */
+
+android_atomic_cmpxchg:
+ stmdb sp!, {r4, lr}
+ mov r4, r0 /* r4 = save oldvalue */
+1: @ android_atomic_cmpxchg
+ mov r3, #kernel_atomic_base
+#ifdef __ARM_HAVE_PC_INTERWORK
+ add lr, pc, #4
+ mov r0, r4 /* r0 = oldvalue */
+ add pc, r3, #(kernel_cmpxchg - kernel_atomic_base)
+#else
+ mov r0, r4 /* r0 = oldvalue */
+ add r3, r3, #(kernel_cmpxchg - kernel_atomic_base)
+ mov lr, pc
+ bx r3
+#endif
+ bcs 2f /* swap was made. we're good, return. */
+ ldr r3, [r2] /* swap not made, see if it's because *ptr!=oldvalue */
+ cmp r3, r4
+ beq 1b
+2: @ android_atomic_cmpxchg
+ ldmia sp!, {r4, lr}
+ bx lr
+
+/*
+ * ----------------------------------------------------------------------------
+ * android_atomic_cmpxchg_64
+ * input: r0-r1=oldvalue, r2-r3=newvalue, arg4 (on stack)=address
+ * output: r0 = 0 (xchg done) or non-zero (xchg not done)
+ */
+/* TODO: NEED IMPLEMENTATION FOR THIS ARCHITECTURE */