summaryrefslogtreecommitdiff
path: root/libpthread/nptl/sysdeps/nios2
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2016-05-28 18:12:58 +0200
committerWaldemar Brodkorb <wbx@uclibc-ng.org>2016-11-04 00:03:07 +0100
commitb8fcdddcbb192fc367ff04bbd753b9deb69b09f3 (patch)
tree8febdb9d4e3d090e9273c29df9ff06116196c8e4 /libpthread/nptl/sysdeps/nios2
parent191739597c6d380692885cfdd8dd8aa4f31f029d (diff)
nios2: sync support with glibc
Only static linking is supported for now. More debugging and analyzing for ld.so, TLS and NPTL is required. But at least you can bootup a static root fileystem in Qemu.
Diffstat (limited to 'libpthread/nptl/sysdeps/nios2')
-rw-r--r--libpthread/nptl/sysdeps/nios2/Makefile.arch4
-rw-r--r--libpthread/nptl/sysdeps/nios2/dl-tls.h48
-rw-r--r--libpthread/nptl/sysdeps/nios2/libc-tls.c32
-rw-r--r--libpthread/nptl/sysdeps/nios2/pthread_spin_lock.c66
-rw-r--r--libpthread/nptl/sysdeps/nios2/pthread_spin_trylock.c27
-rw-r--r--libpthread/nptl/sysdeps/nios2/pthreaddef.h36
-rw-r--r--libpthread/nptl/sysdeps/nios2/tcb-offsets.sym14
-rw-r--r--libpthread/nptl/sysdeps/nios2/tls.h178
8 files changed, 405 insertions, 0 deletions
diff --git a/libpthread/nptl/sysdeps/nios2/Makefile.arch b/libpthread/nptl/sysdeps/nios2/Makefile.arch
new file mode 100644
index 000000000..fbb560b28
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nios2/Makefile.arch
@@ -0,0 +1,4 @@
+# Makefile for uClibc NPTL
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+libc_arch_a_CSRC = libc-tls.c
diff --git a/libpthread/nptl/sysdeps/nios2/dl-tls.h b/libpthread/nptl/sysdeps/nios2/dl-tls.h
new file mode 100644
index 000000000..cd794610b
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nios2/dl-tls.h
@@ -0,0 +1,48 @@
+/* Thread-local storage handling in the ELF dynamic linker. Nios II version.
+ Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+
+/* Type used for the representation of TLS information in the GOT. */
+typedef struct
+{
+ unsigned long int ti_module;
+ unsigned long int ti_offset;
+} tls_index;
+
+/* The thread pointer points 0x7000 past the first static TLS block. */
+#define TLS_TP_OFFSET 0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+ TLS block. */
+#define TLS_DTV_OFFSET 0x8000
+
+/* Compute the value for a GOTTPREL reloc. */
+#define TLS_TPREL_VALUE(sym_map, sym) \
+ ((sym_map)->l_tls_offset + (sym)->st_value - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc. */
+#define TLS_DTPREL_VALUE(sym) \
+ ((sym)->st_value - TLS_DTV_OFFSET)
+
+extern void *__tls_get_addr (tls_index *ti);
+
+# define GET_ADDR_OFFSET (ti->ti_offset + TLS_DTV_OFFSET)
+# define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET)
+
+/* Value used for dtv entries for which the allocation is delayed. */
+#define TLS_DTV_UNALLOCATED ((void *) -1l)
diff --git a/libpthread/nptl/sysdeps/nios2/libc-tls.c b/libpthread/nptl/sysdeps/nios2/libc-tls.c
new file mode 100644
index 000000000..d677979ed
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nios2/libc-tls.c
@@ -0,0 +1,32 @@
+/* Thread-local storage handling in the ELF dynamic linker. Nios II version.
+ Copyright (C) 2005-2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdeps/generic/libc-tls.c>
+#include <dl-tls.h>
+
+/* On Nios II, linker optimizations are not required, so __tls_get_addr
+ can be called even in statically linked binaries. In this case module
+ must be always 1 and PT_TLS segment exist in the binary, otherwise it
+ would not link. */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+ dtv_t *dtv = THREAD_DTV ();
+ return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET;
+}
diff --git a/libpthread/nptl/sysdeps/nios2/pthread_spin_lock.c b/libpthread/nptl/sysdeps/nios2/pthread_spin_lock.c
new file mode 100644
index 000000000..77f5f502e
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nios2/pthread_spin_lock.c
@@ -0,0 +1,66 @@
+/* pthread_spin_lock -- lock a spin lock. Generic version.
+ Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <atomic.h>
+#include "pthreadP.h"
+
+/* A machine-specific version can define SPIN_LOCK_READS_BETWEEN_CMPXCHG
+ to the number of plain reads that it's optimal to spin on between uses
+ of atomic_compare_and_exchange_val_acq. If spinning forever is optimal
+ then use -1. If no plain reads here would ever be optimal, use 0. */
+#define SPIN_LOCK_READS_BETWEEN_CMPXCHG 1000
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+ /* atomic_exchange usually takes less instructions than
+ atomic_compare_and_exchange. On the other hand,
+ atomic_compare_and_exchange potentially generates less bus traffic
+ when the lock is locked.
+ We assume that the first try mostly will be successful, and we use
+ atomic_exchange. For the subsequent tries we use
+ atomic_compare_and_exchange. */
+ if (atomic_exchange_acq (lock, 1) == 0)
+ return 0;
+
+ do
+ {
+ /* The lock is contended and we need to wait. Going straight back
+ to cmpxchg is not a good idea on many targets as that will force
+ expensive memory synchronizations among processors and penalize other
+ running threads.
+ On the other hand, we do want to update memory state on the local core
+ once in a while to avoid spinning indefinitely until some event that
+ will happen to update local memory as a side-effect. */
+ if (SPIN_LOCK_READS_BETWEEN_CMPXCHG >= 0)
+ {
+ int wait = SPIN_LOCK_READS_BETWEEN_CMPXCHG;
+
+ while (*lock != 0 && wait > 0)
+ --wait;
+ }
+ else
+ {
+ while (*lock != 0)
+ ;
+ }
+ }
+ while (atomic_compare_and_exchange_val_acq (lock, 1, 0) != 0);
+
+ return 0;
+}
diff --git a/libpthread/nptl/sysdeps/nios2/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/nios2/pthread_spin_trylock.c
new file mode 100644
index 000000000..4e1a96c03
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nios2/pthread_spin_trylock.c
@@ -0,0 +1,27 @@
+/* pthread_spin_trylock -- trylock a spin lock. Generic version.
+ Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+ return atomic_exchange_acq (lock, 1) ? EBUSY : 0;
+}
diff --git a/libpthread/nptl/sysdeps/nios2/pthreaddef.h b/libpthread/nptl/sysdeps/nios2/pthreaddef.h
new file mode 100644
index 000000000..4268252dd
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nios2/pthreaddef.h
@@ -0,0 +1,36 @@
+/* pthread machine parameter definitions, Nios II version.
+ Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Default stack size. */
+#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning. */
+#define STACK_ALIGN 4
+
+/* Minimal stack size after allocating thread descriptor and guard size. */
+#define MINIMAL_REST_STACK 2048
+
+/* Alignment requirement for TCB. */
+#define TCB_ALIGNMENT 4
+
+/* Location of current stack frame. */
+#define CURRENT_STACK_FRAME __builtin_frame_address (0)
+
+/* XXX Until we have a better place keep the definitions here. */
+#define __exit_thread_inline(val) \
+ INLINE_SYSCALL (exit, 1, (val))
diff --git a/libpthread/nptl/sysdeps/nios2/tcb-offsets.sym b/libpthread/nptl/sysdeps/nios2/tcb-offsets.sym
new file mode 100644
index 000000000..d9ae95258
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nios2/tcb-offsets.sym
@@ -0,0 +1,14 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+# undef __thread_self
+# define __thread_self ((void *) 0)
+# define thread_offsetof(mem) ((ptrdiff_t) THREAD_SELF + offsetof (struct pthread, mem))
+
+MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads)
+PID_OFFSET thread_offsetof (pid)
+TID_OFFSET thread_offsetof (tid)
+POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
diff --git a/libpthread/nptl/sysdeps/nios2/tls.h b/libpthread/nptl/sysdeps/nios2/tls.h
new file mode 100644
index 000000000..9785670b8
--- /dev/null
+++ b/libpthread/nptl/sysdeps/nios2/tls.h
@@ -0,0 +1,178 @@
+/* Definition for thread-local data handling. NPTL/Nios II version.
+ Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv. */
+typedef union dtv
+{
+ size_t counter;
+ struct
+ {
+ void *val;
+ bool is_static;
+ } pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+/* We require TLS support in the tools. */
+#define HAVE_TLS_SUPPORT 1
+#define HAVE_TLS_MODEL_ATTRIBUTE 1
+#define HAVE___THREAD 1
+
+/* Signal that TLS support is available. */
+#define USE_TLS 1
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information. */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks. */
+# define TLS_DTV_AT_TP 1
+
+/* Get the thread descriptor definition. */
+# include <../../descr.h>
+
+typedef struct
+{
+ dtv_t *dtv;
+ uintptr_t pointer_guard;
+ unsigned spare[6];
+} tcbhead_t;
+
+register struct pthread *__thread_self __asm__("r23");
+
+#define READ_THREAD_POINTER() ((void *) __thread_self)
+
+/* This is the size of the initial TCB. Because our TCB is before the thread
+ pointer, we don't need this. */
+# define TLS_INIT_TCB_SIZE 0
+
+/* Alignment requirements for the initial TCB. */
+# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread)
+
+/* This is the size of the TCB. Because our TCB is before the thread
+ pointer, we don't need this. */
+# define TLS_TCB_SIZE 0
+
+/* Alignment requirements for the TCB. */
+# define TLS_TCB_ALIGN __alignof__ (struct pthread)
+
+/* This is the size we need before TCB - actually, it includes the TCB. */
+# define TLS_PRE_TCB_SIZE \
+ (sizeof (struct pthread) \
+ + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* The thread pointer (in hardware register r23) points to the end of
+ the TCB + 0x7000, as for PowerPC and MIPS. */
+# define TLS_TCB_OFFSET 0x7000
+
+/* Install the dtv pointer. The pointer passed is to the element with
+ index -1 which contain the length. */
+# define INSTALL_DTV(tcbp, dtvp) \
+ (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1)
+
+/* Install new dtv for current thread. */
+# define INSTALL_NEW_DTV(dtv) \
+ (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor. */
+# define GET_DTV(tcbp) \
+ (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer. */
+# define TLS_INIT_TP(tcbp, secondcall) \
+ (__thread_self = (struct pthread *) ((char *) tcbp + TLS_TCB_OFFSET), NULL)
+
+/* Value passed to 'clone' for initialization of the thread register. */
+# define TLS_DEFINE_INIT_TP(tp, pd) \
+ void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE
+
+/* Return the address of the dtv for the current thread. */
+# define THREAD_DTV() \
+ (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread. */
+# define THREAD_SELF \
+ ((struct pthread *) (READ_THREAD_POINTER () \
+ - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF. */
+# define DB_THREAD_SELF \
+ REGISTER (32, 32, 23 * 4, -TLS_PRE_TCB_SIZE - TLS_TCB_OFFSET)
+
+/* Access to data in the thread descriptor is easy. */
+# define THREAD_GETMEM(descr, member) \
+ descr->member
+# define THREAD_GETMEM_NC(descr, member, idx) \
+ descr->member[idx]
+# define THREAD_SETMEM(descr, member, value) \
+ descr->member = (value)
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+ descr->member[idx] = (value)
+
+# define THREAD_GET_POINTER_GUARD() \
+ (((tcbhead_t *) (READ_THREAD_POINTER () \
+ - TLS_TCB_OFFSET))[-1].pointer_guard)
+# define THREAD_SET_POINTER_GUARD(value) \
+ (THREAD_GET_POINTER_GUARD () = (value))
+# define THREAD_COPY_POINTER_GUARD(descr) \
+ (((tcbhead_t *) ((void *) (descr) \
+ + TLS_PRE_TCB_SIZE))[-1].pointer_guard \
+ = THREAD_GET_POINTER_GUARD())
+
+/* l_tls_offset == 0 is perfectly valid on Nios II, so we have to use some
+ different value to mean unset l_tls_offset. */
+# define NO_TLS_OFFSET -1
+
+/* Get and set the global scope generation counter in struct pthread. */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED 1
+#define THREAD_GSCOPE_FLAG_WAIT 2
+#define THREAD_GSCOPE_RESET_FLAG() \
+ do \
+ { int __res \
+ = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \
+ THREAD_GSCOPE_FLAG_UNUSED); \
+ if (__res == THREAD_GSCOPE_FLAG_WAIT) \
+ lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+ } \
+ while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+ do \
+ { \
+ THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \
+ atomic_write_barrier (); \
+ } \
+ while (0)
+#define THREAD_GSCOPE_WAIT() \
+ GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */