mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-23 19:30:10 +00:00
powerpc: abort transaction in syscalls
Linux kernel powerpc documentation states issuing a syscall inside a transaction is not recommended and may lead to undefined behavior. It also states syscalls does not abort transactoin neither they run in transactional state. To avoid side-effects being visible outside transactions, GLIBC with lock elision enabled will issue a transaction abort instruction just before all syscalls if hardware supports hardware transactions.
This commit is contained in:
parent
4b45943a6f
commit
56cf276381
17
ChangeLog
17
ChangeLog
@ -1,5 +1,22 @@
|
|||||||
2014-01-12 Adhemerval Zanella <azanella@linux.vnet.ibm.com>
|
2014-01-12 Adhemerval Zanella <azanella@linux.vnet.ibm.com>
|
||||||
|
|
||||||
|
* sysdeps/powerpc/nptl/tls.h (tcbhead_t): Add tm_capable field.
|
||||||
|
(TLS_INIT_TP): Add tm_capable initialization.
|
||||||
|
(TLS_DEFINE_INIT_TP): Likewise.
|
||||||
|
(THREAD_GET_TM_CAPABLE): New file: get tm_capable field value from
|
||||||
|
TCB.
|
||||||
|
(THREAD_SET_TM_CAPABLE): New file: set tm_capable field value in TCB.
|
||||||
|
* sysdeps/powerpc/nptl/tcb-offsets.sym (TM_CAPABLE): Add field offset
|
||||||
|
calculation.
|
||||||
|
* sysdeps/powerpc/powerpc32/sysdep.h (DO_CALL): Abort hardware
|
||||||
|
transactoion is lock elision is built and TCB tm_capable is set.
|
||||||
|
* sysdeps/powerpc/powerpc64/sysdep.h (DO_CALL): Likewise.
|
||||||
|
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
|
||||||
|
(INTERNAL_SYSCALL_NCS): Likewise.
|
||||||
|
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
|
||||||
|
(INTERNAL_SYSCALL_NCS): Likewise.
|
||||||
|
* sysdeps/powerpc/sysdep.h (ABORT_TRANSACTION): New define.
|
||||||
|
|
||||||
* sysdeps/powerpc/nptl/elide.h: New file: generic lock elision support
|
* sysdeps/powerpc/nptl/elide.h: New file: generic lock elision support
|
||||||
for powerpc.
|
for powerpc.
|
||||||
* sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
|
* sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
|
||||||
|
@ -19,6 +19,7 @@ POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (
|
|||||||
TAR_SAVE (offsetof (tcbhead_t, tar_save) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
|
TAR_SAVE (offsetof (tcbhead_t, tar_save) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
|
||||||
DSO_SLOT1 (offsetof (tcbhead_t, dso_slot1) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
|
DSO_SLOT1 (offsetof (tcbhead_t, dso_slot1) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
|
||||||
DSO_SLOT2 (offsetof (tcbhead_t, dso_slot2) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
|
DSO_SLOT2 (offsetof (tcbhead_t, dso_slot2) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
|
||||||
|
TM_CAPABLE (offsetof (tcbhead_t, tm_capable) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
|
||||||
#ifndef __ASSUME_PRIVATE_FUTEX
|
#ifndef __ASSUME_PRIVATE_FUTEX
|
||||||
PRIVATE_FUTEX_OFFSET thread_offsetof (header.private_futex)
|
PRIVATE_FUTEX_OFFSET thread_offsetof (header.private_futex)
|
||||||
#endif
|
#endif
|
||||||
|
@ -63,6 +63,8 @@ typedef union dtv
|
|||||||
are private. */
|
are private. */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
/* Indicate if HTM capable (ISA 2.07). */
|
||||||
|
int tm_capable;
|
||||||
/* Reservation for Dynamic System Optimizer ABI. */
|
/* Reservation for Dynamic System Optimizer ABI. */
|
||||||
uintptr_t dso_slot2;
|
uintptr_t dso_slot2;
|
||||||
uintptr_t dso_slot1;
|
uintptr_t dso_slot1;
|
||||||
@ -130,11 +132,17 @@ register void *__thread_register __asm__ ("r13");
|
|||||||
special attention since 'errno' is not yet available and if the
|
special attention since 'errno' is not yet available and if the
|
||||||
operation can cause a failure 'errno' must not be touched. */
|
operation can cause a failure 'errno' must not be touched. */
|
||||||
# define TLS_INIT_TP(tcbp) \
|
# define TLS_INIT_TP(tcbp) \
|
||||||
(__thread_register = (void *) (tcbp) + TLS_TCB_OFFSET, NULL)
|
({ \
|
||||||
|
__thread_register = (void *) (tcbp) + TLS_TCB_OFFSET; \
|
||||||
|
THREAD_SET_TM_CAPABLE (GLRO (dl_hwcap2) & PPC_FEATURE2_HAS_HTM ? 1 : 0); \
|
||||||
|
NULL; \
|
||||||
|
})
|
||||||
|
|
||||||
/* Value passed to 'clone' for initialization of the thread register. */
|
/* Value passed to 'clone' for initialization of the thread register. */
|
||||||
# define TLS_DEFINE_INIT_TP(tp, pd) \
|
# define TLS_DEFINE_INIT_TP(tp, pd) \
|
||||||
void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE
|
void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE; \
|
||||||
|
(((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].tm_capable) = \
|
||||||
|
THREAD_GET_TM_CAPABLE ();
|
||||||
|
|
||||||
/* Return the address of the dtv for the current thread. */
|
/* Return the address of the dtv for the current thread. */
|
||||||
# define THREAD_DTV() \
|
# define THREAD_DTV() \
|
||||||
@ -188,6 +196,13 @@ register void *__thread_register __asm__ ("r13");
|
|||||||
+ TLS_PRE_TCB_SIZE))[-1].pointer_guard \
|
+ TLS_PRE_TCB_SIZE))[-1].pointer_guard \
|
||||||
= THREAD_GET_POINTER_GUARD())
|
= THREAD_GET_POINTER_GUARD())
|
||||||
|
|
||||||
|
/* tm_capable field in TCB head. */
|
||||||
|
# define THREAD_GET_TM_CAPABLE() \
|
||||||
|
(((tcbhead_t *) ((char *) __thread_register \
|
||||||
|
- TLS_TCB_OFFSET))[-1].tm_capable)
|
||||||
|
# define THREAD_SET_TM_CAPABLE(value) \
|
||||||
|
(THREAD_GET_TM_CAPABLE () = (value))
|
||||||
|
|
||||||
/* l_tls_offset == 0 is perfectly valid on PPC, so we have to use some
|
/* l_tls_offset == 0 is perfectly valid on PPC, so we have to use some
|
||||||
different value to mean unset l_tls_offset. */
|
different value to mean unset l_tls_offset. */
|
||||||
# define NO_TLS_OFFSET -1
|
# define NO_TLS_OFFSET -1
|
||||||
|
@ -88,7 +88,23 @@ GOT_LABEL: ; \
|
|||||||
cfi_endproc; \
|
cfi_endproc; \
|
||||||
ASM_SIZE_DIRECTIVE(name)
|
ASM_SIZE_DIRECTIVE(name)
|
||||||
|
|
||||||
|
#if ! IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
|
||||||
|
# define ABORT_TRANSACTION \
|
||||||
|
cmpwi 2,0; \
|
||||||
|
beq 1f; \
|
||||||
|
lwz 0,TM_CAPABLE(2); \
|
||||||
|
cmpwi 0,0; \
|
||||||
|
beq 1f; \
|
||||||
|
li 0,_ABORT_SYSCALL; \
|
||||||
|
tabort. 0; \
|
||||||
|
.align 4; \
|
||||||
|
1:
|
||||||
|
#else
|
||||||
|
# define ABORT_TRANSACTION
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DO_CALL(syscall) \
|
#define DO_CALL(syscall) \
|
||||||
|
ABORT_TRANSACTION \
|
||||||
li 0,syscall; \
|
li 0,syscall; \
|
||||||
sc
|
sc
|
||||||
|
|
||||||
|
@ -283,7 +283,23 @@ LT_LABELSUFFIX(name,_name_end): ; \
|
|||||||
TRACEBACK_MASK(name,mask) \
|
TRACEBACK_MASK(name,mask) \
|
||||||
END_2(name)
|
END_2(name)
|
||||||
|
|
||||||
|
#if !IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
|
||||||
|
# define ABORT_TRANSACTION \
|
||||||
|
cmpdi 13,0; \
|
||||||
|
beq 1f; \
|
||||||
|
lwz 0,TM_CAPABLE(13); \
|
||||||
|
cmpwi 0,0; \
|
||||||
|
beq 1f; \
|
||||||
|
li 0,_ABORT_SYSCALL; \
|
||||||
|
tabort. 0; \
|
||||||
|
.align 4; \
|
||||||
|
1:
|
||||||
|
#else
|
||||||
|
# define ABORT_TRANSACTION
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DO_CALL(syscall) \
|
#define DO_CALL(syscall) \
|
||||||
|
ABORT_TRANSACTION \
|
||||||
li 0,syscall; \
|
li 0,syscall; \
|
||||||
sc
|
sc
|
||||||
|
|
||||||
|
@ -21,6 +21,10 @@
|
|||||||
*/
|
*/
|
||||||
#define _SYSDEPS_SYSDEP_H 1
|
#define _SYSDEPS_SYSDEP_H 1
|
||||||
#include <bits/hwcap.h>
|
#include <bits/hwcap.h>
|
||||||
|
#ifdef ENABLE_LOCK_ELISION
|
||||||
|
#include <tls.h>
|
||||||
|
#include <htm.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PPC_FEATURE_970 (PPC_FEATURE_POWER4 + PPC_FEATURE_HAS_ALTIVEC)
|
#define PPC_FEATURE_970 (PPC_FEATURE_POWER4 + PPC_FEATURE_HAS_ALTIVEC)
|
||||||
|
|
||||||
@ -164,4 +168,22 @@
|
|||||||
#define ALIGNARG(log2) log2
|
#define ALIGNARG(log2) log2
|
||||||
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
|
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Linux kernel powerpc documentation [1] states issuing a syscall inside a
|
||||||
|
transaction is not recommended and may lead to undefined behavior. It
|
||||||
|
also states syscalls do not abort transactions. To avoid such traps,
|
||||||
|
we abort transaction just before syscalls.
|
||||||
|
|
||||||
|
[1] Documentation/powerpc/transactional_memory.txt [Syscalls] */
|
||||||
|
#if !IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
|
||||||
|
# define ABORT_TRANSACTION \
|
||||||
|
({ \
|
||||||
|
if (THREAD_GET_TM_CAPABLE ()) \
|
||||||
|
__builtin_tabort (_ABORT_SYSCALL); \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
# define ABORT_TRANSACTION
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __ASSEMBLER__ */
|
#endif /* __ASSEMBLER__ */
|
||||||
|
@ -194,6 +194,7 @@
|
|||||||
register long int r11 __asm__ ("r11"); \
|
register long int r11 __asm__ ("r11"); \
|
||||||
register long int r12 __asm__ ("r12"); \
|
register long int r12 __asm__ ("r12"); \
|
||||||
LOADARGS_##nr(name, args); \
|
LOADARGS_##nr(name, args); \
|
||||||
|
ABORT_TRANSACTION; \
|
||||||
__asm__ __volatile__ \
|
__asm__ __volatile__ \
|
||||||
("sc \n\t" \
|
("sc \n\t" \
|
||||||
"mfcr %0" \
|
"mfcr %0" \
|
||||||
|
@ -201,6 +201,7 @@
|
|||||||
register long int r7 __asm__ ("r7"); \
|
register long int r7 __asm__ ("r7"); \
|
||||||
register long int r8 __asm__ ("r8"); \
|
register long int r8 __asm__ ("r8"); \
|
||||||
LOADARGS_##nr (name, ##args); \
|
LOADARGS_##nr (name, ##args); \
|
||||||
|
ABORT_TRANSACTION; \
|
||||||
__asm__ __volatile__ \
|
__asm__ __volatile__ \
|
||||||
("sc\n\t" \
|
("sc\n\t" \
|
||||||
"mfcr %0\n\t" \
|
"mfcr %0\n\t" \
|
||||||
|
Loading…
Reference in New Issue
Block a user