summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extra/Configs/Config.arm8
-rw-r--r--extra/Configs/Config.in1
-rw-r--r--libc/sysdeps/linux/arm/clone.S14
-rw-r--r--libpthread/linuxthreads.old/sysdeps/arm/pt-machine.h56
4 files changed, 65 insertions, 14 deletions
diff --git a/extra/Configs/Config.arm b/extra/Configs/Config.arm
index a16c9197a..00cf98281 100644
--- a/extra/Configs/Config.arm
+++ b/extra/Configs/Config.arm
@@ -28,6 +28,7 @@ config CONFIG_ARM_EABI
config COMPILE_IN_THUMB_MODE
bool "Build using Thumb mode"
select USE_BX
+ select USE_LDREXSTREX
help
Say 'y' here to force building uClibc in thumb mode.
Say 'n' to use your compiler's default mode.
@@ -38,3 +39,10 @@ config USE_BX
Say 'y' to use BX to return from functions on your thumb-aware
processor. Say 'y' if you need to use interworking. Say 'n' if not.
It is safe to say 'y' even if you're not doing interworking.
+
+config USE_LDREXSTREX
+ bool "Use load-store exclusive ASM ops (not supported in SmartFusion)"
+ depends on COMPILE_IN_THUMB_MODE
+ default n
+ help
+ Say 'y' to use LDREX/STREX ASM ops.
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index c7a3b2dd2..31944bea1 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -524,7 +524,6 @@ config LINUXTHREADS_OLD
# linuxthreads and linuxthreads.old need nanosleep()
select UCLIBC_HAS_REALTIME
depends on !TARGET_arc && \
- !TARGET_arm && \
!TARGET_i386 && \
!TARGET_metag && \
!TARGET_mips && \
diff --git a/libc/sysdeps/linux/arm/clone.S b/libc/sysdeps/linux/arm/clone.S
index 29045ef7b..d1c9239da 100644
--- a/libc/sysdeps/linux/arm/clone.S
+++ b/libc/sysdeps/linux/arm/clone.S
@@ -26,7 +26,10 @@
#include <sys/syscall.h>
#include <bits/arm_asm.h>
#include <bits/arm_bx.h>
+
+#if defined __UCLIBC_HAS_THREADS__ && !defined __LINUXTHREADS_OLD__
#include <sysdep-cancel.h>
+#endif
#define CLONE_VM 0x00000100
#define CLONE_THREAD 0x00010000
@@ -57,23 +60,22 @@ __clone:
@ get flags
mov r0, r2
@ new sp is already in r1
- @ load remaining arguments off the stack
- stmfd sp!, {r4}
- ldr r2, [sp, #4]
- ldr r3, [sp, #8]
- ldr r4, [sp, #12]
DO_CALL (clone)
movs a1, a1
blt __error
- ldmnefd sp!, {r4}
beq 1f
bx lr
1:
@ pick the function arg and call address off the stack and execute
ldr r0, [sp, #4]
+#if defined(__USE_BX__)
ldr r1, [sp]
bl 2f @ blx r1
+#else
+ mov lr, pc
+ ldr pc, [sp]
+#endif
@ and we are done, passing the return value through r0
bl HIDDEN_JUMPTARGET(_exit)
diff --git a/libpthread/linuxthreads.old/sysdeps/arm/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/arm/pt-machine.h
index 438c12ab9..2b877f980 100644
--- a/libpthread/linuxthreads.old/sysdeps/arm/pt-machine.h
+++ b/libpthread/linuxthreads.old/sysdeps/arm/pt-machine.h
@@ -21,12 +21,50 @@
#ifndef _PT_MACHINE_H
#define _PT_MACHINE_H 1
-#include <features.h>
+#include <sys/syscall.h>
+#include <unistd.h>
#ifndef PT_EI
# define PT_EI __extern_always_inline
#endif
+#if defined(__thumb__)
+#if defined(__USE_LDREXSTREX__)
+PT_EI long int ldrex(int *spinlock)
+{
+ long int ret;
+ __asm__ __volatile__(
+ "ldrex %0, [%1]\n"
+ : "=r"(ret)
+ : "r"(spinlock) : "memory");
+ return ret;
+}
+
+PT_EI long int strex(int val, int *spinlock)
+{
+ long int ret;
+ __asm__ __volatile__(
+ "strex %0, %1, [%2]\n"
+ : "=r"(ret)
+ : "r" (val), "r"(spinlock) : "memory");
+ return ret;
+}
+
+/* Spinlock implementation; required. */
+PT_EI long int
+testandset (int *spinlock)
+{
+ register unsigned int ret;
+
+ do {
+ ret = ldrex(spinlock);
+ } while (strex(1, spinlock));
+
+ return ret;
+}
+
+#else /* __USE_LDREXSTREX__ */
+
/* This will not work on ARM1 or ARM2 because SWP is lacking on those
machines. Unfortunately we have no way to detect this at compile
time; let's hope nobody tries to use one. */
@@ -36,8 +74,6 @@ PT_EI long int testandset (int *spinlock);
PT_EI long int testandset (int *spinlock)
{
register unsigned int ret;
-
-#if defined(__thumb__)
void *pc;
__asm__ __volatile__(
".align 0\n"
@@ -50,15 +86,21 @@ PT_EI long int testandset (int *spinlock)
"\t.force_thumb"
: "=r"(ret), "=r"(pc)
: "0"(1), "r"(spinlock));
-#else
+ return ret;
+}
+#endif
+#else /* __thumb__ */
+
+PT_EI long int testandset (int *spinlock);
+PT_EI long int testandset (int *spinlock)
+{
+ register unsigned int ret;
__asm__ __volatile__("swp %0, %1, [%2]"
: "=r"(ret)
: "0"(1), "r"(spinlock));
-#endif
-
return ret;
}
-
+#endif
/* Get some notion of the current stack. Need not be exactly the top
of the stack, just something somewhere in the current frame. */