Browse Source

microblaze: add NPTL/TLS support from GNU libc

Not perfect, but a starting point.
Some tests of the test suite are failing.
Waldemar Brodkorb 7 years ago
parent
commit
191739597c
33 changed files with 1394 additions and 100 deletions
  1. 0 1
      extra/Configs/Config.in
  2. 31 24
      include/elf.h
  3. 8 0
      ldso/ldso/microblaze/dl-debug.h
  4. 0 3
      ldso/ldso/microblaze/dl-startup.h
  5. 14 14
      ldso/ldso/microblaze/dl-sysdep.h
  6. 12 10
      ldso/ldso/microblaze/elfinterp.c
  7. 1 1
      libc/sysdeps/linux/microblaze/Makefile.arch
  8. 18 0
      libc/sysdeps/linux/microblaze/__syscall_error.c
  9. 1 2
      libc/sysdeps/linux/microblaze/bits/uClibc_arch_features.h
  10. 8 9
      libc/sysdeps/linux/microblaze/clone.S
  11. 0 6
      libc/sysdeps/linux/microblaze/jmpbuf-offsets.h
  12. 25 0
      libc/sysdeps/linux/microblaze/jmpbuf-unwind.h
  13. 81 2
      libc/sysdeps/linux/microblaze/sysdep.h
  14. 30 28
      libc/sysdeps/linux/microblaze/vfork.S
  15. 4 0
      libpthread/nptl/sysdeps/microblaze/Makefile.arch
  16. 26 0
      libpthread/nptl/sysdeps/microblaze/dl-tls.h
  17. 36 0
      libpthread/nptl/sysdeps/microblaze/libc-tls.c
  18. 62 0
      libpthread/nptl/sysdeps/microblaze/pthread_spin_lock.c
  19. 27 0
      libpthread/nptl/sysdeps/microblaze/pthread_spin_trylock.c
  20. 40 0
      libpthread/nptl/sysdeps/microblaze/pthreaddef.h
  21. 11 0
      libpthread/nptl/sysdeps/microblaze/tcb-offsets.sym
  22. 159 0
      libpthread/nptl/sysdeps/microblaze/tls.h
  23. 13 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/Makefile
  24. 8 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/Makefile.arch
  25. 181 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/bits/pthreadtypes.h
  26. 32 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/bits/semaphore.h
  27. 4 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/clone.S
  28. 22 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/createthread.c
  29. 29 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/fork.c
  30. 278 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/lowlevellock.h
  31. 89 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/pthread_once.c
  32. 139 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/sysdep-cancel.h
  33. 5 0
      libpthread/nptl/sysdeps/unix/sysv/linux/microblaze/vfork.S

+ 0 - 1
extra/Configs/Config.in

@@ -521,7 +521,6 @@ config UCLIBC_HAS_THREADS_NATIVE
 		   !TARGET_hppa && \
 		   !TARGET_hppa && \
 		   !TARGET_ia64 && \
 		   !TARGET_ia64 && \
 		   !TARGET_m68k && \
 		   !TARGET_m68k && \
-		   !TARGET_microblaze && \
 		   !TARGET_nds32 && \
 		   !TARGET_nds32 && \
 		   !TARGET_nios2 && \
 		   !TARGET_nios2 && \
 		   !TARGET_or1k && \
 		   !TARGET_or1k && \

+ 31 - 24
include/elf.h

@@ -3234,30 +3234,37 @@ typedef Elf32_Addr Elf32_Conflict;
 
 
 #define DT_C6000_NUM    4
 #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 */
 /* Meta relocations */
 #define R_METAG_HIADDR16                 0
 #define R_METAG_HIADDR16                 0

+ 8 - 0
ldso/ldso/microblaze/dl-debug.h

@@ -51,4 +51,12 @@ static const char * const _dl_reltypes_tab[] =
 		"R_MICROBLAZE_GOTOFF_64",
 		"R_MICROBLAZE_GOTOFF_64",
 		"R_MICROBLAZE_GOTOFF_32",
 		"R_MICROBLAZE_GOTOFF_32",
 		"R_MICROBLAZE_COPY",
 		"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",
 	};
 	};

+ 0 - 3
ldso/ldso/microblaze/dl-startup.h

@@ -78,9 +78,6 @@ _dl_start_user:\n\
  */
  */
 #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*) ARGS)+1)
 #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*) ARGS)+1)
 
 
-/* The ld.so library requires relocations */
-#define ARCH_NEEDS_BOOTSTRAP_RELOCS
-
 static __always_inline
 static __always_inline
 void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr,
 void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr,
 	unsigned long symbol_addr, unsigned long load_addr, attribute_unused Elf32_Sym *symtab)
 	unsigned long symbol_addr, unsigned long load_addr, attribute_unused Elf32_Sym *symtab)

+ 14 - 14
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
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    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
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
    <http://www.gnu.org/licenses/>.  */
 
 
-/* Use reloca */
 #define ELF_USES_RELOCA
 #define ELF_USES_RELOCA
 
 
 #include <elf.h>
 #include <elf.h>
 
 
-
 /* Initialise the GOT */
 /* 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)
 } while(0)
 
 
 /* Here we define the magic numbers that this dynamic loader should accept */
 /* Here we define the magic numbers that this dynamic loader should accept */
-
 #define MAGIC1 EM_MICROBLAZE
 #define MAGIC1 EM_MICROBLAZE
 #undef  MAGIC2
 #undef  MAGIC2
 /* Used for error messages */
 /* Used for error messages */
 #define ELF_TARGET "microblaze"
 #define ELF_TARGET "microblaze"
 
 
+/* Need bootstrap relocations */
+#define ARCH_NEEDS_BOOTSTRAP_RELOCS
+
 struct elf_resolve;
 struct elf_resolve;
 unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
 unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
 
 
 #define elf_machine_type_class(type) \
 #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)
    | ((type) == R_MICROBLAZE_COPY) * ELF_RTYPE_CLASS_COPY)
 
 
 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
    first element of the GOT.  This must be inlined in a function which
    first element of the GOT.  This must be inlined in a function which
    uses global data.  */
    uses global data.  */
-static inline Elf32_Addr
+static __always_inline Elf32_Addr __attribute__ ((unused))
 elf_machine_dynamic (void)
 elf_machine_dynamic (void)
 {
 {
   Elf32_Addr got_entry_0;
   Elf32_Addr got_entry_0;
@@ -56,7 +58,6 @@ elf_machine_dynamic (void)
   return got_entry_0;
   return got_entry_0;
 }
 }
 
 
-
 /* Return the run-time load address of the shared object.  */
 /* Return the run-time load address of the shared object.  */
 static inline Elf32_Addr
 static inline Elf32_Addr
 elf_machine_load_address (void)
 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
   /* Compute the difference between the runtime address of _DYNAMIC as seen
      by a GOTOFF reference, and the link-time address found in the special
      by a GOTOFF reference, and the link-time address found in the special
      unrelocated first GOT entry.  */
      unrelocated first GOT entry.  */
+
   Elf32_Addr dyn;
   Elf32_Addr dyn;
   __asm__ __volatile__ (
   __asm__ __volatile__ (
     "addik %0,r20,_DYNAMIC@GOTOFF"
     "addik %0,r20,_DYNAMIC@GOTOFF"
@@ -72,8 +74,6 @@ elf_machine_load_address (void)
   return dyn - elf_machine_dynamic ();
   return dyn - elf_machine_dynamic ();
 }
 }
 
 
-
-
 static __always_inline void
 static __always_inline void
 elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
 elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
 		      Elf32_Word relative_count)
 		      Elf32_Word relative_count)

+ 12 - 10
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_NONE:
 		case R_MICROBLAZE_64_NONE:
 		case R_MICROBLAZE_64_NONE:
 			break;
 			break;
-
 		case R_MICROBLAZE_64:
 		case R_MICROBLAZE_64:
 			*reloc_addr = symbol_addr + rpnt->r_addend;
 			*reloc_addr = symbol_addr + rpnt->r_addend;
 			break;
 			break;
-
 		case R_MICROBLAZE_32:
 		case R_MICROBLAZE_32:
 		case R_MICROBLAZE_32_LO:
 		case R_MICROBLAZE_32_LO:
 			*reloc_addr = symbol_addr + rpnt->r_addend;
 			*reloc_addr = symbol_addr + rpnt->r_addend;
 			break;
 			break;
-
 		case R_MICROBLAZE_32_PCREL:
 		case R_MICROBLAZE_32_PCREL:
 		case R_MICROBLAZE_32_PCREL_LO:
 		case R_MICROBLAZE_32_PCREL_LO:
 		case R_MICROBLAZE_64_PCREL:
 		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:
 		case R_MICROBLAZE_SRW32:
 			*reloc_addr = symbol_addr + rpnt->r_addend;
 			*reloc_addr = symbol_addr + rpnt->r_addend;
 			break;
 			break;
-
 		case R_MICROBLAZE_GLOB_DAT:
 		case R_MICROBLAZE_GLOB_DAT:
 		case R_MICROBLAZE_JUMP_SLOT:
 		case R_MICROBLAZE_JUMP_SLOT:
 			*reloc_addr = symbol_addr + rpnt->r_addend;
 			*reloc_addr = symbol_addr + rpnt->r_addend;
 			break;
 			break;
-/* Handled by elf_machine_relative */
 		case R_MICROBLAZE_REL:
 		case R_MICROBLAZE_REL:
 			*reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
 			*reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
 			break;
 			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:
 		case R_MICROBLAZE_COPY:
 			if (symbol_addr) {
 			if (symbol_addr) {
 #if defined (__SUPPORT_LD_DEBUG__)
 #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,
 						    symname, sym_ref.sym->st_size,
 						    symbol_addr, reloc_addr);
 						    symbol_addr, reloc_addr);
 #endif
 #endif
-
 				_dl_memcpy((char *)reloc_addr,
 				_dl_memcpy((char *)reloc_addr,
 					   (char *)symbol_addr,
 					   (char *)symbol_addr,
 					   sym_ref.sym->st_size);
 					   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");
 				_dl_dprintf(_dl_debug_file, "no symbol_addr to copy !?\n");
 #endif
 #endif
 			break;
 			break;
-
 		default:
 		default:
 			return -1;	/* Calls _dl_exit(1). */
 			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)
 		  ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
 {
 {
 	int reloc_type;
 	int reloc_type;
-	int symtab_index;
 	ElfW(Addr) *reloc_addr;
 	ElfW(Addr) *reloc_addr;
 #if defined (__SUPPORT_LD_DEBUG__)
 #if defined (__SUPPORT_LD_DEBUG__)
 	ElfW(Addr) old_val;
 	ElfW(Addr) old_val;
 #endif
 #endif
 
 
 	(void)scope;
 	(void)scope;
-	symtab_index = ELF_R_SYM(rpnt->r_info);
 	(void)strtab;
 	(void)strtab;
 
 
 	reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + rpnt->r_offset);
 	reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + rpnt->r_offset);

+ 1 - 1
libc/sysdeps/linux/microblaze/Makefile.arch

@@ -5,5 +5,5 @@
 #
 #
 # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
 # 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
 SSRC-y := setjmp.S __longjmp.S vfork.S clone.S

+ 18 - 0
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;
+}

+ 1 - 2
libc/sysdeps/linux/microblaze/bits/uClibc_arch_features.h

@@ -6,8 +6,7 @@
 #define _BITS_UCLIBC_ARCH_FEATURES_H
 #define _BITS_UCLIBC_ARCH_FEATURES_H
 
 
 /* instruction used when calling abort() to kill yourself */
 /* 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 ? */
 /* can your target use syscall6() for mmap ? */
 #define __UCLIBC_MMAP_HAS_6_ARGS__
 #define __UCLIBC_MMAP_HAS_6_ARGS__

+ 8 - 9
libc/sysdeps/linux/microblaze/clone.S

@@ -23,6 +23,10 @@
 #define _ERRNO_H	1
 #define _ERRNO_H	1
 #include <bits/errno.h>
 #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,
 /* int clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg,
               pid_t *ptid, struct user_desc *tls, pid_t *ctid);
               pid_t *ptid, struct user_desc *tls, pid_t *ctid);
 
 
@@ -39,8 +43,8 @@
         .text
         .text
 ENTRY (__clone)
 ENTRY (__clone)
 	addik	r3,r0,-EINVAL
 	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
 	addik	r6,r6,-8
 	swi	r5,r6,0			; // Push fn onto child's stack
 	swi	r5,r6,0			; // Push fn onto child's stack
 	swi	r8,r6,4			; // Push arg for child
 	swi	r8,r6,4			; // Push arg for child
@@ -53,7 +57,7 @@ ENTRY (__clone)
 	addk	r0,r0,r0
 	addk	r0,r0,r0
 	addik	r4,r0,-4095
 	addik	r4,r0,-4095
 	cmpu	r4,r4,r3
 	cmpu	r4,r4,r3
-	bgei	r4,1f
+	bgei	r4,SYSCALL_ERROR_LABEL
 	beqi	r3,L(thread_start)
 	beqi	r3,L(thread_start)
 	rtsd	r15,8
 	rtsd	r15,8
 	nop
 	nop
@@ -67,12 +71,7 @@ L(thread_start):
 	addik	r12,r0,SYS_ify(exit)
 	addik	r12,r0,SYS_ify(exit)
 	brki	r14,8
 	brki	r14,8
 	nop
 	nop
-
-1:      rsubk   r3,r3,r0
-        rtsd    r15,8
-        addik   r3,r0,-1        /* delay slot.  */
-
-END(__clone)
+PSEUDO_END(__clone)
 
 
 libc_hidden_def (__clone)
 libc_hidden_def (__clone)
 weak_alias (__clone,clone)
 weak_alias (__clone,clone)

+ 0 - 6
libc/sysdeps/linux/microblaze/jmpbuf-offsets.h

@@ -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)

+ 25 - 0
libc/sysdeps/linux/microblaze/jmpbuf-unwind.h

@@ -10,3 +10,28 @@
    containing a local variable at ADDRESS.  */
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address) \
 #define _JMPBUF_UNWINDS(jmpbuf, address) \
   ((void *) (address) < (void *) (jmpbuf)[0].__sp)
   ((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

+ 81 - 2
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>
 #include <common/sysdep.h>
 
 
 #ifdef  __ASSEMBLER__
 #ifdef  __ASSEMBLER__
 
 
-/* Syntactic details of assembler.  */
-
 # define ALIGNARG(log2) log2
 # define ALIGNARG(log2) log2
 # define ASM_SIZE_DIRECTIVE(name) .size name,.-name
 # define ASM_SIZE_DIRECTIVE(name) .size name,.-name
 
 
@@ -22,4 +38,67 @@
 #  define L(name) $L##name
 #  define L(name) $L##name
 # endif
 # 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
 #endif

+ 30 - 28
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.
 /* Clone the calling process, but without copying the whole address space.
    The calling process is suspended until the new process exits or is
    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,
    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.  */
    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
 1:      rsubk   r3,r3,r0
         rtsd    r15,8
         rtsd    r15,8
         addik   r3,r0,-1        /* delay slot.  */
         addik   r3,r0,-1        /* delay slot.  */
 
 
-2:	rtsd	r15, 8			/* error return */
-	nop
-       .size   __vfork, .-__vfork
+END(__vfork)
 
 
 weak_alias(__vfork, vfork)
 weak_alias(__vfork, vfork)
 libc_hidden_def(vfork)
 libc_hidden_def(vfork)

+ 4 - 0
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

+ 26 - 0
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);

+ 36 - 0
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

+ 62 - 0
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;
+}

+ 27 - 0
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;
+}

+ 40 - 0
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))

+ 11 - 0
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)

+ 159 - 0
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.  */

+ 13 - 0
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

+ 8 - 0
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

+ 181 - 0
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.  */

+ 32 - 0
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;

+ 4 - 0
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"

+ 22 - 0
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>

+ 29 - 0
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"

+ 278 - 0
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 */

+ 89 - 0
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)

+ 139 - 0
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

+ 5 - 0
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>