use inline atomics and thread pointer on arm models supporting them
authorRich Felker <dalias@aerifal.cx>
Mon, 7 Apr 2014 08:03:18 +0000 (04:03 -0400)
committerRich Felker <dalias@aerifal.cx>
Mon, 7 Apr 2014 08:03:18 +0000 (04:03 -0400)
this is perhaps not the optimal implementation; a_cas still compiles
to nested loops due to the different interface contracts of the kuser
helper cas function (whose contract this patch implements) and the
a_cas function (whose contract mimics the x86 cmpxchg). fixing this
may be possible, but it's more complicated and thus deferred until a
later time.

aside from improving performance and code size, this patch also
provides a means of producing binaries which can run on hardened
kernels where the kuser helpers have been disabled. however, at
present this requires producing binaries for armv6k or later, which
will not run on older cpus. a real solution to the problem of kernels
that omit the kuser helpers would be runtime detection, so that
universal binaries which run on all arm cpu models can also be
compatible with all kernel hardening profiles. robust detection
however is a much harder problem, and will be addressed at a later
time.

arch/arm/atomic.h
arch/arm/pthread_arch.h

index 734d2871787a85bc5ebc79f0dcceda0f42edeae3..fe88225b9eb28bd22f9ade60dd91553cfa633d24 100644 (file)
@@ -22,7 +22,28 @@ static inline int a_ctz_64(uint64_t x)
        return a_ctz_l(y);
 }
 
+#if __ARM_ARCH_6__ || __ARM_ARCH_6K__ || __ARM_ARCH_6ZK__ \
+ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ \
+ || __ARM_ARCH >= 7
+static inline int __k_cas(int t, int s, volatile int *p)
+{
+       int ret;
+       __asm__(
+               "       mcr p15,0,r0,c7,c10,5\n"
+               "1:     ldrex %0,%3\n"
+               "       subs %0,%0,%1\n"
+               "       strexeq %0,%2,%3\n"
+               "       teqeq %0,#1\n"
+               "       beq 1b\n"
+               "       mcr p15,0,r0,c7,c10,5\n"
+               : "=&r"(ret)
+               : "r"(t), "r"(s), "m"(*p)
+               : "memory", "cc" );
+       return ret;
+}
+#else
 #define __k_cas ((int (*)(int, int, volatile int *))0xffff0fc0)
+#endif
 
 static inline int a_cas(volatile int *p, int t, int s)
 {
index 43a1c012f466dcd41bc6444edfd4c265c722f7cd..ec77a8337b10991b54df11896dbed015175a67a3 100644 (file)
@@ -1,8 +1,22 @@
-typedef char *(*__ptr_func_t)(void) __attribute__((const));
+#if __ARM_ARCH_6K__ || __ARM_ARCH_6ZK__ \
+ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ \
+ || __ARM_ARCH >= 7
+
+static inline __attribute__((const)) pthread_t __pthread_self()
+{
+       char *p;
+       __asm__( "mrc p15,0,%0,c13,c0,3" : "=r"(p) );
+       return (void *)(p+8-sizeof(struct pthread));
+}
+
+#else
 
+typedef char *(*__ptr_func_t)(void) __attribute__((const));
 #define __pthread_self() \
        ((pthread_t)(((__ptr_func_t)0xffff0fe0)()+8-sizeof(struct pthread)))
 
+#endif
+
 #define TLS_ABOVE_TP
 #define TP_ADJ(p) ((char *)(p) + sizeof(struct pthread) - 8)