00db10
commit 56cf2763819d2f721c98f2b8bcc04a3c673837d3
00db10
Author: Adhemerval Zanella <azanella@linux.vnet.ibm.com>
00db10
Date:   Fri Nov 7 12:34:52 2014 -0500
00db10
00db10
    powerpc: abort transaction in syscalls
00db10
    
00db10
    Linux kernel powerpc documentation states issuing a syscall inside a
00db10
    transaction is not recommended and may lead to undefined behavior. It
00db10
    also states syscalls does not abort transactoin neither they run in
00db10
    transactional state.
00db10
    
00db10
    To avoid side-effects being visible outside transactions, GLIBC with
00db10
    lock elision enabled will issue a transaction abort instruction just
00db10
    before all syscalls if hardware supports hardware transactions.
00db10
00db10
Index: glibc-2.17-c758a686/nptl/sysdeps/powerpc/tcb-offsets.sym
00db10
===================================================================
00db10
--- glibc-2.17-c758a686.orig/nptl/sysdeps/powerpc/tcb-offsets.sym
00db10
+++ glibc-2.17-c758a686/nptl/sysdeps/powerpc/tcb-offsets.sym
00db10
@@ -15,6 +15,7 @@ MULTIPLE_THREADS_OFFSET		thread_offsetof
00db10
 PID				thread_offsetof (pid)
00db10
 TID				thread_offsetof (tid)
00db10
 POINTER_GUARD			(offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
00db10
+TM_CAPABLE			(offsetof (tcbhead_t, tm_capable) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
00db10
 #ifndef __ASSUME_PRIVATE_FUTEX
00db10
 PRIVATE_FUTEX_OFFSET		thread_offsetof (header.private_futex)
00db10
 #endif
00db10
Index: glibc-2.17-c758a686/nptl/sysdeps/powerpc/tls.h
00db10
===================================================================
00db10
--- glibc-2.17-c758a686.orig/nptl/sysdeps/powerpc/tls.h
00db10
+++ glibc-2.17-c758a686/nptl/sysdeps/powerpc/tls.h
00db10
@@ -61,6 +61,15 @@ typedef union dtv
00db10
    are private.  */
00db10
 typedef struct
00db10
 {
00db10
+  /* Indicate if HTM capable (ISA 2.07).  */
00db10
+  uint32_t tm_capable;
00db10
+  /* Reservation for AT_PLATFORM data - powerpc64.  */
00db10
+#ifdef __powerpc64__
00db10
+  uint32_t at_platform;
00db10
+#endif
00db10
+  /* Reservation for Dynamic System Optimizer ABI.  */
00db10
+  uintptr_t dso_slot2;
00db10
+  uintptr_t dso_slot1;
00db10
   /* GCC split stack support.  */
00db10
   void *__private_ss;
00db10
   /* Reservation for the Event-Based Branching ABI.  */
00db10
@@ -123,7 +132,11 @@ register void *__thread_register __asm__
00db10
    special attention since 'errno' is not yet available and if the
00db10
    operation can cause a failure 'errno' must not be touched.  */
00db10
 # define TLS_INIT_TP(tcbp, secondcall) \
00db10
-    (__thread_register = (void *) (tcbp) + TLS_TCB_OFFSET, NULL)
00db10
+  ({ 									      \
00db10
+    __thread_register = (void *) (tcbp) + TLS_TCB_OFFSET;		      \
00db10
+    THREAD_SET_TM_CAPABLE (GLRO (dl_hwcap2) & PPC_FEATURE2_HAS_HTM ? 1 : 0);  \
00db10
+    NULL;								      \
00db10
+  })
00db10
 
00db10
 /* Return the address of the dtv for the current thread.  */
00db10
 # define THREAD_DTV() \
00db10
@@ -177,6 +190,13 @@ register void *__thread_register __asm__
00db10
 		     + TLS_PRE_TCB_SIZE))[-1].pointer_guard		      \
00db10
      = THREAD_GET_POINTER_GUARD())
00db10
 
00db10
+/* tm_capable field in TCB head.  */
00db10
+# define THREAD_GET_TM_CAPABLE() \
00db10
+    (((tcbhead_t *) ((char *) __thread_register				      \
00db10
+		     - TLS_TCB_OFFSET))[-1].tm_capable)
00db10
+# define THREAD_SET_TM_CAPABLE(value) \
00db10
+    (THREAD_GET_TM_CAPABLE () = (value))
00db10
+
00db10
 /* l_tls_offset == 0 is perfectly valid on PPC, so we have to use some
00db10
    different value to mean unset l_tls_offset.  */
00db10
 # define NO_TLS_OFFSET		-1
00db10
Index: glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/sysdep.h
00db10
===================================================================
00db10
--- glibc-2.17-c758a686.orig/sysdeps/powerpc/powerpc32/sysdep.h
00db10
+++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc32/sysdep.h
00db10
@@ -89,7 +89,23 @@ GOT_LABEL:			;					      \
00db10
   cfi_endproc;								      \
00db10
   ASM_SIZE_DIRECTIVE(name)
00db10
 
00db10
+#if ! IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
00db10
+# define ABORT_TRANSACTION \
00db10
+    cmpwi    2,0;		\
00db10
+    beq      1f;		\
00db10
+    lwz      0,TM_CAPABLE(2);	\
00db10
+    cmpwi    0,0;		\
00db10
+    beq	     1f;		\
00db10
+    li	     0,_ABORT_SYSCALL;	\
00db10
+    tabort.  0;			\
00db10
+    .align 4;			\
00db10
+1:
00db10
+#else
00db10
+# define ABORT_TRANSACTION
00db10
+#endif
00db10
+
00db10
 #define DO_CALL(syscall)						      \
00db10
+    ABORT_TRANSACTION							      \
00db10
     li 0,syscall;							      \
00db10
     sc
00db10
 
00db10
Index: glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/sysdep.h
00db10
===================================================================
00db10
--- glibc-2.17-c758a686.orig/sysdeps/powerpc/powerpc64/sysdep.h
00db10
+++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/sysdep.h
00db10
@@ -283,7 +283,23 @@ LT_LABELSUFFIX(name,_name_end): ; \
00db10
   TRACEBACK_MASK(name,mask)	\
00db10
   END_2(name)
00db10
 
00db10
+#if !IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
00db10
+# define ABORT_TRANSACTION \
00db10
+    cmpdi    13,0;		\
00db10
+    beq      1f;		\
00db10
+    lwz      0,TM_CAPABLE(13);	\
00db10
+    cmpwi    0,0;		\
00db10
+    beq	     1f;		\
00db10
+    li	     0,_ABORT_SYSCALL;	\
00db10
+    tabort.  0;			\
00db10
+    .align 4;                   \
00db10
+1:
00db10
+#else
00db10
+# define ABORT_TRANSACTION
00db10
+#endif
00db10
+
00db10
 #define DO_CALL(syscall) \
00db10
+    ABORT_TRANSACTION \
00db10
     li 0,syscall; \
00db10
     sc
00db10
 
00db10
Index: glibc-2.17-c758a686/sysdeps/powerpc/sysdep.h
00db10
===================================================================
00db10
--- glibc-2.17-c758a686.orig/sysdeps/powerpc/sysdep.h
00db10
+++ glibc-2.17-c758a686/sysdeps/powerpc/sysdep.h
00db10
@@ -21,6 +21,10 @@
00db10
  */
00db10
 #define _SYS_AUXV_H 1
00db10
 #include <bits/hwcap.h>
00db10
+#ifdef ENABLE_LOCK_ELISION
00db10
+#include <tls.h>
00db10
+#include <htm.h>
00db10
+#endif
00db10
 
00db10
 #define PPC_FEATURE_970 (PPC_FEATURE_POWER4 + PPC_FEATURE_HAS_ALTIVEC)
00db10
 
00db10
@@ -164,4 +168,22 @@
00db10
 #define ALIGNARG(log2) log2
00db10
 #define ASM_SIZE_DIRECTIVE(name) .size name,.-name
00db10
 
00db10
+#else
00db10
+
00db10
+/* Linux kernel powerpc documentation [1] states issuing a syscall inside a
00db10
+   transaction is not recommended and may lead to undefined behavior.  It
00db10
+   also states syscalls do not abort transactions.  To avoid such traps,
00db10
+   we abort transaction just before syscalls.
00db10
+
00db10
+   [1] Documentation/powerpc/transactional_memory.txt [Syscalls]  */
00db10
+#if !IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
00db10
+# define ABORT_TRANSACTION \
00db10
+  ({ 						\
00db10
+    if (THREAD_GET_TM_CAPABLE ())		\
00db10
+      __builtin_tabort (_ABORT_SYSCALL);	\
00db10
+  })
00db10
+#else
00db10
+# define ABORT_TRANSACTION
00db10
+#endif
00db10
+
00db10
 #endif	/* __ASSEMBLER__ */
00db10
Index: glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
00db10
===================================================================
00db10
--- glibc-2.17-c758a686.orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
00db10
+++ glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
00db10
@@ -194,6 +194,7 @@
00db10
     register long int r11 __asm__ ("r11");				\
00db10
     register long int r12 __asm__ ("r12");				\
00db10
     LOADARGS_##nr(name, args);						\
00db10
+    ABORT_TRANSACTION;							\
00db10
     __asm__ __volatile__						\
00db10
       ("sc   \n\t"							\
00db10
        "mfcr %0"							\
00db10
Index: glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
00db10
===================================================================
00db10
--- glibc-2.17-c758a686.orig/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
00db10
+++ glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
00db10
@@ -201,6 +201,7 @@
00db10
     register long int r7  __asm__ ("r7");				\
00db10
     register long int r8  __asm__ ("r8");				\
00db10
     LOADARGS_##nr (name, ##args);					\
00db10
+    ABORT_TRANSACTION;							\
00db10
     __asm__ __volatile__						\
00db10
       ("sc\n\t"								\
00db10
        "mfcr  %0\n\t"							\
00db10
Index: glibc-2.17-c758a686/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c
00db10
===================================================================
00db10
--- glibc-2.17-c758a686.orig/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c
00db10
+++ glibc-2.17-c758a686/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c
00db10
@@ -16,9 +16,16 @@
00db10
    License along with the GNU C Library; if not, see
00db10
    <http://www.gnu.org/licenses/>.  */
00db10
 
00db10
+/* RHEL 7-specific changes: The functions PREPARE_CREATE and TLS_VALUE
00db10
+   are used by createthread.c to override thread setup.  In upstream
00db10
+   they appear in TLS_DEFINE_INIT_TP.  */
00db10
+# define PREPARE_CREATE \
00db10
+  void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE;            \
00db10
+  (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].tm_capable) =        \
00db10
+  THREAD_GET_TM_CAPABLE ();
00db10
+
00db10
 /* Value passed to 'clone' for initialization of the thread register.  */
00db10
-#define TLS_VALUE ((void *) (pd) \
00db10
-		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
00db10
+# define TLS_VALUE tp
00db10
 
00db10
 /* Get the real implementation.	 */
00db10
 #include <nptl/sysdeps/pthread/createthread.c>