summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@uclibc-ng.org>2016-10-31 18:05:44 +0100
committerWaldemar Brodkorb <wbx@uclibc-ng.org>2016-11-03 20:37:48 +0100
commit191739597c6d380692885cfdd8dd8aa4f31f029d (patch)
treeb3f05ce72f7a87433905698dd58371048c904812
parent7825930078208462655e107677656c45014e91b4 (diff)
microblaze: add NPTL/TLS support from GNU libc
Not perfect, but a starting point. Some tests of the test suite are failing.
-rw-r--r--extra/Configs/Config.in1
-rw-r--r--include/elf.h55
-rw-r--r--ldso/ldso/microblaze/dl-debug.h8
-rw-r--r--ldso/ldso/microblaze/dl-startup.h3
-rw-r--r--ldso/ldso/microblaze/dl-sysdep.h28
-rw-r--r--ldso/ldso/microblaze/elfinterp.c22
-rw-r--r--libc/sysdeps/linux/microblaze/Makefile.arch2
-rw-r--r--libc/sysdeps/linux/microblaze/__syscall_error.c18
-rw-r--r--libc/sysdeps/linux/microblaze/bits/uClibc_arch_features.h3
-rw-r--r--libc/sysdeps/linux/microblaze/clone.S17
-rw-r--r--libc/sysdeps/linux/microblaze/jmpbuf-offsets.h6
-rw-r--r--libc/sysdeps/linux/microblaze/jmpbuf-unwind.h25
-rw-r--r--libc/sysdeps/linux/microblaze/sysdep.h83
-rw-r--r--libc/sysdeps/linux/microblaze/vfork.S58
-rw-r--r--libpthread/nptl/sysdeps/microblaze/Makefile.arch4
-rw-r--r--libpthread/nptl/sysdeps/microblaze/dl-tls.h26
-rw-r--r--libpthread/nptl/sysdeps/microblaze/libc-tls.c36
-rw-r--r--libpthread/nptl/sysdeps/microblaze/pthread_spin_lock.c62
-rw-r--r--libpthread/nptl/sysdeps/microblaze/pthread_spin_trylock.c27
-rw-r--r--libpthread/nptl/sysdeps/microblaze/pthreaddef.h40
-rw-r--r--libpthread/nptl/sysdeps/microblaze/tcb-offsets.sym11
-rw-r--r--libpthread/nptl/sysdeps/microblaze/tls.h159
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/Makefile13
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/Makefile.arch8
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/bits/pthreadtypes.h181
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/bits/semaphore.h32
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/clone.S4
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/createthread.c22
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/fork.c29
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/lowlevellock.h278
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/pthread_once.c89
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/sysdep-cancel.h139
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/vfork.S5
33 files changed, 1394 insertions, 100 deletions
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index b25946461..cb2d4d1a2 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -521,7 +521,6 @@ config UCLIBC_HAS_THREADS_NATIVE
!TARGET_hppa && \
!TARGET_ia64 && \
!TARGET_m68k && \
- !TARGET_microblaze && \
!TARGET_nds32 && \
!TARGET_nios2 && \
!TARGET_or1k && \
diff --git a/include/elf.h b/include/elf.h
index 17a6143b5..cca3d3832 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -3234,30 +3234,37 @@ typedef Elf32_Addr Elf32_Conflict;
#define DT_C6000_NUM 4
-/* microblaze specific relocs */
-#define R_MICROBLAZE_NONE 0
-#define R_MICROBLAZE_32 1
-#define R_MICROBLAZE_32_PCREL 2
-#define R_MICROBLAZE_64_PCREL 3
-#define R_MICROBLAZE_32_PCREL_LO 4
-#define R_MICROBLAZE_64 5
-#define R_MICROBLAZE_32_LO 6
-#define R_MICROBLAZE_SRO32 7
-#define R_MICROBLAZE_SRW32 8
-#define R_MICROBLAZE_64_NONE 9
-#define R_MICROBLAZE_32_SYM_OP_SYM 10
-#define R_MICROBLAZE_GNU_VTINHERIT 11
-#define R_MICROBLAZE_GNU_VTENTRY 12
-#define R_MICROBLAZE_GOTPC_64 13 /* PC-relative GOT offset */
-#define R_MICROBLAZE_GOT_64 14 /* GOT entry offset */
-#define R_MICROBLAZE_PLT_64 15 /* PLT offset (PC-relative */
-#define R_MICROBLAZE_REL 16 /* adjust by program base */
-#define R_MICROBLAZE_JUMP_SLOT 17 /* create PLT entry */
-#define R_MICROBLAZE_GLOB_DAT 18 /* create GOT entry */
-#define R_MICROBLAZE_GOTOFF_64 19 /* offset relative to GOT */
-#define R_MICROBLAZE_GOTOFF_32 20 /* offset relative to GOT */
-#define R_MICROBLAZE_COPY 21 /* runtime copy */
-#define R_MICROBLAZE_NUM 22
+/* MicroBlaze relocations */
+#define R_MICROBLAZE_NONE 0 /* No reloc. */
+#define R_MICROBLAZE_32 1 /* Direct 32 bit. */
+#define R_MICROBLAZE_32_PCREL 2 /* PC relative 32 bit. */
+#define R_MICROBLAZE_64_PCREL 3 /* PC relative 64 bit. */
+#define R_MICROBLAZE_32_PCREL_LO 4 /* Low 16 bits of PCREL32. */
+#define R_MICROBLAZE_64 5 /* Direct 64 bit. */
+#define R_MICROBLAZE_32_LO 6 /* Low 16 bit. */
+#define R_MICROBLAZE_SRO32 7 /* Read-only small data area. */
+#define R_MICROBLAZE_SRW32 8 /* Read-write small data area. */
+#define R_MICROBLAZE_64_NONE 9 /* No reloc. */
+#define R_MICROBLAZE_32_SYM_OP_SYM 10 /* Symbol Op Symbol relocation. */
+#define R_MICROBLAZE_GNU_VTINHERIT 11 /* GNU C++ vtable hierarchy. */
+#define R_MICROBLAZE_GNU_VTENTRY 12 /* GNU C++ vtable member usage. */
+#define R_MICROBLAZE_GOTPC_64 13 /* PC-relative GOT offset. */
+#define R_MICROBLAZE_GOT_64 14 /* GOT entry offset. */
+#define R_MICROBLAZE_PLT_64 15 /* PLT offset (PC-relative). */
+#define R_MICROBLAZE_REL 16 /* Adjust by program base. */
+#define R_MICROBLAZE_JUMP_SLOT 17 /* Create PLT entry. */
+#define R_MICROBLAZE_GLOB_DAT 18 /* Create GOT entry. */
+#define R_MICROBLAZE_GOTOFF_64 19 /* 64 bit offset to GOT. */
+#define R_MICROBLAZE_GOTOFF_32 20 /* 32 bit offset to GOT. */
+#define R_MICROBLAZE_COPY 21 /* Runtime copy. */
+#define R_MICROBLAZE_TLS 22 /* TLS Reloc. */
+#define R_MICROBLAZE_TLSGD 23 /* TLS General Dynamic. */
+#define R_MICROBLAZE_TLSLD 24 /* TLS Local Dynamic. */
+#define R_MICROBLAZE_TLSDTPMOD32 25 /* TLS Module ID. */
+#define R_MICROBLAZE_TLSDTPREL32 26 /* TLS Offset Within TLS Block. */
+#define R_MICROBLAZE_TLSDTPREL64 27 /* TLS Offset Within TLS Block. */
+#define R_MICROBLAZE_TLSGOTTPREL32 28 /* TLS Offset From Thread Pointer. */
+#define R_MICROBLAZE_TLSTPREL32 29 /* TLS Offset From Thread Pointer. */
/* Meta relocations */
#define R_METAG_HIADDR16 0
diff --git a/ldso/ldso/microblaze/dl-debug.h b/ldso/ldso/microblaze/dl-debug.h
index 6fd7bd59f..30b27bb2a 100644
--- a/ldso/ldso/microblaze/dl-debug.h
+++ b/ldso/ldso/microblaze/dl-debug.h
@@ -51,4 +51,12 @@ static const char * const _dl_reltypes_tab[] =
"R_MICROBLAZE_GOTOFF_64",
"R_MICROBLAZE_GOTOFF_32",
"R_MICROBLAZE_COPY",
+ "R_MICROBLAZE_TLS",
+ "R_MICROBLAZE_TLSGD",
+ "R_MICROBLAZE_TLSLD",
+ "R_MICROBLAZE_TLSDTPMOD32",
+ "R_MICROBLAZE_TLSDTPREL32",
+ "R_MICROBLAZE_TLSDTPREL64",
+ "R_MICROBLAZE_TLSGOTTPREL32",
+ "R_MICROBLAZE_TLSTPREL32",
};
diff --git a/ldso/ldso/microblaze/dl-startup.h b/ldso/ldso/microblaze/dl-startup.h
index ba15a87c3..720c53aab 100644
--- a/ldso/ldso/microblaze/dl-startup.h
+++ b/ldso/ldso/microblaze/dl-startup.h
@@ -78,9 +78,6 @@ _dl_start_user:\n\
*/
#define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*) ARGS)+1)
-/* The ld.so library requires relocations */
-#define ARCH_NEEDS_BOOTSTRAP_RELOCS
-
static __always_inline
void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr,
unsigned long symbol_addr, unsigned long load_addr, attribute_unused Elf32_Sym *symtab)
diff --git a/ldso/ldso/microblaze/dl-sysdep.h b/ldso/ldso/microblaze/dl-sysdep.h
index b293d27cc..43200271e 100644
--- a/ldso/ldso/microblaze/dl-sysdep.h
+++ b/ldso/ldso/microblaze/dl-sysdep.h
@@ -1,5 +1,3 @@
-/* elf reloc code for the microblaze platform, based on glibc 2.3.6, dl-machine.h */
-
/*
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -15,37 +13,41 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-/* Use reloca */
#define ELF_USES_RELOCA
#include <elf.h>
-
/* Initialise the GOT */
-#define INIT_GOT(GOT_BASE,MODULE) \
-do { \
- GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \
- GOT_BASE[1] = (unsigned long) MODULE; \
+#define INIT_GOT(GOT_BASE,MODULE) \
+do { \
+ GOT_BASE[1] = (unsigned long) MODULE; \
+ GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \
} while(0)
/* Here we define the magic numbers that this dynamic loader should accept */
-
#define MAGIC1 EM_MICROBLAZE
#undef MAGIC2
/* Used for error messages */
#define ELF_TARGET "microblaze"
+/* Need bootstrap relocations */
+#define ARCH_NEEDS_BOOTSTRAP_RELOCS
+
struct elf_resolve;
unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
#define elf_machine_type_class(type) \
- (((type) == R_MICROBLAZE_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT \
+ (((type) == R_MICROBLAZE_JUMP_SLOT || \
+ (type) == R_MICROBLAZE_TLSDTPREL32 || \
+ (type) == R_MICROBLAZE_TLSDTPMOD32 || \
+ (type) == R_MICROBLAZE_TLSTPREL32) \
+ * ELF_RTYPE_CLASS_PLT \
| ((type) == R_MICROBLAZE_COPY) * ELF_RTYPE_CLASS_COPY)
/* Return the link-time address of _DYNAMIC. Conveniently, this is the
first element of the GOT. This must be inlined in a function which
uses global data. */
-static inline Elf32_Addr
+static __always_inline Elf32_Addr __attribute__ ((unused))
elf_machine_dynamic (void)
{
Elf32_Addr got_entry_0;
@@ -56,7 +58,6 @@ elf_machine_dynamic (void)
return got_entry_0;
}
-
/* Return the run-time load address of the shared object. */
static inline Elf32_Addr
elf_machine_load_address (void)
@@ -64,6 +65,7 @@ elf_machine_load_address (void)
/* Compute the difference between the runtime address of _DYNAMIC as seen
by a GOTOFF reference, and the link-time address found in the special
unrelocated first GOT entry. */
+
Elf32_Addr dyn;
__asm__ __volatile__ (
"addik %0,r20,_DYNAMIC@GOTOFF"
@@ -72,8 +74,6 @@ elf_machine_load_address (void)
return dyn - elf_machine_dynamic ();
}
-
-
static __always_inline void
elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
Elf32_Word relative_count)
diff --git a/ldso/ldso/microblaze/elfinterp.c b/ldso/ldso/microblaze/elfinterp.c
index 1f6aeffb7..33aef2f3e 100644
--- a/ldso/ldso/microblaze/elfinterp.c
+++ b/ldso/ldso/microblaze/elfinterp.c
@@ -214,16 +214,13 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
case R_MICROBLAZE_NONE:
case R_MICROBLAZE_64_NONE:
break;
-
case R_MICROBLAZE_64:
*reloc_addr = symbol_addr + rpnt->r_addend;
break;
-
case R_MICROBLAZE_32:
case R_MICROBLAZE_32_LO:
*reloc_addr = symbol_addr + rpnt->r_addend;
break;
-
case R_MICROBLAZE_32_PCREL:
case R_MICROBLAZE_32_PCREL_LO:
case R_MICROBLAZE_64_PCREL:
@@ -231,16 +228,25 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
case R_MICROBLAZE_SRW32:
*reloc_addr = symbol_addr + rpnt->r_addend;
break;
-
case R_MICROBLAZE_GLOB_DAT:
case R_MICROBLAZE_JUMP_SLOT:
*reloc_addr = symbol_addr + rpnt->r_addend;
break;
-/* Handled by elf_machine_relative */
case R_MICROBLAZE_REL:
*reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
break;
-
+#if defined USE_TLS && USE_TLS
+ case R_MICROBLAZE_TLSDTPMOD32:
+ *reloc_addr = tls_tpnt->l_tls_modid;
+ break;
+ case R_MICROBLAZE_TLSDTPREL32:
+ *reloc_addr = symbol_addr;
+ break;
+ case R_MICROBLAZE_TLSTPREL32:
+ CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
+ *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend;
+ break;
+#endif
case R_MICROBLAZE_COPY:
if (symbol_addr) {
#if defined (__SUPPORT_LD_DEBUG__)
@@ -250,7 +256,6 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
symname, sym_ref.sym->st_size,
symbol_addr, reloc_addr);
#endif
-
_dl_memcpy((char *)reloc_addr,
(char *)symbol_addr,
sym_ref.sym->st_size);
@@ -260,7 +265,6 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
_dl_dprintf(_dl_debug_file, "no symbol_addr to copy !?\n");
#endif
break;
-
default:
return -1; /* Calls _dl_exit(1). */
}
@@ -279,14 +283,12 @@ _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
{
int reloc_type;
- int symtab_index;
ElfW(Addr) *reloc_addr;
#if defined (__SUPPORT_LD_DEBUG__)
ElfW(Addr) old_val;
#endif
(void)scope;
- symtab_index = ELF_R_SYM(rpnt->r_info);
(void)strtab;
reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + rpnt->r_offset);
diff --git a/libc/sysdeps/linux/microblaze/Makefile.arch b/libc/sysdeps/linux/microblaze/Makefile.arch
index e23515ed0..b89f7f945 100644
--- a/libc/sysdeps/linux/microblaze/Makefile.arch
+++ b/libc/sysdeps/linux/microblaze/Makefile.arch
@@ -5,5 +5,5 @@
#
# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
-CSRC-y :=
+CSRC-y := __syscall_error.c
SSRC-y := setjmp.S __longjmp.S vfork.S clone.S
diff --git a/libc/sysdeps/linux/microblaze/__syscall_error.c b/libc/sysdeps/linux/microblaze/__syscall_error.c
new file mode 100644
index 000000000..2b642e816
--- /dev/null
+++ b/libc/sysdeps/linux/microblaze/__syscall_error.c
@@ -0,0 +1,18 @@
+/* Wrapper for setting errno.
+ *
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <errno.h>
+#include <features.h>
+
+/* This routine is jumped to by all the syscall handlers, to stash
+ * an error number into errno. */
+int __syscall_error(int err_no) attribute_hidden;
+int __syscall_error(int err_no)
+{
+ __set_errno(-err_no);
+ return -1;
+}
diff --git a/libc/sysdeps/linux/microblaze/bits/uClibc_arch_features.h b/libc/sysdeps/linux/microblaze/bits/uClibc_arch_features.h
index ea767abbf..321d699b0 100644
--- a/libc/sysdeps/linux/microblaze/bits/uClibc_arch_features.h
+++ b/libc/sysdeps/linux/microblaze/bits/uClibc_arch_features.h
@@ -6,8 +6,7 @@
#define _BITS_UCLIBC_ARCH_FEATURES_H
/* instruction used when calling abort() to kill yourself */
-/*#define __UCLIBC_ABORT_INSTRUCTION__ "asm instruction"*/
-#undef __UCLIBC_ABORT_INSTRUCTION__
+#define __UCLIBC_ABORT_INSTRUCTION__ "brki r0, -1"
/* can your target use syscall6() for mmap ? */
#define __UCLIBC_MMAP_HAS_6_ARGS__
diff --git a/libc/sysdeps/linux/microblaze/clone.S b/libc/sysdeps/linux/microblaze/clone.S
index 46d4fe6b4..69c20453f 100644
--- a/libc/sysdeps/linux/microblaze/clone.S
+++ b/libc/sysdeps/linux/microblaze/clone.S
@@ -23,6 +23,10 @@
#define _ERRNO_H 1
#include <bits/errno.h>
+#if defined __UCLIBC_HAS_THREADS__ && !defined __UCLIBC_HAS_LINUXTHREADS__
+#include <sysdep-cancel.h>
+#endif
+
/* int clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg,
pid_t *ptid, struct user_desc *tls, pid_t *ctid);
@@ -39,8 +43,8 @@
.text
ENTRY (__clone)
addik r3,r0,-EINVAL
- beqi r5,1f ; // Invalid func
- beqi r6,1f ; // Invalid stack
+ beqi r5,SYSCALL_ERROR_LABEL ; // Invalid func
+ beqi r6,SYSCALL_ERROR_LABEL ; // Invalid stack
addik r6,r6,-8
swi r5,r6,0 ; // Push fn onto child's stack
swi r8,r6,4 ; // Push arg for child
@@ -53,7 +57,7 @@ ENTRY (__clone)
addk r0,r0,r0
addik r4,r0,-4095
cmpu r4,r4,r3
- bgei r4,1f
+ bgei r4,SYSCALL_ERROR_LABEL
beqi r3,L(thread_start)
rtsd r15,8
nop
@@ -67,12 +71,7 @@ L(thread_start):
addik r12,r0,SYS_ify(exit)
brki r14,8
nop
-
-1: rsubk r3,r3,r0
- rtsd r15,8
- addik r3,r0,-1 /* delay slot. */
-
-END(__clone)
+PSEUDO_END(__clone)
libc_hidden_def (__clone)
weak_alias (__clone,clone)
diff --git a/libc/sysdeps/linux/microblaze/jmpbuf-offsets.h b/libc/sysdeps/linux/microblaze/jmpbuf-offsets.h
deleted file mode 100644
index c6cccc739..000000000
--- a/libc/sysdeps/linux/microblaze/jmpbuf-offsets.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
- * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
- *
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
-#define JB_SIZE (4 * 18)
diff --git a/libc/sysdeps/linux/microblaze/jmpbuf-unwind.h b/libc/sysdeps/linux/microblaze/jmpbuf-unwind.h
index 2c1c0793c..155792b37 100644
--- a/libc/sysdeps/linux/microblaze/jmpbuf-unwind.h
+++ b/libc/sysdeps/linux/microblaze/jmpbuf-unwind.h
@@ -10,3 +10,28 @@
containing a local variable at ADDRESS. */
#define _JMPBUF_UNWINDS(jmpbuf, address) \
((void *) (address) < (void *) (jmpbuf)[0].__sp)
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <stdint.h>
+#include <unwind.h>
+
+/* Test if longjmp to JMPBUF would unwind the frame
+ containing a local variable at ADDRESS. */
+#undef _JMPBUF_UNWINDS
+#define _JMPBUF_UNWINDS(jmpbuf, address) \
+ ((void *) (address) < (void *) (jmpbuf)[0].__sp)
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+ _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+static inline uintptr_t __attribute__ ((unused))
+_jmpbuf_sp (__jmp_buf regs)
+{
+ void *sp = (void *) regs[0].__sp;
+ return (uintptr_t) sp;
+}
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+ ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj))
+
+#endif
diff --git a/libc/sysdeps/linux/microblaze/sysdep.h b/libc/sysdeps/linux/microblaze/sysdep.h
index 1f01a2a1d..a463d339e 100644
--- a/libc/sysdeps/linux/microblaze/sysdep.h
+++ b/libc/sysdeps/linux/microblaze/sysdep.h
@@ -1,9 +1,25 @@
+/* Copyright (C) 2000-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 <common/sysdep.h>
#ifdef __ASSEMBLER__
-/* Syntactic details of assembler. */
-
# define ALIGNARG(log2) log2
# define ASM_SIZE_DIRECTIVE(name) .size name,.-name
@@ -22,4 +38,67 @@
# define L(name) $L##name
# endif
+/* We don't want the label for the error handler to be visible in the symbol
+ table when we define it here. */
+# ifdef __PIC__
+# define SYSCALL_ERROR_LABEL 0f
+# else
+# define SYSCALL_ERROR_LABEL __syscall_error
+# endif
+
+# define DO_CALL(syscall_name, args) \
+ addik r12,r0,SYS_ify (syscall_name); \
+ brki r14,8; \
+ addk r0,r0,r0;
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args) \
+ .text; \
+ ENTRY (name) \
+ DO_CALL (syscall_name, args); \
+ addik r12,r0,-4095; \
+ cmpu r12,r12,r3; \
+ bgei r12,SYSCALL_ERROR_LABEL;
+
+# undef PSEUDO_END
+# define PSEUDO_END(name) \
+ SYSCALL_ERROR_HANDLER; \
+ END (name)
+
+#ifdef __PIC__
+# define SYSCALL_ERROR_LABEL_DCL 0
+# if defined _LIBC_REENTRANT
+# define SYSCALL_ERROR_HANDLER \
+SYSCALL_ERROR_LABEL_DCL: \
+ addik r1,r1,-16; \
+ swi r15,r1,0; \
+ swi r20,r1,8; \
+ rsubk r3,r3,r0; \
+ swi r3,r1,12; \
+ mfs r20,rpc; \
+ addik r20,r20,_GLOBAL_OFFSET_TABLE_+8; \
+ brlid r15,__errno_location@PLT; \
+ nop; \
+ lwi r4,r1,12; \
+ swi r4,r3,0; \
+ lwi r20,r1,8; \
+ lwi r15,r1,0; \
+ addik r1,r1,16; \
+ rtsd r15,8; \
+ addik r3,r0,-1;
+# else /* !_LIBC_REENTRANT. */
+# define SYSCALL_ERROR_HANDLER \
+SYSCALL_ERROR_LABEL_DCL: \
+ mfs r12,rpc; \
+ addik r12,r12,_GLOBAL_OFFSET_TABLE_+8; \
+ lwi r12,r12,errno@GOT; \
+ rsubk r3,r3,r0; \
+ swi r3,r12,0; \
+ rtsd r15,8; \
+ addik r3,r0,-1;
+# endif /* _LIBC_REENTRANT. */
+#else
+# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
+#endif /* PIC. */
+
#endif
diff --git a/libc/sysdeps/linux/microblaze/vfork.S b/libc/sysdeps/linux/microblaze/vfork.S
index cadd1167d..11b9e2758 100644
--- a/libc/sysdeps/linux/microblaze/vfork.S
+++ b/libc/sysdeps/linux/microblaze/vfork.S
@@ -1,42 +1,44 @@
-/*
- * libc/sysdeps/linux/microblaze/vfork.S -- `vfork' syscall for linux/microblaze
- *
- * Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au>
- * Copyright (C) 2001 NEC Corporation
- * Copyright (C) 2001 Miles Bader <miles@gnu.org>
- *
- * This file is subject to the terms and conditions of the GNU Lesser
- * General Public License. See the file COPYING.LIB in the main
- * directory of this archive for more details.
- *
- * Written by Miles Bader <miles@gnu.org>
- * Microblaze port by John Williams
- */
-
-#include <sys/syscall.h>
+/* 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 <sysdep.h>
+#define _ERRNO_H 1
+#include <bits/errno.h>
/* Clone the calling process, but without copying the whole address space.
The calling process is suspended until the new process exits or is
replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process. */
- .globl __vfork
- .hidden __vfork
- .align 4
-__vfork:
- addi r12, r0, SYS_vfork
- brki r14, 0x08;
- addi r4, r3, 125 /* minimum err value */
- blti r4, 1f /* is r3 < -125? */
- bri 2f /* normal return */
+ENTRY(__vfork)
+
+ DO_CALL (vfork, 0)
+ addik r12,r0,-4095
+ cmpu r12,r12,r3
+ bgei r12,1f
+ rtsd r15,8
+ nop
1: rsubk r3,r3,r0
rtsd r15,8
addik r3,r0,-1 /* delay slot. */
-2: rtsd r15, 8 /* error return */
- nop
- .size __vfork, .-__vfork
+END(__vfork)
weak_alias(__vfork, vfork)
libc_hidden_def(vfork)
diff --git a/libpthread/nptl/sysdeps/microblaze/Makefile.arch b/libpthread/nptl/sysdeps/microblaze/Makefile.arch
new file mode 100644
index 000000000..b69fb48da
--- /dev/null
+++ b/libpthread/nptl/sysdeps/microblaze/Makefile.arch
@@ -0,0 +1,4 @@
+# Makefile for uClibc NPTL
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+
+libc_arch_a_CSRC = libc-tls.c
diff --git a/libpthread/nptl/sysdeps/microblaze/dl-tls.h b/libpthread/nptl/sysdeps/microblaze/dl-tls.h
new file mode 100644
index 000000000..5613e21e2
--- /dev/null
+++ b/libpthread/nptl/sysdeps/microblaze/dl-tls.h
@@ -0,0 +1,26 @@
+/* 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/>. */
+
+/* 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;
+
+extern void *__tls_get_addr (tls_index *ti);
diff --git a/libpthread/nptl/sysdeps/microblaze/libc-tls.c b/libpthread/nptl/sysdeps/microblaze/libc-tls.c
new file mode 100644
index 000000000..7f440fb06
--- /dev/null
+++ b/libpthread/nptl/sysdeps/microblaze/libc-tls.c
@@ -0,0 +1,36 @@
+/* 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 Microblaze, 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. */
+
+#if defined(USE_TLS) && USE_TLS
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+ dtv_t *dtv = THREAD_DTV ();
+ return (char *) dtv[1].pointer.val + ti->ti_offset;
+}
+
+#endif
diff --git a/libpthread/nptl/sysdeps/microblaze/pthread_spin_lock.c b/libpthread/nptl/sysdeps/microblaze/pthread_spin_lock.c
new file mode 100644
index 000000000..e393a73ac
--- /dev/null
+++ b/libpthread/nptl/sysdeps/microblaze/pthread_spin_lock.c
@@ -0,0 +1,62 @@
+/* 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"
+
+#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/microblaze/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/microblaze/pthread_spin_trylock.c
new file mode 100644
index 000000000..4e1a96c03
--- /dev/null
+++ b/libpthread/nptl/sysdeps/microblaze/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/microblaze/pthreaddef.h b/libpthread/nptl/sysdeps/microblaze/pthreaddef.h
new file mode 100644
index 000000000..47e87dd71
--- /dev/null
+++ b/libpthread/nptl/sysdeps/microblaze/pthreaddef.h
@@ -0,0 +1,40 @@
+/* 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/>. */
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Default stack size. */
+#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning. */
+#define STACK_ALIGN 16
+
+/* Minimal stack size after allocating thread descriptor and guard size. */
+#define MINIMAL_REST_STACK 2048
+
+/* Alignment requirement for TCB. */
+#define TCB_ALIGNMENT 16
+
+/* 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/microblaze/tcb-offsets.sym b/libpthread/nptl/sysdeps/microblaze/tcb-offsets.sym
new file mode 100644
index 000000000..18afbee29
--- /dev/null
+++ b/libpthread/nptl/sysdeps/microblaze/tcb-offsets.sym
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+#define thread_offsetof(mem) (long)(offsetof (struct pthread, mem) - sizeof (struct pthread))
+
+MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads)
+PID_OFFSET thread_offsetof (pid)
+TID_OFFSET thread_offsetof (tid)
diff --git a/libpthread/nptl/sysdeps/microblaze/tls.h b/libpthread/nptl/sysdeps/microblaze/tls.h
new file mode 100644
index 000000000..b5bcde95a
--- /dev/null
+++ b/libpthread/nptl/sysdeps/microblaze/tls.h
@@ -0,0 +1,159 @@
+/* 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/>. */
+
+#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___THREAD 1
+#define HAVE_TLS_MODEL_ATTRIBUTE 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;
+ void *private;
+} tcbhead_t;
+
+#define READ_THREAD_POINTER() \
+ ({ register void *__microblaze_thread_area __asm__ ("r21"); \
+ __microblaze_thread_area; })
+
+/* This is the size of the initial TCB. */
+# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB. */
+# define TLS_INIT_TCB_ALIGN 16
+
+/* This is the size of the TCB. */
+# define TLS_TCB_SIZE sizeof (tcbhead_t)
+
+/* This is the size we need before TCB. */
+# define TLS_PRE_TCB_SIZE sizeof (struct pthread)
+
+/* Alignment requirements for the TCB. */
+# define TLS_TCB_ALIGN 16
+
+/* 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))->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))->dtv)
+
+/* Code to initially initialize the thread pointer.
+ r21 is reserved for thread pointer. */
+# define TLS_INIT_TP(tcbp, secondcall) \
+ ({ __asm__ __volatile__ ("or r21,r0,%0" : : "r" ((void *)tcbp)); NULL; })
+
+# define TLS_DEFINE_INIT_TP(tp, pd) void *tp = (pd) + 1
+
+/* Return the address of the dtv for the current thread. */
+# define THREAD_DTV() \
+ (((tcbhead_t *) READ_THREAD_POINTER())->dtv)
+
+/* Return the thread descriptor for the current thread. */
+# define THREAD_SELF \
+ (((struct pthread *) READ_THREAD_POINTER()) - 1)
+
+/* Magic for libthread_db to know how to do THREAD_SELF. */
+# define DB_THREAD_SELF \
+ CONST_THREAD_AREA (32, sizeof (struct pthread))
+
+/* Read member of the thread descriptor directly. */
+# define THREAD_GETMEM(descr, member) (descr->member)
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant. */
+# define THREAD_GETMEM_NC(descr, member, idx) \
+ (descr->member[idx])
+
+/* Set member of the thread descriptor directly. */
+# define THREAD_SETMEM(descr, member, value) \
+ (descr->member = (value))
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant. */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+ (descr->member[idx] = (value))
+
+/* 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. */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/Makefile
new file mode 100644
index 000000000..729adf6f9
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org>
+#
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../../../../../
+top_builddir=../../../../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/Makefile.arch
new file mode 100644
index 000000000..77707a085
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/Makefile.arch
@@ -0,0 +1,8 @@
+# Makefile for uClibc NPTL
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+
+libpthread_linux_arch_SSRC =
+libpthread_linux_arch_CSRC = pthread_once.c
+
+libc_linux_arch_CSRC = fork.c
+libc_linux_arch_SSRC = clone.S vfork.S
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/bits/pthreadtypes.h
new file mode 100644
index 000000000..9e9e307cf
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/bits/pthreadtypes.h
@@ -0,0 +1,181 @@
+/* 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/>. */
+
+#ifndef _BITS_PTHREADTYPES_H
+# define _BITS_PTHREADTYPES_H 1
+
+# include <endian.h>
+
+# define __SIZEOF_PTHREAD_ATTR_T 36
+# define __SIZEOF_PTHREAD_MUTEX_T 24
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_COND_COMPAT_T 12
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 32
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 20
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+
+/* Thread identifiers. The structure of the attribute type is not
+ exposed on purpose. */
+typedef unsigned long int pthread_t;
+
+union pthread_attr_t
+{
+ char __size[__SIZEOF_PTHREAD_ATTR_T];
+ long int __align;
+};
+
+# ifndef __have_pthread_attr_t
+typedef union pthread_attr_t pthread_attr_t;
+# define __have_pthread_attr_t 1
+# endif
+
+typedef struct __pthread_internal_slist
+{
+ struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+
+/* Data structures for mutex handling. The structure of the attribute
+ type is not exposed on purpose. */
+typedef union
+{
+ struct __pthread_mutex_s
+ {
+ int __lock;
+ unsigned int __count;
+ int __owner;
+ /* KIND must stay at this position in the structure to maintain
+ binary compatibility. */
+ int __kind;
+ unsigned int __nusers;
+ __extension__ union
+ {
+ int __spins;
+ __pthread_slist_t __list;
+ };
+ } __data;
+ char __size[__SIZEOF_PTHREAD_MUTEX_T];
+ long int __align;
+} pthread_mutex_t;
+
+/* Mutex __spins initializer used by PTHREAD_MUTEX_INITIALIZER. */
+#define __PTHREAD_SPINS 0
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+ int __align;
+} pthread_mutexattr_t;
+
+/* Data structure for conditional variable handling. The structure of
+ the attribute type is not exposed on purpose. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __futex;
+ __extension__ unsigned long long int __total_seq;
+ __extension__ unsigned long long int __wakeup_seq;
+ __extension__ unsigned long long int __woken_seq;
+ void *__mutex;
+ unsigned int __nwaiters;
+ unsigned int __broadcast_seq;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_COND_T];
+ __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+ int __align;
+} pthread_condattr_t;
+
+/* Keys for thread-specific data. */
+typedef unsigned int pthread_key_t;
+
+/* Once-only execution. */
+typedef int pthread_once_t;
+
+# if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling. The
+ structure of the attribute type is not exposed on purpose. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __nr_readers;
+ unsigned int __readers_wakeup;
+ unsigned int __writer_wakeup;
+ unsigned int __nr_readers_queued;
+ unsigned int __nr_writers_queued;
+# if __BYTE_ORDER == __BIG_ENDIAN
+ unsigned char __pad1;
+ unsigned char __pad2;
+ unsigned char __shared;
+ /* FLAGS must stay at this position in the structure to maintain
+ binary compatibility. */
+ unsigned char __flags;
+# else
+ /* FLAGS must stay at this position in the structure to maintain
+ binary compatibility. */
+ unsigned char __flags;
+ unsigned char __shared;
+ unsigned char __pad1;
+ unsigned char __pad2;
+# endif
+ int __writer;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+ long int __align;
+} pthread_rwlock_t;
+
+#define __PTHREAD_RWLOCK_ELISION_EXTRA 0
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+ long int __align;
+} pthread_rwlockattr_t;
+# endif
+
+# ifdef __USE_XOPEN2K
+/* POSIX spinlock data type. */
+typedef volatile int pthread_spinlock_t;
+
+/* POSIX barriers data type. The structure of the type is
+ deliberately not exposed. */
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIER_T];
+ long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+ int __align;
+} pthread_barrierattr_t;
+# endif
+
+#endif /* bits/pthreadtypes.h. */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/bits/semaphore.h
new file mode 100644
index 000000000..ea05026a0
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/bits/semaphore.h
@@ -0,0 +1,32 @@
+/* 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/>. */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+#define __SIZEOF_SEM_T 16
+
+/* Value returned if `sem_open' failed. */
+#define SEM_FAILED ((sem_t *) 0)
+
+typedef union
+{
+ char __size[__SIZEOF_SEM_T];
+ long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/clone.S
new file mode 100644
index 000000000..faa78d936
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/clone.S
@@ -0,0 +1,4 @@
+#define RESET_PID
+#include <tls.h>
+#include <tcb-offsets.h>
+#include "../../../../../../../libc/sysdeps/linux/microblaze/clone.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/createthread.c
new file mode 100644
index 000000000..10a9ac39f
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/createthread.c
@@ -0,0 +1,22 @@
+/* Copyright (C) 2005 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/>. */
+
+/* Value passed to 'clone' for initialization of the thread register. */
+#define TLS_VALUE (pd + 1)
+
+/* Get the real implementation. */
+#include <sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/fork.c
new file mode 100644
index 000000000..ba5c700da
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/fork.c
@@ -0,0 +1,29 @@
+/* Copyright (C) 2013 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 <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+
+#define ARCH_FORK() \
+ INLINE_SYSCALL (clone, 5, \
+ CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \
+ NULL, NULL, &THREAD_SELF->tid)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/lowlevellock.h
new file mode 100644
index 000000000..e8dce9ddb
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/lowlevellock.h
@@ -0,0 +1,278 @@
+/* Copyright (C) 2005, 2006, 2007, 2008, 2009 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; see the file COPYING.LIB. If
+ not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H 1
+
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+#define FUTEX_REQUEUE 3
+#define FUTEX_CMP_REQUEUE 4
+#define FUTEX_WAKE_OP 5
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1)
+#define FUTEX_LOCK_PI 6
+#define FUTEX_UNLOCK_PI 7
+#define FUTEX_TRYLOCK_PI 8
+#define FUTEX_WAIT_BITSET 9
+#define FUTEX_WAKE_BITSET 10
+#define FUTEX_PRIVATE_FLAG 128
+#define FUTEX_CLOCK_REALTIME 256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+/* Values for 'private' parameter of locking macros. Yes, the
+ definition seems to be backwards. But it is not. The bit will be
+ reversed before passing to the system call. */
+#define LLL_PRIVATE 0
+#define LLL_SHARED FUTEX_PRIVATE_FLAG
+
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private. */
+# ifdef __ASSUME_PRIVATE_FUTEX
+# define __lll_private_flag(fl, private) \
+ ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+# define __lll_private_flag(fl, private) \
+ ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+# define __lll_private_flag(fl, private) \
+ (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+# define __lll_private_flag(fl, private) \
+ (__builtin_constant_p (private) \
+ ? ((private) == 0 \
+ ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \
+ : (fl)) \
+ : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG) \
+ & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
+# endif
+#endif
+
+
+#define lll_futex_wait(futexp, val, private) \
+ lll_futex_timed_wait(futexp, val, NULL, private)
+
+#define lll_futex_timed_wait(futexp, val, timespec, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __sysret; \
+ __sysret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
+ __lll_private_flag (FUTEX_WAIT, private), \
+ (val), (timespec)); \
+ __sysret; \
+ })
+
+#define lll_futex_wake(futexp, nr, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __sysret; \
+ __sysret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
+ __lll_private_flag (FUTEX_WAKE, private), \
+ (nr), 0); \
+ __sysret; \
+ })
+
+#define lll_robust_dead(futexv, private) \
+ do \
+ { \
+ int *__futexp = &(futexv); \
+ atomic_or (__futexp, FUTEX_OWNER_DIED); \
+ lll_futex_wake (__futexp, 1, private); \
+ } \
+ while (0)
+
+/* Returns non-zero if error happened, zero if success. */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __sysret; \
+ __sysret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
+ __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+ (nr_wake), (nr_move), (mutex), (val)); \
+ INTERNAL_SYSCALL_ERROR_P (__sysret, __err); \
+ })
+
+
+/* Returns non-zero if error happened, zero if success. */
+#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __sysret; \
+ __sysret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
+ __lll_private_flag (FUTEX_WAKE_OP, private), \
+ (nr_wake), (nr_wake2), (futexp2), \
+ FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \
+ INTERNAL_SYSCALL_ERROR_P (__sysret, __err); \
+ })
+
+
+#define lll_trylock(lock) \
+ atomic_compare_and_exchange_val_acq(&(lock), 1, 0)
+
+#define lll_cond_trylock(lock) \
+ atomic_compare_and_exchange_val_acq(&(lock), 2, 0)
+
+#define __lll_robust_trylock(futex, id) \
+ (atomic_compare_and_exchange_val_acq (futex, id, 0) != 0)
+#define lll_robust_trylock(lock, id) \
+ __lll_robust_trylock (&(lock), id)
+
+extern void __lll_lock_wait_private (int *futex) attribute_hidden;
+extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
+extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
+
+#define __lll_lock(futex, private) \
+ ((void) ({ \
+ int *__futex = (futex); \
+ if (unlikely(atomic_compare_and_exchange_val_acq (__futex, 1, 0))) \
+ { \
+ if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
+ __lll_lock_wait_private (__futex); \
+ else \
+ __lll_lock_wait (__futex, private); \
+ } \
+ }))
+#define lll_lock(futex, private) __lll_lock (&(futex), private)
+
+
+#define __lll_robust_lock(futex, id, private) \
+ ({ \
+ int *__futex = (futex); \
+ int __val = 0; \
+ \
+ if (unlikely(atomic_compare_and_exchange_bool_acq (__futex, id, 0))) \
+ __val = __lll_robust_lock_wait (__futex, private); \
+ __val; \
+ })
+#define lll_robust_lock(futex, id, private) \
+ __lll_robust_lock (&(futex), id, private)
+
+
+#define __lll_cond_lock(futex, private) \
+ ((void) ({ \
+ int *__futex = (futex); \
+ if (unlikely(atomic_exchange_acq (__futex, 2))) \
+ __lll_lock_wait (__futex, private); \
+ }))
+#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
+
+
+#define lll_robust_cond_lock(futex, id, private) \
+ __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
+
+
+extern int __lll_timedlock_wait (int *futex, const struct timespec *,
+ int private) attribute_hidden;
+extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
+ int private) attribute_hidden;
+
+#define __lll_timedlock(futex, abstime, private) \
+ ({ \
+ int *__futex = (futex); \
+ int __val = 0; \
+ \
+ if (unlikely(atomic_exchange_acq (__futex, 1))) \
+ __val = __lll_timedlock_wait (__futex, abstime, private); \
+ __val; \
+ })
+#define lll_timedlock(futex, abstime, private) \
+ __lll_timedlock (&(futex), abstime, private)
+
+
+#define __lll_robust_timedlock(futex, abstime, id, private) \
+ ({ \
+ int *__futex = (futex); \
+ int __val = 0; \
+ \
+ if (unlikely(atomic_compare_and_exchange_bool_acq (__futex, id, 0))) \
+ __val = __lll_robust_timedlock_wait (__futex, abstime, private); \
+ __val; \
+ })
+#define lll_robust_timedlock(futex, abstime, id, private) \
+ __lll_robust_timedlock (&(futex), abstime, id, private)
+
+
+#define __lll_unlock(futex, private) \
+ (void) \
+ ({ int *__futex = (futex); \
+ int __oldval = atomic_exchange_rel (__futex, 0); \
+ if (unlikely(__oldval > 1)) \
+ lll_futex_wake (__futex, 1, private); \
+ })
+#define lll_unlock(futex, private) __lll_unlock(&(futex), private)
+
+
+#define __lll_robust_unlock(futex, private) \
+ (void) \
+ ({ int *__futex = (futex); \
+ int __oldval = atomic_exchange_rel (__futex, 0); \
+ if (unlikely(__oldval & FUTEX_WAITERS)) \
+ lll_futex_wake (__futex, 1, private); \
+ })
+#define lll_robust_unlock(futex, private) \
+ __lll_robust_unlock(&(futex), private)
+
+
+#define lll_islocked(futex) \
+ (futex != 0)
+
+
+/* Our internal lock implementation is identical to the binary-compatible
+ mutex implementation. */
+
+/* Initializers for lock. */
+#define LLL_LOCK_INITIALIZER (0)
+#define LLL_LOCK_INITIALIZER_LOCKED (1)
+
+/* The states of a lock are:
+ 0 - untaken
+ 1 - taken by one user
+ >1 - taken by more users */
+
+/* The kernel notifies a process which uses CLONE_CLEARTID via futex
+ wakeup when the clone terminates. The memory location contains the
+ thread ID while the clone is running and is reset to zero
+ afterwards. */
+#define lll_wait_tid(tid) \
+ do { \
+ __typeof (tid) __tid; \
+ while ((__tid = (tid)) != 0) \
+ lll_futex_wait (&(tid), __tid, LLL_SHARED);\
+ } while (0)
+
+extern int __lll_timedwait_tid (int *, const struct timespec *)
+ attribute_hidden;
+
+#define lll_timedwait_tid(tid, abstime) \
+ ({ \
+ int __res = 0; \
+ if ((tid) != 0) \
+ __res = __lll_timedwait_tid (&(tid), (abstime)); \
+ __res; \
+ })
+
+#endif /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/pthread_once.c
new file mode 100644
index 000000000..46085d3b5
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/pthread_once.c
@@ -0,0 +1,89 @@
+/* Copyright (C) 2004-2013 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 "pthreadP.h"
+#include <lowlevellock.h>
+
+unsigned long int __fork_generation attribute_hidden;
+
+static void
+clear_once_control (void *arg)
+{
+ pthread_once_t *once_control = (pthread_once_t *) arg;
+
+ *once_control = 0;
+ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+int
+__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
+{
+ for (;;)
+ {
+ int oldval;
+ int newval;
+
+ /* Pseudo code:
+ newval = __fork_generation | 1;
+ oldval = *once_control;
+ if ((oldval & 2) == 0)
+ *once_control = newval;
+ Do this atomically.
+ */
+ do
+ {
+ newval = __fork_generation | 1;
+ oldval = *once_control;
+ if (oldval & 2)
+ break;
+ } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval);
+
+ /* Check if the initializer has already been done. */
+ if ((oldval & 2) != 0)
+ return 0;
+
+ /* Check if another thread already runs the initializer. */
+ if ((oldval & 1) == 0)
+ break;
+
+ /* Check whether the initializer execution was interrupted by a fork. */
+ if (oldval != newval)
+ break;
+
+ /* Same generation, some other thread was faster. Wait. */
+ lll_futex_wait (once_control, oldval, LLL_PRIVATE);
+ }
+
+ /* This thread is the first here. Do the initialization.
+ Register a cleanup handler so that in case the thread gets
+ interrupted the initialization can be restarted. */
+ pthread_cleanup_push (clear_once_control, once_control);
+
+ init_routine ();
+
+ pthread_cleanup_pop (0);
+
+ /* Say that the initialisation is done. */
+ *once_control = __fork_generation | 2;
+
+ /* Wake up all other threads. */
+ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+
+ return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/sysdep-cancel.h
new file mode 100644
index 000000000..2af79cab5
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/sysdep-cancel.h
@@ -0,0 +1,139 @@
+/* Copyright (C) 2014-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 <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+#ifdef __ASSEMBLER__
+
+#undef ret
+#define ret
+
+# if !IS_IN_librt || !defined(PIC)
+# define AC_STACK_SIZE 16 /* space for r15, async_cancel arg and 2 temp words */
+# define AC_SET_GOT /* empty */
+# define AC_RESTORE_GOT /* empty */
+# else
+# define AC_STACK_SIZE 20 /* extra 4 bytes for r20 */
+# define AC_SET_GOT \
+ swi r20, r1, AC_STACK_SIZE-4; \
+ mfs r20, rpc; \
+ addik r20, r20, _GLOBAL_OFFSET_TABLE_+8;
+# define AC_RESTORE_GOT \
+ lwi r20, r1, AC_STACK_SIZE-4;
+# endif
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args) \
+ .text; \
+ ENTRY (name) \
+ SINGLE_THREAD_P(r12); \
+ bnei r12, L(pseudo_cancel); \
+ .globl __##syscall_name##_nocancel; \
+ .type __##syscall_name##_nocancel,@function; \
+__##syscall_name##_nocancel: \
+ DO_CALL (syscall_name, args); \
+ addik r4, r0, -4095; \
+ cmpu r4, r4, r3; \
+ rsubk r3,r3,r0; \
+ rtsd r15,8; \
+ addik r3,r0,-1; \
+ rtsd r15, 8; \
+ nop; \
+ .size __##syscall_name##_nocancel, .-__##syscall_name##_nocancel; \
+L(pseudo_cancel): \
+ addik r1, r1, -AC_STACK_SIZE; \
+ swi r15, r1, 0; \
+ AC_SET_GOT \
+ DOCARGS_##args \
+ CENABLE; \
+ swi r3, r1, 8; \
+ UNDOCARGS_##args \
+ DO_CALL (syscall_name, args); \
+ swi r3, r1, 12; \
+ lwi r5, r1, 8; \
+ CDISABLE; \
+ lwi r3, r1, 12; \
+ lwi r15, r1, 0; \
+ AC_RESTORE_GOT \
+ addik r1, r1, AC_STACK_SIZE; \
+ addik r4, r0, -4095; \
+ cmpu r4, r4, r3; \
+ rsubk r3,r3,r0; \
+ rtsd r15,8; \
+ addik r3,r0,-1; \
+ rtsd r15, 8; \
+ nop;
+
+/*
+ * Macros to save/restore syscall arguments across CENABLE
+ * The arguments are saved into the caller's stack (original r1 + 4)
+ */
+
+# define DOCARGS_0
+# define DOCARGS_1 swi r5, r1, AC_STACK_SIZE + 4;
+# define DOCARGS_2 swi r6, r1, AC_STACK_SIZE + 8; DOCARGS_1
+# define DOCARGS_3 swi r7, r1, AC_STACK_SIZE + 12; DOCARGS_2
+# define DOCARGS_4 swi r8, r1, AC_STACK_SIZE + 16; DOCARGS_3
+# define DOCARGS_5 swi r9, r1, AC_STACK_SIZE + 20; DOCARGS_4
+# define DOCARGS_6 swi r10, r1, AC_STACK_SIZE + 24; DOCARGS_5
+
+# define UNDOCARGS_0
+# define UNDOCARGS_1 lwi r5, r1, AC_STACK_SIZE + 4;
+# define UNDOCARGS_2 UNDOCARGS_1 lwi r6, r1, AC_STACK_SIZE + 8;
+# define UNDOCARGS_3 UNDOCARGS_2 lwi r7, r1, AC_STACK_SIZE + 12;
+# define UNDOCARGS_4 UNDOCARGS_3 lwi r8, r1, AC_STACK_SIZE + 16;
+# define UNDOCARGS_5 UNDOCARGS_4 lwi r9, r1, AC_STACK_SIZE + 20;
+# define UNDOCARGS_6 UNDOCARGS_5 lwi r10, r1, AC_STACK_SIZE + 24;
+
+# ifdef PIC
+# define PSEUDO_JMP(sym) brlid r15, sym##@PLTPC; addk r0, r0, r0
+# else
+# define PSEUDO_JMP(sym) brlid r15, sym; addk r0, r0, r0
+# endif
+
+# if defined IS_IN_libpthread
+# define CENABLE PSEUDO_JMP (__pthread_enable_asynccancel)
+# define CDISABLE PSEUDO_JMP (__pthread_disable_asynccancel)
+# define __local_multiple_threads __pthread_multiple_threads
+# elif !defined NOT_IN_libc
+# define CENABLE PSEUDO_JMP (__libc_enable_asynccancel)
+# define CDISABLE PSEUDO_JMP (__libc_disable_asynccancel)
+# define __local_multiple_threads __libc_multiple_threads
+# elif defined IS_IN_librt
+# define CENABLE PSEUDO_JMP (__librt_enable_asynccancel)
+# define CDISABLE PSEUDO_JMP (__librt_disable_asynccancel)
+# else
+# error Unsupported library
+# endif
+
+#define SINGLE_THREAD_P(reg) \
+ lwi reg, r0, MULTIPLE_THREADS_OFFSET(reg)
+
+#else /* !__ASSEMBLER__ */
+# define SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/vfork.S
new file mode 100644
index 000000000..433671717
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/vfork.S
@@ -0,0 +1,5 @@
+#define SAVE_PID
+#define RESTORE_PID
+#include <tls.h>
+#include <tcb-offsets.h>
+#include <libc/sysdeps/linux/microblaze/vfork.S>