public inbox for libc-ports@sourceware.org
 help / color / mirror / Atom feed
* [M68K/ColdFire] NPTL support and other updates
@ 2009-08-25 12:27 Maxim Kuvyrkov
  2009-08-25 12:36 ` [M68K/ColdFire patch 1/n] Update sysdep.h Maxim Kuvyrkov
                   ` (8 more replies)
  0 siblings, 9 replies; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 12:27 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

Good day,

In this thread I will post patches to M68K/ColdFire port that add NPTL 
support and other necessary updates to make trunk GLIBC build and work 
properly.

The patches posted here were tested against 2.10 branch on a ColdFire 
system with no test failures in elf/ and nptl/ directories.

Truth be told, I mainly focused on the ColdFire port, and didn't test 
the work on usual m68k.  Still, to my knowledge, the only place m68k 
functionality is missing, is atomic macros implementations in 
./sysdeps/unix/sysv/linux/m68k/nptl/atomic.h, which should be straight 
forward to fix: the memory barrier macro should be the same as in 
coldfire's implementation and compare_exchange macro should be a wrapper 
for 'cas'.

Further, I still have one more patch in my pipeline.  The patch fixes 
register-dump.h and regs.h, but I need some time to verify that the 
fixed versions correlate with ColdFire kernels.

Even further, to make the port build on trunk (not 2.10 branch), one 
needs to update ____longjmp_chk, something I had not yet started on.

Finally, to build M68K/ColdFire GLIBC *without bugs*, one will need the 
very recent snapshots of binutils, gcc and kernel.  The threads for 
binutils and gcc patches that fix last /known to date/ bugs are 
(http://sourceware.org/ml/binutils/2009-08/msg00461.html) and 
(http://gcc.gnu.org/ml/gcc-patches/2009-08/msg01253.html).  The kernel 
patches (http://marc.info/?l=linux-m68k&m=125054669119207&q=p4 and 
http://marc.info/?l=linux-m68k&m=125105890201426&q=p3) are not intrusive 
and can be ported to the kernel version of one's choice.

Andreas, I thank you in advance for reviewing this work.

Last, but not least, I'd like to give credit for this work to my 
colleagues at CodeSourcery, especially, Joseph S. Myers and Daniel 
Jacobowitz, for their help and expertise during this project.

Regards,

--
Maxim Kuvyrkov
CodeSourcery

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [M68K/ColdFire patch 1/n] Update sysdep.h
  2009-08-25 12:27 [M68K/ColdFire] NPTL support and other updates Maxim Kuvyrkov
@ 2009-08-25 12:36 ` Maxim Kuvyrkov
  2009-08-25 12:39 ` [M68K/ColdFire patch 2/n] Add CFI information to dl-trampoline.S Maxim Kuvyrkov
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 12:36 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 346 bytes --]

This simple patch updates sysdep.h.

The definition of NEED_STATIC_SYSINFO_DSO at the bottom of the file is a 
no-op at the moment, but it serves as a helpful remainder for future 
improvement.  The improvement would be to implement linking in kernel 
vDSO for static executables.

Any comments?  OK to commit?

Thanks,

--
Maxim K.
CodeSourcery

[-- Attachment #2: 0001-Update-sysdep.h.patch --]
[-- Type: text/plain, Size: 3191 bytes --]

From d5d20e06bf49c6586ce2e64e627c25d825341324 Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Mon, 24 Aug 2009 12:28:47 +0400
Subject: [PATCH 1/5] Update sysdep.h.

	* sysdeps/unix/sysv/linux/m68k/sysdep.h (tls.h): Include.
	(INTERNAL_SYSCALL): Convert to INTERNAL_SYSCALL_NCS.
	(PTR_MANGLE, PTR_DEMANGLE): Define.
	(NEED_STATIC_SYSINFO_DSO): Define.

Note: support for NEED_STATIC_SYSINFO_DSO is not yet implemented in the main
GLIBC tree.
---
 sysdeps/unix/sysv/linux/m68k/sysdep.h |   23 ++++++++++++++++++++---
 1 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/sysdeps/unix/sysv/linux/m68k/sysdep.h b/sysdeps/unix/sysv/linux/m68k/sysdep.h
index 12687d8..afc0e13 100644
--- a/sysdeps/unix/sysv/linux/m68k/sysdep.h
+++ b/sysdeps/unix/sysv/linux/m68k/sysdep.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2006, 2009
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>,
    December 1995.
@@ -23,6 +24,7 @@
 
 #include <sysdeps/unix/sysdep.h>
 #include <sysdeps/m68k/sysdep.h>
+#include <tls.h>
 
 /* Defines RTLD_PRIVATE_ERRNO.  */
 #include <dl-sysdep.h>
@@ -148,9 +150,11 @@ SYSCALL_ERROR_LABEL:							      \
 	arg 3		%d3	     call-saved
 	arg 4		%d4	     call-saved
 	arg 5		%d5	     call-saved
+	arg 6		%a0	     call-clobbered
 
    The stack layout upon entering the function is:
 
+	24(%sp)		Arg# 6
 	20(%sp)		Arg# 5
 	16(%sp)		Arg# 4
 	12(%sp)		Arg# 3
@@ -229,7 +233,7 @@ SYSCALL_ERROR_LABEL:							      \
    normally.  It will never touch errno.  This returns just what the kernel
    gave back.  */
 #undef INTERNAL_SYSCALL
-#define INTERNAL_SYSCALL(name, err, nr, args...)	\
+#define INTERNAL_SYSCALL_NCS(name, err, nr, args...)	\
   ({ unsigned int _sys_result;				\
      {							\
        /* Load argument values in temporary variables
@@ -237,7 +241,7 @@ SYSCALL_ERROR_LABEL:							      \
 	  before the call used registers are set.  */	\
        LOAD_ARGS_##nr (args)				\
        LOAD_REGS_##nr					\
-       register int _d0 asm ("%d0") = __NR_##name;	\
+       register int _d0 asm ("%d0") = name;		\
        asm volatile ("trap #0"				\
 		     : "=d" (_d0)			\
 		     : "0" (_d0) ASM_ARGS_##nr		\
@@ -245,6 +249,8 @@ SYSCALL_ERROR_LABEL:							      \
        _sys_result = _d0;				\
      }							\
      (int) _sys_result; })
+#define INTERNAL_SYSCALL(name, err, nr, args...)	\
+  INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)
 
 #undef INTERNAL_SYSCALL_ERROR_P
 #define INTERNAL_SYSCALL_ERROR_P(val, err)		\
@@ -300,4 +306,15 @@ SYSCALL_ERROR_LABEL:							      \
 #define ASM_ARGS_6	ASM_ARGS_5, "a" (_a0)
 
 #endif /* not __ASSEMBLER__ */
+
+/* Pointer mangling is not yet supported for M68K.  */
+#define PTR_MANGLE(var) (void) (var)
+#define PTR_DEMANGLE(var) (void) (var)
+
+#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
+/* M68K needs system-supplied DSO to access TLS helpers
+   even when statically linked.  */
+# define NEED_STATIC_SYSINFO_DSO 1
+#endif
+
 #endif
-- 
1.6.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [M68K/ColdFire patch 2/n] Add CFI information to dl-trampoline.S
  2009-08-25 12:27 [M68K/ColdFire] NPTL support and other updates Maxim Kuvyrkov
  2009-08-25 12:36 ` [M68K/ColdFire patch 1/n] Update sysdep.h Maxim Kuvyrkov
@ 2009-08-25 12:39 ` Maxim Kuvyrkov
  2009-08-25 12:52 ` [M68K/ColdFire patch 3/n] Update jmpbuf-unwind.h Maxim Kuvyrkov
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 12:39 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 187 bytes --]

This patch adds frame unwind information to _dl_runtime_resolve() to 
make debugging of the resolver more pleasant.

Any comments?  OK to commit?

Thanks,

--
Maxim Kuvyrkov
CodeSourcery

[-- Attachment #2: 0002-Add-frame-unwind-information-to-_dl_runtime_resolve.patch --]
[-- Type: text/plain, Size: 1779 bytes --]

From 6db3a545be78373ca431e982fd354c8315e2519a Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Mon, 24 Aug 2009 12:29:56 +0400
Subject: [PATCH 2/5] Add frame unwind information to _dl_runtime_resolve.

	* sysdeps/m68k/dl-trampoline.S: Add frame unwinding informarion.

This patch adds frame unwind information to _dl_runtime_resolve.
The initial CFA offset of 12 was determined by trial and error and
with debugger's assistance.
---
 sysdeps/m68k/dl-trampoline.S |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/sysdeps/m68k/dl-trampoline.S b/sysdeps/m68k/dl-trampoline.S
index e324da1..1a46b1e 100644
--- a/sysdeps/m68k/dl-trampoline.S
+++ b/sysdeps/m68k/dl-trampoline.S
@@ -1,5 +1,5 @@
 /* PLT trampolines.  m68k version.
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 2005, 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
@@ -23,23 +23,32 @@
 	.globl _dl_runtime_resolve
 	.type _dl_runtime_resolve, @function
 _dl_runtime_resolve:
+	cfi_startproc
+	cfi_def_cfa (%sp, 12)
 	| Save %a0 (struct return address) and %a1.
 	move.l %a0, -(%sp)
+	cfi_adjust_cfa_offset (4)
 	move.l %a1, -(%sp)
+	cfi_adjust_cfa_offset (4)
 	| Call the real address resolver.
 	jbsr _dl_fixup
 	| Restore register %a0 and %a1.
 	move.l (%sp)+, %a1
+	cfi_adjust_cfa_offset (-4)
 	move.l (%sp)+, %a0
+	cfi_adjust_cfa_offset (-4)
 	| Pop parameters
 	addq.l #8, %sp
+	cfi_adjust_cfa_offset (-8)
 	| Call real function.
 #ifdef __mcoldfire__
 	move.l %d0,-(%sp)
+	cfi_adjust_cfa_offset (4)
 	rts
 #else
 	jmp (%d0)
 #endif
+	cfi_endproc
 	.size _dl_runtime_resolve, . - _dl_runtime_resolve
 
 	.text
-- 
1.6.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [M68K/ColdFire patch 3/n] Update jmpbuf-unwind.h
  2009-08-25 12:27 [M68K/ColdFire] NPTL support and other updates Maxim Kuvyrkov
  2009-08-25 12:36 ` [M68K/ColdFire patch 1/n] Update sysdep.h Maxim Kuvyrkov
  2009-08-25 12:39 ` [M68K/ColdFire patch 2/n] Add CFI information to dl-trampoline.S Maxim Kuvyrkov
@ 2009-08-25 12:52 ` Maxim Kuvyrkov
  2009-08-25 12:58 ` [M68K/ColdFire patch 4/n] Remove kernel headers Maxim Kuvyrkov
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 12:52 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 159 bytes --]

This patch updates jmpbuf-unwind.h.

The implementation was borrowed from what other major architectures do.

Any comments?

Thanks,

--
Maxim K.
CodeSourcery

[-- Attachment #2: 0003-Update-jmpbuf-unwind.h.patch --]
[-- Type: text/plain, Size: 1742 bytes --]

From efd28b55921422dc141672336bed8a33284dfbfb Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Mon, 24 Aug 2009 12:35:48 +0400
Subject: [PATCH 3/5] Update jmpbuf-unwind.h.

	* sysdeps/m68k/jmpbuf-unwind.h: Update.
---
 sysdeps/m68k/jmpbuf-unwind.h |   23 ++++++++++++++++++++++-
 1 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/sysdeps/m68k/jmpbuf-unwind.h b/sysdeps/m68k/jmpbuf-unwind.h
index 3490c79..d001039 100644
--- a/sysdeps/m68k/jmpbuf-unwind.h
+++ b/sysdeps/m68k/jmpbuf-unwind.h
@@ -1,5 +1,5 @@
 /* Examine __jmp_buf for unwinding frames.  m68k version.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 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
@@ -18,8 +18,29 @@
    02111-1307 USA.  */
 
 #include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
 
 /* Test if longjmp to JMPBUF would unwind the frame
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address, demangle)		\
   ((void *) (address) < (void *) demangle ((jmpbuf)->__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)
+{
+  uintptr_t sp = regs[0].__sp;
+#ifdef PTR_DEMANGLE
+  PTR_DEMANGLE (sp);
+#endif
+  return sp;
+}
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj))
+
+/* We use the normal longjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
-- 
1.6.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [M68K/ColdFire patch 4/n] Remove kernel headers
  2009-08-25 12:27 [M68K/ColdFire] NPTL support and other updates Maxim Kuvyrkov
                   ` (2 preceding siblings ...)
  2009-08-25 12:52 ` [M68K/ColdFire patch 3/n] Update jmpbuf-unwind.h Maxim Kuvyrkov
@ 2009-08-25 12:58 ` Maxim Kuvyrkov
  2009-08-25 13:21   ` Andreas Schwab
  2009-08-25 13:04 ` [M68K/ColdFire patch 5/n] Main NPTL patch Maxim Kuvyrkov
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 12:58 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 346 bytes --]

This patch removes 2 kernel headers -- sigcontext.h and ucontext.h -- 
from GLIBC's m68k port.  These headers are installed by the kernel, that 
has a better idea of how it lays out the signal context.

This elegant patch is a result of about a day of debugging unwinding of 
the signal frames.

Any comments?

Thanks,

--
Maxim K.
CodeSourcery


[-- Attachment #2: 0004-Remove-kernel-headers.patch --]
[-- Type: text/plain, Size: 5642 bytes --]

From ebeebdf8a32ac5b6af243fd277857989367e8f3f Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Mon, 24 Aug 2009 12:37:32 +0400
Subject: [PATCH 4/5] Remove kernel headers.

	* sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h: Remove, use
	kernel version instead.
	* sysdeps/unix/sysv/linux/m68k/sys/ucontext.h: Same.
---
 sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h |   62 -------------
 sysdeps/unix/sysv/linux/m68k/sys/ucontext.h    |  113 ------------------------
 2 files changed, 0 insertions(+), 175 deletions(-)
 delete mode 100644 sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h
 delete mode 100644 sysdeps/unix/sysv/linux/m68k/sys/ucontext.h

diff --git a/sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h b/sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h
deleted file mode 100644
index 8ad0c96..0000000
--- a/sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (C) 2006 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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#if !defined _SIGNAL_H && !defined _SYS_UCONTEXT_H
-# error "Never use <bits/sigcontext.h> directly; include <signal.h> instead."
-#endif
-
-#ifndef _BITS_SIGCONTEXT_H
-#define _BITS_SIGCONTEXT_H 1
-
-struct sigcontext {
-  unsigned long sc_mask;
-  unsigned long sc_usp;
-  unsigned long sc_d0;
-  unsigned long sc_d1;
-#ifdef __mcoldfire__
-  unsigned long sc_d2;
-  unsigned long sc_d3;
-  unsigned long sc_d4;
-  unsigned long sc_d5;
-  unsigned long sc_d6;
-  unsigned long sc_d7;
-#endif
-  unsigned long sc_a0;
-  unsigned long sc_a1;
-#ifdef __mcoldfire__
-  unsigned long sc_a2;
-  unsigned long sc_a3;
-  unsigned long sc_a4;
-  unsigned long sc_a5;
-  unsigned long sc_a6;
-#endif
-  unsigned short sc_sr;
-  unsigned long sc_pc;
-  unsigned short sc_formatvec;
-#ifdef __mcoldfire__
-  unsigned long sc_fpregs[8][2];
-  unsigned long sc_fpcntl[3];
-  unsigned char sc_fpstate[16];
-#else
-  unsigned long sc_fpregs[2*3];
-  unsigned long sc_fpcntl[3];
-  unsigned char sc_fpstate[216];
-#endif
-};
-
-#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/sys/ucontext.h b/sysdeps/unix/sysv/linux/m68k/sys/ucontext.h
deleted file mode 100644
index 776466b..0000000
--- a/sysdeps/unix/sysv/linux/m68k/sys/ucontext.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* Copyright (C) 1997, 1999, 2001 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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-/* System V/m68k ABI compliant context switching support.  */
-
-#ifndef _SYS_UCONTEXT_H
-#define _SYS_UCONTEXT_H	1
-
-#include <features.h>
-#include <signal.h>
-
-/* Type for general register.  */
-typedef int greg_t;
-
-/* Number of general registers.  */
-#define NGREG	18
-
-/* Container for all general registers.  */
-typedef greg_t gregset_t[NGREG];
-
-/* Number of each register is the `gregset_t' array.  */
-enum
-{
-  R_D0 = 0,
-#define R_D0	R_D0
-  R_D1 = 1,
-#define R_D1	R_D1
-  R_D2 = 2,
-#define R_D2	R_D2
-  R_D3 = 3,
-#define R_D3	R_D3
-  R_D4 = 4,
-#define R_D4	R_D4
-  R_D5 = 5,
-#define R_D5	R_D5
-  R_D6 = 6,
-#define R_D6	R_D6
-  R_D7 = 7,
-#define R_D7	R_D7
-  R_A0 = 8,
-#define R_A0	R_A0
-  R_A1 = 9,
-#define R_A1	R_A1
-  R_A2 = 10,
-#define R_A2	R_A2
-  R_A3 = 11,
-#define R_A3	R_A3
-  R_A4 = 12,
-#define R_A4	R_A4
-  R_A5 = 13,
-#define R_A5	R_A5
-  R_A6 = 14,
-#define R_A6	R_A6
-  R_A7 = 15,
-#define R_A7	R_A7
-  R_SP = 15,
-#define R_SP	R_SP
-  R_PC = 16,
-#define R_PC	R_PC
-  R_PS = 17
-#define R_PS	R_PS
-};
-
-/* Structure to describe FPU registers.  */
-typedef struct fpregset
-{
-  int f_pcr;
-  int f_psr;
-  int f_fpiaddr;
-#ifdef __mcoldfire__
-  int f_fpregs[8][2];
-#else
-  int f_fpregs[8][3];
-#endif
-} fpregset_t;
-
-/* Context to describe whole processor state.  */
-typedef struct
-{
-  int version;
-  gregset_t gregs;
-  fpregset_t fpregs;
-} mcontext_t;
-
-#define MCONTEXT_VERSION 2
-
-/* Userlevel context.  */
-typedef struct ucontext
-{
-  unsigned long uc_flags;
-  struct ucontext *uc_link;
-  stack_t uc_stack;
-  mcontext_t uc_mcontext;
-  unsigned long uc_filler[80];
-  __sigset_t uc_sigmask;
-} ucontext_t;
-
-#endif /* sys/ucontext.h */
-- 
1.6.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [M68K/ColdFire patch 5/n] Main NPTL patch
  2009-08-25 12:27 [M68K/ColdFire] NPTL support and other updates Maxim Kuvyrkov
                   ` (3 preceding siblings ...)
  2009-08-25 12:58 ` [M68K/ColdFire patch 4/n] Remove kernel headers Maxim Kuvyrkov
@ 2009-08-25 13:04 ` Maxim Kuvyrkov
  2009-08-30 18:03   ` Maxim Kuvyrkov
  2009-08-25 13:39 ` [M68K/ColdFire patch 6/n] Add TLS relocations to elf/elf.h Maxim Kuvyrkov
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 13:04 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 222 bytes --]

This is the main NPTL patch.  During development of this work I tried to 
make things work in the exactly same way as on other major architectures.

I expect there will be comments on this one :)

--
Maxim K.
CodeSourcery

[-- Attachment #2: 0005-Nptl-support-for-m68k-ColdFire.patch --]
[-- Type: text/plain, Size: 77936 bytes --]

From 4a3efb9ace74a204a0449ed385351ebf560dca59 Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Tue, 25 Aug 2009 16:42:47 +0400
Subject: [PATCH 5/5] Nptl support for m68k/ColdFire.

	* sysdeps/unix/sysv/linux/m68k/clone.S: Support RESET_PID.
	* sysdeps/unix/sysv/linux/m68k/m68k-helpers.S: New.
	* sysdeps/unix/sysv/linux/m68k/Makefile: Add new files to lists.
	* sysdeps/unix/sysv/linux/m68k/vfork.S: Add SAVE_PID/RESTORE_PID.
	* sysdeps/unix/sysv/linux/m68k/m68k-vdso.c: New.
	* sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h: New.
	* sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h: New.
	* sysdeps/unix/sysv/linux/m68k/Versions: Add symbols for NPTL support.
	* sysdeps/unix/sysv/linux/m68k/init-first.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/clone.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/fork.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/vfork.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/createthread.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c: New.
	* sysdeps/unix/sysv/linux/m68k/socket.S: Update cancelation code.
	* sysdeps/m68k/dl-tls.h: New.
	* sysdeps/m68k/libc-tls.c: New.
	* sysdeps/m68k/tls-macros.h: New.
	* sysdeps/m68k/dl-machine.h: Handle TLS relocations.
	* sysdeps/m68k/nptl/tcb-offsets.sym: New.
	* sysdeps/m68k/nptl/pthread_spin_trylock.c: New.
	* sysdeps/m68k/nptl/tls.h: New.
	* sysdeps/m68k/nptl/pthread_spin_lock.c: New.
	* sysdeps/m68k/nptl/pthreaddef.h: New.
	* sysdeps/m68k/nptl/Makefile: New.

This patch contains the main code of m68k/ColdFire NPTL support.
Please note that several additional fixes (see subsequent patches)
are necessary to make GLIBC build and work properly.
---
 sysdeps/m68k/dl-machine.h                          |   23 ++-
 sysdeps/m68k/dl-tls.h                              |   47 ++++
 sysdeps/m68k/libc-tls.c                            |   37 +++
 sysdeps/m68k/nptl/Makefile                         |   21 ++
 sysdeps/m68k/nptl/pthread_spin_lock.c              |   30 ++
 sysdeps/m68k/nptl/pthread_spin_trylock.c           |   27 ++
 sysdeps/m68k/nptl/pthreaddef.h                     |   38 +++
 sysdeps/m68k/nptl/tcb-offsets.sym                  |   11 +
 sysdeps/m68k/nptl/tls.h                            |  176 ++++++++++++
 sysdeps/m68k/tls-macros.h                          |   69 +++++
 sysdeps/unix/sysv/linux/m68k/Makefile              |    6 +
 sysdeps/unix/sysv/linux/m68k/Versions              |   12 +
 sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h      |   60 +++++
 sysdeps/unix/sysv/linux/m68k/clone.S               |   52 ++++-
 .../sysv/linux/m68k/coldfire/nptl/bits/atomic.h    |  104 ++++++++
 sysdeps/unix/sysv/linux/m68k/init-first.c          |   69 +++++
 sysdeps/unix/sysv/linux/m68k/m68k-helpers.S        |  108 ++++++++
 sysdeps/unix/sysv/linux/m68k/m68k-vdso.c           |   34 +++
 .../unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h  |  171 ++++++++++++
 sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h |   35 +++
 sysdeps/unix/sysv/linux/m68k/nptl/clone.S          |    2 +
 sysdeps/unix/sysv/linux/m68k/nptl/createthread.c   |   24 ++
 sysdeps/unix/sysv/linux/m68k/nptl/fork.c           |   29 ++
 sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h   |  280 ++++++++++++++++++++
 sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S       |   35 +++
 sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c   |   90 +++++++
 sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h  |  148 +++++++++++
 sysdeps/unix/sysv/linux/m68k/nptl/vfork.S          |   37 +++
 sysdeps/unix/sysv/linux/m68k/socket.S              |   28 ++-
 sysdeps/unix/sysv/linux/m68k/vfork.S               |   18 ++-
 30 files changed, 1807 insertions(+), 14 deletions(-)
 create mode 100644 sysdeps/m68k/dl-tls.h
 create mode 100644 sysdeps/m68k/libc-tls.c
 create mode 100644 sysdeps/m68k/nptl/Makefile
 create mode 100644 sysdeps/m68k/nptl/pthread_spin_lock.c
 create mode 100644 sysdeps/m68k/nptl/pthread_spin_trylock.c
 create mode 100644 sysdeps/m68k/nptl/pthreaddef.h
 create mode 100644 sysdeps/m68k/nptl/tcb-offsets.sym
 create mode 100644 sysdeps/m68k/nptl/tls.h
 create mode 100644 sysdeps/m68k/tls-macros.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/init-first.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
 create mode 100644 sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/clone.S
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/fork.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/vfork.S

diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
index 08a4396..098dc8d 100644
--- a/sysdeps/m68k/dl-machine.h
+++ b/sysdeps/m68k/dl-machine.h
@@ -1,5 +1,6 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  m68k version.
-   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 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
@@ -24,6 +25,7 @@
 
 #include <sys/param.h>
 #include <sysdep.h>
+#include <dl-tls.h>
 
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int
@@ -262,6 +264,25 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 	case R_68K_PC32:
 	  *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
 	  break;
+#if defined USE_TLS && !defined RTLD_BOOTSTRAP
+	case R_68K_TLS_DTPMOD32:
+	  /* Get the information from the link map returned by the
+	     resolv function.  */
+	  if (sym_map != NULL)
+	    *reloc_addr = sym_map->l_tls_modid;
+	  break;
+	case R_68K_TLS_DTPREL32:
+	  if (sym != NULL)
+	    *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
+	  break;
+	case R_68K_TLS_TPREL32:
+	  if (sym != NULL)
+	    {
+	      CHECK_STATIC_TLS (map, sym_map);
+	      *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
+	    }
+	  break;
+#endif /* defined USE_TLS && !defined RTLD_BOOTSTRAP */
 	case R_68K_NONE:		/* Alright, Wilbur.  */
 	  break;
 	default:
diff --git a/sysdeps/m68k/dl-tls.h b/sysdeps/m68k/dl-tls.h
new file mode 100644
index 0000000..249e0e2
--- /dev/null
+++ b/sysdeps/m68k/dl-tls.h
@@ -0,0 +1,47 @@
+/* Thread-local storage handling in the ELF dynamic linker.  M68K version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* The thread pointer points 0x7000 past the first static TLS block.  */
+#define TLS_TP_OFFSET		0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET		0x8000
+
+/* Compute the value for a TPREL reloc.  */
+#define TLS_TPREL_VALUE(sym_map, sym, reloc)				\
+  ((sym_map)->l_tls_offset + (sym)->st_value + (reloc)->r_addend	\
+   - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc.  */
+#define TLS_DTPREL_VALUE(sym, reloc)				\
+  ((sym)->st_value + (reloc)->r_addend - TLS_DTV_OFFSET)
+
+extern void *__tls_get_addr (tls_index *ti);
+
+#define GET_ADDR_OFFSET	        (ti->ti_offset + TLS_DTV_OFFSET)
+#define __TLS_GET_ADDR(__ti)	(__tls_get_addr (__ti) - TLS_DTV_OFFSET)
diff --git a/sysdeps/m68k/libc-tls.c b/sysdeps/m68k/libc-tls.c
new file mode 100644
index 0000000..b4e5129
--- /dev/null
+++ b/sysdeps/m68k/libc-tls.c
@@ -0,0 +1,37 @@
+/* Thread-local storage handling in the ELF dynamic linker.  m68k version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <csu/libc-tls.c>
+#include <dl-tls.h>
+
+#if USE_TLS
+
+/* On M68K, linker optimizations are not required, so __tls_get_addr
+   can be called even in statically linked binaries.  In this case module
+   must be always 1 and PT_TLS segment exist in the binary, otherwise it
+   would not link.  */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET;
+}
+
+#endif
diff --git a/sysdeps/m68k/nptl/Makefile b/sysdeps/m68k/nptl/Makefile
new file mode 100644
index 0000000..f0bcefb
--- /dev/null
+++ b/sysdeps/m68k/nptl/Makefile
@@ -0,0 +1,21 @@
+# Copyright (C) 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; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/sysdeps/m68k/nptl/pthread_spin_lock.c b/sysdeps/m68k/nptl/pthread_spin_lock.c
new file mode 100644
index 0000000..413e8cc
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthread_spin_lock.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  while (atomic_compare_and_exchange_val_acq(lock, 1, 0) != 0)
+   while (*lock != 0)
+    ;
+
+  return 0;
+}
diff --git a/sysdeps/m68k/nptl/pthread_spin_trylock.c b/sysdeps/m68k/nptl/pthread_spin_trylock.c
new file mode 100644
index 0000000..d2b4870
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthread_spin_trylock.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  return atomic_compare_and_exchange_val_acq(lock, 1, 0) ? EBUSY : 0;
+}
diff --git a/sysdeps/m68k/nptl/pthreaddef.h b/sysdeps/m68k/nptl/pthreaddef.h
new file mode 100644
index 0000000..e52694d
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthreaddef.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* 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/sysdeps/m68k/nptl/tcb-offsets.sym b/sysdeps/m68k/nptl/tcb-offsets.sym
new file mode 100644
index 0000000..b1bba65
--- /dev/null
+++ b/sysdeps/m68k/nptl/tcb-offsets.sym
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Derive offsets relative to the thread register.
+#define thread_offsetof(mem)	(long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads)
+PID_OFFSET			thread_offsetof (pid)
+TID_OFFSET			thread_offsetof (tid)
diff --git a/sysdeps/m68k/nptl/tls.h b/sysdeps/m68k/nptl/tls.h
new file mode 100644
index 0000000..887ee68
--- /dev/null
+++ b/sysdeps/m68k/nptl/tls.h
@@ -0,0 +1,176 @@
+/* Definition for thread-local data handling.  NPTL/m68k version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H	1
+
+#include <dl-sysdep.h>
+
+#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.  */
+#ifndef HAVE_TLS_SUPPORT
+# error "TLS support is required."
+#endif
+
+/* 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 <nptl/descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_INIT_TCB_SIZE	0
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN	__alignof__ (struct pthread)
+
+/* This is the size of the TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_TCB_SIZE		0
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN		__alignof__ (struct pthread)
+
+/* This is the size we need before TCB - actually, it includes the TCB.  */
+# define TLS_PRE_TCB_SIZE						\
+  (sizeof (struct pthread)						\
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* The thread pointer (TP) points to the end of the
+   TCB + 0x7000, as for PowerPC and MIPS.  This implies that TCB address is
+   TP - 0x7000.  As we define TLS_DTV_AT_TP we can
+   assume that the pthread struct is allocated immediately ahead of the
+   TCB.  This implies that the pthread_descr address is
+   TP - (TLS_PRE_TCB_SIZE + 0x7000).  */
+# define TLS_TCB_OFFSET	0x7000
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV () = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall)					\
+  ({									\
+    INTERNAL_SYSCALL_DECL (err);					\
+    int _sys_result;							\
+									\
+    _sys_result = INTERNAL_SYSCALL (write_tp, err, 1,			\
+				    ((void *) (tcbp)) + TLS_TCB_OFFSET); \
+    INTERNAL_SYSCALL_ERROR_P (_sys_result, err) ? "unknown error" : NULL; })
+
+extern void * __m68k_read_tp (void);
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) (__m68k_read_tp () - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+  ((struct pthread *) (__m68k_read_tp () - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Access to data in the thread descriptor is easy.  */
+# define THREAD_GETMEM(descr, member) \
+  descr->member
+# define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+# define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* l_tls_offset == 0 is perfectly valid on M68K, so we have to use some
+   different value to mean unset l_tls_offset.  */
+# define NO_TLS_OFFSET		-1
+
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG()					\
+  do									\
+    { int __res								\
+	= atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,	\
+			       THREAD_GSCOPE_FLAG_UNUSED);		\
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)				\
+	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+    }									\
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG()					\
+  do									\
+    {									\
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;	\
+      atomic_write_barrier ();						\
+    }									\
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif	/* tls.h */
diff --git a/sysdeps/m68k/tls-macros.h b/sysdeps/m68k/tls-macros.h
new file mode 100644
index 0000000..a15f8b9
--- /dev/null
+++ b/sysdeps/m68k/tls-macros.h
@@ -0,0 +1,69 @@
+/* Macros for accessing thread-local storage.  m68k version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define TLS_GD(x)							\
+  ({									\
+    void *__result;							\
+    extern void *__tls_get_addr (void *);				\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "lea " #x "@TLSGD(%0), %0"					\
+	 : "=&a" (__result));						\
+    (int *) __tls_get_addr (__result); })
+
+#define TLS_LD(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void *__tls_get_addr (void *);				\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "lea " #x "@TLSLDM(%0), %0"					\
+	 : "=&a" (__tp));						\
+    __tp = (char *) __tls_get_addr (__tp);				\
+    asm ("movel #" #x "@TLSLDO, %0"					\
+	 : "=a" (__offset));						\
+    (int *) (__tp + __offset); })
+
+#define TLS_IE(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void * __m68k_read_tp (void);				\
+									\
+    __tp = (char *) __m68k_read_tp ();					\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "movel " #x "@TLSIE(%0), %0"					\
+	 : "=&a" (__offset));						\
+    (int *) (__tp + __offset); })
+
+#define TLS_LE(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void * __m68k_read_tp (void);				\
+									\
+    __tp = (char *) __m68k_read_tp ();					\
+    asm ("movel #" #x "@TLSLE, %0"					\
+	 : "=a" (__offset));						\
+    (int *) (__tp + __offset); })
+
diff --git a/sysdeps/unix/sysv/linux/m68k/Makefile b/sysdeps/unix/sysv/linux/m68k/Makefile
index 6bb4f6b..64627c6 100644
--- a/sysdeps/unix/sysv/linux/m68k/Makefile
+++ b/sysdeps/unix/sysv/linux/m68k/Makefile
@@ -2,12 +2,18 @@
 
 m68k-syntax-flag = -DMOTOROLA_SYNTAX
 
+ifeq ($(subdir),csu)
+sysdep_routines += m68k-helpers m68k-vdso
+endif
+
 ifeq ($(subdir),misc)
 sysdep_routines += mremap
 sysdep_headers += sys/reg.h
 endif
 
 ifeq ($(subdir),elf)
+sysdep_routines += dl-vdso m68k-vdso
+sysdep-rtld-routines += m68k-vdso
 sysdep-others += lddlibc4
 install-bin += lddlibc4
 endif
diff --git a/sysdeps/unix/sysv/linux/m68k/Versions b/sysdeps/unix/sysv/linux/m68k/Versions
index 5650f7f..152f7aa 100644
--- a/sysdeps/unix/sysv/linux/m68k/Versions
+++ b/sysdeps/unix/sysv/linux/m68k/Versions
@@ -31,5 +31,17 @@ libc {
   }
   GLIBC_2.11 {
     fallocate64;
+    __m68k_read_tp;
+  }
+  GLIBC_PRIVATE {
+    __vdso_atomic_cmpxchg_32; __vdso_atomic_barrier;
+  }
+}
+
+ld {
+  GLIBC_PRIVATE {
+    __rtld___vdso_read_tp;
+    __rtld___vdso_atomic_cmpxchg_32;
+    __rtld___vdso_atomic_barrier;
   }
 }
diff --git a/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
new file mode 100644
index 0000000..3d809cf
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
@@ -0,0 +1,60 @@
+/* Resolve function pointers to VDSO functions.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+#ifndef _M68K_VDSO_H
+#define _M68K_VDSO_H
+
+#ifdef SHARED
+
+# ifdef IS_IN_rtld
+# define M68K_VDSO_SYMBOL(name) __rtld_##name
+# define STR_M68K_VDSO_SYMBOL(name) "__rtld_" #name
+# else
+# define M68K_VDSO_SYMBOL(name) name
+# define STR_M68K_VDSO_SYMBOL(name) #name
+# endif
+
+# ifndef __ASSEMBLER__
+
+/* We define __rtld_* copies for rtld.
+   We need them visible in libc to initialize.  */
+#  if defined IS_IN_rtld || !defined NOT_IN_libc
+extern void *__rtld___vdso_read_tp;
+extern void *__rtld___vdso_atomic_cmpxchg_32;
+extern void *__rtld___vdso_atomic_barrier;
+
+/* These stubs are meant to be invoked only from the assembly.  */
+extern void __vdso_read_tp_stub (void);
+extern void __vdso_atomic_cmpxchg_32_stub (void);
+extern void __vdso_atomic_barrier_stub (void);
+#  endif /* IS_IN_rtld || !NOT_IN_libc */
+
+/* RTLD should only use its own copies.  */
+#  ifndef IS_IN_rtld
+extern void *__vdso_read_tp;
+extern void *__vdso_atomic_cmpxchg_32;
+extern void *__vdso_atomic_barrier;
+#  endif /* !IS_IN_rtld */
+
+# endif /* !__ASSEMBLER__ */
+
+#endif /* SHARED */
+
+#endif /* _M68K_VDSO_H */
diff --git a/sysdeps/unix/sysv/linux/m68k/clone.S b/sysdeps/unix/sysv/linux/m68k/clone.S
index a179f8e..4135cd0 100644
--- a/sysdeps/unix/sysv/linux/m68k/clone.S
+++ b/sysdeps/unix/sysv/linux/m68k/clone.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996,97,98,2002,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
 
@@ -17,14 +17,21 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-/* clone is even more special than fork as it mucks with stacks
+/* clone() is even more special than fork() as it mucks with stacks
    and invokes a function in the right context after its all over.  */
 
 #include <sysdep.h>
 #define _ERRNO_H	1
 #include <bits/errno.h>
+#ifdef RESET_PID
+#include <tls.h>
+#endif
+
+#define CLONE_VM      0x00000100
+#define CLONE_THREAD  0x00010000
 
-/* 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,
+	     void *parent_tidptr, void *tls, void *child_tidptr) */
 
         .text
 ENTRY (__clone)
@@ -42,7 +49,17 @@ ENTRY (__clone)
 	movel	16(%sp), -(%a1)
 
 	/* Do the system call */
-	movel	12(%sp), %d1		/* get flags */
+	movel	12+0(%sp), %d1		/* get flags */
+	movel	%d3, -(%a1)             /* save %d3 and get parent_tidptr */
+	movel	%d3, -(%sp)
+	movel	20+4(%sp), %d3
+	movel	%d4, -(%a1)		/* save %d4 and get child_tidptr */
+	movel	%d4, -(%sp)
+	movel	28+8(%sp), %d4
+	movel	%d5, -(%a1)             /* save %d5 and get tls */
+	movel	%d5, -(%sp)
+	movel	24+12(%sp), %d5
+	/* save %d2 and get stack pointer */
 #ifdef __mcoldfire__
 	movel	%d2, -(%a1)
 	movel	%d2, -(%sp)
@@ -57,6 +74,9 @@ ENTRY (__clone)
 #else
 	exg	%d2, %a1		/* restore %d2 */
 #endif
+	movel	(%sp)+, %d5             /* restore %d5, %d4 and %d3 */
+	movel	(%sp)+, %d4
+	movel	(%sp)+, %d3
 
 	tstl	%d0
 	jmi	SYSCALL_ERROR_LABEL
@@ -65,11 +85,35 @@ ENTRY (__clone)
 	rts
 
 thread_start:
+	cfi_startproc
+	cfi_undefined (pc)	/* Mark end of stack */
 	subl	%fp, %fp	/* terminate the stack frame */
+#ifdef RESET_PID
+	/* Check and see if we need to reset the PID.  */
+	movel	%d1, %a1
+	andl	#CLONE_THREAD, %d1
+	jne	donepid
+	movel	%a1, %d1
+	movel	#-1, %d0
+	andl	#CLONE_VM, %d1
+	jne	gotpid
+	movel	#SYS_ify (getpid), %d0
+	trap	#0
+gotpid:
+	movel	%a0, -(%sp)
+	movel	%d0, -(%sp)
+	bsrl	__m68k_read_tp@PLTPC
+	movel	(%sp)+, %d0
+	movel	%d0, PID_OFFSET(%a0)
+	movel	%d0, TID_OFFSET(%a0)
+	movel	(%sp)+, %a0
+donepid:
+#endif
 	jsr	(%a0)
 	movel	%d0, %d1
 	movel	#SYS_ify (exit), %d0
 	trap	#0
+	cfi_endproc
 
 PSEUDO_END (__clone)
 
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
new file mode 100644
index 0000000..972eb17
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H	1
+
+#include <stdint.h>
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+/* Coldfire has no atomic compare-and-exchange operation, but the
+   kernel provides userspace atomicity operations.  Use them.  */
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+/* The only basic operation needed is compare and exchange.  */
+/* For ColdFire we'll have to trap into the kernel mode anyway,
+   so trap from the library rather then from the kernel wrapper.  */
+#ifdef SHARED
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  ({									\
+    /* Use temporary variables to workaround call-clobberness of */	\
+    /* the registers.  */						\
+    __typeof (mem) _mem = mem;						\
+    __typeof (oldval) _oldval = oldval;					\
+    __typeof (newval) _newval = newval;					\
+    register __typeof (mem) _a0 asm ("a0") = _mem;			\
+    register __typeof (oldval) _d0 asm ("d0") = _oldval;		\
+    register __typeof (newval) _d1 asm ("d1") = _newval;		\
+    void *tmp;								\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %2\n\t"			\
+	 "lea (-6, %%pc, %2), %2\n\t"					\
+	 "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)	\
+	 "@GOT(%2), %2\n\t"						\
+	 "movel (%2), %2\n\t"						\
+	 "jsr (%2)\n\t"							\
+	 : "+d" (_d0), "+m" (*_a0), "=&a" (tmp)				\
+	 : "a" (_a0), "d" (_d1));					\
+    _d0;								\
+  })
+#else
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  ({									\
+    /* Use temporary variables to workaround call-clobberness of */	\
+    /* the registers.  */						\
+    __typeof (mem) _mem = mem;						\
+    __typeof (oldval) _oldval = oldval;					\
+    __typeof (newval) _newval = newval;					\
+    register __typeof (oldval) _d0 asm ("d0")				\
+      = SYS_ify (atomic_cmpxchg_32);					\
+    register __typeof (mem) _a0 asm ("a0") = _mem;			\
+    register __typeof (oldval) _d2 asm ("d2") = _oldval;		\
+    register __typeof (newval) _d1 asm ("d1") = _newval;		\
+									\
+    asm ("trap #0"							\
+	 : "+d" (_d0), "+m" (*_a0)					\
+	 : "a" (_a0), "d" (_d2), "d" (_d1));				\
+    _d0;								\
+  })
+#endif
+
+#ifdef SHARED
+# define atomic_full_barrier()					 \
+  ({								 \
+    void *tmp;							 \
+								 \
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"		 \
+	 "lea (-6, %pc, %0), %0\n\t"				 \
+	 "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_barrier)	 \
+	 "@GOT(%0), %0\n\t"					 \
+	 "movel (%0), %0\n\t"					 \
+	 "jsr (%0)\n\t"						 \
+	 : "=&a" (tmp));					 \
+  })
+#else
+# define atomic_full_barrier()				\
+  (INTERNAL_SYSCALL (atomic_barrier, , 0), (void) 0)
+#endif
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/init-first.c b/sysdeps/unix/sysv/linux/m68k/init-first.c
new file mode 100644
index 0000000..951b6fe
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/init-first.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Note: linking in vDSO to a static binary requires changes to
+   the main GLIBC proper.  Not yet implemented.  */
+#ifdef SHARED
+
+#include <dl-vdso.h>
+#include <bits/m68k-vdso.h>
+
+static inline void
+_libc_vdso_platform_setup (void)
+{
+  void *p;
+
+  PREPARE_VERSION (linux26, "LINUX_2.6", 61765110);
+
+  /* It may happen that rtld didn't initialize the vDSO, so fallback
+     to the syscall implementations if _dl_vdso_vsym returns NULL.
+     This may happen when a static executable dlopen's a dynamic library.
+     This really is nothing more than a workaround for rtld/csu
+     deficiency.  Ideally, init code would setup the vDSO for static
+     binaries too.  */
+
+  p = _dl_vdso_vsym ("__kernel_read_tp", &linux26);
+  if (p != NULL)
+    __vdso_read_tp = p;
+  else
+    assert (__vdso_read_tp == (void *) __vdso_read_tp_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_cmpxchg_32", &linux26);
+  if (p != NULL)
+    __vdso_atomic_cmpxchg_32 = p;
+  else
+    assert (__vdso_atomic_cmpxchg_32
+	    == (void *) __vdso_atomic_cmpxchg_32_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_barrier", &linux26);
+  if (p != NULL)
+    __vdso_atomic_barrier = p;
+  else
+    assert (__vdso_atomic_barrier == (void *) __vdso_atomic_barrier_stub);
+
+  /* Non-shared libc has only one set of the VDSO pointers.  */
+  __rtld___vdso_read_tp = __vdso_read_tp;
+  __rtld___vdso_atomic_cmpxchg_32 = __vdso_atomic_cmpxchg_32;
+  __rtld___vdso_atomic_barrier = __vdso_atomic_barrier;
+}
+
+#define VDSO_SETUP _libc_vdso_platform_setup
+
+#endif /* SHARED */
+
+#include <sysdeps/unix/sysv/linux/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
new file mode 100644
index 0000000..580c565
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
@@ -0,0 +1,108 @@
+/* Copyright (C) 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.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifdef HAVE_TLS_SUPPORT
+
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+	.text
+
+	.hidden __vdso_read_tp_stub
+ENTRY (__vdso_read_tp_stub)
+	cfi_startproc
+	move.l	#__NR_read_tp, %d0
+	trap	#0
+	move.l	%d0, %a0
+	rts
+	cfi_endproc
+END (__vdso_read_tp_stub)
+
+# ifdef SHARED
+/* GCC will emit calls to this routine.  Linux has an
+   equivalent helper function (which clobbers fewer registers than
+   a normal function call) in a vdso; tail call to the
+   helper.  */
+# ifdef IS_IN_rtld
+/* rtld gets a hidden copy of __m68k_read_tp.  */
+	.hidden __m68k_read_tp
+# endif
+ENTRY (__m68k_read_tp)
+	cfi_startproc
+	move.l	#_GLOBAL_OFFSET_TABLE_@GOTPC, %a0
+	lea	(-6, %pc, %a0), %a0
+	move.l	M68K_VDSO_SYMBOL (__vdso_read_tp)@GOT(%a0), %a0
+	move.l	(%a0), %a0
+	jmp	(%a0)
+	cfi_endproc
+END (__m68k_read_tp)
+
+/* The following two stubs are for macros in atomic.h, they can't
+   clobber anything.  */
+
+	.hidden __vdso_atomic_cmpxchg_32_stub
+ENTRY (__vdso_atomic_cmpxchg_32_stub)
+	cfi_startproc
+	move.l	%d2, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
+	move.l	%d0, %d2
+	move.l	#SYS_ify (atomic_cmpxchg_32), %d0
+	trap	#0
+	move.l	(%sp)+, %d2
+	cfi_adjust_cfa_offset (-4)
+	cfi_restore (%d2)
+	rts
+	cfi_endproc
+END (__vdso_atomic_cmpxchg_32_stub)
+	
+	.hidden __vdso_atomic_barrier_stub
+ENTRY (__vdso_atomic_barrier_stub)
+	cfi_startproc
+	move.l	%d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	move.l	#SYS_ify (atomic_barrier), %d0
+	trap	#0
+	move.l	(%sp)+, %d0
+	cfi_adjust_cfa_offset (-4)
+	rts
+	cfi_endproc
+END (__vdso_atomic_barrier_stub)
+# else /* !SHARED */
+/* If the vDSO is not available, use a syscall to get TP.  */
+	strong_alias (__vdso_read_tp_stub, __m68k_read_tp)
+# endif /* SHARED */
+
+#endif /* HAVE_TLS_SUPPORT */
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
new file mode 100644
index 0000000..a605039
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifdef SHARED
+
+#include <bits/m68k-vdso.h>
+
+/* Because these pointers are used from other libraries than libc,
+   they are exported at GLIBC_PRIVATE version.
+   We initialize them to syscall implementation so that they will be ready
+   to use from the very beginning.  */
+void * M68K_VDSO_SYMBOL (__vdso_read_tp)
+= (void *) __vdso_read_tp_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)
+= (void *) __vdso_atomic_cmpxchg_32_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_barrier)
+= (void *) __vdso_atomic_barrier_stub;
+
+#endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
new file mode 100644
index 0000000..b3c719c
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
@@ -0,0 +1,171 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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_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
+   deliberately not exposed.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+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 deliberately not exposed.  */
+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;
+
+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 deliberately not exposed.  */
+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 deliberately not exposed.  */
+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;
+    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;
+    int __writer;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+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/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
new file mode 100644
index 0000000..c72ddcc
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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/sysdeps/unix/sysv/linux/m68k/nptl/clone.S b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
new file mode 100644
index 0000000..e7388fe
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include "../clone.S"
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
new file mode 100644
index 0000000..537a5e9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE ((void *) (pd) \
+		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation.	 */
+#include <nptl/sysdeps/pthread/createthread.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/fork.c b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
new file mode 100644
index 0000000..1e4de36
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
@@ -0,0 +1,29 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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, &THREAD_SELF->tid, NULL)
+
+#include <sysdeps/unix/sysv/linux/fork.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
new file mode 100644
index 0000000..8ab444b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
@@ -0,0 +1,280 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Borrowed from ARM's version.  */
+
+#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 <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 __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAIT, private),	      \
+			      (val), (timespec));			      \
+    __ret;								      \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAKE, private),	      \
+			      (nr), 0);					      \
+    __ret;								      \
+  })
+
+#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 __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),		      \
+			      __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+			      (nr_wake), (nr_move), (mutex), (val));	      \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __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 __ret;							      \
+    __ret = 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 (__ret, __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(lock, id)			\
+  atomic_compare_and_exchange_val_acq (&(lock), id, 0)
+
+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 (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex,       \
+								1, 0), 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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+								0), 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 (__builtin_expect (atomic_exchange_acq (__futex, 2), 0))		      \
+      __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 (__builtin_expect (atomic_exchange_acq (__futex, 1), 0))	      \
+       __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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+								0), 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 (__builtin_expect (__oldval > 1, 0))			\
+	 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 (__builtin_expect (__oldval & FUTEX_WAITERS, 0))	\
+	 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/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
new file mode 100644
index 0000000..087a3bb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
@@ -0,0 +1,35 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+	bsrl	__m68k_read_tp@PLTPC	; /* Get the thread pointer.  */ \
+	movel	%a0, %a1		; /* Save TP for RESTORE_PID.  */ \
+	movel	PID_OFFSET(%a1), %d0	; /* Get the PID.  */ \
+	movel	%d0, %d1		; /* Save PID for RESTORE_PID.  */ \
+	negl	%d0			; /* Negate the PID.  */ \
+	movel	%d0, PID_OFFSET(%a1)	; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+	tstl	%d0			; \
+	beq	1f			; /* If we are the parent... */ \
+	movel	%d1, PID_OFFSET(%a1)	; /* Restore the PID.  */ \
+1:	
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
new file mode 100644
index 0000000..6ef86b2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
@@ -0,0 +1,90 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
new file mode 100644
index 0000000..5ed7486
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
@@ -0,0 +1,148 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				      \
+  .text;								      \
+  ENTRY (name)								      \
+    SINGLE_THREAD_P;							      \
+    jne .Lpseudo_cancel;						      \
+  .type __##syscall_name##_nocancel,@function;			              \
+  .globl __##syscall_name##_nocancel;				 	      \
+  __##syscall_name##_nocancel:					              \
+    DO_CALL (syscall_name, args);					      \
+    cmp.l &-4095, %d0;							      \
+    jcc SYSCALL_ERROR_LABEL;						      \
+    rts;								      \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \
+  .Lpseudo_cancel:							      \
+    cfi_startproc;							      \
+    CENABLE;								      \
+    DOCARGS_##args							      \
+    move.l %d0, -(%sp); /* Save result of CENABLE.  */  		      \
+    cfi_adjust_cfa_offset (4); \
+    move.l &SYS_ify (syscall_name), %d0;				      \
+    trap &0;								      \
+    move.l %d0, %d2;							      \
+    CDISABLE;								      \
+    addq.l &4, %sp; /* Remove result of CENABLE from the stack.  */           \
+    cfi_adjust_cfa_offset (-4); \
+    move.l %d2, %d0;							      \
+    UNDOCARGS_##args							      \
+    cmp.l &-4095, %d0;							      \
+    jcc SYSCALL_ERROR_LABEL;		                                      \
+    cfi_endproc
+
+/* Note: we use D2 to save syscall's return value as D0 will be clobbered in
+   CDISABLE.  */
+# define DOCARGS_0	move.l %d2, -(%sp);		\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d2, 0);
+# define UNDOCARGS_0	move.l (%sp)+, %d2;	\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d2);
+
+# define DOCARGS_1	_DOCARGS_1 (4); DOCARGS_0
+# define _DOCARGS_1(n)	move.l n(%sp), %d1;
+# define UNDOCARGS_1	UNDOCARGS_0
+
+# define DOCARGS_2	_DOCARGS_2 (8)
+# define _DOCARGS_2(n)	DOCARGS_0 move.l n+4(%sp), %d2; _DOCARGS_1 (n)
+# define UNDOCARGS_2	UNDOCARGS_0
+
+/* TODO: We can optimize DOCARGS_{3, 4} by saving registers to a0 and a1
+   instead of pushing them on stack.  */
+# define DOCARGS_3	_DOCARGS_3 (12)
+# define _DOCARGS_3(n)	move.l %d3, -(%sp);				\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d3, 0);			\
+  move.l n+4(%sp), %d3; _DOCARGS_2 (n)
+# define UNDOCARGS_3	UNDOCARGS_2 move.l (%sp)+, %d3;		\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d3);
+
+# define DOCARGS_4	_DOCARGS_4 (16)
+# define _DOCARGS_4(n)	move.l %d4, -(%sp);			\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d4, 0);		\
+  move.l n+4(%sp), %d4; _DOCARGS_3 (n)
+# define UNDOCARGS_4	UNDOCARGS_3 move.l (%sp)+, %d4;	\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d4);
+
+# define DOCARGS_5	_DOCARGS_5 (20)
+# define _DOCARGS_5(n)	move.l %d5, %a1; cfi_register (%d5, a1); \
+  move.l n(%sp), %d5; _DOCARGS_4 (n-4)
+# define UNDOCARGS_5	UNDOCARGS_4 move.l %a1, %d5; cfi_restore (%d5);
+
+# define DOCARGS_6	_DOCARGS_6 (24)
+# define _DOCARGS_6(n)	move.l n(%sp), %a0; _DOCARGS_5 (n-4)
+# define UNDOCARGS_6	UNDOCARGS_5
+
+# ifdef PIC
+#  define PSEUDO_JMP(sym) jbsr sym ## @PLTPC
+# else
+#  define PSEUDO_JMP(sym) jbsr sym
+# endif
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	PSEUDO_JMP (__pthread_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__pthread_disable_asynccancel)
+# elif !defined NOT_IN_libc
+#  define CENABLE	PSEUDO_JMP (__libc_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__libc_disable_asynccancel)
+# elif defined IS_IN_librt
+#  define CENABLE	PSEUDO_JMP (__librt_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__librt_disable_asynccancel)
+# else
+#  error Unsupported library
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P						\
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\
+				   header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P			\
+  PSEUDO_JMP (__m68k_read_tp);		        \
+  tst.l MULTIPLE_THREADS_OFFSET(%a0)
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION (1)
+
+#endif
+
+#ifndef __ASSEMBLER__
+# ifdef SHARED
+#  define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (M68K_VDSO_SYMBOL (__vdso_read_tp) != NULL \
+		    ? THREAD_GETMEM (THREAD_SELF, \
+				     header.multiple_threads) == 0 \
+		    : 1, 1)
+# else
+#  define RTLD_SINGLE_THREAD_P					  \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,			  \
+				   header.multiple_threads) == 0, \
+		    1)
+# endif
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
new file mode 100644
index 0000000..d7fd1de
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
@@ -0,0 +1,37 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+	bsrl	__m68k_read_tp@PLTPC	; /* Get the thread pointer.  */ \
+	movel	%a0, %a1		; /* Save TP for RESTORE_PID.  */ \
+	movel	PID_OFFSET(%a1), %d0	; /* Get the PID.  */ \
+	movel	%d0, %d1		; /* Save PID for RESTORE_PID.  */ \
+	negl	%d0			; /* Negate the PID.  */ \
+	bne	1f			; /* If it was zero... */ \
+	movel	#0x80000000, %d0	; /* use 0x80000000 instead.  */ \
+1:	movel	%d0, PID_OFFSET(%a1)	; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+	tstl	%d0			; \
+	beq	1f			; /* If we are the parent... */ \
+	movel	%d1, PID_OFFSET(%a1)	; /* Restore the PID.  */ \
+1:	
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/socket.S b/sysdeps/unix/sysv/linux/m68k/socket.S
index 2690f18..d895e94 100644
--- a/sysdeps/unix/sysv/linux/m68k/socket.S
+++ b/sysdeps/unix/sysv/linux/m68k/socket.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 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
@@ -41,8 +41,11 @@
 
 .globl __socket
 ENTRY (__socket)
-#if defined NEED_CANCELLATION && defined CENABLE
-	SINGLE_THREAD_P (%a0)
+#ifdef NEED_CANCELLATION
+# if !defined CENABLE || !defined CDISABLE
+#  error CENABLE and/or CDISABLE is not defined
+# endif
+	SINGLE_THREAD_P
 	jne 1f
 #endif
 
@@ -69,21 +72,26 @@ ENTRY (__socket)
 	/* Successful; return the syscall's value.  */
 	rts
 
-#if defined NEED_CANCELLATION && defined CENABLE
-1:	/* Enable asynchronous cancellation.  */
+#ifdef NEED_CANCELLATION
+1:	cfi_startproc
+	/* Enable asynchronous cancellation.  */
 	CENABLE
 
-	/* Save registers.  */
+	/* Save D2.  */
 	move.l %d2, -(%sp)
-	move.l %d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
 
-	move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
+	/* Save the result of CENABLE.  */
+	move.l %d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
 
 	/* Use ## so `socket' is a separate token that might be #define'd.  */
 	move.l #P (SOCKOP_,socket), %d1	/* Subcode is first arg to syscall.  */
 	lea 4+8(%sp), %a1		/* Address of args is 2nd arg.  */
 	move.l %a1, %d2
 
+	move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
 	/* Do the system call trap.  */
 	trap #0
 
@@ -91,14 +99,18 @@ ENTRY (__socket)
 	move.l %d0, %d2
 	CDISABLE
 	addq.l #4, %sp
+	cfi_adjust_cfa_offset (-4)
 	move.l %d2, %d0
 
 	/* Restore registers.  */
 	move.l (%sp)+, %d2
+	cfi_adjust_cfa_offset (-4)
+	cfi_restore (%d2)
 
 	/* %d0 is < 0 if there was an error.  */
 	tst.l %d0
 	jmi SYSCALL_ERROR_LABEL
+	cfi_endproc
 
 	/* Successful; return the syscall's value.  */
 	rts
diff --git a/sysdeps/unix/sysv/linux/m68k/vfork.S b/sysdeps/unix/sysv/linux/m68k/vfork.S
index 8027b2f..5084a85 100644
--- a/sysdeps/unix/sysv/linux/m68k/vfork.S
+++ b/sysdeps/unix/sysv/linux/m68k/vfork.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2002, 2003, 2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab <schwab@gnu.org>.
 
@@ -22,6 +22,14 @@
 #include <bits/errno.h>
 #include <kernel-features.h>
 
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
 /* 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,
@@ -31,12 +39,20 @@ ENTRY (__vfork)
 
 #ifdef __NR_vfork
 
+	/* SAVE_PID clobbers call-clobbered registers and
+	   saves data in D1 and A1.  */
+
+	SAVE_PID
+	
 	/* Pop the return PC value into A0.  */
 	movel	%sp@+, %a0
 
 	/* Stuff the syscall number in D0 and trap into the kernel.  */
 	movel	#SYS_ify (vfork), %d0
 	trap	#0
+
+	RESTORE_PID
+
 	tstl	%d0
 	jmi	.Lerror		/* Branch forward if it failed.  */
 
-- 
1.6.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 4/n] Remove kernel headers
  2009-08-25 12:58 ` [M68K/ColdFire patch 4/n] Remove kernel headers Maxim Kuvyrkov
@ 2009-08-25 13:21   ` Andreas Schwab
  2009-08-25 14:25     ` Maxim Kuvyrkov
  0 siblings, 1 reply; 31+ messages in thread
From: Andreas Schwab @ 2009-08-25 13:21 UTC (permalink / raw)
  To: Maxim Kuvyrkov; +Cc: libc-ports

Maxim Kuvyrkov <maxim@codesourcery.com> writes:

> This patch removes 2 kernel headers -- sigcontext.h and ucontext.h -- 
> from GLIBC's m68k port. These headers are installed by the kernel,
> that has a better idea of how it lays out the signal context.
>
> This elegant patch is a result of about a day of debugging unwinding
> of the signal frames.
>
> Any comments?

You are breaking the ABI.

Andreas.

-- 
Andreas Schwab, schwab@redhat.com
GPG Key fingerprint = D4E8 DBE3 3813 BB5D FA84  5EC7 45C6 250E 6F00 984E
"And now for something completely different."

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [M68K/ColdFire patch 6/n] Add TLS relocations to elf/elf.h
  2009-08-25 12:27 [M68K/ColdFire] NPTL support and other updates Maxim Kuvyrkov
                   ` (4 preceding siblings ...)
  2009-08-25 13:04 ` [M68K/ColdFire patch 5/n] Main NPTL patch Maxim Kuvyrkov
@ 2009-08-25 13:39 ` Maxim Kuvyrkov
  2010-02-09 17:28   ` [m68k] " Maxim Kuvyrkov
  2009-08-25 13:43 ` [M68K/ColdFire patch 7/n] Handle libgcc_s.so.2 Maxim Kuvyrkov
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 13:39 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 166 bytes --]

This patch humbly adds definitions of the new TLS relocations to GLIBC.

This is one of the two patches that touch files outside of ports/.

--
Maxim K.
CodeSourcery

[-- Attachment #2: 0001-Add-m68k-TLS-relocations.patch --]
[-- Type: text/plain, Size: 2161 bytes --]

From f6b0706def343f5716b01d59626a0f823bdec2ea Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Tue, 25 Aug 2009 17:34:30 +0400
Subject: [PATCH] Add m68k TLS relocations.

	* elf/elf.h: Define m68k TLS relocations.
---
 elf/elf.h |   23 ++++++++++++++++++++++-
 1 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/elf/elf.h b/elf/elf.h
index ce6de07..61673de 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1117,8 +1117,29 @@ typedef struct
 #define R_68K_GLOB_DAT	20		/* Create GOT entry */
 #define R_68K_JMP_SLOT	21		/* Create PLT entry */
 #define R_68K_RELATIVE	22		/* Adjust by program base */
+#define R_68K_TLS_GD32      25          /* 32 bit GOT offset for GD */
+#define R_68K_TLS_GD16      26          /* 16 bit GOT offset for GD */
+#define R_68K_TLS_GD8       27          /* 8 bit GOT offset for GD */
+#define R_68K_TLS_LDM32     28          /* 32 bit GOT offset for LDM */
+#define R_68K_TLS_LDM16     29          /* 16 bit GOT offset for LDM */
+#define R_68K_TLS_LDM8      30          /* 8 bit GOT offset for LDM */
+#define R_68K_TLS_LDO32     31          /* 32 bit module-relative offset */
+#define R_68K_TLS_LDO16     32          /* 16 bit module-relative offset */
+#define R_68K_TLS_LDO8      33          /* 8 bit module-relative offset */
+#define R_68K_TLS_IE32      34          /* 32 bit GOT offset for IE */
+#define R_68K_TLS_IE16      35          /* 16 bit GOT offset for IE */
+#define R_68K_TLS_IE8       36          /* 8 bit GOT offset for IE */
+#define R_68K_TLS_LE32      37          /* 32 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_LE16      38          /* 16 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_LE8       39          /* 8 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_DTPMOD32  40          /* 32 bit module number */
+#define R_68K_TLS_DTPREL32  41          /* 32 bit module-relative offset */
+#define R_68K_TLS_TPREL32   42          /* 32 bit TP-relative offset */
 /* Keep this the last entry.  */
-#define R_68K_NUM	23
+#define R_68K_NUM	43
 
 /* Intel 80386 specific definitions.  */
 
-- 
1.6.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [M68K/ColdFire patch 7/n] Handle libgcc_s.so.2
  2009-08-25 12:27 [M68K/ColdFire] NPTL support and other updates Maxim Kuvyrkov
                   ` (5 preceding siblings ...)
  2009-08-25 13:39 ` [M68K/ColdFire patch 6/n] Add TLS relocations to elf/elf.h Maxim Kuvyrkov
@ 2009-08-25 13:43 ` Maxim Kuvyrkov
  2009-09-07 20:36 ` [M68K/ColdFire] NPTL support and other updates Andreas Schwab
  2010-02-09 19:01 ` Maxim Kuvyrkov
  8 siblings, 0 replies; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 13:43 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

As m68k GCC port has bumped version of libgcc_s.so to 2, one will need 
the patches from PR4457 
(http://sourceware.org/bugzilla/show_bug.cgi?id=4457) to fix that.

Regards,

--
Maxim K.
CodeSourcery

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 4/n] Remove kernel headers
  2009-08-25 13:21   ` Andreas Schwab
@ 2009-08-25 14:25     ` Maxim Kuvyrkov
  2009-08-25 14:41       ` Andreas Schwab
  0 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 14:25 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-ports

Andreas Schwab wrote:
> Maxim Kuvyrkov <maxim@codesourcery.com> writes:
> 
>> This patch removes 2 kernel headers -- sigcontext.h and ucontext.h -- 
>> from GLIBC's m68k port. These headers are installed by the kernel,
>> that has a better idea of how it lays out the signal context.
>>
>> This elegant patch is a result of about a day of debugging unwinding
>> of the signal frames.
>>
>> Any comments?
> 
> You are breaking the ABI.

Why?

For m68k the change is close to no-op, both kernel and GLIBC headers 
define the structures to be the same.

For ColdFire, there are two changes to GLIBC headers:

1. GLIBC headers set the size of the storage for FP registers to 8 
bytes.  While ColdFire FP register are 64-bit, the kernel does not 
distinguish between ColdFire and m68k in this case (and why should it?) 
and stores the FP registers to the 12-byte entries as on m68k.

2. GLIBC headers expect sigcontext structure to hold all 16 
general-purpose registers.  What is the foundation for this change from 
how m68k defines this structure?  The ColdFire kernel patches available 
at bitshrine.org do not change sigcontext.

Regards,

--
Maxim K.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 4/n] Remove kernel headers
  2009-08-25 14:25     ` Maxim Kuvyrkov
@ 2009-08-25 14:41       ` Andreas Schwab
  2009-08-25 15:28         ` Maxim Kuvyrkov
  0 siblings, 1 reply; 31+ messages in thread
From: Andreas Schwab @ 2009-08-25 14:41 UTC (permalink / raw)
  To: Maxim Kuvyrkov; +Cc: libc-ports

Maxim Kuvyrkov <maxim@codesourcery.com> writes:

> For m68k the change is close to no-op, both kernel and GLIBC headers
> define the structures to be the same.

No.  The SysV version of ucontext_t does not match the kernel definition
in any way.

Andreas.

-- 
Andreas Schwab, schwab@redhat.com
GPG Key fingerprint = D4E8 DBE3 3813 BB5D FA84  5EC7 45C6 250E 6F00 984E
"And now for something completely different."

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 4/n] Remove kernel headers
  2009-08-25 14:41       ` Andreas Schwab
@ 2009-08-25 15:28         ` Maxim Kuvyrkov
  2009-08-25 15:44           ` Andreas Schwab
  0 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 15:28 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-ports

Andreas Schwab wrote:
> Maxim Kuvyrkov <maxim@codesourcery.com> writes:
> 
>> For m68k the change is close to no-op, both kernel and GLIBC headers
>> define the structures to be the same.
> 
> No.  The SysV version of ucontext_t does not match the kernel definition
> in any way.

I'm afraid I don't follow you here.  From your words I get the idea that 
the difference between linux definition of ucontext_t and GLIBC's is 
intentional.  What I don't understand is how things are supposed to work 
then.

The ports/sysdeps/unix/sysv/linux/m68k/sys/ucontext.h file does indeed 
describe the SysV version of ucontext_t, not that of linux's.  But why 
it isn't in ports/sysdeps/unix/sysv/m68k/sys/ directory then?

--
Maxim

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 4/n] Remove kernel headers
  2009-08-25 15:28         ` Maxim Kuvyrkov
@ 2009-08-25 15:44           ` Andreas Schwab
  2009-08-25 16:52             ` Maxim Kuvyrkov
  0 siblings, 1 reply; 31+ messages in thread
From: Andreas Schwab @ 2009-08-25 15:44 UTC (permalink / raw)
  To: Maxim Kuvyrkov; +Cc: libc-ports

Maxim Kuvyrkov <maxim@codesourcery.com> writes:

> The ports/sysdeps/unix/sysv/linux/m68k/sys/ucontext.h file does indeed
> describe the SysV version of ucontext_t, not that of linux's.

No, it doesn't.  It describes exactly the Linux kernel definition
(modulo sigmask size).  If you remove it you get the wrong SysV version.

> But why it isn't in ports/sysdeps/unix/sysv/m68k/sys/ directory then?

I don't understand that question.

Andreas.

-- 
Andreas Schwab, schwab@redhat.com
GPG Key fingerprint = D4E8 DBE3 3813 BB5D FA84  5EC7 45C6 250E 6F00 984E
"And now for something completely different."

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 4/n] Remove kernel headers
  2009-08-25 15:44           ` Andreas Schwab
@ 2009-08-25 16:52             ` Maxim Kuvyrkov
  2009-08-25 18:16               ` Andreas Schwab
  0 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-25 16:52 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-ports

Andreas Schwab wrote:
> Maxim Kuvyrkov <maxim@codesourcery.com> writes:
> 
>> The ports/sysdeps/unix/sysv/linux/m68k/sys/ucontext.h file does indeed
>> describe the SysV version of ucontext_t, not that of linux's.
> 
> No, it doesn't.  It describes exactly the Linux kernel definition
> (modulo sigmask size).  If you remove it you get the wrong SysV version.

Ah, now I understand what you mean; ucontext.h cannot be simply removed 
because then GLIBC's build process will pick up 
sysdeps/m68k/sys/ucontext.h, which describes SysV, not Linux, ABI.

Still, what was the foundation for coldfire-specific changes to 
fpregset_t, i.e., the use of 8-byte entries instead of 12-byte as for 
m68k?  I assume this should be removed along with similar changes in 
reg.h and register-dump.h.  If you agree, I'll follow up with a separate 
patch to ucontext.h, reg.h and register-dump.h.

Regarding the sigcontext.h header, there's no competing version in 
./sysdeps/m68k/, so this one can be removed in favor of the header 
installed by the kernel.  Or would you like to keep the file and just 
bring it into sync with the kernel?

Regards,

--
Maxim K.
CodeSourcery

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 4/n] Remove kernel headers
  2009-08-25 16:52             ` Maxim Kuvyrkov
@ 2009-08-25 18:16               ` Andreas Schwab
  2009-08-30 17:46                 ` Maxim Kuvyrkov
  0 siblings, 1 reply; 31+ messages in thread
From: Andreas Schwab @ 2009-08-25 18:16 UTC (permalink / raw)
  To: Maxim Kuvyrkov; +Cc: libc-ports

Maxim Kuvyrkov <maxim@codesourcery.com> writes:

> Still, what was the foundation for coldfire-specific changes to
> fpregset_t, i.e., the use of 8-byte entries instead of 12-byte as for
> m68k?

The coldfire has 64 bit fpu registers.  The patches were from Richard
Sandiford.

> Regarding the sigcontext.h header, there's no competing version in
> ./sysdeps/m68k/, so this one can be removed in favor of the header
> installed by the kernel.

Of course, the generic linux version will be used instead, but if the
kernel header is clean than that will work.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 4/n] Remove kernel headers
  2009-08-25 18:16               ` Andreas Schwab
@ 2009-08-30 17:46                 ` Maxim Kuvyrkov
  2009-10-02 10:51                   ` Maxim Kuvyrkov
  0 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-30 17:46 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-ports

Andreas Schwab wrote:
> Maxim Kuvyrkov <maxim@codesourcery.com> writes:
> 
>> Still, what was the foundation for coldfire-specific changes to
>> fpregset_t, i.e., the use of 8-byte entries instead of 12-byte as for
>> m68k?
> 
> The coldfire has 64 bit fpu registers.  The patches were from Richard
> Sandiford.

I did some digging in the archives and found several things I was not 
aware before:

1. Sigcontext ABI of ColdFire is different from M68K's.  It should be 
what the current GLIBC copy is; i.e., struct sigcontext should contain 
%d2-%d7, %a2-%a6 and have fpregs[8][2].

2. A kernel patch was developed by Freescale and CodeSourcery to account 
for the changes in ABI and also to fix various bugs.  This patch is 
against the 2.6.10 kernel and is available at 
http://www.codesourcery.com/archives/coldfire-gnu-discuss/msg00141.html.

3. The kernel changes mentioned above are not included in the latest 
stable LTIBs for ColdFire Linux boards: ltib-m5475-20080808 and 
ltib-mcf5445x-20071214.  This led to great confusion on my part as I 
considered the kernel sources in these LTIBs to represent true ABI.

>> Regarding the sigcontext.h header, there's no competing version in
>> ./sysdeps/m68k/, so this one can be removed in favor of the header
>> installed by the kernel.
> 
> Of course, the generic linux version will be used instead, but if the
> kernel header is clean than that will work.

In the light of the above, I think it is too early to fall back to the 
kernel headers.  I will seek to the necessary ABI changes to get to the 
upstream kernel and then will follow up on GLIBC switching to use 
kernel's sigcontext.h.

As things stand, GLIBC contains the true ColdFire sigcontext ABI at the 
moment.

Please consider the patch at the beginning of the thread bogus in 
several different ways :).

Thanks,

--
Maxim K.
CodeSourcery

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 5/n] Main NPTL patch
  2009-08-25 13:04 ` [M68K/ColdFire patch 5/n] Main NPTL patch Maxim Kuvyrkov
@ 2009-08-30 18:03   ` Maxim Kuvyrkov
  2009-10-02 10:46     ` Maxim Kuvyrkov
  0 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-08-30 18:03 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 492 bytes --]

Maxim Kuvyrkov wrote:
> This is the main NPTL patch.  During development of this work I tried to 
> make things work in the exactly same way as on other major architectures.
> 
> I expect there will be comments on this one :)

After I did a clean rebuild of the work, I've caught several small 
issues that were introduced by the last-minute cleanups.  So here is an 
updated patch; I'm also attaching the difference between the patches for 
easier review.

Thanks!

--
Maxim K.
CodeSourcery

[-- Attachment #2: 0001-Small-fixes.patch --]
[-- Type: text/plain, Size: 2532 bytes --]

From e2e870928504c8c2f8b40313af8370885b9fe31a Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Fri, 28 Aug 2009 00:34:06 +0400
Subject: [PATCH] Small fixes.

---
 sysdeps/m68k/nptl/tls.h                       |    6 ------
 sysdeps/unix/sysv/linux/m68k/Makefile         |    4 ++--
 sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c |    1 +
 sysdeps/unix/sysv/linux/m68k/m68k-helpers.S   |    4 ----
 4 files changed, 3 insertions(+), 12 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c

diff --git a/sysdeps/m68k/nptl/tls.h b/sysdeps/m68k/nptl/tls.h
index 887ee68..5b9817e 100644
--- a/sysdeps/m68k/nptl/tls.h
+++ b/sysdeps/m68k/nptl/tls.h
@@ -42,12 +42,6 @@ typedef union dtv
 # include <tcb-offsets.h>
 #endif /* __ASSEMBLER__ */
 
-
-/* We require TLS support in the tools.  */
-#ifndef HAVE_TLS_SUPPORT
-# error "TLS support is required."
-#endif
-
 /* Signal that TLS support is available.  */
 #define USE_TLS	1
 
diff --git a/sysdeps/unix/sysv/linux/m68k/Makefile b/sysdeps/unix/sysv/linux/m68k/Makefile
index 64627c6..97d9584 100644
--- a/sysdeps/unix/sysv/linux/m68k/Makefile
+++ b/sysdeps/unix/sysv/linux/m68k/Makefile
@@ -3,7 +3,7 @@
 m68k-syntax-flag = -DMOTOROLA_SYNTAX
 
 ifeq ($(subdir),csu)
-sysdep_routines += m68k-helpers m68k-vdso
+sysdep_routines += m68k-helpers
 endif
 
 ifeq ($(subdir),misc)
@@ -12,7 +12,7 @@ sysdep_headers += sys/reg.h
 endif
 
 ifeq ($(subdir),elf)
-sysdep_routines += dl-vdso m68k-vdso
+sysdep_routines += dl-vdso libc-m68k-vdso
 sysdep-rtld-routines += m68k-vdso
 sysdep-others += lddlibc4
 install-bin += lddlibc4
diff --git a/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
new file mode 100644
index 0000000..45982e9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
@@ -0,0 +1 @@
+#include "m68k-vdso.c"
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
index 580c565..d9ccb4f 100644
--- a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
@@ -33,8 +33,6 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#ifdef HAVE_TLS_SUPPORT
-
 #include <sysdep.h>
 #include <bits/m68k-vdso.h>
 
@@ -104,5 +102,3 @@ END (__vdso_atomic_barrier_stub)
 /* If the vDSO is not available, use a syscall to get TP.  */
 	strong_alias (__vdso_read_tp_stub, __m68k_read_tp)
 # endif /* SHARED */
-
-#endif /* HAVE_TLS_SUPPORT */
-- 
1.6.4


[-- Attachment #3: 0001-Nptl-support-for-m68k-ColdFire.patch --]
[-- Type: text/plain, Size: 78185 bytes --]

From 96785edb18c558b45049627dc166d2456af67886 Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Sun, 30 Aug 2009 21:55:02 +0400
Subject: [PATCH] Nptl support for m68k/ColdFire.

This patch contains the main code of m68k/ColdFire NPTL support.
Please note that several additional fixes (see subsequent patches)
are necessary to make GLIBC build and work properly.

	* sysdeps/unix/sysv/linux/m68k/clone.S: Support RESET_PID.
	* sysdeps/unix/sysv/linux/m68k/m68k-helpers.S: New.
	* sysdeps/unix/sysv/linux/m68k/Makefile: Add new files to lists.
	* sysdeps/unix/sysv/linux/m68k/vfork.S: Add SAVE_PID/RESTORE_PID.
	* sysdeps/unix/sysv/linux/m68k/m68k-vdso.c: New.
	* sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c: New.
	* sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h: New.
	* sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h: New.
	* sysdeps/unix/sysv/linux/m68k/Versions: Add symbols for NPTL support.
	* sysdeps/unix/sysv/linux/m68k/init-first.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/clone.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/fork.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/vfork.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/createthread.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c: New.
	* sysdeps/unix/sysv/linux/m68k/socket.S: Update cancelation code.
	* sysdeps/m68k/dl-tls.h: New.
	* sysdeps/m68k/libc-tls.c: New.
	* sysdeps/m68k/tls-macros.h: New.
	* sysdeps/m68k/dl-machine.h: Handle TLS relocations.
	* sysdeps/m68k/nptl/tcb-offsets.sym: New.
	* sysdeps/m68k/nptl/pthread_spin_trylock.c: New.
	* sysdeps/m68k/nptl/tls.h: New.
	* sysdeps/m68k/nptl/pthread_spin_lock.c: New.
	* sysdeps/m68k/nptl/pthreaddef.h: New.
	* sysdeps/m68k/nptl/Makefile: New.
---
 sysdeps/m68k/dl-machine.h                          |   23 ++-
 sysdeps/m68k/dl-tls.h                              |   47 ++++
 sysdeps/m68k/libc-tls.c                            |   37 +++
 sysdeps/m68k/nptl/Makefile                         |   21 ++
 sysdeps/m68k/nptl/pthread_spin_lock.c              |   30 ++
 sysdeps/m68k/nptl/pthread_spin_trylock.c           |   27 ++
 sysdeps/m68k/nptl/pthreaddef.h                     |   38 +++
 sysdeps/m68k/nptl/tcb-offsets.sym                  |   11 +
 sysdeps/m68k/nptl/tls.h                            |  170 ++++++++++++
 sysdeps/m68k/tls-macros.h                          |   69 +++++
 sysdeps/unix/sysv/linux/m68k/Makefile              |    6 +
 sysdeps/unix/sysv/linux/m68k/Versions              |   12 +
 sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h      |   60 +++++
 sysdeps/unix/sysv/linux/m68k/clone.S               |   52 ++++-
 .../sysv/linux/m68k/coldfire/nptl/bits/atomic.h    |  104 ++++++++
 sysdeps/unix/sysv/linux/m68k/init-first.c          |   69 +++++
 sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c      |    1 +
 sysdeps/unix/sysv/linux/m68k/m68k-helpers.S        |  104 ++++++++
 sysdeps/unix/sysv/linux/m68k/m68k-vdso.c           |   34 +++
 .../unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h  |  171 ++++++++++++
 sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h |   35 +++
 sysdeps/unix/sysv/linux/m68k/nptl/clone.S          |    2 +
 sysdeps/unix/sysv/linux/m68k/nptl/createthread.c   |   24 ++
 sysdeps/unix/sysv/linux/m68k/nptl/fork.c           |   29 ++
 sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h   |  280 ++++++++++++++++++++
 sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S       |   35 +++
 sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c   |   90 +++++++
 sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h  |  148 +++++++++++
 sysdeps/unix/sysv/linux/m68k/nptl/vfork.S          |   37 +++
 sysdeps/unix/sysv/linux/m68k/socket.S              |   28 ++-
 sysdeps/unix/sysv/linux/m68k/vfork.S               |   18 ++-
 31 files changed, 1798 insertions(+), 14 deletions(-)
 create mode 100644 sysdeps/m68k/dl-tls.h
 create mode 100644 sysdeps/m68k/libc-tls.c
 create mode 100644 sysdeps/m68k/nptl/Makefile
 create mode 100644 sysdeps/m68k/nptl/pthread_spin_lock.c
 create mode 100644 sysdeps/m68k/nptl/pthread_spin_trylock.c
 create mode 100644 sysdeps/m68k/nptl/pthreaddef.h
 create mode 100644 sysdeps/m68k/nptl/tcb-offsets.sym
 create mode 100644 sysdeps/m68k/nptl/tls.h
 create mode 100644 sysdeps/m68k/tls-macros.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/init-first.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
 create mode 100644 sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/clone.S
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/fork.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/vfork.S

diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
index 08a4396..098dc8d 100644
--- a/sysdeps/m68k/dl-machine.h
+++ b/sysdeps/m68k/dl-machine.h
@@ -1,5 +1,6 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  m68k version.
-   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 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
@@ -24,6 +25,7 @@
 
 #include <sys/param.h>
 #include <sysdep.h>
+#include <dl-tls.h>
 
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int
@@ -262,6 +264,25 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 	case R_68K_PC32:
 	  *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
 	  break;
+#if defined USE_TLS && !defined RTLD_BOOTSTRAP
+	case R_68K_TLS_DTPMOD32:
+	  /* Get the information from the link map returned by the
+	     resolv function.  */
+	  if (sym_map != NULL)
+	    *reloc_addr = sym_map->l_tls_modid;
+	  break;
+	case R_68K_TLS_DTPREL32:
+	  if (sym != NULL)
+	    *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
+	  break;
+	case R_68K_TLS_TPREL32:
+	  if (sym != NULL)
+	    {
+	      CHECK_STATIC_TLS (map, sym_map);
+	      *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
+	    }
+	  break;
+#endif /* defined USE_TLS && !defined RTLD_BOOTSTRAP */
 	case R_68K_NONE:		/* Alright, Wilbur.  */
 	  break;
 	default:
diff --git a/sysdeps/m68k/dl-tls.h b/sysdeps/m68k/dl-tls.h
new file mode 100644
index 0000000..249e0e2
--- /dev/null
+++ b/sysdeps/m68k/dl-tls.h
@@ -0,0 +1,47 @@
+/* Thread-local storage handling in the ELF dynamic linker.  M68K version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* The thread pointer points 0x7000 past the first static TLS block.  */
+#define TLS_TP_OFFSET		0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET		0x8000
+
+/* Compute the value for a TPREL reloc.  */
+#define TLS_TPREL_VALUE(sym_map, sym, reloc)				\
+  ((sym_map)->l_tls_offset + (sym)->st_value + (reloc)->r_addend	\
+   - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc.  */
+#define TLS_DTPREL_VALUE(sym, reloc)				\
+  ((sym)->st_value + (reloc)->r_addend - TLS_DTV_OFFSET)
+
+extern void *__tls_get_addr (tls_index *ti);
+
+#define GET_ADDR_OFFSET	        (ti->ti_offset + TLS_DTV_OFFSET)
+#define __TLS_GET_ADDR(__ti)	(__tls_get_addr (__ti) - TLS_DTV_OFFSET)
diff --git a/sysdeps/m68k/libc-tls.c b/sysdeps/m68k/libc-tls.c
new file mode 100644
index 0000000..b4e5129
--- /dev/null
+++ b/sysdeps/m68k/libc-tls.c
@@ -0,0 +1,37 @@
+/* Thread-local storage handling in the ELF dynamic linker.  m68k version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <csu/libc-tls.c>
+#include <dl-tls.h>
+
+#if USE_TLS
+
+/* On M68K, linker optimizations are not required, so __tls_get_addr
+   can be called even in statically linked binaries.  In this case module
+   must be always 1 and PT_TLS segment exist in the binary, otherwise it
+   would not link.  */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET;
+}
+
+#endif
diff --git a/sysdeps/m68k/nptl/Makefile b/sysdeps/m68k/nptl/Makefile
new file mode 100644
index 0000000..f0bcefb
--- /dev/null
+++ b/sysdeps/m68k/nptl/Makefile
@@ -0,0 +1,21 @@
+# Copyright (C) 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; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/sysdeps/m68k/nptl/pthread_spin_lock.c b/sysdeps/m68k/nptl/pthread_spin_lock.c
new file mode 100644
index 0000000..413e8cc
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthread_spin_lock.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  while (atomic_compare_and_exchange_val_acq(lock, 1, 0) != 0)
+   while (*lock != 0)
+    ;
+
+  return 0;
+}
diff --git a/sysdeps/m68k/nptl/pthread_spin_trylock.c b/sysdeps/m68k/nptl/pthread_spin_trylock.c
new file mode 100644
index 0000000..d2b4870
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthread_spin_trylock.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  return atomic_compare_and_exchange_val_acq(lock, 1, 0) ? EBUSY : 0;
+}
diff --git a/sysdeps/m68k/nptl/pthreaddef.h b/sysdeps/m68k/nptl/pthreaddef.h
new file mode 100644
index 0000000..e52694d
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthreaddef.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* 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/sysdeps/m68k/nptl/tcb-offsets.sym b/sysdeps/m68k/nptl/tcb-offsets.sym
new file mode 100644
index 0000000..b1bba65
--- /dev/null
+++ b/sysdeps/m68k/nptl/tcb-offsets.sym
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Derive offsets relative to the thread register.
+#define thread_offsetof(mem)	(long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads)
+PID_OFFSET			thread_offsetof (pid)
+TID_OFFSET			thread_offsetof (tid)
diff --git a/sysdeps/m68k/nptl/tls.h b/sysdeps/m68k/nptl/tls.h
new file mode 100644
index 0000000..5b9817e
--- /dev/null
+++ b/sysdeps/m68k/nptl/tls.h
@@ -0,0 +1,170 @@
+/* Definition for thread-local data handling.  NPTL/m68k version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H	1
+
+#include <dl-sysdep.h>
+
+#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__ */
+
+/* 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 <nptl/descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_INIT_TCB_SIZE	0
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN	__alignof__ (struct pthread)
+
+/* This is the size of the TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_TCB_SIZE		0
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN		__alignof__ (struct pthread)
+
+/* This is the size we need before TCB - actually, it includes the TCB.  */
+# define TLS_PRE_TCB_SIZE						\
+  (sizeof (struct pthread)						\
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* The thread pointer (TP) points to the end of the
+   TCB + 0x7000, as for PowerPC and MIPS.  This implies that TCB address is
+   TP - 0x7000.  As we define TLS_DTV_AT_TP we can
+   assume that the pthread struct is allocated immediately ahead of the
+   TCB.  This implies that the pthread_descr address is
+   TP - (TLS_PRE_TCB_SIZE + 0x7000).  */
+# define TLS_TCB_OFFSET	0x7000
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV () = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall)					\
+  ({									\
+    INTERNAL_SYSCALL_DECL (err);					\
+    int _sys_result;							\
+									\
+    _sys_result = INTERNAL_SYSCALL (write_tp, err, 1,			\
+				    ((void *) (tcbp)) + TLS_TCB_OFFSET); \
+    INTERNAL_SYSCALL_ERROR_P (_sys_result, err) ? "unknown error" : NULL; })
+
+extern void * __m68k_read_tp (void);
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) (__m68k_read_tp () - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+  ((struct pthread *) (__m68k_read_tp () - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Access to data in the thread descriptor is easy.  */
+# define THREAD_GETMEM(descr, member) \
+  descr->member
+# define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+# define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* l_tls_offset == 0 is perfectly valid on M68K, so we have to use some
+   different value to mean unset l_tls_offset.  */
+# define NO_TLS_OFFSET		-1
+
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG()					\
+  do									\
+    { int __res								\
+	= atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,	\
+			       THREAD_GSCOPE_FLAG_UNUSED);		\
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)				\
+	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+    }									\
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG()					\
+  do									\
+    {									\
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;	\
+      atomic_write_barrier ();						\
+    }									\
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif	/* tls.h */
diff --git a/sysdeps/m68k/tls-macros.h b/sysdeps/m68k/tls-macros.h
new file mode 100644
index 0000000..a15f8b9
--- /dev/null
+++ b/sysdeps/m68k/tls-macros.h
@@ -0,0 +1,69 @@
+/* Macros for accessing thread-local storage.  m68k version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define TLS_GD(x)							\
+  ({									\
+    void *__result;							\
+    extern void *__tls_get_addr (void *);				\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "lea " #x "@TLSGD(%0), %0"					\
+	 : "=&a" (__result));						\
+    (int *) __tls_get_addr (__result); })
+
+#define TLS_LD(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void *__tls_get_addr (void *);				\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "lea " #x "@TLSLDM(%0), %0"					\
+	 : "=&a" (__tp));						\
+    __tp = (char *) __tls_get_addr (__tp);				\
+    asm ("movel #" #x "@TLSLDO, %0"					\
+	 : "=a" (__offset));						\
+    (int *) (__tp + __offset); })
+
+#define TLS_IE(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void * __m68k_read_tp (void);				\
+									\
+    __tp = (char *) __m68k_read_tp ();					\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "movel " #x "@TLSIE(%0), %0"					\
+	 : "=&a" (__offset));						\
+    (int *) (__tp + __offset); })
+
+#define TLS_LE(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void * __m68k_read_tp (void);				\
+									\
+    __tp = (char *) __m68k_read_tp ();					\
+    asm ("movel #" #x "@TLSLE, %0"					\
+	 : "=a" (__offset));						\
+    (int *) (__tp + __offset); })
+
diff --git a/sysdeps/unix/sysv/linux/m68k/Makefile b/sysdeps/unix/sysv/linux/m68k/Makefile
index 6bb4f6b..97d9584 100644
--- a/sysdeps/unix/sysv/linux/m68k/Makefile
+++ b/sysdeps/unix/sysv/linux/m68k/Makefile
@@ -2,12 +2,18 @@
 
 m68k-syntax-flag = -DMOTOROLA_SYNTAX
 
+ifeq ($(subdir),csu)
+sysdep_routines += m68k-helpers
+endif
+
 ifeq ($(subdir),misc)
 sysdep_routines += mremap
 sysdep_headers += sys/reg.h
 endif
 
 ifeq ($(subdir),elf)
+sysdep_routines += dl-vdso libc-m68k-vdso
+sysdep-rtld-routines += m68k-vdso
 sysdep-others += lddlibc4
 install-bin += lddlibc4
 endif
diff --git a/sysdeps/unix/sysv/linux/m68k/Versions b/sysdeps/unix/sysv/linux/m68k/Versions
index 5650f7f..152f7aa 100644
--- a/sysdeps/unix/sysv/linux/m68k/Versions
+++ b/sysdeps/unix/sysv/linux/m68k/Versions
@@ -31,5 +31,17 @@ libc {
   }
   GLIBC_2.11 {
     fallocate64;
+    __m68k_read_tp;
+  }
+  GLIBC_PRIVATE {
+    __vdso_atomic_cmpxchg_32; __vdso_atomic_barrier;
+  }
+}
+
+ld {
+  GLIBC_PRIVATE {
+    __rtld___vdso_read_tp;
+    __rtld___vdso_atomic_cmpxchg_32;
+    __rtld___vdso_atomic_barrier;
   }
 }
diff --git a/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
new file mode 100644
index 0000000..3d809cf
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
@@ -0,0 +1,60 @@
+/* Resolve function pointers to VDSO functions.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+#ifndef _M68K_VDSO_H
+#define _M68K_VDSO_H
+
+#ifdef SHARED
+
+# ifdef IS_IN_rtld
+# define M68K_VDSO_SYMBOL(name) __rtld_##name
+# define STR_M68K_VDSO_SYMBOL(name) "__rtld_" #name
+# else
+# define M68K_VDSO_SYMBOL(name) name
+# define STR_M68K_VDSO_SYMBOL(name) #name
+# endif
+
+# ifndef __ASSEMBLER__
+
+/* We define __rtld_* copies for rtld.
+   We need them visible in libc to initialize.  */
+#  if defined IS_IN_rtld || !defined NOT_IN_libc
+extern void *__rtld___vdso_read_tp;
+extern void *__rtld___vdso_atomic_cmpxchg_32;
+extern void *__rtld___vdso_atomic_barrier;
+
+/* These stubs are meant to be invoked only from the assembly.  */
+extern void __vdso_read_tp_stub (void);
+extern void __vdso_atomic_cmpxchg_32_stub (void);
+extern void __vdso_atomic_barrier_stub (void);
+#  endif /* IS_IN_rtld || !NOT_IN_libc */
+
+/* RTLD should only use its own copies.  */
+#  ifndef IS_IN_rtld
+extern void *__vdso_read_tp;
+extern void *__vdso_atomic_cmpxchg_32;
+extern void *__vdso_atomic_barrier;
+#  endif /* !IS_IN_rtld */
+
+# endif /* !__ASSEMBLER__ */
+
+#endif /* SHARED */
+
+#endif /* _M68K_VDSO_H */
diff --git a/sysdeps/unix/sysv/linux/m68k/clone.S b/sysdeps/unix/sysv/linux/m68k/clone.S
index a179f8e..4135cd0 100644
--- a/sysdeps/unix/sysv/linux/m68k/clone.S
+++ b/sysdeps/unix/sysv/linux/m68k/clone.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996,97,98,2002,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
 
@@ -17,14 +17,21 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-/* clone is even more special than fork as it mucks with stacks
+/* clone() is even more special than fork() as it mucks with stacks
    and invokes a function in the right context after its all over.  */
 
 #include <sysdep.h>
 #define _ERRNO_H	1
 #include <bits/errno.h>
+#ifdef RESET_PID
+#include <tls.h>
+#endif
+
+#define CLONE_VM      0x00000100
+#define CLONE_THREAD  0x00010000
 
-/* 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,
+	     void *parent_tidptr, void *tls, void *child_tidptr) */
 
         .text
 ENTRY (__clone)
@@ -42,7 +49,17 @@ ENTRY (__clone)
 	movel	16(%sp), -(%a1)
 
 	/* Do the system call */
-	movel	12(%sp), %d1		/* get flags */
+	movel	12+0(%sp), %d1		/* get flags */
+	movel	%d3, -(%a1)             /* save %d3 and get parent_tidptr */
+	movel	%d3, -(%sp)
+	movel	20+4(%sp), %d3
+	movel	%d4, -(%a1)		/* save %d4 and get child_tidptr */
+	movel	%d4, -(%sp)
+	movel	28+8(%sp), %d4
+	movel	%d5, -(%a1)             /* save %d5 and get tls */
+	movel	%d5, -(%sp)
+	movel	24+12(%sp), %d5
+	/* save %d2 and get stack pointer */
 #ifdef __mcoldfire__
 	movel	%d2, -(%a1)
 	movel	%d2, -(%sp)
@@ -57,6 +74,9 @@ ENTRY (__clone)
 #else
 	exg	%d2, %a1		/* restore %d2 */
 #endif
+	movel	(%sp)+, %d5             /* restore %d5, %d4 and %d3 */
+	movel	(%sp)+, %d4
+	movel	(%sp)+, %d3
 
 	tstl	%d0
 	jmi	SYSCALL_ERROR_LABEL
@@ -65,11 +85,35 @@ ENTRY (__clone)
 	rts
 
 thread_start:
+	cfi_startproc
+	cfi_undefined (pc)	/* Mark end of stack */
 	subl	%fp, %fp	/* terminate the stack frame */
+#ifdef RESET_PID
+	/* Check and see if we need to reset the PID.  */
+	movel	%d1, %a1
+	andl	#CLONE_THREAD, %d1
+	jne	donepid
+	movel	%a1, %d1
+	movel	#-1, %d0
+	andl	#CLONE_VM, %d1
+	jne	gotpid
+	movel	#SYS_ify (getpid), %d0
+	trap	#0
+gotpid:
+	movel	%a0, -(%sp)
+	movel	%d0, -(%sp)
+	bsrl	__m68k_read_tp@PLTPC
+	movel	(%sp)+, %d0
+	movel	%d0, PID_OFFSET(%a0)
+	movel	%d0, TID_OFFSET(%a0)
+	movel	(%sp)+, %a0
+donepid:
+#endif
 	jsr	(%a0)
 	movel	%d0, %d1
 	movel	#SYS_ify (exit), %d0
 	trap	#0
+	cfi_endproc
 
 PSEUDO_END (__clone)
 
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
new file mode 100644
index 0000000..972eb17
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H	1
+
+#include <stdint.h>
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+/* Coldfire has no atomic compare-and-exchange operation, but the
+   kernel provides userspace atomicity operations.  Use them.  */
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+/* The only basic operation needed is compare and exchange.  */
+/* For ColdFire we'll have to trap into the kernel mode anyway,
+   so trap from the library rather then from the kernel wrapper.  */
+#ifdef SHARED
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  ({									\
+    /* Use temporary variables to workaround call-clobberness of */	\
+    /* the registers.  */						\
+    __typeof (mem) _mem = mem;						\
+    __typeof (oldval) _oldval = oldval;					\
+    __typeof (newval) _newval = newval;					\
+    register __typeof (mem) _a0 asm ("a0") = _mem;			\
+    register __typeof (oldval) _d0 asm ("d0") = _oldval;		\
+    register __typeof (newval) _d1 asm ("d1") = _newval;		\
+    void *tmp;								\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %2\n\t"			\
+	 "lea (-6, %%pc, %2), %2\n\t"					\
+	 "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)	\
+	 "@GOT(%2), %2\n\t"						\
+	 "movel (%2), %2\n\t"						\
+	 "jsr (%2)\n\t"							\
+	 : "+d" (_d0), "+m" (*_a0), "=&a" (tmp)				\
+	 : "a" (_a0), "d" (_d1));					\
+    _d0;								\
+  })
+#else
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  ({									\
+    /* Use temporary variables to workaround call-clobberness of */	\
+    /* the registers.  */						\
+    __typeof (mem) _mem = mem;						\
+    __typeof (oldval) _oldval = oldval;					\
+    __typeof (newval) _newval = newval;					\
+    register __typeof (oldval) _d0 asm ("d0")				\
+      = SYS_ify (atomic_cmpxchg_32);					\
+    register __typeof (mem) _a0 asm ("a0") = _mem;			\
+    register __typeof (oldval) _d2 asm ("d2") = _oldval;		\
+    register __typeof (newval) _d1 asm ("d1") = _newval;		\
+									\
+    asm ("trap #0"							\
+	 : "+d" (_d0), "+m" (*_a0)					\
+	 : "a" (_a0), "d" (_d2), "d" (_d1));				\
+    _d0;								\
+  })
+#endif
+
+#ifdef SHARED
+# define atomic_full_barrier()					 \
+  ({								 \
+    void *tmp;							 \
+								 \
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"		 \
+	 "lea (-6, %pc, %0), %0\n\t"				 \
+	 "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_barrier)	 \
+	 "@GOT(%0), %0\n\t"					 \
+	 "movel (%0), %0\n\t"					 \
+	 "jsr (%0)\n\t"						 \
+	 : "=&a" (tmp));					 \
+  })
+#else
+# define atomic_full_barrier()				\
+  (INTERNAL_SYSCALL (atomic_barrier, , 0), (void) 0)
+#endif
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/init-first.c b/sysdeps/unix/sysv/linux/m68k/init-first.c
new file mode 100644
index 0000000..951b6fe
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/init-first.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Note: linking in vDSO to a static binary requires changes to
+   the main GLIBC proper.  Not yet implemented.  */
+#ifdef SHARED
+
+#include <dl-vdso.h>
+#include <bits/m68k-vdso.h>
+
+static inline void
+_libc_vdso_platform_setup (void)
+{
+  void *p;
+
+  PREPARE_VERSION (linux26, "LINUX_2.6", 61765110);
+
+  /* It may happen that rtld didn't initialize the vDSO, so fallback
+     to the syscall implementations if _dl_vdso_vsym returns NULL.
+     This may happen when a static executable dlopen's a dynamic library.
+     This really is nothing more than a workaround for rtld/csu
+     deficiency.  Ideally, init code would setup the vDSO for static
+     binaries too.  */
+
+  p = _dl_vdso_vsym ("__kernel_read_tp", &linux26);
+  if (p != NULL)
+    __vdso_read_tp = p;
+  else
+    assert (__vdso_read_tp == (void *) __vdso_read_tp_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_cmpxchg_32", &linux26);
+  if (p != NULL)
+    __vdso_atomic_cmpxchg_32 = p;
+  else
+    assert (__vdso_atomic_cmpxchg_32
+	    == (void *) __vdso_atomic_cmpxchg_32_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_barrier", &linux26);
+  if (p != NULL)
+    __vdso_atomic_barrier = p;
+  else
+    assert (__vdso_atomic_barrier == (void *) __vdso_atomic_barrier_stub);
+
+  /* Non-shared libc has only one set of the VDSO pointers.  */
+  __rtld___vdso_read_tp = __vdso_read_tp;
+  __rtld___vdso_atomic_cmpxchg_32 = __vdso_atomic_cmpxchg_32;
+  __rtld___vdso_atomic_barrier = __vdso_atomic_barrier;
+}
+
+#define VDSO_SETUP _libc_vdso_platform_setup
+
+#endif /* SHARED */
+
+#include <sysdeps/unix/sysv/linux/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
new file mode 100644
index 0000000..45982e9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
@@ -0,0 +1 @@
+#include "m68k-vdso.c"
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
new file mode 100644
index 0000000..d9ccb4f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
@@ -0,0 +1,104 @@
+/* Copyright (C) 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.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+	.text
+
+	.hidden __vdso_read_tp_stub
+ENTRY (__vdso_read_tp_stub)
+	cfi_startproc
+	move.l	#__NR_read_tp, %d0
+	trap	#0
+	move.l	%d0, %a0
+	rts
+	cfi_endproc
+END (__vdso_read_tp_stub)
+
+# ifdef SHARED
+/* GCC will emit calls to this routine.  Linux has an
+   equivalent helper function (which clobbers fewer registers than
+   a normal function call) in a vdso; tail call to the
+   helper.  */
+# ifdef IS_IN_rtld
+/* rtld gets a hidden copy of __m68k_read_tp.  */
+	.hidden __m68k_read_tp
+# endif
+ENTRY (__m68k_read_tp)
+	cfi_startproc
+	move.l	#_GLOBAL_OFFSET_TABLE_@GOTPC, %a0
+	lea	(-6, %pc, %a0), %a0
+	move.l	M68K_VDSO_SYMBOL (__vdso_read_tp)@GOT(%a0), %a0
+	move.l	(%a0), %a0
+	jmp	(%a0)
+	cfi_endproc
+END (__m68k_read_tp)
+
+/* The following two stubs are for macros in atomic.h, they can't
+   clobber anything.  */
+
+	.hidden __vdso_atomic_cmpxchg_32_stub
+ENTRY (__vdso_atomic_cmpxchg_32_stub)
+	cfi_startproc
+	move.l	%d2, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
+	move.l	%d0, %d2
+	move.l	#SYS_ify (atomic_cmpxchg_32), %d0
+	trap	#0
+	move.l	(%sp)+, %d2
+	cfi_adjust_cfa_offset (-4)
+	cfi_restore (%d2)
+	rts
+	cfi_endproc
+END (__vdso_atomic_cmpxchg_32_stub)
+	
+	.hidden __vdso_atomic_barrier_stub
+ENTRY (__vdso_atomic_barrier_stub)
+	cfi_startproc
+	move.l	%d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	move.l	#SYS_ify (atomic_barrier), %d0
+	trap	#0
+	move.l	(%sp)+, %d0
+	cfi_adjust_cfa_offset (-4)
+	rts
+	cfi_endproc
+END (__vdso_atomic_barrier_stub)
+# else /* !SHARED */
+/* If the vDSO is not available, use a syscall to get TP.  */
+	strong_alias (__vdso_read_tp_stub, __m68k_read_tp)
+# endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
new file mode 100644
index 0000000..a605039
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifdef SHARED
+
+#include <bits/m68k-vdso.h>
+
+/* Because these pointers are used from other libraries than libc,
+   they are exported at GLIBC_PRIVATE version.
+   We initialize them to syscall implementation so that they will be ready
+   to use from the very beginning.  */
+void * M68K_VDSO_SYMBOL (__vdso_read_tp)
+= (void *) __vdso_read_tp_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)
+= (void *) __vdso_atomic_cmpxchg_32_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_barrier)
+= (void *) __vdso_atomic_barrier_stub;
+
+#endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
new file mode 100644
index 0000000..b3c719c
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
@@ -0,0 +1,171 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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_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
+   deliberately not exposed.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+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 deliberately not exposed.  */
+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;
+
+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 deliberately not exposed.  */
+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 deliberately not exposed.  */
+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;
+    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;
+    int __writer;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+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/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
new file mode 100644
index 0000000..c72ddcc
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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/sysdeps/unix/sysv/linux/m68k/nptl/clone.S b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
new file mode 100644
index 0000000..e7388fe
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include "../clone.S"
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
new file mode 100644
index 0000000..537a5e9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE ((void *) (pd) \
+		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation.	 */
+#include <nptl/sysdeps/pthread/createthread.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/fork.c b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
new file mode 100644
index 0000000..1e4de36
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
@@ -0,0 +1,29 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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, &THREAD_SELF->tid, NULL)
+
+#include <sysdeps/unix/sysv/linux/fork.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
new file mode 100644
index 0000000..8ab444b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
@@ -0,0 +1,280 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Borrowed from ARM's version.  */
+
+#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 <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 __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAIT, private),	      \
+			      (val), (timespec));			      \
+    __ret;								      \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAKE, private),	      \
+			      (nr), 0);					      \
+    __ret;								      \
+  })
+
+#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 __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),		      \
+			      __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+			      (nr_wake), (nr_move), (mutex), (val));	      \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __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 __ret;							      \
+    __ret = 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 (__ret, __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(lock, id)			\
+  atomic_compare_and_exchange_val_acq (&(lock), id, 0)
+
+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 (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex,       \
+								1, 0), 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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+								0), 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 (__builtin_expect (atomic_exchange_acq (__futex, 2), 0))		      \
+      __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 (__builtin_expect (atomic_exchange_acq (__futex, 1), 0))	      \
+       __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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+								0), 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 (__builtin_expect (__oldval > 1, 0))			\
+	 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 (__builtin_expect (__oldval & FUTEX_WAITERS, 0))	\
+	 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/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
new file mode 100644
index 0000000..087a3bb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
@@ -0,0 +1,35 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+	bsrl	__m68k_read_tp@PLTPC	; /* Get the thread pointer.  */ \
+	movel	%a0, %a1		; /* Save TP for RESTORE_PID.  */ \
+	movel	PID_OFFSET(%a1), %d0	; /* Get the PID.  */ \
+	movel	%d0, %d1		; /* Save PID for RESTORE_PID.  */ \
+	negl	%d0			; /* Negate the PID.  */ \
+	movel	%d0, PID_OFFSET(%a1)	; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+	tstl	%d0			; \
+	beq	1f			; /* If we are the parent... */ \
+	movel	%d1, PID_OFFSET(%a1)	; /* Restore the PID.  */ \
+1:	
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
new file mode 100644
index 0000000..6ef86b2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
@@ -0,0 +1,90 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
new file mode 100644
index 0000000..5ed7486
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
@@ -0,0 +1,148 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				      \
+  .text;								      \
+  ENTRY (name)								      \
+    SINGLE_THREAD_P;							      \
+    jne .Lpseudo_cancel;						      \
+  .type __##syscall_name##_nocancel,@function;			              \
+  .globl __##syscall_name##_nocancel;				 	      \
+  __##syscall_name##_nocancel:					              \
+    DO_CALL (syscall_name, args);					      \
+    cmp.l &-4095, %d0;							      \
+    jcc SYSCALL_ERROR_LABEL;						      \
+    rts;								      \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \
+  .Lpseudo_cancel:							      \
+    cfi_startproc;							      \
+    CENABLE;								      \
+    DOCARGS_##args							      \
+    move.l %d0, -(%sp); /* Save result of CENABLE.  */  		      \
+    cfi_adjust_cfa_offset (4); \
+    move.l &SYS_ify (syscall_name), %d0;				      \
+    trap &0;								      \
+    move.l %d0, %d2;							      \
+    CDISABLE;								      \
+    addq.l &4, %sp; /* Remove result of CENABLE from the stack.  */           \
+    cfi_adjust_cfa_offset (-4); \
+    move.l %d2, %d0;							      \
+    UNDOCARGS_##args							      \
+    cmp.l &-4095, %d0;							      \
+    jcc SYSCALL_ERROR_LABEL;		                                      \
+    cfi_endproc
+
+/* Note: we use D2 to save syscall's return value as D0 will be clobbered in
+   CDISABLE.  */
+# define DOCARGS_0	move.l %d2, -(%sp);		\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d2, 0);
+# define UNDOCARGS_0	move.l (%sp)+, %d2;	\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d2);
+
+# define DOCARGS_1	_DOCARGS_1 (4); DOCARGS_0
+# define _DOCARGS_1(n)	move.l n(%sp), %d1;
+# define UNDOCARGS_1	UNDOCARGS_0
+
+# define DOCARGS_2	_DOCARGS_2 (8)
+# define _DOCARGS_2(n)	DOCARGS_0 move.l n+4(%sp), %d2; _DOCARGS_1 (n)
+# define UNDOCARGS_2	UNDOCARGS_0
+
+/* TODO: We can optimize DOCARGS_{3, 4} by saving registers to a0 and a1
+   instead of pushing them on stack.  */
+# define DOCARGS_3	_DOCARGS_3 (12)
+# define _DOCARGS_3(n)	move.l %d3, -(%sp);				\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d3, 0);			\
+  move.l n+4(%sp), %d3; _DOCARGS_2 (n)
+# define UNDOCARGS_3	UNDOCARGS_2 move.l (%sp)+, %d3;		\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d3);
+
+# define DOCARGS_4	_DOCARGS_4 (16)
+# define _DOCARGS_4(n)	move.l %d4, -(%sp);			\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d4, 0);		\
+  move.l n+4(%sp), %d4; _DOCARGS_3 (n)
+# define UNDOCARGS_4	UNDOCARGS_3 move.l (%sp)+, %d4;	\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d4);
+
+# define DOCARGS_5	_DOCARGS_5 (20)
+# define _DOCARGS_5(n)	move.l %d5, %a1; cfi_register (%d5, a1); \
+  move.l n(%sp), %d5; _DOCARGS_4 (n-4)
+# define UNDOCARGS_5	UNDOCARGS_4 move.l %a1, %d5; cfi_restore (%d5);
+
+# define DOCARGS_6	_DOCARGS_6 (24)
+# define _DOCARGS_6(n)	move.l n(%sp), %a0; _DOCARGS_5 (n-4)
+# define UNDOCARGS_6	UNDOCARGS_5
+
+# ifdef PIC
+#  define PSEUDO_JMP(sym) jbsr sym ## @PLTPC
+# else
+#  define PSEUDO_JMP(sym) jbsr sym
+# endif
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	PSEUDO_JMP (__pthread_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__pthread_disable_asynccancel)
+# elif !defined NOT_IN_libc
+#  define CENABLE	PSEUDO_JMP (__libc_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__libc_disable_asynccancel)
+# elif defined IS_IN_librt
+#  define CENABLE	PSEUDO_JMP (__librt_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__librt_disable_asynccancel)
+# else
+#  error Unsupported library
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P						\
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\
+				   header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P			\
+  PSEUDO_JMP (__m68k_read_tp);		        \
+  tst.l MULTIPLE_THREADS_OFFSET(%a0)
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION (1)
+
+#endif
+
+#ifndef __ASSEMBLER__
+# ifdef SHARED
+#  define RTLD_SINGLE_THREAD_P \
+  __builtin_expect (M68K_VDSO_SYMBOL (__vdso_read_tp) != NULL \
+		    ? THREAD_GETMEM (THREAD_SELF, \
+				     header.multiple_threads) == 0 \
+		    : 1, 1)
+# else
+#  define RTLD_SINGLE_THREAD_P					  \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,			  \
+				   header.multiple_threads) == 0, \
+		    1)
+# endif
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
new file mode 100644
index 0000000..d7fd1de
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
@@ -0,0 +1,37 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+	bsrl	__m68k_read_tp@PLTPC	; /* Get the thread pointer.  */ \
+	movel	%a0, %a1		; /* Save TP for RESTORE_PID.  */ \
+	movel	PID_OFFSET(%a1), %d0	; /* Get the PID.  */ \
+	movel	%d0, %d1		; /* Save PID for RESTORE_PID.  */ \
+	negl	%d0			; /* Negate the PID.  */ \
+	bne	1f			; /* If it was zero... */ \
+	movel	#0x80000000, %d0	; /* use 0x80000000 instead.  */ \
+1:	movel	%d0, PID_OFFSET(%a1)	; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+	tstl	%d0			; \
+	beq	1f			; /* If we are the parent... */ \
+	movel	%d1, PID_OFFSET(%a1)	; /* Restore the PID.  */ \
+1:	
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/socket.S b/sysdeps/unix/sysv/linux/m68k/socket.S
index 2690f18..d895e94 100644
--- a/sysdeps/unix/sysv/linux/m68k/socket.S
+++ b/sysdeps/unix/sysv/linux/m68k/socket.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 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
@@ -41,8 +41,11 @@
 
 .globl __socket
 ENTRY (__socket)
-#if defined NEED_CANCELLATION && defined CENABLE
-	SINGLE_THREAD_P (%a0)
+#ifdef NEED_CANCELLATION
+# if !defined CENABLE || !defined CDISABLE
+#  error CENABLE and/or CDISABLE is not defined
+# endif
+	SINGLE_THREAD_P
 	jne 1f
 #endif
 
@@ -69,21 +72,26 @@ ENTRY (__socket)
 	/* Successful; return the syscall's value.  */
 	rts
 
-#if defined NEED_CANCELLATION && defined CENABLE
-1:	/* Enable asynchronous cancellation.  */
+#ifdef NEED_CANCELLATION
+1:	cfi_startproc
+	/* Enable asynchronous cancellation.  */
 	CENABLE
 
-	/* Save registers.  */
+	/* Save D2.  */
 	move.l %d2, -(%sp)
-	move.l %d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
 
-	move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
+	/* Save the result of CENABLE.  */
+	move.l %d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
 
 	/* Use ## so `socket' is a separate token that might be #define'd.  */
 	move.l #P (SOCKOP_,socket), %d1	/* Subcode is first arg to syscall.  */
 	lea 4+8(%sp), %a1		/* Address of args is 2nd arg.  */
 	move.l %a1, %d2
 
+	move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
 	/* Do the system call trap.  */
 	trap #0
 
@@ -91,14 +99,18 @@ ENTRY (__socket)
 	move.l %d0, %d2
 	CDISABLE
 	addq.l #4, %sp
+	cfi_adjust_cfa_offset (-4)
 	move.l %d2, %d0
 
 	/* Restore registers.  */
 	move.l (%sp)+, %d2
+	cfi_adjust_cfa_offset (-4)
+	cfi_restore (%d2)
 
 	/* %d0 is < 0 if there was an error.  */
 	tst.l %d0
 	jmi SYSCALL_ERROR_LABEL
+	cfi_endproc
 
 	/* Successful; return the syscall's value.  */
 	rts
diff --git a/sysdeps/unix/sysv/linux/m68k/vfork.S b/sysdeps/unix/sysv/linux/m68k/vfork.S
index 8027b2f..5084a85 100644
--- a/sysdeps/unix/sysv/linux/m68k/vfork.S
+++ b/sysdeps/unix/sysv/linux/m68k/vfork.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2002, 2003, 2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab <schwab@gnu.org>.
 
@@ -22,6 +22,14 @@
 #include <bits/errno.h>
 #include <kernel-features.h>
 
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
 /* 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,
@@ -31,12 +39,20 @@ ENTRY (__vfork)
 
 #ifdef __NR_vfork
 
+	/* SAVE_PID clobbers call-clobbered registers and
+	   saves data in D1 and A1.  */
+
+	SAVE_PID
+	
 	/* Pop the return PC value into A0.  */
 	movel	%sp@+, %a0
 
 	/* Stuff the syscall number in D0 and trap into the kernel.  */
 	movel	#SYS_ify (vfork), %d0
 	trap	#0
+
+	RESTORE_PID
+
 	tstl	%d0
 	jmi	.Lerror		/* Branch forward if it failed.  */
 
-- 
1.6.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire] NPTL support and other updates
  2009-08-25 12:27 [M68K/ColdFire] NPTL support and other updates Maxim Kuvyrkov
                   ` (6 preceding siblings ...)
  2009-08-25 13:43 ` [M68K/ColdFire patch 7/n] Handle libgcc_s.so.2 Maxim Kuvyrkov
@ 2009-09-07 20:36 ` Andreas Schwab
  2009-09-08  5:52   ` Maxim Kuvyrkov
  2010-02-09 19:01 ` Maxim Kuvyrkov
  8 siblings, 1 reply; 31+ messages in thread
From: Andreas Schwab @ 2009-09-07 20:36 UTC (permalink / raw)
  To: Maxim Kuvyrkov; +Cc: libc-ports

Maxim Kuvyrkov <maxim@codesourcery.com> writes:

> Truth be told, I mainly focused on the ColdFire port, and didn't test the
> work on usual m68k.

I did some simple tests in aranym and the results look pretty good.

>  Still, to my knowledge, the only place m68k
> functionality is missing, is atomic macros implementations in
> ./sysdeps/unix/sysv/linux/m68k/nptl/atomic.h, which should be straight
> forward to fix: the memory barrier macro should be the same as in
> coldfire's implementation and compare_exchange macro should be a wrapper
> for 'cas'.

The generic macros in sysdeps/m68k/m680x0/m68020/bits/atomic.h should be
good enough, aren't they?

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire] NPTL support and other updates
  2009-09-07 20:36 ` [M68K/ColdFire] NPTL support and other updates Andreas Schwab
@ 2009-09-08  5:52   ` Maxim Kuvyrkov
  2009-09-13 17:07     ` Andreas Schwab
  0 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-09-08  5:52 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-ports

Andreas Schwab wrote:
> Maxim Kuvyrkov <maxim@codesourcery.com> writes:
> 
>> Truth be told, I mainly focused on the ColdFire port, and didn't test the
>> work on usual m68k.
> 
> I did some simple tests in aranym and the results look pretty good.
> 
>>  Still, to my knowledge, the only place m68k
>> functionality is missing, is atomic macros implementations in
>> ./sysdeps/unix/sysv/linux/m68k/nptl/atomic.h, which should be straight
>> forward to fix: the memory barrier macro should be the same as in
>> coldfire's implementation and compare_exchange macro should be a wrapper
>> for 'cas'.
> 
> The generic macros in sysdeps/m68k/m680x0/m68020/bits/atomic.h should be
> good enough, aren't they?

Yes, now that I'm looking at it, the compare_and_exchange macros are good.

You still need to add the definition for atomic_full_barrier macro to 
handle SMPs, even though current linux kernel has no support for it.

--
Maxim

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire] NPTL support and other updates
  2009-09-08  5:52   ` Maxim Kuvyrkov
@ 2009-09-13 17:07     ` Andreas Schwab
  0 siblings, 0 replies; 31+ messages in thread
From: Andreas Schwab @ 2009-09-13 17:07 UTC (permalink / raw)
  To: Maxim Kuvyrkov; +Cc: libc-ports

Maxim Kuvyrkov <maxim@codesourcery.com> writes:

> You still need to add the definition for atomic_full_barrier macro to
> handle SMPs, even though current linux kernel has no support for it.

I've never really cared about SMP on m68k, and I don't think we have to
start worrying.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 5/n] Main NPTL patch
  2009-08-30 18:03   ` Maxim Kuvyrkov
@ 2009-10-02 10:46     ` Maxim Kuvyrkov
  2009-10-23  9:39       ` Maxim Kuvyrkov
  0 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-10-02 10:46 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 891 bytes --]

Maxim Kuvyrkov wrote:
> Maxim Kuvyrkov wrote:
>> This is the main NPTL patch.  During development of this work I tried 
>> to make things work in the exactly same way as on other major 
>> architectures.
>>
>> I expect there will be comments on this one :)
> 
> After I did a clean rebuild of the work, I've caught several small 
> issues that were introduced by the last-minute cleanups.  So here is an 
> updated patch; I'm also attaching the difference between the patches for 
> easier review.

While investigating GLIBC testsuite failures I've fixed a bug in the 
initialization of the vDSO pointers.  Attached are the patch that fixes 
the bug and the whole updated NPTL patch.

With this fix, a patch for mmap2 and fixes to sigcontext and siginfo 
kernel headers (discussed on linux-m68k@) there are no unexpected 
failures in the GLIBC testsuite.

Regards,

--
Maxim K.
CodeSourcery

[-- Attachment #2: 0001-Don-t-bind-rtld-s-vdso-pointers-to-libc-symbols.patch --]
[-- Type: text/plain, Size: 2823 bytes --]

From c63be986e1dbe830ea5a54c006c406f3c19ac4e5 Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Fri, 2 Oct 2009 14:24:58 +0400
Subject: [PATCH] Don't bind rtld's vdso pointers to libc symbols

	* sysdeps/unix/sysv/linux/m68k/init-first.c
	(_libc_vsdo_platform_setup): Don't bind rtld's pointers to libc
	symbols.
	* sysdeps/unix/sysv/linux/m68k/sysdep-cancel.h (RTLD_SINGLE_THREAD_P):
	Simplify.

Signed-off-by: Maxim Kuvyrkov <maxim@codesourcery.com>
---
 sysdeps/unix/sysv/linux/m68k/init-first.c         |   20 ++++++++++++--------
 sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h |   10 +---------
 2 files changed, 13 insertions(+), 17 deletions(-)

diff --git a/sysdeps/unix/sysv/linux/m68k/init-first.c b/sysdeps/unix/sysv/linux/m68k/init-first.c
index 951b6fe..8b0ad05 100644
--- a/sysdeps/unix/sysv/linux/m68k/init-first.c
+++ b/sysdeps/unix/sysv/linux/m68k/init-first.c
@@ -39,27 +39,31 @@ _libc_vdso_platform_setup (void)
 
   p = _dl_vdso_vsym ("__kernel_read_tp", &linux26);
   if (p != NULL)
-    __vdso_read_tp = p;
+    {
+      __vdso_read_tp = p;
+      __rtld___vdso_read_tp = p;
+    }
   else
     assert (__vdso_read_tp == (void *) __vdso_read_tp_stub);
 
   p = _dl_vdso_vsym ("__kernel_atomic_cmpxchg_32", &linux26);
   if (p != NULL)
-    __vdso_atomic_cmpxchg_32 = p;
+    {
+      __vdso_atomic_cmpxchg_32 = p;
+      __rtld___vdso_atomic_cmpxchg_32 = p;
+    }
   else
     assert (__vdso_atomic_cmpxchg_32
 	    == (void *) __vdso_atomic_cmpxchg_32_stub);
 
   p = _dl_vdso_vsym ("__kernel_atomic_barrier", &linux26);
   if (p != NULL)
-    __vdso_atomic_barrier = p;
+    {
+      __vdso_atomic_barrier = p;
+      __rtld___vdso_atomic_barrier = p;
+    }
   else
     assert (__vdso_atomic_barrier == (void *) __vdso_atomic_barrier_stub);
-
-  /* Non-shared libc has only one set of the VDSO pointers.  */
-  __rtld___vdso_read_tp = __vdso_read_tp;
-  __rtld___vdso_atomic_cmpxchg_32 = __vdso_atomic_cmpxchg_32;
-  __rtld___vdso_atomic_barrier = __vdso_atomic_barrier;
 }
 
 #define VDSO_SETUP _libc_vdso_platform_setup
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
index 5ed7486..4bfb068 100644
--- a/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
@@ -133,16 +133,8 @@
 #endif
 
 #ifndef __ASSEMBLER__
-# ifdef SHARED
-#  define RTLD_SINGLE_THREAD_P \
-  __builtin_expect (M68K_VDSO_SYMBOL (__vdso_read_tp) != NULL \
-		    ? THREAD_GETMEM (THREAD_SELF, \
-				     header.multiple_threads) == 0 \
-		    : 1, 1)
-# else
-#  define RTLD_SINGLE_THREAD_P					  \
+# define RTLD_SINGLE_THREAD_P					  \
   __builtin_expect (THREAD_GETMEM (THREAD_SELF,			  \
 				   header.multiple_threads) == 0, \
 		    1)
-# endif
 #endif
-- 
1.6.4


[-- Attachment #3: 0001-Nptl-support-for-m68k-ColdFire.patch --]
[-- Type: text/plain, Size: 77893 bytes --]

From 34391d2bf5f2a5c0a15461fe0b412c6a60b0b3c1 Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Tue, 25 Aug 2009 16:42:47 +0400
Subject: [PATCH] Nptl support for m68k/ColdFire.

	* sysdeps/unix/sysv/linux/m68k/clone.S: Support RESET_PID.
	* sysdeps/unix/sysv/linux/m68k/m68k-helpers.S: New.
	* sysdeps/unix/sysv/linux/m68k/Makefile: Add new files to lists.
	* sysdeps/unix/sysv/linux/m68k/vfork.S: Add SAVE_PID/RESTORE_PID.
	* sysdeps/unix/sysv/linux/m68k/m68k-vdso.c: New.
	* sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h: New.
	* sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h: New.
	* sysdeps/unix/sysv/linux/m68k/Versions: Add symbols for NPTL support.
	* sysdeps/unix/sysv/linux/m68k/init-first.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/clone.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/fork.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/vfork.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/createthread.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c: New.
	* sysdeps/unix/sysv/linux/m68k/socket.S: Update cancelation code.
	* sysdeps/m68k/dl-tls.h: New.
	* sysdeps/m68k/libc-tls.c: New.
	* sysdeps/m68k/tls-macros.h: New.
	* sysdeps/m68k/dl-machine.h: Handle TLS relocations.
	* sysdeps/m68k/nptl/tcb-offsets.sym: New.
	* sysdeps/m68k/nptl/pthread_spin_trylock.c: New.
	* sysdeps/m68k/nptl/tls.h: New.
	* sysdeps/m68k/nptl/pthread_spin_lock.c: New.
	* sysdeps/m68k/nptl/pthreaddef.h: New.
	* sysdeps/m68k/nptl/Makefile: New.

This patch contains the main code of m68k/ColdFire NPTL support.
Please note that several additional fixes (see subsequent patches)
are necessary to make GLIBC build and work properly.

Signed-off-by: Maxim Kuvyrkov <maxim@codesourcery.com>
---
 sysdeps/m68k/dl-machine.h                          |   23 ++-
 sysdeps/m68k/dl-tls.h                              |   47 ++++
 sysdeps/m68k/libc-tls.c                            |   37 +++
 sysdeps/m68k/nptl/Makefile                         |   21 ++
 sysdeps/m68k/nptl/pthread_spin_lock.c              |   30 ++
 sysdeps/m68k/nptl/pthread_spin_trylock.c           |   27 ++
 sysdeps/m68k/nptl/pthreaddef.h                     |   38 +++
 sysdeps/m68k/nptl/tcb-offsets.sym                  |   11 +
 sysdeps/m68k/nptl/tls.h                            |  170 ++++++++++++
 sysdeps/m68k/tls-macros.h                          |   69 +++++
 sysdeps/unix/sysv/linux/m68k/Makefile              |    6 +
 sysdeps/unix/sysv/linux/m68k/Versions              |   12 +
 sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h      |   60 +++++
 sysdeps/unix/sysv/linux/m68k/clone.S               |   52 ++++-
 .../sysv/linux/m68k/coldfire/nptl/bits/atomic.h    |  104 ++++++++
 sysdeps/unix/sysv/linux/m68k/init-first.c          |   73 +++++
 sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c      |    1 +
 sysdeps/unix/sysv/linux/m68k/m68k-helpers.S        |  104 ++++++++
 sysdeps/unix/sysv/linux/m68k/m68k-vdso.c           |   34 +++
 .../unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h  |  171 ++++++++++++
 sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h |   35 +++
 sysdeps/unix/sysv/linux/m68k/nptl/clone.S          |    2 +
 sysdeps/unix/sysv/linux/m68k/nptl/createthread.c   |   24 ++
 sysdeps/unix/sysv/linux/m68k/nptl/fork.c           |   29 ++
 sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h   |  280 ++++++++++++++++++++
 sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S       |   35 +++
 sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c   |   90 +++++++
 sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h  |  140 ++++++++++
 sysdeps/unix/sysv/linux/m68k/nptl/vfork.S          |   37 +++
 sysdeps/unix/sysv/linux/m68k/socket.S              |   28 ++-
 sysdeps/unix/sysv/linux/m68k/vfork.S               |   18 ++-
 31 files changed, 1794 insertions(+), 14 deletions(-)
 create mode 100644 sysdeps/m68k/dl-tls.h
 create mode 100644 sysdeps/m68k/libc-tls.c
 create mode 100644 sysdeps/m68k/nptl/Makefile
 create mode 100644 sysdeps/m68k/nptl/pthread_spin_lock.c
 create mode 100644 sysdeps/m68k/nptl/pthread_spin_trylock.c
 create mode 100644 sysdeps/m68k/nptl/pthreaddef.h
 create mode 100644 sysdeps/m68k/nptl/tcb-offsets.sym
 create mode 100644 sysdeps/m68k/nptl/tls.h
 create mode 100644 sysdeps/m68k/tls-macros.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/init-first.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
 create mode 100644 sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/clone.S
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/fork.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
 create mode 100644 sysdeps/unix/sysv/linux/m68k/nptl/vfork.S

diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
index 08a4396..098dc8d 100644
--- a/sysdeps/m68k/dl-machine.h
+++ b/sysdeps/m68k/dl-machine.h
@@ -1,5 +1,6 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  m68k version.
-   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 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
@@ -24,6 +25,7 @@
 
 #include <sys/param.h>
 #include <sysdep.h>
+#include <dl-tls.h>
 
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int
@@ -262,6 +264,25 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 	case R_68K_PC32:
 	  *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
 	  break;
+#if defined USE_TLS && !defined RTLD_BOOTSTRAP
+	case R_68K_TLS_DTPMOD32:
+	  /* Get the information from the link map returned by the
+	     resolv function.  */
+	  if (sym_map != NULL)
+	    *reloc_addr = sym_map->l_tls_modid;
+	  break;
+	case R_68K_TLS_DTPREL32:
+	  if (sym != NULL)
+	    *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
+	  break;
+	case R_68K_TLS_TPREL32:
+	  if (sym != NULL)
+	    {
+	      CHECK_STATIC_TLS (map, sym_map);
+	      *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
+	    }
+	  break;
+#endif /* defined USE_TLS && !defined RTLD_BOOTSTRAP */
 	case R_68K_NONE:		/* Alright, Wilbur.  */
 	  break;
 	default:
diff --git a/sysdeps/m68k/dl-tls.h b/sysdeps/m68k/dl-tls.h
new file mode 100644
index 0000000..249e0e2
--- /dev/null
+++ b/sysdeps/m68k/dl-tls.h
@@ -0,0 +1,47 @@
+/* Thread-local storage handling in the ELF dynamic linker.  M68K version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* The thread pointer points 0x7000 past the first static TLS block.  */
+#define TLS_TP_OFFSET		0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET		0x8000
+
+/* Compute the value for a TPREL reloc.  */
+#define TLS_TPREL_VALUE(sym_map, sym, reloc)				\
+  ((sym_map)->l_tls_offset + (sym)->st_value + (reloc)->r_addend	\
+   - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc.  */
+#define TLS_DTPREL_VALUE(sym, reloc)				\
+  ((sym)->st_value + (reloc)->r_addend - TLS_DTV_OFFSET)
+
+extern void *__tls_get_addr (tls_index *ti);
+
+#define GET_ADDR_OFFSET	        (ti->ti_offset + TLS_DTV_OFFSET)
+#define __TLS_GET_ADDR(__ti)	(__tls_get_addr (__ti) - TLS_DTV_OFFSET)
diff --git a/sysdeps/m68k/libc-tls.c b/sysdeps/m68k/libc-tls.c
new file mode 100644
index 0000000..b4e5129
--- /dev/null
+++ b/sysdeps/m68k/libc-tls.c
@@ -0,0 +1,37 @@
+/* Thread-local storage handling in the ELF dynamic linker.  m68k version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <csu/libc-tls.c>
+#include <dl-tls.h>
+
+#if USE_TLS
+
+/* On M68K, linker optimizations are not required, so __tls_get_addr
+   can be called even in statically linked binaries.  In this case module
+   must be always 1 and PT_TLS segment exist in the binary, otherwise it
+   would not link.  */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET;
+}
+
+#endif
diff --git a/sysdeps/m68k/nptl/Makefile b/sysdeps/m68k/nptl/Makefile
new file mode 100644
index 0000000..f0bcefb
--- /dev/null
+++ b/sysdeps/m68k/nptl/Makefile
@@ -0,0 +1,21 @@
+# Copyright (C) 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; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/sysdeps/m68k/nptl/pthread_spin_lock.c b/sysdeps/m68k/nptl/pthread_spin_lock.c
new file mode 100644
index 0000000..413e8cc
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthread_spin_lock.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  while (atomic_compare_and_exchange_val_acq(lock, 1, 0) != 0)
+   while (*lock != 0)
+    ;
+
+  return 0;
+}
diff --git a/sysdeps/m68k/nptl/pthread_spin_trylock.c b/sysdeps/m68k/nptl/pthread_spin_trylock.c
new file mode 100644
index 0000000..d2b4870
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthread_spin_trylock.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  return atomic_compare_and_exchange_val_acq(lock, 1, 0) ? EBUSY : 0;
+}
diff --git a/sysdeps/m68k/nptl/pthreaddef.h b/sysdeps/m68k/nptl/pthreaddef.h
new file mode 100644
index 0000000..e52694d
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthreaddef.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* 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/sysdeps/m68k/nptl/tcb-offsets.sym b/sysdeps/m68k/nptl/tcb-offsets.sym
new file mode 100644
index 0000000..b1bba65
--- /dev/null
+++ b/sysdeps/m68k/nptl/tcb-offsets.sym
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Derive offsets relative to the thread register.
+#define thread_offsetof(mem)	(long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads)
+PID_OFFSET			thread_offsetof (pid)
+TID_OFFSET			thread_offsetof (tid)
diff --git a/sysdeps/m68k/nptl/tls.h b/sysdeps/m68k/nptl/tls.h
new file mode 100644
index 0000000..5b9817e
--- /dev/null
+++ b/sysdeps/m68k/nptl/tls.h
@@ -0,0 +1,170 @@
+/* Definition for thread-local data handling.  NPTL/m68k version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H	1
+
+#include <dl-sysdep.h>
+
+#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__ */
+
+/* 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 <nptl/descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_INIT_TCB_SIZE	0
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN	__alignof__ (struct pthread)
+
+/* This is the size of the TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_TCB_SIZE		0
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN		__alignof__ (struct pthread)
+
+/* This is the size we need before TCB - actually, it includes the TCB.  */
+# define TLS_PRE_TCB_SIZE						\
+  (sizeof (struct pthread)						\
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* The thread pointer (TP) points to the end of the
+   TCB + 0x7000, as for PowerPC and MIPS.  This implies that TCB address is
+   TP - 0x7000.  As we define TLS_DTV_AT_TP we can
+   assume that the pthread struct is allocated immediately ahead of the
+   TCB.  This implies that the pthread_descr address is
+   TP - (TLS_PRE_TCB_SIZE + 0x7000).  */
+# define TLS_TCB_OFFSET	0x7000
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV () = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall)					\
+  ({									\
+    INTERNAL_SYSCALL_DECL (err);					\
+    int _sys_result;							\
+									\
+    _sys_result = INTERNAL_SYSCALL (write_tp, err, 1,			\
+				    ((void *) (tcbp)) + TLS_TCB_OFFSET); \
+    INTERNAL_SYSCALL_ERROR_P (_sys_result, err) ? "unknown error" : NULL; })
+
+extern void * __m68k_read_tp (void);
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) (__m68k_read_tp () - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+  ((struct pthread *) (__m68k_read_tp () - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Access to data in the thread descriptor is easy.  */
+# define THREAD_GETMEM(descr, member) \
+  descr->member
+# define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+# define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* l_tls_offset == 0 is perfectly valid on M68K, so we have to use some
+   different value to mean unset l_tls_offset.  */
+# define NO_TLS_OFFSET		-1
+
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG()					\
+  do									\
+    { int __res								\
+	= atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,	\
+			       THREAD_GSCOPE_FLAG_UNUSED);		\
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)				\
+	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+    }									\
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG()					\
+  do									\
+    {									\
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;	\
+      atomic_write_barrier ();						\
+    }									\
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif	/* tls.h */
diff --git a/sysdeps/m68k/tls-macros.h b/sysdeps/m68k/tls-macros.h
new file mode 100644
index 0000000..a15f8b9
--- /dev/null
+++ b/sysdeps/m68k/tls-macros.h
@@ -0,0 +1,69 @@
+/* Macros for accessing thread-local storage.  m68k version.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define TLS_GD(x)							\
+  ({									\
+    void *__result;							\
+    extern void *__tls_get_addr (void *);				\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "lea " #x "@TLSGD(%0), %0"					\
+	 : "=&a" (__result));						\
+    (int *) __tls_get_addr (__result); })
+
+#define TLS_LD(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void *__tls_get_addr (void *);				\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "lea " #x "@TLSLDM(%0), %0"					\
+	 : "=&a" (__tp));						\
+    __tp = (char *) __tls_get_addr (__tp);				\
+    asm ("movel #" #x "@TLSLDO, %0"					\
+	 : "=a" (__offset));						\
+    (int *) (__tp + __offset); })
+
+#define TLS_IE(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void * __m68k_read_tp (void);				\
+									\
+    __tp = (char *) __m68k_read_tp ();					\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "movel " #x "@TLSIE(%0), %0"					\
+	 : "=&a" (__offset));						\
+    (int *) (__tp + __offset); })
+
+#define TLS_LE(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void * __m68k_read_tp (void);				\
+									\
+    __tp = (char *) __m68k_read_tp ();					\
+    asm ("movel #" #x "@TLSLE, %0"					\
+	 : "=a" (__offset));						\
+    (int *) (__tp + __offset); })
+
diff --git a/sysdeps/unix/sysv/linux/m68k/Makefile b/sysdeps/unix/sysv/linux/m68k/Makefile
index 6bb4f6b..97d9584 100644
--- a/sysdeps/unix/sysv/linux/m68k/Makefile
+++ b/sysdeps/unix/sysv/linux/m68k/Makefile
@@ -2,12 +2,18 @@
 
 m68k-syntax-flag = -DMOTOROLA_SYNTAX
 
+ifeq ($(subdir),csu)
+sysdep_routines += m68k-helpers
+endif
+
 ifeq ($(subdir),misc)
 sysdep_routines += mremap
 sysdep_headers += sys/reg.h
 endif
 
 ifeq ($(subdir),elf)
+sysdep_routines += dl-vdso libc-m68k-vdso
+sysdep-rtld-routines += m68k-vdso
 sysdep-others += lddlibc4
 install-bin += lddlibc4
 endif
diff --git a/sysdeps/unix/sysv/linux/m68k/Versions b/sysdeps/unix/sysv/linux/m68k/Versions
index 5650f7f..152f7aa 100644
--- a/sysdeps/unix/sysv/linux/m68k/Versions
+++ b/sysdeps/unix/sysv/linux/m68k/Versions
@@ -31,5 +31,17 @@ libc {
   }
   GLIBC_2.11 {
     fallocate64;
+    __m68k_read_tp;
+  }
+  GLIBC_PRIVATE {
+    __vdso_atomic_cmpxchg_32; __vdso_atomic_barrier;
+  }
+}
+
+ld {
+  GLIBC_PRIVATE {
+    __rtld___vdso_read_tp;
+    __rtld___vdso_atomic_cmpxchg_32;
+    __rtld___vdso_atomic_barrier;
   }
 }
diff --git a/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
new file mode 100644
index 0000000..3d809cf
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
@@ -0,0 +1,60 @@
+/* Resolve function pointers to VDSO functions.
+   Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+#ifndef _M68K_VDSO_H
+#define _M68K_VDSO_H
+
+#ifdef SHARED
+
+# ifdef IS_IN_rtld
+# define M68K_VDSO_SYMBOL(name) __rtld_##name
+# define STR_M68K_VDSO_SYMBOL(name) "__rtld_" #name
+# else
+# define M68K_VDSO_SYMBOL(name) name
+# define STR_M68K_VDSO_SYMBOL(name) #name
+# endif
+
+# ifndef __ASSEMBLER__
+
+/* We define __rtld_* copies for rtld.
+   We need them visible in libc to initialize.  */
+#  if defined IS_IN_rtld || !defined NOT_IN_libc
+extern void *__rtld___vdso_read_tp;
+extern void *__rtld___vdso_atomic_cmpxchg_32;
+extern void *__rtld___vdso_atomic_barrier;
+
+/* These stubs are meant to be invoked only from the assembly.  */
+extern void __vdso_read_tp_stub (void);
+extern void __vdso_atomic_cmpxchg_32_stub (void);
+extern void __vdso_atomic_barrier_stub (void);
+#  endif /* IS_IN_rtld || !NOT_IN_libc */
+
+/* RTLD should only use its own copies.  */
+#  ifndef IS_IN_rtld
+extern void *__vdso_read_tp;
+extern void *__vdso_atomic_cmpxchg_32;
+extern void *__vdso_atomic_barrier;
+#  endif /* !IS_IN_rtld */
+
+# endif /* !__ASSEMBLER__ */
+
+#endif /* SHARED */
+
+#endif /* _M68K_VDSO_H */
diff --git a/sysdeps/unix/sysv/linux/m68k/clone.S b/sysdeps/unix/sysv/linux/m68k/clone.S
index a179f8e..4135cd0 100644
--- a/sysdeps/unix/sysv/linux/m68k/clone.S
+++ b/sysdeps/unix/sysv/linux/m68k/clone.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996,97,98,2002,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
 
@@ -17,14 +17,21 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-/* clone is even more special than fork as it mucks with stacks
+/* clone() is even more special than fork() as it mucks with stacks
    and invokes a function in the right context after its all over.  */
 
 #include <sysdep.h>
 #define _ERRNO_H	1
 #include <bits/errno.h>
+#ifdef RESET_PID
+#include <tls.h>
+#endif
+
+#define CLONE_VM      0x00000100
+#define CLONE_THREAD  0x00010000
 
-/* 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,
+	     void *parent_tidptr, void *tls, void *child_tidptr) */
 
         .text
 ENTRY (__clone)
@@ -42,7 +49,17 @@ ENTRY (__clone)
 	movel	16(%sp), -(%a1)
 
 	/* Do the system call */
-	movel	12(%sp), %d1		/* get flags */
+	movel	12+0(%sp), %d1		/* get flags */
+	movel	%d3, -(%a1)             /* save %d3 and get parent_tidptr */
+	movel	%d3, -(%sp)
+	movel	20+4(%sp), %d3
+	movel	%d4, -(%a1)		/* save %d4 and get child_tidptr */
+	movel	%d4, -(%sp)
+	movel	28+8(%sp), %d4
+	movel	%d5, -(%a1)             /* save %d5 and get tls */
+	movel	%d5, -(%sp)
+	movel	24+12(%sp), %d5
+	/* save %d2 and get stack pointer */
 #ifdef __mcoldfire__
 	movel	%d2, -(%a1)
 	movel	%d2, -(%sp)
@@ -57,6 +74,9 @@ ENTRY (__clone)
 #else
 	exg	%d2, %a1		/* restore %d2 */
 #endif
+	movel	(%sp)+, %d5             /* restore %d5, %d4 and %d3 */
+	movel	(%sp)+, %d4
+	movel	(%sp)+, %d3
 
 	tstl	%d0
 	jmi	SYSCALL_ERROR_LABEL
@@ -65,11 +85,35 @@ ENTRY (__clone)
 	rts
 
 thread_start:
+	cfi_startproc
+	cfi_undefined (pc)	/* Mark end of stack */
 	subl	%fp, %fp	/* terminate the stack frame */
+#ifdef RESET_PID
+	/* Check and see if we need to reset the PID.  */
+	movel	%d1, %a1
+	andl	#CLONE_THREAD, %d1
+	jne	donepid
+	movel	%a1, %d1
+	movel	#-1, %d0
+	andl	#CLONE_VM, %d1
+	jne	gotpid
+	movel	#SYS_ify (getpid), %d0
+	trap	#0
+gotpid:
+	movel	%a0, -(%sp)
+	movel	%d0, -(%sp)
+	bsrl	__m68k_read_tp@PLTPC
+	movel	(%sp)+, %d0
+	movel	%d0, PID_OFFSET(%a0)
+	movel	%d0, TID_OFFSET(%a0)
+	movel	(%sp)+, %a0
+donepid:
+#endif
 	jsr	(%a0)
 	movel	%d0, %d1
 	movel	#SYS_ify (exit), %d0
 	trap	#0
+	cfi_endproc
 
 PSEUDO_END (__clone)
 
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
new file mode 100644
index 0000000..972eb17
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
@@ -0,0 +1,104 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H	1
+
+#include <stdint.h>
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+/* Coldfire has no atomic compare-and-exchange operation, but the
+   kernel provides userspace atomicity operations.  Use them.  */
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+/* The only basic operation needed is compare and exchange.  */
+/* For ColdFire we'll have to trap into the kernel mode anyway,
+   so trap from the library rather then from the kernel wrapper.  */
+#ifdef SHARED
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  ({									\
+    /* Use temporary variables to workaround call-clobberness of */	\
+    /* the registers.  */						\
+    __typeof (mem) _mem = mem;						\
+    __typeof (oldval) _oldval = oldval;					\
+    __typeof (newval) _newval = newval;					\
+    register __typeof (mem) _a0 asm ("a0") = _mem;			\
+    register __typeof (oldval) _d0 asm ("d0") = _oldval;		\
+    register __typeof (newval) _d1 asm ("d1") = _newval;		\
+    void *tmp;								\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %2\n\t"			\
+	 "lea (-6, %%pc, %2), %2\n\t"					\
+	 "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)	\
+	 "@GOT(%2), %2\n\t"						\
+	 "movel (%2), %2\n\t"						\
+	 "jsr (%2)\n\t"							\
+	 : "+d" (_d0), "+m" (*_a0), "=&a" (tmp)				\
+	 : "a" (_a0), "d" (_d1));					\
+    _d0;								\
+  })
+#else
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  ({									\
+    /* Use temporary variables to workaround call-clobberness of */	\
+    /* the registers.  */						\
+    __typeof (mem) _mem = mem;						\
+    __typeof (oldval) _oldval = oldval;					\
+    __typeof (newval) _newval = newval;					\
+    register __typeof (oldval) _d0 asm ("d0")				\
+      = SYS_ify (atomic_cmpxchg_32);					\
+    register __typeof (mem) _a0 asm ("a0") = _mem;			\
+    register __typeof (oldval) _d2 asm ("d2") = _oldval;		\
+    register __typeof (newval) _d1 asm ("d1") = _newval;		\
+									\
+    asm ("trap #0"							\
+	 : "+d" (_d0), "+m" (*_a0)					\
+	 : "a" (_a0), "d" (_d2), "d" (_d1));				\
+    _d0;								\
+  })
+#endif
+
+#ifdef SHARED
+# define atomic_full_barrier()					 \
+  ({								 \
+    void *tmp;							 \
+								 \
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"		 \
+	 "lea (-6, %pc, %0), %0\n\t"				 \
+	 "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_barrier)	 \
+	 "@GOT(%0), %0\n\t"					 \
+	 "movel (%0), %0\n\t"					 \
+	 "jsr (%0)\n\t"						 \
+	 : "=&a" (tmp));					 \
+  })
+#else
+# define atomic_full_barrier()				\
+  (INTERNAL_SYSCALL (atomic_barrier, , 0), (void) 0)
+#endif
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/init-first.c b/sysdeps/unix/sysv/linux/m68k/init-first.c
new file mode 100644
index 0000000..8b0ad05
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/init-first.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Note: linking in vDSO to a static binary requires changes to
+   the main GLIBC proper.  Not yet implemented.  */
+#ifdef SHARED
+
+#include <dl-vdso.h>
+#include <bits/m68k-vdso.h>
+
+static inline void
+_libc_vdso_platform_setup (void)
+{
+  void *p;
+
+  PREPARE_VERSION (linux26, "LINUX_2.6", 61765110);
+
+  /* It may happen that rtld didn't initialize the vDSO, so fallback
+     to the syscall implementations if _dl_vdso_vsym returns NULL.
+     This may happen when a static executable dlopen's a dynamic library.
+     This really is nothing more than a workaround for rtld/csu
+     deficiency.  Ideally, init code would setup the vDSO for static
+     binaries too.  */
+
+  p = _dl_vdso_vsym ("__kernel_read_tp", &linux26);
+  if (p != NULL)
+    {
+      __vdso_read_tp = p;
+      __rtld___vdso_read_tp = p;
+    }
+  else
+    assert (__vdso_read_tp == (void *) __vdso_read_tp_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_cmpxchg_32", &linux26);
+  if (p != NULL)
+    {
+      __vdso_atomic_cmpxchg_32 = p;
+      __rtld___vdso_atomic_cmpxchg_32 = p;
+    }
+  else
+    assert (__vdso_atomic_cmpxchg_32
+	    == (void *) __vdso_atomic_cmpxchg_32_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_barrier", &linux26);
+  if (p != NULL)
+    {
+      __vdso_atomic_barrier = p;
+      __rtld___vdso_atomic_barrier = p;
+    }
+  else
+    assert (__vdso_atomic_barrier == (void *) __vdso_atomic_barrier_stub);
+}
+
+#define VDSO_SETUP _libc_vdso_platform_setup
+
+#endif /* SHARED */
+
+#include <sysdeps/unix/sysv/linux/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
new file mode 100644
index 0000000..45982e9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
@@ -0,0 +1 @@
+#include "m68k-vdso.c"
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
new file mode 100644
index 0000000..d9ccb4f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
@@ -0,0 +1,104 @@
+/* Copyright (C) 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.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+	.text
+
+	.hidden __vdso_read_tp_stub
+ENTRY (__vdso_read_tp_stub)
+	cfi_startproc
+	move.l	#__NR_read_tp, %d0
+	trap	#0
+	move.l	%d0, %a0
+	rts
+	cfi_endproc
+END (__vdso_read_tp_stub)
+
+# ifdef SHARED
+/* GCC will emit calls to this routine.  Linux has an
+   equivalent helper function (which clobbers fewer registers than
+   a normal function call) in a vdso; tail call to the
+   helper.  */
+# ifdef IS_IN_rtld
+/* rtld gets a hidden copy of __m68k_read_tp.  */
+	.hidden __m68k_read_tp
+# endif
+ENTRY (__m68k_read_tp)
+	cfi_startproc
+	move.l	#_GLOBAL_OFFSET_TABLE_@GOTPC, %a0
+	lea	(-6, %pc, %a0), %a0
+	move.l	M68K_VDSO_SYMBOL (__vdso_read_tp)@GOT(%a0), %a0
+	move.l	(%a0), %a0
+	jmp	(%a0)
+	cfi_endproc
+END (__m68k_read_tp)
+
+/* The following two stubs are for macros in atomic.h, they can't
+   clobber anything.  */
+
+	.hidden __vdso_atomic_cmpxchg_32_stub
+ENTRY (__vdso_atomic_cmpxchg_32_stub)
+	cfi_startproc
+	move.l	%d2, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
+	move.l	%d0, %d2
+	move.l	#SYS_ify (atomic_cmpxchg_32), %d0
+	trap	#0
+	move.l	(%sp)+, %d2
+	cfi_adjust_cfa_offset (-4)
+	cfi_restore (%d2)
+	rts
+	cfi_endproc
+END (__vdso_atomic_cmpxchg_32_stub)
+	
+	.hidden __vdso_atomic_barrier_stub
+ENTRY (__vdso_atomic_barrier_stub)
+	cfi_startproc
+	move.l	%d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	move.l	#SYS_ify (atomic_barrier), %d0
+	trap	#0
+	move.l	(%sp)+, %d0
+	cfi_adjust_cfa_offset (-4)
+	rts
+	cfi_endproc
+END (__vdso_atomic_barrier_stub)
+# else /* !SHARED */
+/* If the vDSO is not available, use a syscall to get TP.  */
+	strong_alias (__vdso_read_tp_stub, __m68k_read_tp)
+# endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
new file mode 100644
index 0000000..a605039
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifdef SHARED
+
+#include <bits/m68k-vdso.h>
+
+/* Because these pointers are used from other libraries than libc,
+   they are exported at GLIBC_PRIVATE version.
+   We initialize them to syscall implementation so that they will be ready
+   to use from the very beginning.  */
+void * M68K_VDSO_SYMBOL (__vdso_read_tp)
+= (void *) __vdso_read_tp_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)
+= (void *) __vdso_atomic_cmpxchg_32_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_barrier)
+= (void *) __vdso_atomic_barrier_stub;
+
+#endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
new file mode 100644
index 0000000..b3c719c
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
@@ -0,0 +1,171 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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_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
+   deliberately not exposed.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+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 deliberately not exposed.  */
+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;
+
+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 deliberately not exposed.  */
+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 deliberately not exposed.  */
+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;
+    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;
+    int __writer;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+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/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
new file mode 100644
index 0000000..c72ddcc
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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/sysdeps/unix/sysv/linux/m68k/nptl/clone.S b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
new file mode 100644
index 0000000..e7388fe
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include "../clone.S"
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
new file mode 100644
index 0000000..537a5e9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE ((void *) (pd) \
+		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation.	 */
+#include <nptl/sysdeps/pthread/createthread.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/fork.c b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
new file mode 100644
index 0000000..1e4de36
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
@@ -0,0 +1,29 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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, &THREAD_SELF->tid, NULL)
+
+#include <sysdeps/unix/sysv/linux/fork.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
new file mode 100644
index 0000000..8ab444b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
@@ -0,0 +1,280 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Borrowed from ARM's version.  */
+
+#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 <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 __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAIT, private),	      \
+			      (val), (timespec));			      \
+    __ret;								      \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAKE, private),	      \
+			      (nr), 0);					      \
+    __ret;								      \
+  })
+
+#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 __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),		      \
+			      __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+			      (nr_wake), (nr_move), (mutex), (val));	      \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __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 __ret;							      \
+    __ret = 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 (__ret, __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(lock, id)			\
+  atomic_compare_and_exchange_val_acq (&(lock), id, 0)
+
+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 (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex,       \
+								1, 0), 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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+								0), 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 (__builtin_expect (atomic_exchange_acq (__futex, 2), 0))		      \
+      __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 (__builtin_expect (atomic_exchange_acq (__futex, 1), 0))	      \
+       __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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+								0), 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 (__builtin_expect (__oldval > 1, 0))			\
+	 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 (__builtin_expect (__oldval & FUTEX_WAITERS, 0))	\
+	 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/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
new file mode 100644
index 0000000..087a3bb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
@@ -0,0 +1,35 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+	bsrl	__m68k_read_tp@PLTPC	; /* Get the thread pointer.  */ \
+	movel	%a0, %a1		; /* Save TP for RESTORE_PID.  */ \
+	movel	PID_OFFSET(%a1), %d0	; /* Get the PID.  */ \
+	movel	%d0, %d1		; /* Save PID for RESTORE_PID.  */ \
+	negl	%d0			; /* Negate the PID.  */ \
+	movel	%d0, PID_OFFSET(%a1)	; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+	tstl	%d0			; \
+	beq	1f			; /* If we are the parent... */ \
+	movel	%d1, PID_OFFSET(%a1)	; /* Restore the PID.  */ \
+1:	
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
new file mode 100644
index 0000000..6ef86b2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
@@ -0,0 +1,90 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
new file mode 100644
index 0000000..4bfb068
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
@@ -0,0 +1,140 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				      \
+  .text;								      \
+  ENTRY (name)								      \
+    SINGLE_THREAD_P;							      \
+    jne .Lpseudo_cancel;						      \
+  .type __##syscall_name##_nocancel,@function;			              \
+  .globl __##syscall_name##_nocancel;				 	      \
+  __##syscall_name##_nocancel:					              \
+    DO_CALL (syscall_name, args);					      \
+    cmp.l &-4095, %d0;							      \
+    jcc SYSCALL_ERROR_LABEL;						      \
+    rts;								      \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \
+  .Lpseudo_cancel:							      \
+    cfi_startproc;							      \
+    CENABLE;								      \
+    DOCARGS_##args							      \
+    move.l %d0, -(%sp); /* Save result of CENABLE.  */  		      \
+    cfi_adjust_cfa_offset (4); \
+    move.l &SYS_ify (syscall_name), %d0;				      \
+    trap &0;								      \
+    move.l %d0, %d2;							      \
+    CDISABLE;								      \
+    addq.l &4, %sp; /* Remove result of CENABLE from the stack.  */           \
+    cfi_adjust_cfa_offset (-4); \
+    move.l %d2, %d0;							      \
+    UNDOCARGS_##args							      \
+    cmp.l &-4095, %d0;							      \
+    jcc SYSCALL_ERROR_LABEL;		                                      \
+    cfi_endproc
+
+/* Note: we use D2 to save syscall's return value as D0 will be clobbered in
+   CDISABLE.  */
+# define DOCARGS_0	move.l %d2, -(%sp);		\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d2, 0);
+# define UNDOCARGS_0	move.l (%sp)+, %d2;	\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d2);
+
+# define DOCARGS_1	_DOCARGS_1 (4); DOCARGS_0
+# define _DOCARGS_1(n)	move.l n(%sp), %d1;
+# define UNDOCARGS_1	UNDOCARGS_0
+
+# define DOCARGS_2	_DOCARGS_2 (8)
+# define _DOCARGS_2(n)	DOCARGS_0 move.l n+4(%sp), %d2; _DOCARGS_1 (n)
+# define UNDOCARGS_2	UNDOCARGS_0
+
+/* TODO: We can optimize DOCARGS_{3, 4} by saving registers to a0 and a1
+   instead of pushing them on stack.  */
+# define DOCARGS_3	_DOCARGS_3 (12)
+# define _DOCARGS_3(n)	move.l %d3, -(%sp);				\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d3, 0);			\
+  move.l n+4(%sp), %d3; _DOCARGS_2 (n)
+# define UNDOCARGS_3	UNDOCARGS_2 move.l (%sp)+, %d3;		\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d3);
+
+# define DOCARGS_4	_DOCARGS_4 (16)
+# define _DOCARGS_4(n)	move.l %d4, -(%sp);			\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d4, 0);		\
+  move.l n+4(%sp), %d4; _DOCARGS_3 (n)
+# define UNDOCARGS_4	UNDOCARGS_3 move.l (%sp)+, %d4;	\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d4);
+
+# define DOCARGS_5	_DOCARGS_5 (20)
+# define _DOCARGS_5(n)	move.l %d5, %a1; cfi_register (%d5, a1); \
+  move.l n(%sp), %d5; _DOCARGS_4 (n-4)
+# define UNDOCARGS_5	UNDOCARGS_4 move.l %a1, %d5; cfi_restore (%d5);
+
+# define DOCARGS_6	_DOCARGS_6 (24)
+# define _DOCARGS_6(n)	move.l n(%sp), %a0; _DOCARGS_5 (n-4)
+# define UNDOCARGS_6	UNDOCARGS_5
+
+# ifdef PIC
+#  define PSEUDO_JMP(sym) jbsr sym ## @PLTPC
+# else
+#  define PSEUDO_JMP(sym) jbsr sym
+# endif
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	PSEUDO_JMP (__pthread_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__pthread_disable_asynccancel)
+# elif !defined NOT_IN_libc
+#  define CENABLE	PSEUDO_JMP (__libc_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__libc_disable_asynccancel)
+# elif defined IS_IN_librt
+#  define CENABLE	PSEUDO_JMP (__librt_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__librt_disable_asynccancel)
+# else
+#  error Unsupported library
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P						\
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\
+				   header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P			\
+  PSEUDO_JMP (__m68k_read_tp);		        \
+  tst.l MULTIPLE_THREADS_OFFSET(%a0)
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION (1)
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P					  \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,			  \
+				   header.multiple_threads) == 0, \
+		    1)
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
new file mode 100644
index 0000000..d7fd1de
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
@@ -0,0 +1,37 @@
+/* Copyright (C) 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; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+	bsrl	__m68k_read_tp@PLTPC	; /* Get the thread pointer.  */ \
+	movel	%a0, %a1		; /* Save TP for RESTORE_PID.  */ \
+	movel	PID_OFFSET(%a1), %d0	; /* Get the PID.  */ \
+	movel	%d0, %d1		; /* Save PID for RESTORE_PID.  */ \
+	negl	%d0			; /* Negate the PID.  */ \
+	bne	1f			; /* If it was zero... */ \
+	movel	#0x80000000, %d0	; /* use 0x80000000 instead.  */ \
+1:	movel	%d0, PID_OFFSET(%a1)	; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+	tstl	%d0			; \
+	beq	1f			; /* If we are the parent... */ \
+	movel	%d1, PID_OFFSET(%a1)	; /* Restore the PID.  */ \
+1:	
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/socket.S b/sysdeps/unix/sysv/linux/m68k/socket.S
index 2690f18..d895e94 100644
--- a/sysdeps/unix/sysv/linux/m68k/socket.S
+++ b/sysdeps/unix/sysv/linux/m68k/socket.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 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
@@ -41,8 +41,11 @@
 
 .globl __socket
 ENTRY (__socket)
-#if defined NEED_CANCELLATION && defined CENABLE
-	SINGLE_THREAD_P (%a0)
+#ifdef NEED_CANCELLATION
+# if !defined CENABLE || !defined CDISABLE
+#  error CENABLE and/or CDISABLE is not defined
+# endif
+	SINGLE_THREAD_P
 	jne 1f
 #endif
 
@@ -69,21 +72,26 @@ ENTRY (__socket)
 	/* Successful; return the syscall's value.  */
 	rts
 
-#if defined NEED_CANCELLATION && defined CENABLE
-1:	/* Enable asynchronous cancellation.  */
+#ifdef NEED_CANCELLATION
+1:	cfi_startproc
+	/* Enable asynchronous cancellation.  */
 	CENABLE
 
-	/* Save registers.  */
+	/* Save D2.  */
 	move.l %d2, -(%sp)
-	move.l %d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
 
-	move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
+	/* Save the result of CENABLE.  */
+	move.l %d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
 
 	/* Use ## so `socket' is a separate token that might be #define'd.  */
 	move.l #P (SOCKOP_,socket), %d1	/* Subcode is first arg to syscall.  */
 	lea 4+8(%sp), %a1		/* Address of args is 2nd arg.  */
 	move.l %a1, %d2
 
+	move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
 	/* Do the system call trap.  */
 	trap #0
 
@@ -91,14 +99,18 @@ ENTRY (__socket)
 	move.l %d0, %d2
 	CDISABLE
 	addq.l #4, %sp
+	cfi_adjust_cfa_offset (-4)
 	move.l %d2, %d0
 
 	/* Restore registers.  */
 	move.l (%sp)+, %d2
+	cfi_adjust_cfa_offset (-4)
+	cfi_restore (%d2)
 
 	/* %d0 is < 0 if there was an error.  */
 	tst.l %d0
 	jmi SYSCALL_ERROR_LABEL
+	cfi_endproc
 
 	/* Successful; return the syscall's value.  */
 	rts
diff --git a/sysdeps/unix/sysv/linux/m68k/vfork.S b/sysdeps/unix/sysv/linux/m68k/vfork.S
index 8027b2f..5084a85 100644
--- a/sysdeps/unix/sysv/linux/m68k/vfork.S
+++ b/sysdeps/unix/sysv/linux/m68k/vfork.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2002, 2003, 2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab <schwab@gnu.org>.
 
@@ -22,6 +22,14 @@
 #include <bits/errno.h>
 #include <kernel-features.h>
 
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
 /* 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,
@@ -31,12 +39,20 @@ ENTRY (__vfork)
 
 #ifdef __NR_vfork
 
+	/* SAVE_PID clobbers call-clobbered registers and
+	   saves data in D1 and A1.  */
+
+	SAVE_PID
+	
 	/* Pop the return PC value into A0.  */
 	movel	%sp@+, %a0
 
 	/* Stuff the syscall number in D0 and trap into the kernel.  */
 	movel	#SYS_ify (vfork), %d0
 	trap	#0
+
+	RESTORE_PID
+
 	tstl	%d0
 	jmi	.Lerror		/* Branch forward if it failed.  */
 
-- 
1.6.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 4/n] Remove kernel headers
  2009-08-30 17:46                 ` Maxim Kuvyrkov
@ 2009-10-02 10:51                   ` Maxim Kuvyrkov
  0 siblings, 0 replies; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-10-02 10:51 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-ports

Maxim Kuvyrkov wrote:
> Andreas Schwab wrote:
>> Maxim Kuvyrkov <maxim@codesourcery.com> writes:
>>
>>> Still, what was the foundation for coldfire-specific changes to
>>> fpregset_t, i.e., the use of 8-byte entries instead of 12-byte as for
>>> m68k?
>>
>> The coldfire has 64 bit fpu registers.  The patches were from Richard
>> Sandiford.
> 
> I did some digging in the archives and found several things I was not 
> aware before:
> 
> 1. Sigcontext ABI of ColdFire is different from M68K's.  It should be 
> what the current GLIBC copy is; i.e., struct sigcontext should contain 
> %d2-%d7, %a2-%a6 and have fpregs[8][2].
> 
> 2. A kernel patch was developed by Freescale and CodeSourcery to account 
> for the changes in ABI and also to fix various bugs.  This patch is 
> against the 2.6.10 kernel and is available at 
> http://www.codesourcery.com/archives/coldfire-gnu-discuss/msg00141.html.
> 
> 3. The kernel changes mentioned above are not included in the latest 
> stable LTIBs for ColdFire Linux boards: ltib-m5475-20080808 and 
> ltib-mcf5445x-20071214.  This led to great confusion on my part as I 
> considered the kernel sources in these LTIBs to represent true ABI.
> 
>>> Regarding the sigcontext.h header, there's no competing version in
>>> ./sysdeps/m68k/, so this one can be removed in favor of the header
>>> installed by the kernel.
>>
>> Of course, the generic linux version will be used instead, but if the
>> kernel header is clean than that will work.
> 
> In the light of the above, I think it is too early to fall back to the 
> kernel headers.  I will seek to the necessary ABI changes to get to the 
> upstream kernel and then will follow up on GLIBC switching to use 
> kernel's sigcontext.h.
> 
> As things stand, GLIBC contains the true ColdFire sigcontext ABI at the 
> moment.

Update:

ColdFire kernel sigcontext ABI is now being discussed in this thread 
(http://marc.info/?l=linux-m68k&m=125365546306821&w=2).  Once the kernel 
changes are in, I will follow up with a corresponding GLIBC patch.

Regards,

--
Maxim K.
CodeSourcery

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 5/n] Main NPTL patch
  2009-10-02 10:46     ` Maxim Kuvyrkov
@ 2009-10-23  9:39       ` Maxim Kuvyrkov
  2009-10-29 16:16         ` Joseph S. Myers
  0 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2009-10-23  9:39 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 1595 bytes --]

Maxim Kuvyrkov wrote:

>> After I did a clean rebuild of the work, I've caught several small 
>> issues that were introduced by the last-minute cleanups.  So here is 
>> an updated patch; I'm also attaching the difference between the 
>> patches for easier review.
> 
> While investigating GLIBC testsuite failures I've fixed a bug in the 
> initialization of the vDSO pointers.  Attached are the patch that fixes 
> the bug and the whole updated NPTL patch.
> 
> With this fix, a patch for mmap2 and fixes to sigcontext and siginfo 
> kernel headers (discussed on linux-m68k@) there are no unexpected 
> failures in the GLIBC testsuite.

The following patch fixes a bug in runtime linker that may cause a 
program to fail during relocation with divide-by-zero exception.

This bug is responsible for 2 libstdc++ failures.

The scenario under which the bug manifests itself is when an executable 
doesn't have a TLS storage, but references a TLS variable, which is 
defined in a library, using a TPREL32 relocation.  The bug is in runtime 
linker binding undefined TLS reference to the executable itself instead 
of the library's TLS storage.  Then the linker tries to allocate static 
TLS storage for the executable and fails calculating alignment for TLS 
block due to uninitialized alignment field (set to 0) in executable's phdrs.

The attached patch adds handling of TLS relocations to 
elf_machine_type_class similarly to other targets.

The second patch is a simple fix to make gdb print nicer backtraces when 
debugging the runtime linker.

Thanks and regards,

--
Maxim K.
CodeSourcery

[-- Attachment #2: 0001-Fix-rtld-symbol-binding-bug.patch --]
[-- Type: text/plain, Size: 1566 bytes --]

From 867ab4cbbc7d86faf639293ee52e0179ad0597ac Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Fri, 23 Oct 2009 13:25:57 +0400
Subject: [PATCH] Fix rtld symbol binding bug

        * sysdeps/m68k/dl-machine.h (elf_machine_type_class): Handle
	TLS relocations.

Signed-off-by: Maxim Kuvyrkov <maxim@codesourcery.com>
---
 sysdeps/m68k/dl-machine.h |   10 +++++++---
 1 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
index 08a4396..031d16e 100644
--- a/sysdeps/m68k/dl-machine.h
+++ b/sysdeps/m68k/dl-machine.h
@@ -159,12 +159,16 @@ _dl_start_user:\n\
 	.size _dl_start_user, . - _dl_start_user\n\
 	.previous");
 
-/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
-   PLT entries should not be allowed to define the value.
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
+   TLS variable, so undefined references should not be allowed to
+   define the value.
    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
    of the main executable's symbols, as for a COPY reloc.  */
 #define elf_machine_type_class(type) \
-  ((((type) == R_68K_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
+  ((((type) == R_68K_JMP_SLOT	     \
+     || (type) == R_68K_TLS_DTPMOD32 \
+     || (type) == R_68K_TLS_DTPREL32 \
+     || (type) == R_68K_TLS_TPREL32) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_68K_COPY) * ELF_RTYPE_CLASS_COPY))
 
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
-- 
1.6.4


[-- Attachment #3: 0001-Init-rtld-stack-frame.patch --]
[-- Type: text/plain, Size: 844 bytes --]

From 6862845d9b6155aaacd69c9573ffc2856e1a0a5a Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Fri, 23 Oct 2009 13:22:57 +0400
Subject: [PATCH] Init rtld stack frame

	* sysdeps/m68k/dl-machine.h (RTLD_START): Terminate stack frame to
	generate better backtraces.

Signed-off-by: Maxim Kuvyrkov <maxim@codesourcery.com>
---
 sysdeps/m68k/dl-machine.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
index 08a4396..749d5eb 100644
--- a/sysdeps/m68k/dl-machine.h
+++ b/sysdeps/m68k/dl-machine.h
@@ -121,6 +121,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 	.globl _start\n\
 	.type _start,@function\n\
 _start:\n\
+	sub.l %fp, %fp\n\
 	move.l %sp, -(%sp)\n\
 	jbsr _dl_start\n\
 	addq.l #4, %sp\n\
-- 
1.6.4


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire patch 5/n] Main NPTL patch
  2009-10-23  9:39       ` Maxim Kuvyrkov
@ 2009-10-29 16:16         ` Joseph S. Myers
  0 siblings, 0 replies; 31+ messages in thread
From: Joseph S. Myers @ 2009-10-29 16:16 UTC (permalink / raw)
  To: Maxim Kuvyrkov; +Cc: libc-ports, Andreas Schwab

Now we have 2.11 announced as coming very soon, could someone please 
review at least the main NPTL patch and get at least the allocation of the 
GLIBC_2.11 symbol version for __m68k_read_tp checked in so we can avoid 
further ABI changes in that regard?

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [m68k] Add TLS relocations to elf/elf.h
  2009-08-25 13:39 ` [M68K/ColdFire patch 6/n] Add TLS relocations to elf/elf.h Maxim Kuvyrkov
@ 2010-02-09 17:28   ` Maxim Kuvyrkov
  0 siblings, 0 replies; 31+ messages in thread
From: Maxim Kuvyrkov @ 2010-02-09 17:28 UTC (permalink / raw)
  To: libc-alpha; +Cc: Andreas Schwab, libc-ports

[-- Attachment #1: Type: text/plain, Size: 354 bytes --]

<resubmitting the patch with CC to libc-alpha@>

This patch adds definitions of the new TLS relocations to GLIBC.

The rest of the submission of NPTL support for m68k is done in this 
thread of libc-ports@ 
<http://sourceware.org/ml/libc-ports/2009-08/msg00005.html>.

Regards,

-- 
Maxim Kuvyrkov
CodeSourcery
maxim@codesourcery.com
(650) 331-3385 x724

[-- Attachment #2: 0001-Add-m68k-TLS-relocations.patch --]
[-- Type: text/plain, Size: 2219 bytes --]

From f6b0706def343f5716b01d59626a0f823bdec2ea Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Tue, 25 Aug 2009 17:34:30 +0400
Subject: [PATCH] Add m68k TLS relocations.

	* elf/elf.h: Define m68k TLS relocations.

Signed-off-by: Maxim Kuvyrkov <maxim@codesourcery.com>
---
 elf/elf.h |   23 ++++++++++++++++++++++-
 1 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/elf/elf.h b/elf/elf.h
index ce6de07..61673de 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1117,8 +1117,29 @@ typedef struct
 #define R_68K_GLOB_DAT	20		/* Create GOT entry */
 #define R_68K_JMP_SLOT	21		/* Create PLT entry */
 #define R_68K_RELATIVE	22		/* Adjust by program base */
+#define R_68K_TLS_GD32      25          /* 32 bit GOT offset for GD */
+#define R_68K_TLS_GD16      26          /* 16 bit GOT offset for GD */
+#define R_68K_TLS_GD8       27          /* 8 bit GOT offset for GD */
+#define R_68K_TLS_LDM32     28          /* 32 bit GOT offset for LDM */
+#define R_68K_TLS_LDM16     29          /* 16 bit GOT offset for LDM */
+#define R_68K_TLS_LDM8      30          /* 8 bit GOT offset for LDM */
+#define R_68K_TLS_LDO32     31          /* 32 bit module-relative offset */
+#define R_68K_TLS_LDO16     32          /* 16 bit module-relative offset */
+#define R_68K_TLS_LDO8      33          /* 8 bit module-relative offset */
+#define R_68K_TLS_IE32      34          /* 32 bit GOT offset for IE */
+#define R_68K_TLS_IE16      35          /* 16 bit GOT offset for IE */
+#define R_68K_TLS_IE8       36          /* 8 bit GOT offset for IE */
+#define R_68K_TLS_LE32      37          /* 32 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_LE16      38          /* 16 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_LE8       39          /* 8 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_DTPMOD32  40          /* 32 bit module number */
+#define R_68K_TLS_DTPREL32  41          /* 32 bit module-relative offset */
+#define R_68K_TLS_TPREL32   42          /* 32 bit TP-relative offset */
 /* Keep this the last entry.  */
-#define R_68K_NUM	23
+#define R_68K_NUM	43
 
 /* Intel 80386 specific definitions.  */
 
-- 
1.6.6.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire] NPTL support and other updates
  2009-08-25 12:27 [M68K/ColdFire] NPTL support and other updates Maxim Kuvyrkov
                   ` (7 preceding siblings ...)
  2009-09-07 20:36 ` [M68K/ColdFire] NPTL support and other updates Andreas Schwab
@ 2010-02-09 19:01 ` Maxim Kuvyrkov
  2010-03-01 12:17   ` Joseph S. Myers
  2010-03-07 19:49   ` Andreas Schwab
  8 siblings, 2 replies; 31+ messages in thread
From: Maxim Kuvyrkov @ 2010-02-09 19:01 UTC (permalink / raw)
  To: libc-ports; +Cc: Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 543 bytes --]

On 8/25/09 4:26 PM, Maxim Kuvyrkov wrote:
> Good day,
>
> In this thread I will post patches to M68K/ColdFire port that add NPTL
> support and other necessary updates to make trunk GLIBC build and work
> properly.

Attached is the m68k NPTL patch updated to the current HEAD.

The patch differs from the previous version only in the names of kernel 
syscalls which were renamed in the final version of NPTL kernel support.

Andreas, does it look OK to you?

Regards,

-- 
Maxim Kuvyrkov
CodeSourcery
maxim@codesourcery.com
(650) 331-3385 x724

[-- Attachment #2: m68k-nptl.patch --]
[-- Type: text/plain, Size: 79599 bytes --]

2010-02-09  Maxim Kuvyrkov  <maxim@codesourcery.com>

	NPTL support for m68k/ColdFire
	* sysdeps/unix/sysv/linux/m68k/sysdep.h (tls.h): Include.
	(INTERNAL_SYSCALL): Convert to INTERNAL_SYSCALL_NCS.
	(PTR_MANGLE, PTR_DEMANGLE): Define.
	(NEED_STATIC_SYSINFO_DSO): Define.
	* sysdeps/unix/sysv/linux/m68k/clone.S: Support RESET_PID.
	* sysdeps/unix/sysv/linux/m68k/m68k-helpers.S: New.
	* sysdeps/unix/sysv/linux/m68k/Makefile: Add new files to lists.
	* sysdeps/unix/sysv/linux/m68k/vfork.S: Add SAVE_PID/RESTORE_PID.
	* sysdeps/unix/sysv/linux/m68k/m68k-vdso.c: New.
	* sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c: New.
	* sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h: New.
	* sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h: New.
	* sysdeps/unix/sysv/linux/m68k/Versions: Add symbols for NPTL support.
	* sysdeps/unix/sysv/linux/m68k/init-first.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/clone.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/fork.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/vfork.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/createthread.c: New.
	* sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c: New.
	* sysdeps/unix/sysv/linux/m68k/socket.S: Update cancelation code.
	* sysdeps/m68k/dl-tls.h: New.
	* sysdeps/m68k/libc-tls.c: New.
	* sysdeps/m68k/tls-macros.h: New.
	* sysdeps/m68k/dl-machine.h (RTLD_START): Terminate stack frame to
	generate better backtraces.
	(elf_machine_type_class, elf_machine_rela): Handle TLS relocations.
	* sysdeps/m68k/dl-machine.h: Handle TLS relocations.
	* sysdeps/m68k/nptl/tcb-offsets.sym: New.
	* sysdeps/m68k/nptl/pthread_spin_trylock.c: New.
	* sysdeps/m68k/nptl/tls.h: New.
	* sysdeps/m68k/nptl/pthread_spin_lock.c: New.
	* sysdeps/m68k/nptl/pthreaddef.h: New.
	* sysdeps/m68k/nptl/Makefile: New.

diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
index 08a4396..9bc35e7 100644
--- a/sysdeps/m68k/dl-machine.h
+++ b/sysdeps/m68k/dl-machine.h
@@ -1,5 +1,6 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  m68k version.
-   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2010
+   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
@@ -24,6 +25,7 @@
 
 #include <sys/param.h>
 #include <sysdep.h>
+#include <dl-tls.h>
 
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int
@@ -121,6 +123,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 	.globl _start\n\
 	.type _start,@function\n\
 _start:\n\
+	sub.l %fp, %fp\n\
 	move.l %sp, -(%sp)\n\
 	jbsr _dl_start\n\
 	addq.l #4, %sp\n\
@@ -159,12 +162,16 @@ _dl_start_user:\n\
 	.size _dl_start_user, . - _dl_start_user\n\
 	.previous");
 
-/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
-   PLT entries should not be allowed to define the value.
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
+   TLS variable, so undefined references should not be allowed to
+   define the value.
    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
    of the main executable's symbols, as for a COPY reloc.  */
 #define elf_machine_type_class(type) \
-  ((((type) == R_68K_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
+  ((((type) == R_68K_JMP_SLOT	     \
+     || (type) == R_68K_TLS_DTPMOD32 \
+     || (type) == R_68K_TLS_DTPREL32 \
+     || (type) == R_68K_TLS_TPREL32) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_68K_COPY) * ELF_RTYPE_CLASS_COPY))
 
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
@@ -262,6 +269,25 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 	case R_68K_PC32:
 	  *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
 	  break;
+#if defined USE_TLS && !defined RTLD_BOOTSTRAP
+	case R_68K_TLS_DTPMOD32:
+	  /* Get the information from the link map returned by the
+	     resolv function.  */
+	  if (sym_map != NULL)
+	    *reloc_addr = sym_map->l_tls_modid;
+	  break;
+	case R_68K_TLS_DTPREL32:
+	  if (sym != NULL)
+	    *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
+	  break;
+	case R_68K_TLS_TPREL32:
+	  if (sym != NULL)
+	    {
+	      CHECK_STATIC_TLS (map, sym_map);
+	      *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
+	    }
+	  break;
+#endif /* defined USE_TLS && !defined RTLD_BOOTSTRAP */
 	case R_68K_NONE:		/* Alright, Wilbur.  */
 	  break;
 	default:
diff --git a/sysdeps/m68k/dl-tls.h b/sysdeps/m68k/dl-tls.h
new file mode 100644
index 0000000..f2ce998
--- /dev/null
+++ b/sysdeps/m68k/dl-tls.h
@@ -0,0 +1,48 @@
+/* Thread-local storage handling in the ELF dynamic linker.  M68K version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* The thread pointer points 0x7000 past the first static TLS block.  */
+#define TLS_TP_OFFSET		0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET		0x8000
+
+/* Compute the value for a TPREL reloc.  */
+#define TLS_TPREL_VALUE(sym_map, sym, reloc)				\
+  ((sym_map)->l_tls_offset + (sym)->st_value + (reloc)->r_addend	\
+   - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc.  */
+#define TLS_DTPREL_VALUE(sym, reloc)				\
+  ((sym)->st_value + (reloc)->r_addend - TLS_DTV_OFFSET)
+
+extern void *__tls_get_addr (tls_index *ti);
+
+#define GET_ADDR_OFFSET	        (ti->ti_offset + TLS_DTV_OFFSET)
+#define __TLS_GET_ADDR(__ti)	(__tls_get_addr (__ti) - TLS_DTV_OFFSET)
diff --git a/sysdeps/m68k/libc-tls.c b/sysdeps/m68k/libc-tls.c
new file mode 100644
index 0000000..e865fac
--- /dev/null
+++ b/sysdeps/m68k/libc-tls.c
@@ -0,0 +1,38 @@
+/* Thread-local storage handling in the ELF dynamic linker.  m68k version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <csu/libc-tls.c>
+#include <dl-tls.h>
+
+#if USE_TLS
+
+/* On M68K, linker optimizations are not required, so __tls_get_addr
+   can be called even in statically linked binaries.  In this case module
+   must be always 1 and PT_TLS segment exist in the binary, otherwise it
+   would not link.  */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET;
+}
+
+#endif
diff --git a/sysdeps/m68k/nptl/Makefile b/sysdeps/m68k/nptl/Makefile
new file mode 100644
index 0000000..f36fc8f
--- /dev/null
+++ b/sysdeps/m68k/nptl/Makefile
@@ -0,0 +1,22 @@
+# Copyright (C) 2010 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+#
+# 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, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/sysdeps/m68k/nptl/pthread_spin_lock.c b/sysdeps/m68k/nptl/pthread_spin_lock.c
new file mode 100644
index 0000000..1cc16c8
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthread_spin_lock.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  while (atomic_compare_and_exchange_val_acq(lock, 1, 0) != 0)
+   while (*lock != 0)
+    ;
+
+  return 0;
+}
diff --git a/sysdeps/m68k/nptl/pthread_spin_trylock.c b/sysdeps/m68k/nptl/pthread_spin_trylock.c
new file mode 100644
index 0000000..831bffb
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthread_spin_trylock.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  return atomic_compare_and_exchange_val_acq(lock, 1, 0) ? EBUSY : 0;
+}
diff --git a/sysdeps/m68k/nptl/pthreaddef.h b/sysdeps/m68k/nptl/pthreaddef.h
new file mode 100644
index 0000000..0a54907
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthreaddef.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* 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/sysdeps/m68k/nptl/tcb-offsets.sym b/sysdeps/m68k/nptl/tcb-offsets.sym
new file mode 100644
index 0000000..b1bba65
--- /dev/null
+++ b/sysdeps/m68k/nptl/tcb-offsets.sym
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Derive offsets relative to the thread register.
+#define thread_offsetof(mem)	(long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads)
+PID_OFFSET			thread_offsetof (pid)
+TID_OFFSET			thread_offsetof (tid)
diff --git a/sysdeps/m68k/nptl/tls.h b/sysdeps/m68k/nptl/tls.h
new file mode 100644
index 0000000..c29824c
--- /dev/null
+++ b/sysdeps/m68k/nptl/tls.h
@@ -0,0 +1,171 @@
+/* Definition for thread-local data handling.  NPTL/m68k version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H	1
+
+#include <dl-sysdep.h>
+
+#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__ */
+
+/* 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 <nptl/descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_INIT_TCB_SIZE	0
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN	__alignof__ (struct pthread)
+
+/* This is the size of the TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_TCB_SIZE		0
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN		__alignof__ (struct pthread)
+
+/* This is the size we need before TCB - actually, it includes the TCB.  */
+# define TLS_PRE_TCB_SIZE						\
+  (sizeof (struct pthread)						\
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* The thread pointer (TP) points to the end of the
+   TCB + 0x7000, as for PowerPC and MIPS.  This implies that TCB address is
+   TP - 0x7000.  As we define TLS_DTV_AT_TP we can
+   assume that the pthread struct is allocated immediately ahead of the
+   TCB.  This implies that the pthread_descr address is
+   TP - (TLS_PRE_TCB_SIZE + 0x7000).  */
+# define TLS_TCB_OFFSET	0x7000
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV () = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall)					\
+  ({									\
+    INTERNAL_SYSCALL_DECL (err);					\
+    int _sys_result;							\
+									\
+    _sys_result = INTERNAL_SYSCALL (set_thread_area, err, 1,		\
+				    ((void *) (tcbp)) + TLS_TCB_OFFSET); \
+    INTERNAL_SYSCALL_ERROR_P (_sys_result, err) ? "unknown error" : NULL; })
+
+extern void * __m68k_read_tp (void);
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) (__m68k_read_tp () - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+  ((struct pthread *) (__m68k_read_tp () - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Access to data in the thread descriptor is easy.  */
+# define THREAD_GETMEM(descr, member) \
+  descr->member
+# define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+# define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* l_tls_offset == 0 is perfectly valid on M68K, so we have to use some
+   different value to mean unset l_tls_offset.  */
+# define NO_TLS_OFFSET		-1
+
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG()					\
+  do									\
+    { int __res								\
+	= atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,	\
+			       THREAD_GSCOPE_FLAG_UNUSED);		\
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)				\
+	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+    }									\
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG()					\
+  do									\
+    {									\
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;	\
+      atomic_write_barrier ();						\
+    }									\
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif	/* tls.h */
diff --git a/sysdeps/m68k/tls-macros.h b/sysdeps/m68k/tls-macros.h
new file mode 100644
index 0000000..d03d7b9
--- /dev/null
+++ b/sysdeps/m68k/tls-macros.h
@@ -0,0 +1,70 @@
+/* Macros for accessing thread-local storage.  m68k version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define TLS_GD(x)							\
+  ({									\
+    void *__result;							\
+    extern void *__tls_get_addr (void *);				\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "lea " #x "@TLSGD(%0), %0"					\
+	 : "=&a" (__result));						\
+    (int *) __tls_get_addr (__result); })
+
+#define TLS_LD(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void *__tls_get_addr (void *);				\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "lea " #x "@TLSLDM(%0), %0"					\
+	 : "=&a" (__tp));						\
+    __tp = (char *) __tls_get_addr (__tp);				\
+    asm ("movel #" #x "@TLSLDO, %0"					\
+	 : "=a" (__offset));						\
+    (int *) (__tp + __offset); })
+
+#define TLS_IE(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void * __m68k_read_tp (void);				\
+									\
+    __tp = (char *) __m68k_read_tp ();					\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "movel " #x "@TLSIE(%0), %0"					\
+	 : "=&a" (__offset));						\
+    (int *) (__tp + __offset); })
+
+#define TLS_LE(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void * __m68k_read_tp (void);				\
+									\
+    __tp = (char *) __m68k_read_tp ();					\
+    asm ("movel #" #x "@TLSLE, %0"					\
+	 : "=a" (__offset));						\
+    (int *) (__tp + __offset); })
+
diff --git a/sysdeps/unix/sysv/linux/m68k/Makefile b/sysdeps/unix/sysv/linux/m68k/Makefile
index 6bb4f6b..97d9584 100644
--- a/sysdeps/unix/sysv/linux/m68k/Makefile
+++ b/sysdeps/unix/sysv/linux/m68k/Makefile
@@ -2,12 +2,18 @@
 
 m68k-syntax-flag = -DMOTOROLA_SYNTAX
 
+ifeq ($(subdir),csu)
+sysdep_routines += m68k-helpers
+endif
+
 ifeq ($(subdir),misc)
 sysdep_routines += mremap
 sysdep_headers += sys/reg.h
 endif
 
 ifeq ($(subdir),elf)
+sysdep_routines += dl-vdso libc-m68k-vdso
+sysdep-rtld-routines += m68k-vdso
 sysdep-others += lddlibc4
 install-bin += lddlibc4
 endif
diff --git a/sysdeps/unix/sysv/linux/m68k/Versions b/sysdeps/unix/sysv/linux/m68k/Versions
index 5650f7f..8a941f8 100644
--- a/sysdeps/unix/sysv/linux/m68k/Versions
+++ b/sysdeps/unix/sysv/linux/m68k/Versions
@@ -32,4 +32,18 @@ libc {
   GLIBC_2.11 {
     fallocate64;
   }
+  GLIBC_2.12 {
+    __m68k_read_tp;
+  }
+  GLIBC_PRIVATE {
+    __vdso_atomic_cmpxchg_32; __vdso_atomic_barrier;
+  }
+}
+
+ld {
+  GLIBC_PRIVATE {
+    __rtld___vdso_read_tp;
+    __rtld___vdso_atomic_cmpxchg_32;
+    __rtld___vdso_atomic_barrier;
+  }
 }
diff --git a/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
new file mode 100644
index 0000000..c361060
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
@@ -0,0 +1,61 @@
+/* Resolve function pointers to VDSO functions.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+#ifndef _M68K_VDSO_H
+#define _M68K_VDSO_H
+
+#ifdef SHARED
+
+# ifdef IS_IN_rtld
+# define M68K_VDSO_SYMBOL(name) __rtld_##name
+# define STR_M68K_VDSO_SYMBOL(name) "__rtld_" #name
+# else
+# define M68K_VDSO_SYMBOL(name) name
+# define STR_M68K_VDSO_SYMBOL(name) #name
+# endif
+
+# ifndef __ASSEMBLER__
+
+/* We define __rtld_* copies for rtld.
+   We need them visible in libc to initialize.  */
+#  if defined IS_IN_rtld || !defined NOT_IN_libc
+extern void *__rtld___vdso_read_tp;
+extern void *__rtld___vdso_atomic_cmpxchg_32;
+extern void *__rtld___vdso_atomic_barrier;
+
+/* These stubs are meant to be invoked only from the assembly.  */
+extern void __vdso_read_tp_stub (void);
+extern void __vdso_atomic_cmpxchg_32_stub (void);
+extern void __vdso_atomic_barrier_stub (void);
+#  endif /* IS_IN_rtld || !NOT_IN_libc */
+
+/* RTLD should only use its own copies.  */
+#  ifndef IS_IN_rtld
+extern void *__vdso_read_tp;
+extern void *__vdso_atomic_cmpxchg_32;
+extern void *__vdso_atomic_barrier;
+#  endif /* !IS_IN_rtld */
+
+# endif /* !__ASSEMBLER__ */
+
+#endif /* SHARED */
+
+#endif /* _M68K_VDSO_H */
diff --git a/sysdeps/unix/sysv/linux/m68k/clone.S b/sysdeps/unix/sysv/linux/m68k/clone.S
index a179f8e..401e2ef 100644
--- a/sysdeps/unix/sysv/linux/m68k/clone.S
+++ b/sysdeps/unix/sysv/linux/m68k/clone.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996,97,98,2002,2010 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
 
@@ -17,14 +17,21 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-/* clone is even more special than fork as it mucks with stacks
+/* clone() is even more special than fork() as it mucks with stacks
    and invokes a function in the right context after its all over.  */
 
 #include <sysdep.h>
 #define _ERRNO_H	1
 #include <bits/errno.h>
+#ifdef RESET_PID
+#include <tls.h>
+#endif
+
+#define CLONE_VM      0x00000100
+#define CLONE_THREAD  0x00010000
 
-/* 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,
+	     void *parent_tidptr, void *tls, void *child_tidptr) */
 
         .text
 ENTRY (__clone)
@@ -42,7 +49,17 @@ ENTRY (__clone)
 	movel	16(%sp), -(%a1)
 
 	/* Do the system call */
-	movel	12(%sp), %d1		/* get flags */
+	movel	12+0(%sp), %d1		/* get flags */
+	movel	%d3, -(%a1)             /* save %d3 and get parent_tidptr */
+	movel	%d3, -(%sp)
+	movel	20+4(%sp), %d3
+	movel	%d4, -(%a1)		/* save %d4 and get child_tidptr */
+	movel	%d4, -(%sp)
+	movel	28+8(%sp), %d4
+	movel	%d5, -(%a1)             /* save %d5 and get tls */
+	movel	%d5, -(%sp)
+	movel	24+12(%sp), %d5
+	/* save %d2 and get stack pointer */
 #ifdef __mcoldfire__
 	movel	%d2, -(%a1)
 	movel	%d2, -(%sp)
@@ -57,6 +74,9 @@ ENTRY (__clone)
 #else
 	exg	%d2, %a1		/* restore %d2 */
 #endif
+	movel	(%sp)+, %d5             /* restore %d5, %d4 and %d3 */
+	movel	(%sp)+, %d4
+	movel	(%sp)+, %d3
 
 	tstl	%d0
 	jmi	SYSCALL_ERROR_LABEL
@@ -65,11 +85,35 @@ ENTRY (__clone)
 	rts
 
 thread_start:
+	cfi_startproc
+	cfi_undefined (pc)	/* Mark end of stack */
 	subl	%fp, %fp	/* terminate the stack frame */
+#ifdef RESET_PID
+	/* Check and see if we need to reset the PID.  */
+	movel	%d1, %a1
+	andl	#CLONE_THREAD, %d1
+	jne	donepid
+	movel	%a1, %d1
+	movel	#-1, %d0
+	andl	#CLONE_VM, %d1
+	jne	gotpid
+	movel	#SYS_ify (getpid), %d0
+	trap	#0
+gotpid:
+	movel	%a0, -(%sp)
+	movel	%d0, -(%sp)
+	bsrl	__m68k_read_tp@PLTPC
+	movel	(%sp)+, %d0
+	movel	%d0, PID_OFFSET(%a0)
+	movel	%d0, TID_OFFSET(%a0)
+	movel	(%sp)+, %a0
+donepid:
+#endif
 	jsr	(%a0)
 	movel	%d0, %d1
 	movel	#SYS_ify (exit), %d0
 	trap	#0
+	cfi_endproc
 
 PSEUDO_END (__clone)
 
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
new file mode 100644
index 0000000..1198bb9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
@@ -0,0 +1,105 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H	1
+
+#include <stdint.h>
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+/* Coldfire has no atomic compare-and-exchange operation, but the
+   kernel provides userspace atomicity operations.  Use them.  */
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+/* The only basic operation needed is compare and exchange.  */
+/* For ColdFire we'll have to trap into the kernel mode anyway,
+   so trap from the library rather then from the kernel wrapper.  */
+#ifdef SHARED
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  ({									\
+    /* Use temporary variables to workaround call-clobberness of */	\
+    /* the registers.  */						\
+    __typeof (mem) _mem = mem;						\
+    __typeof (oldval) _oldval = oldval;					\
+    __typeof (newval) _newval = newval;					\
+    register __typeof (mem) _a0 asm ("a0") = _mem;			\
+    register __typeof (oldval) _d0 asm ("d0") = _oldval;		\
+    register __typeof (newval) _d1 asm ("d1") = _newval;		\
+    void *tmp;								\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %2\n\t"			\
+	 "lea (-6, %%pc, %2), %2\n\t"					\
+	 "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)	\
+	 "@GOT(%2), %2\n\t"						\
+	 "movel (%2), %2\n\t"						\
+	 "jsr (%2)\n\t"							\
+	 : "+d" (_d0), "+m" (*_a0), "=&a" (tmp)				\
+	 : "a" (_a0), "d" (_d1));					\
+    _d0;								\
+  })
+#else
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  ({									\
+    /* Use temporary variables to workaround call-clobberness of */	\
+    /* the registers.  */						\
+    __typeof (mem) _mem = mem;						\
+    __typeof (oldval) _oldval = oldval;					\
+    __typeof (newval) _newval = newval;					\
+    register __typeof (oldval) _d0 asm ("d0")				\
+      = SYS_ify (atomic_cmpxchg_32);					\
+    register __typeof (mem) _a0 asm ("a0") = _mem;			\
+    register __typeof (oldval) _d2 asm ("d2") = _oldval;		\
+    register __typeof (newval) _d1 asm ("d1") = _newval;		\
+									\
+    asm ("trap #0"							\
+	 : "+d" (_d0), "+m" (*_a0)					\
+	 : "a" (_a0), "d" (_d2), "d" (_d1));				\
+    _d0;								\
+  })
+#endif
+
+#ifdef SHARED
+# define atomic_full_barrier()					 \
+  ({								 \
+    void *tmp;							 \
+								 \
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"		 \
+	 "lea (-6, %pc, %0), %0\n\t"				 \
+	 "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_barrier)	 \
+	 "@GOT(%0), %0\n\t"					 \
+	 "movel (%0), %0\n\t"					 \
+	 "jsr (%0)\n\t"						 \
+	 : "=&a" (tmp));					 \
+  })
+#else
+# define atomic_full_barrier()				\
+  (INTERNAL_SYSCALL (atomic_barrier, , 0), (void) 0)
+#endif
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/init-first.c b/sysdeps/unix/sysv/linux/m68k/init-first.c
new file mode 100644
index 0000000..f8168d1
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/init-first.c
@@ -0,0 +1,74 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Note: linking in vDSO to a static binary requires changes to
+   the main GLIBC proper.  Not yet implemented.  */
+#ifdef SHARED
+
+#include <dl-vdso.h>
+#include <bits/m68k-vdso.h>
+
+static inline void
+_libc_vdso_platform_setup (void)
+{
+  void *p;
+
+  PREPARE_VERSION (linux26, "LINUX_2.6", 61765110);
+
+  /* It may happen that rtld didn't initialize the vDSO, so fallback
+     to the syscall implementations if _dl_vdso_vsym returns NULL.
+     This may happen when a static executable dlopen's a dynamic library.
+     This really is nothing more than a workaround for rtld/csu
+     deficiency.  Ideally, init code would setup the vDSO for static
+     binaries too.  */
+
+  p = _dl_vdso_vsym ("__kernel_read_tp", &linux26);
+  if (p != NULL)
+    {
+      __vdso_read_tp = p;
+      __rtld___vdso_read_tp = p;
+    }
+  else
+    assert (__vdso_read_tp == (void *) __vdso_read_tp_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_cmpxchg_32", &linux26);
+  if (p != NULL)
+    {
+      __vdso_atomic_cmpxchg_32 = p;
+      __rtld___vdso_atomic_cmpxchg_32 = p;
+    }
+  else
+    assert (__vdso_atomic_cmpxchg_32
+	    == (void *) __vdso_atomic_cmpxchg_32_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_barrier", &linux26);
+  if (p != NULL)
+    {
+      __vdso_atomic_barrier = p;
+      __rtld___vdso_atomic_barrier = p;
+    }
+  else
+    assert (__vdso_atomic_barrier == (void *) __vdso_atomic_barrier_stub);
+}
+
+#define VDSO_SETUP _libc_vdso_platform_setup
+
+#endif /* SHARED */
+
+#include <sysdeps/unix/sysv/linux/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
new file mode 100644
index 0000000..45982e9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
@@ -0,0 +1 @@
+#include "m68k-vdso.c"
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
new file mode 100644
index 0000000..00db4bb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
@@ -0,0 +1,105 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+	.text
+
+	.hidden __vdso_read_tp_stub
+ENTRY (__vdso_read_tp_stub)
+	cfi_startproc
+	move.l	#__NR_get_thread_area, %d0
+	trap	#0
+	move.l	%d0, %a0
+	rts
+	cfi_endproc
+END (__vdso_read_tp_stub)
+
+# ifdef SHARED
+/* GCC will emit calls to this routine.  Linux has an
+   equivalent helper function (which clobbers fewer registers than
+   a normal function call) in a vdso; tail call to the
+   helper.  */
+# ifdef IS_IN_rtld
+/* rtld gets a hidden copy of __m68k_read_tp.  */
+	.hidden __m68k_read_tp
+# endif
+ENTRY (__m68k_read_tp)
+	cfi_startproc
+	move.l	#_GLOBAL_OFFSET_TABLE_@GOTPC, %a0
+	lea	(-6, %pc, %a0), %a0
+	move.l	M68K_VDSO_SYMBOL (__vdso_read_tp)@GOT(%a0), %a0
+	move.l	(%a0), %a0
+	jmp	(%a0)
+	cfi_endproc
+END (__m68k_read_tp)
+
+/* The following two stubs are for macros in atomic.h, they can't
+   clobber anything.  */
+
+	.hidden __vdso_atomic_cmpxchg_32_stub
+ENTRY (__vdso_atomic_cmpxchg_32_stub)
+	cfi_startproc
+	move.l	%d2, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
+	move.l	%d0, %d2
+	move.l	#SYS_ify (atomic_cmpxchg_32), %d0
+	trap	#0
+	move.l	(%sp)+, %d2
+	cfi_adjust_cfa_offset (-4)
+	cfi_restore (%d2)
+	rts
+	cfi_endproc
+END (__vdso_atomic_cmpxchg_32_stub)
+	
+	.hidden __vdso_atomic_barrier_stub
+ENTRY (__vdso_atomic_barrier_stub)
+	cfi_startproc
+	move.l	%d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	move.l	#SYS_ify (atomic_barrier), %d0
+	trap	#0
+	move.l	(%sp)+, %d0
+	cfi_adjust_cfa_offset (-4)
+	rts
+	cfi_endproc
+END (__vdso_atomic_barrier_stub)
+# else /* !SHARED */
+/* If the vDSO is not available, use a syscall to get TP.  */
+	strong_alias (__vdso_read_tp_stub, __m68k_read_tp)
+# endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
new file mode 100644
index 0000000..73b2570
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifdef SHARED
+
+#include <bits/m68k-vdso.h>
+
+/* Because these pointers are used from other libraries than libc,
+   they are exported at GLIBC_PRIVATE version.
+   We initialize them to syscall implementation so that they will be ready
+   to use from the very beginning.  */
+void * M68K_VDSO_SYMBOL (__vdso_read_tp)
+= (void *) __vdso_read_tp_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)
+= (void *) __vdso_atomic_cmpxchg_32_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_barrier)
+= (void *) __vdso_atomic_barrier_stub;
+
+#endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
new file mode 100644
index 0000000..0140810
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
@@ -0,0 +1,172 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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_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
+   deliberately not exposed.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+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 deliberately not exposed.  */
+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;
+
+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 deliberately not exposed.  */
+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 deliberately not exposed.  */
+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;
+    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;
+    int __writer;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+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/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
new file mode 100644
index 0000000..2950cc9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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/sysdeps/unix/sysv/linux/m68k/nptl/clone.S b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
new file mode 100644
index 0000000..e7388fe
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include "../clone.S"
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
new file mode 100644
index 0000000..be11444
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE ((void *) (pd) \
+		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation.	 */
+#include <nptl/sysdeps/pthread/createthread.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/fork.c b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
new file mode 100644
index 0000000..dc1584e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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, &THREAD_SELF->tid, NULL)
+
+#include <sysdeps/unix/sysv/linux/fork.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
new file mode 100644
index 0000000..926077d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
@@ -0,0 +1,281 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Borrowed from ARM's version.  */
+
+#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 <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 __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAIT, private),	      \
+			      (val), (timespec));			      \
+    __ret;								      \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAKE, private),	      \
+			      (nr), 0);					      \
+    __ret;								      \
+  })
+
+#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 __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),		      \
+			      __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+			      (nr_wake), (nr_move), (mutex), (val));	      \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __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 __ret;							      \
+    __ret = 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 (__ret, __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(lock, id)			\
+  atomic_compare_and_exchange_val_acq (&(lock), id, 0)
+
+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 (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex,       \
+								1, 0), 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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+								0), 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 (__builtin_expect (atomic_exchange_acq (__futex, 2), 0))		      \
+      __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 (__builtin_expect (atomic_exchange_acq (__futex, 1), 0))	      \
+       __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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+								0), 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 (__builtin_expect (__oldval > 1, 0))			\
+	 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 (__builtin_expect (__oldval & FUTEX_WAITERS, 0))	\
+	 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/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
new file mode 100644
index 0000000..36c9270
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
@@ -0,0 +1,36 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+	bsrl	__m68k_read_tp@PLTPC	; /* Get the thread pointer.  */ \
+	movel	%a0, %a1		; /* Save TP for RESTORE_PID.  */ \
+	movel	PID_OFFSET(%a1), %d0	; /* Get the PID.  */ \
+	movel	%d0, %d1		; /* Save PID for RESTORE_PID.  */ \
+	negl	%d0			; /* Negate the PID.  */ \
+	movel	%d0, PID_OFFSET(%a1)	; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+	tstl	%d0			; \
+	beq	1f			; /* If we are the parent... */ \
+	movel	%d1, PID_OFFSET(%a1)	; /* Restore the PID.  */ \
+1:	
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
new file mode 100644
index 0000000..415045f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
@@ -0,0 +1,91 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
new file mode 100644
index 0000000..87e2d55
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
@@ -0,0 +1,141 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				      \
+  .text;								      \
+  ENTRY (name)								      \
+    SINGLE_THREAD_P;							      \
+    jne .Lpseudo_cancel;						      \
+  .type __##syscall_name##_nocancel,@function;			              \
+  .globl __##syscall_name##_nocancel;				 	      \
+  __##syscall_name##_nocancel:					              \
+    DO_CALL (syscall_name, args);					      \
+    cmp.l &-4095, %d0;							      \
+    jcc SYSCALL_ERROR_LABEL;						      \
+    rts;								      \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \
+  .Lpseudo_cancel:							      \
+    cfi_startproc;							      \
+    CENABLE;								      \
+    DOCARGS_##args							      \
+    move.l %d0, -(%sp); /* Save result of CENABLE.  */  		      \
+    cfi_adjust_cfa_offset (4); \
+    move.l &SYS_ify (syscall_name), %d0;				      \
+    trap &0;								      \
+    move.l %d0, %d2;							      \
+    CDISABLE;								      \
+    addq.l &4, %sp; /* Remove result of CENABLE from the stack.  */           \
+    cfi_adjust_cfa_offset (-4); \
+    move.l %d2, %d0;							      \
+    UNDOCARGS_##args							      \
+    cmp.l &-4095, %d0;							      \
+    jcc SYSCALL_ERROR_LABEL;		                                      \
+    cfi_endproc
+
+/* Note: we use D2 to save syscall's return value as D0 will be clobbered in
+   CDISABLE.  */
+# define DOCARGS_0	move.l %d2, -(%sp);		\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d2, 0);
+# define UNDOCARGS_0	move.l (%sp)+, %d2;	\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d2);
+
+# define DOCARGS_1	_DOCARGS_1 (4); DOCARGS_0
+# define _DOCARGS_1(n)	move.l n(%sp), %d1;
+# define UNDOCARGS_1	UNDOCARGS_0
+
+# define DOCARGS_2	_DOCARGS_2 (8)
+# define _DOCARGS_2(n)	DOCARGS_0 move.l n+4(%sp), %d2; _DOCARGS_1 (n)
+# define UNDOCARGS_2	UNDOCARGS_0
+
+/* TODO: We can optimize DOCARGS_{3, 4} by saving registers to a0 and a1
+   instead of pushing them on stack.  */
+# define DOCARGS_3	_DOCARGS_3 (12)
+# define _DOCARGS_3(n)	move.l %d3, -(%sp);				\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d3, 0);			\
+  move.l n+4(%sp), %d3; _DOCARGS_2 (n)
+# define UNDOCARGS_3	UNDOCARGS_2 move.l (%sp)+, %d3;		\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d3);
+
+# define DOCARGS_4	_DOCARGS_4 (16)
+# define _DOCARGS_4(n)	move.l %d4, -(%sp);			\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d4, 0);		\
+  move.l n+4(%sp), %d4; _DOCARGS_3 (n)
+# define UNDOCARGS_4	UNDOCARGS_3 move.l (%sp)+, %d4;	\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d4);
+
+# define DOCARGS_5	_DOCARGS_5 (20)
+# define _DOCARGS_5(n)	move.l %d5, %a1; cfi_register (%d5, a1); \
+  move.l n(%sp), %d5; _DOCARGS_4 (n-4)
+# define UNDOCARGS_5	UNDOCARGS_4 move.l %a1, %d5; cfi_restore (%d5);
+
+# define DOCARGS_6	_DOCARGS_6 (24)
+# define _DOCARGS_6(n)	move.l n(%sp), %a0; _DOCARGS_5 (n-4)
+# define UNDOCARGS_6	UNDOCARGS_5
+
+# ifdef PIC
+#  define PSEUDO_JMP(sym) jbsr sym ## @PLTPC
+# else
+#  define PSEUDO_JMP(sym) jbsr sym
+# endif
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	PSEUDO_JMP (__pthread_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__pthread_disable_asynccancel)
+# elif !defined NOT_IN_libc
+#  define CENABLE	PSEUDO_JMP (__libc_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__libc_disable_asynccancel)
+# elif defined IS_IN_librt
+#  define CENABLE	PSEUDO_JMP (__librt_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__librt_disable_asynccancel)
+# else
+#  error Unsupported library
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P						\
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\
+				   header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P			\
+  PSEUDO_JMP (__m68k_read_tp);		        \
+  tst.l MULTIPLE_THREADS_OFFSET(%a0)
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION (1)
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P					  \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,			  \
+				   header.multiple_threads) == 0, \
+		    1)
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
new file mode 100644
index 0000000..8599c3d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
@@ -0,0 +1,38 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+	bsrl	__m68k_read_tp@PLTPC	; /* Get the thread pointer.  */ \
+	movel	%a0, %a1		; /* Save TP for RESTORE_PID.  */ \
+	movel	PID_OFFSET(%a1), %d0	; /* Get the PID.  */ \
+	movel	%d0, %d1		; /* Save PID for RESTORE_PID.  */ \
+	negl	%d0			; /* Negate the PID.  */ \
+	bne	1f			; /* If it was zero... */ \
+	movel	#0x80000000, %d0	; /* use 0x80000000 instead.  */ \
+1:	movel	%d0, PID_OFFSET(%a1)	; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+	tstl	%d0			; \
+	beq	1f			; /* If we are the parent... */ \
+	movel	%d1, PID_OFFSET(%a1)	; /* Restore the PID.  */ \
+1:	
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/socket.S b/sysdeps/unix/sysv/linux/m68k/socket.S
index 2690f18..147a3b2 100644
--- a/sysdeps/unix/sysv/linux/m68k/socket.S
+++ b/sysdeps/unix/sysv/linux/m68k/socket.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2010 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
@@ -41,8 +41,11 @@
 
 .globl __socket
 ENTRY (__socket)
-#if defined NEED_CANCELLATION && defined CENABLE
-	SINGLE_THREAD_P (%a0)
+#ifdef NEED_CANCELLATION
+# if !defined CENABLE || !defined CDISABLE
+#  error CENABLE and/or CDISABLE is not defined
+# endif
+	SINGLE_THREAD_P
 	jne 1f
 #endif
 
@@ -69,21 +72,26 @@ ENTRY (__socket)
 	/* Successful; return the syscall's value.  */
 	rts
 
-#if defined NEED_CANCELLATION && defined CENABLE
-1:	/* Enable asynchronous cancellation.  */
+#ifdef NEED_CANCELLATION
+1:	cfi_startproc
+	/* Enable asynchronous cancellation.  */
 	CENABLE
 
-	/* Save registers.  */
+	/* Save D2.  */
 	move.l %d2, -(%sp)
-	move.l %d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
 
-	move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
+	/* Save the result of CENABLE.  */
+	move.l %d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
 
 	/* Use ## so `socket' is a separate token that might be #define'd.  */
 	move.l #P (SOCKOP_,socket), %d1	/* Subcode is first arg to syscall.  */
 	lea 4+8(%sp), %a1		/* Address of args is 2nd arg.  */
 	move.l %a1, %d2
 
+	move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
 	/* Do the system call trap.  */
 	trap #0
 
@@ -91,14 +99,18 @@ ENTRY (__socket)
 	move.l %d0, %d2
 	CDISABLE
 	addq.l #4, %sp
+	cfi_adjust_cfa_offset (-4)
 	move.l %d2, %d0
 
 	/* Restore registers.  */
 	move.l (%sp)+, %d2
+	cfi_adjust_cfa_offset (-4)
+	cfi_restore (%d2)
 
 	/* %d0 is < 0 if there was an error.  */
 	tst.l %d0
 	jmi SYSCALL_ERROR_LABEL
+	cfi_endproc
 
 	/* Successful; return the syscall's value.  */
 	rts
diff --git a/sysdeps/unix/sysv/linux/m68k/sysdep.h b/sysdeps/unix/sysv/linux/m68k/sysdep.h
index 12687d8..e3aed15 100644
--- a/sysdeps/unix/sysv/linux/m68k/sysdep.h
+++ b/sysdeps/unix/sysv/linux/m68k/sysdep.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2006, 2010
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>,
    December 1995.
@@ -23,6 +24,7 @@
 
 #include <sysdeps/unix/sysdep.h>
 #include <sysdeps/m68k/sysdep.h>
+#include <tls.h>
 
 /* Defines RTLD_PRIVATE_ERRNO.  */
 #include <dl-sysdep.h>
@@ -148,9 +150,11 @@ SYSCALL_ERROR_LABEL:							      \
 	arg 3		%d3	     call-saved
 	arg 4		%d4	     call-saved
 	arg 5		%d5	     call-saved
+	arg 6		%a0	     call-clobbered
 
    The stack layout upon entering the function is:
 
+	24(%sp)		Arg# 6
 	20(%sp)		Arg# 5
 	16(%sp)		Arg# 4
 	12(%sp)		Arg# 3
@@ -229,7 +233,7 @@ SYSCALL_ERROR_LABEL:							      \
    normally.  It will never touch errno.  This returns just what the kernel
    gave back.  */
 #undef INTERNAL_SYSCALL
-#define INTERNAL_SYSCALL(name, err, nr, args...)	\
+#define INTERNAL_SYSCALL_NCS(name, err, nr, args...)	\
   ({ unsigned int _sys_result;				\
      {							\
        /* Load argument values in temporary variables
@@ -237,7 +241,7 @@ SYSCALL_ERROR_LABEL:							      \
 	  before the call used registers are set.  */	\
        LOAD_ARGS_##nr (args)				\
        LOAD_REGS_##nr					\
-       register int _d0 asm ("%d0") = __NR_##name;	\
+       register int _d0 asm ("%d0") = name;		\
        asm volatile ("trap #0"				\
 		     : "=d" (_d0)			\
 		     : "0" (_d0) ASM_ARGS_##nr		\
@@ -245,6 +249,8 @@ SYSCALL_ERROR_LABEL:							      \
        _sys_result = _d0;				\
      }							\
      (int) _sys_result; })
+#define INTERNAL_SYSCALL(name, err, nr, args...)	\
+  INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)
 
 #undef INTERNAL_SYSCALL_ERROR_P
 #define INTERNAL_SYSCALL_ERROR_P(val, err)		\
@@ -300,4 +306,15 @@ SYSCALL_ERROR_LABEL:							      \
 #define ASM_ARGS_6	ASM_ARGS_5, "a" (_a0)
 
 #endif /* not __ASSEMBLER__ */
+
+/* Pointer mangling is not yet supported for M68K.  */
+#define PTR_MANGLE(var) (void) (var)
+#define PTR_DEMANGLE(var) (void) (var)
+
+#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
+/* M68K needs system-supplied DSO to access TLS helpers
+   even when statically linked.  */
+# define NEED_STATIC_SYSINFO_DSO 1
+#endif
+
 #endif
diff --git a/sysdeps/unix/sysv/linux/m68k/vfork.S b/sysdeps/unix/sysv/linux/m68k/vfork.S
index 8027b2f..61bbf2f 100644
--- a/sysdeps/unix/sysv/linux/m68k/vfork.S
+++ b/sysdeps/unix/sysv/linux/m68k/vfork.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2002, 2003, 2010 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab <schwab@gnu.org>.
 
@@ -22,6 +22,14 @@
 #include <bits/errno.h>
 #include <kernel-features.h>
 
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
 /* 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,
@@ -31,12 +39,20 @@ ENTRY (__vfork)
 
 #ifdef __NR_vfork
 
+	/* SAVE_PID clobbers call-clobbered registers and
+	   saves data in D1 and A1.  */
+
+	SAVE_PID
+	
 	/* Pop the return PC value into A0.  */
 	movel	%sp@+, %a0
 
 	/* Stuff the syscall number in D0 and trap into the kernel.  */
 	movel	#SYS_ify (vfork), %d0
 	trap	#0
+
+	RESTORE_PID
+
 	tstl	%d0
 	jmi	.Lerror		/* Branch forward if it failed.  */
 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire] NPTL support and other updates
  2010-02-09 19:01 ` Maxim Kuvyrkov
@ 2010-03-01 12:17   ` Joseph S. Myers
  2010-03-07 19:49   ` Andreas Schwab
  1 sibling, 0 replies; 31+ messages in thread
From: Joseph S. Myers @ 2010-03-01 12:17 UTC (permalink / raw)
  To: Maxim Kuvyrkov; +Cc: libc-ports, Andreas Schwab

I believe all the prerequisites for this are now in place: GCC and 
Binutils support has been in the respective repositories for some time, 
the relocations went in elf.h in the libc repository on 10 Feb and the 
kernel support went in kernel.org git over the weekend.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire] NPTL support and other updates
  2010-02-09 19:01 ` Maxim Kuvyrkov
  2010-03-01 12:17   ` Joseph S. Myers
@ 2010-03-07 19:49   ` Andreas Schwab
  2010-03-08  7:33     ` Maxim Kuvyrkov
  1 sibling, 1 reply; 31+ messages in thread
From: Andreas Schwab @ 2010-03-07 19:49 UTC (permalink / raw)
  To: Maxim Kuvyrkov; +Cc: libc-ports

Maxim Kuvyrkov <maxim@codesourcery.com> writes:

> Attached is the m68k NPTL patch updated to the current HEAD.
>
> The patch differs from the previous version only in the names of kernel
> syscalls which were renamed in the final version of NPTL kernel support.

/home/andreas/src/libc/branch/tls/m68k/nptl/libpthread_pic.a(unwind.os): In function `unwind_stop':
/home/andreas/src/libc/branch/tls/libc/nptl/unwind.c:96: undefined reference to `__libc_unwind_longjmp'
/home/andreas/src/libc/branch/tls/libc/nptl/unwind.c:62: undefined reference to `_JMPBUF_CFA_UNWINDS_ADJ'
/home/andreas/src/libc/branch/tls/m68k/nptl/libpthread_pic.a(pt-cleanup.os): In function `*__GI___pthread_cleanup_upto':
/home/andreas/src/libc/branch/tls/libc/nptl/pt-cleanup.c:38: undefined reference to `_JMPBUF_UNWINDS_ADJ'
collect2: ld returned 1 exit status

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire] NPTL support and other updates
  2010-03-07 19:49   ` Andreas Schwab
@ 2010-03-08  7:33     ` Maxim Kuvyrkov
  2010-03-08 18:41       ` Andreas Schwab
  0 siblings, 1 reply; 31+ messages in thread
From: Maxim Kuvyrkov @ 2010-03-08  7:33 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-ports

On 3/7/10 10:48 PM, Andreas Schwab wrote:
> Maxim Kuvyrkov<maxim@codesourcery.com>  writes:
>
>> Attached is the m68k NPTL patch updated to the current HEAD.
>>
>> The patch differs from the previous version only in the names of kernel
>> syscalls which were renamed in the final version of NPTL kernel support.
>
> /home/andreas/src/libc/branch/tls/m68k/nptl/libpthread_pic.a(unwind.os): In function `unwind_stop':
> /home/andreas/src/libc/branch/tls/libc/nptl/unwind.c:96: undefined reference to `__libc_unwind_longjmp'
> /home/andreas/src/libc/branch/tls/libc/nptl/unwind.c:62: undefined reference to `_JMPBUF_CFA_UNWINDS_ADJ'
> /home/andreas/src/libc/branch/tls/m68k/nptl/libpthread_pic.a(pt-cleanup.os): In function `*__GI___pthread_cleanup_upto':
> /home/andreas/src/libc/branch/tls/libc/nptl/pt-cleanup.c:38: undefined reference to `_JMPBUF_UNWINDS_ADJ'
> collect2: ld returned 1 exit status

Andreas,

Do you have the `[M68K/ColdFire patch 3/n] Update jmpbuf-unwind.h' patch 
applied to your tree?  It was posted together with NPTL patches here 
http://sourceware.org/ml/libc-ports/2009-08/msg00008.html .

Thanks,

-- 
Maxim Kuvyrkov
CodeSourcery
maxim@codesourcery.com
(650) 331-3385 x724

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire] NPTL support and other updates
  2010-03-08  7:33     ` Maxim Kuvyrkov
@ 2010-03-08 18:41       ` Andreas Schwab
  2010-03-09 10:52         ` Maxim Kuvyrkov
  0 siblings, 1 reply; 31+ messages in thread
From: Andreas Schwab @ 2010-03-08 18:41 UTC (permalink / raw)
  To: Maxim Kuvyrkov; +Cc: libc-ports

Maxim Kuvyrkov <maxim@codesourcery.com> writes:

> Do you have the `[M68K/ColdFire patch 3/n] Update jmpbuf-unwind.h' patch
> applied to your tree?

I was assuming the patch is complete.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [M68K/ColdFire] NPTL support and other updates
  2010-03-08 18:41       ` Andreas Schwab
@ 2010-03-09 10:52         ` Maxim Kuvyrkov
  0 siblings, 0 replies; 31+ messages in thread
From: Maxim Kuvyrkov @ 2010-03-09 10:52 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-ports

[-- Attachment #1: Type: text/plain, Size: 965 bytes --]

On 3/8/10 9:41 PM, Andreas Schwab wrote:
> Maxim Kuvyrkov<maxim@codesourcery.com>  writes:
>
>> Do you have the `[M68K/ColdFire patch 3/n] Update jmpbuf-unwind.h' patch
>> applied to your tree?
>
> I was assuming the patch is complete.

Here are all the other patches that update various pieces of m68k port:

* 0003--sysdeps-m68k-jmpbuf-unwind.h-Update.patch
Update jmpbuf-unwind.h.

* 0004--sysdeps-unix-sysv-linux-m68k-bits-siginfo.h-Remo.patch
Remove siginfo.h in favor of the kernel header.

* 0005--Update-ColdFire-sigcontext-ABI.patch
Update ColdFire sigcontext ABI (not necessary if building for classic m68k).

And the m68k-nptl-full.patch is the lump-sum of the m68k-nptl.patch 
attached in the previous message and the above 3 patches.

You will also need a recent checkout of the linux kernel (e.g., 
v2.6.34-rc1) to pick up the fixed siginfo and sigcontext headers.

Regards,

-- 
Maxim Kuvyrkov
CodeSourcery
maxim@codesourcery.com
(650) 331-3385 x724

[-- Attachment #2: 0003--sysdeps-m68k-jmpbuf-unwind.h-Update.patch --]
[-- Type: text/plain, Size: 1775 bytes --]

From 424c6c6a6f970ad6a00603c0265e4a6380d8cadd Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Tue, 9 Mar 2010 02:20:36 -0800
Subject: [PATCH 3/5] 	* sysdeps/m68k/jmpbuf-unwind.h: Update.


Signed-off-by: Maxim Kuvyrkov <maxim@codesourcery.com>
---
 sysdeps/m68k/jmpbuf-unwind.h |   23 ++++++++++++++++++++++-
 1 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/sysdeps/m68k/jmpbuf-unwind.h b/sysdeps/m68k/jmpbuf-unwind.h
index 3490c79..d001039 100644
--- a/sysdeps/m68k/jmpbuf-unwind.h
+++ b/sysdeps/m68k/jmpbuf-unwind.h
@@ -1,5 +1,5 @@
 /* Examine __jmp_buf for unwinding frames.  m68k version.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 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
@@ -18,8 +18,29 @@
    02111-1307 USA.  */
 
 #include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
 
 /* Test if longjmp to JMPBUF would unwind the frame
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address, demangle)		\
   ((void *) (address) < (void *) demangle ((jmpbuf)->__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)
+{
+  uintptr_t sp = regs[0].__sp;
+#ifdef PTR_DEMANGLE
+  PTR_DEMANGLE (sp);
+#endif
+  return sp;
+}
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj))
+
+/* We use the normal longjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
-- 
1.6.2.4


[-- Attachment #3: 0004--sysdeps-unix-sysv-linux-m68k-bits-siginfo.h-Remo.patch --]
[-- Type: text/plain, Size: 10415 bytes --]

From d5ea99ce14192875a17f9a96714e961b44984306 Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Tue, 9 Mar 2010 02:32:38 -0800
Subject: [PATCH 4/5] 	* sysdeps/unix/sysv/linux/m68k/bits/siginfo.h: Remove, switch to
 	generic siginfo layout as the kernel did.


Signed-off-by: Maxim Kuvyrkov <maxim@codesourcery.com>
---
 sysdeps/unix/sysv/linux/m68k/bits/siginfo.h |  316 ---------------------------
 1 files changed, 0 insertions(+), 316 deletions(-)
 delete mode 100644 sysdeps/unix/sysv/linux/m68k/bits/siginfo.h

diff --git a/sysdeps/unix/sysv/linux/m68k/bits/siginfo.h b/sysdeps/unix/sysv/linux/m68k/bits/siginfo.h
deleted file mode 100644
index 1ded1c2..0000000
--- a/sysdeps/unix/sysv/linux/m68k/bits/siginfo.h
+++ /dev/null
@@ -1,316 +0,0 @@
-/* siginfo_t, sigevent and constants.  m68k linux version.
-   Copyright (C) 1997-2002, 2003 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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#if !defined _SIGNAL_H && !defined __need_siginfo_t \
-    && !defined __need_sigevent_t
-# error "Never include this file directly.  Use <signal.h> instead"
-#endif
-
-#include <bits/wordsize.h>
-
-#if (!defined __have_sigval_t \
-     && (defined _SIGNAL_H || defined __need_siginfo_t \
-	 || defined __need_sigevent_t))
-# define __have_sigval_t	1
-
-/* Type for data associated with a signal.  */
-typedef union sigval
-  {
-    int sival_int;
-    void *sival_ptr;
-  } sigval_t;
-#endif
-
-#if (!defined __have_siginfo_t \
-     && (defined _SIGNAL_H || defined __need_siginfo_t))
-# define __have_siginfo_t	1
-
-# define __SI_MAX_SIZE     128
-# if __WORDSIZE == 64
-#  define __SI_PAD_SIZE     ((__SI_MAX_SIZE / sizeof (int)) - 4)
-# else
-#  define __SI_PAD_SIZE     ((__SI_MAX_SIZE / sizeof (int)) - 3)
-# endif
-
-typedef struct siginfo
-  {
-    int si_signo;		/* Signal number.  */
-    int si_errno;		/* If non-zero, an errno value associated with
-				   this signal, as defined in <errno.h>.  */
-    int si_code;		/* Signal code.  */
-
-    union
-      {
-	int _pad[__SI_PAD_SIZE];
-
-	 /* kill().  */
-	struct
-	  {
-	    __pid_t si_pid;	/* Sending process ID.  */
-	    unsigned short __pad; /* 16-bit version of si_uid.  */
-	    __uid_t si_uid;	/* Real user ID of sending process.  */
-	  } _kill;
-
-	/* POSIX.1b timers.  */
-	struct
-	  {
-	    int si_tid;		/* Timer ID.  */
-	    int si_overrun;	/* Overrun count.  */
-	    sigval_t si_sigval;	/* Signal value.  */
-	  } _timer;
-
-	/* POSIX.1b signals.  */
-	struct
-	  {
-	    __pid_t si_pid;	/* Sending process ID.  */
-	    unsigned short __pad; /* 16-bit version of si_uid.  */
-	    sigval_t si_sigval;	/* Signal value.  */
-	    __uid_t si_uid;	/* Real user ID of sending process.  */
-	  } _rt;
-
-	/* SIGCHLD.  */
-	struct
-	  {
-	    __pid_t si_pid;	/* Which child.  */
-	    unsigned short __pad; /* 16-bit version of si_uid.  */
-	    int si_status;	/* Exit value or signal.  */
-	    __clock_t si_utime;
-	    __clock_t si_stime;
-	    __uid_t si_uid;	/* Real user ID of sending process.  */
-	  } _sigchld;
-
-	/* SIGILL, SIGFPE, SIGSEGV, SIGBUS.  */
-	struct
-	  {
-	    void *si_addr;	/* Faulting insn/memory ref.  */
-	  } _sigfault;
-
-	/* SIGPOLL.  */
-	struct
-	  {
-	    long int si_band;	/* Band event for SIGPOLL.  */
-	    int si_fd;
-	  } _sigpoll;
-      } _sifields;
-  } siginfo_t;
-
-
-/* X/Open requires some more fields with fixed names.  */
-# define si_pid		_sifields._kill.si_pid
-# define si_uid		_sifields._kill.si_uid
-# define si_timerid	_sifields._timer.si_tid
-# define si_overrun	_sifields._timer.si_overrun
-# define si_status	_sifields._sigchld.si_status
-# define si_utime	_sifields._sigchld.si_utime
-# define si_stime	_sifields._sigchld.si_stime
-# define si_value	_sifields._rt.si_sigval
-# define si_int		_sifields._rt.si_sigval.sival_int
-# define si_ptr		_sifields._rt.si_sigval.sival_ptr
-# define si_addr	_sifields._sigfault.si_addr
-# define si_band	_sifields._sigpoll.si_band
-# define si_fd		_sifields._sigpoll.si_fd
-
-
-/* Values for `si_code'.  Positive values are reserved for kernel-generated
-   signals.  */
-enum
-{
-  SI_ASYNCNL = -60,		/* Sent by asynch name lookup completion.  */
-# define SI_ASYNCNL	SI_ASYNCNL
-  SI_TKILL = -6,		/* Sent by tkill.  */
-# define SI_TKILL	SI_TKILL
-  SI_SIGIO,			/* Sent by queued SIGIO. */
-# define SI_SIGIO	SI_SIGIO
-  SI_ASYNCIO,			/* Sent by AIO completion.  */
-# define SI_ASYNCIO	SI_ASYNCIO
-  SI_MESGQ,			/* Sent by real time mesq state change.  */
-# define SI_MESGQ	SI_MESGQ
-  SI_TIMER,			/* Sent by timer expiration.  */
-# define SI_TIMER	SI_TIMER
-  SI_QUEUE,			/* Sent by sigqueue.  */
-# define SI_QUEUE	SI_QUEUE
-  SI_USER,			/* Sent by kill, sigsend, raise.  */
-# define SI_USER	SI_USER
-  SI_KERNEL = 0x80		/* Send by kernel.  */
-#define SI_KERNEL	SI_KERNEL
-};
-
-
-/* `si_code' values for SIGILL signal.  */
-enum
-{
-  ILL_ILLOPC = 1,		/* Illegal opcode.  */
-# define ILL_ILLOPC	ILL_ILLOPC
-  ILL_ILLOPN,			/* Illegal operand.  */
-# define ILL_ILLOPN	ILL_ILLOPN
-  ILL_ILLADR,			/* Illegal addressing mode.  */
-# define ILL_ILLADR	ILL_ILLADR
-  ILL_ILLTRP,			/* Illegal trap. */
-# define ILL_ILLTRP	ILL_ILLTRP
-  ILL_PRVOPC,			/* Privileged opcode.  */
-# define ILL_PRVOPC	ILL_PRVOPC
-  ILL_PRVREG,			/* Privileged register.  */
-# define ILL_PRVREG	ILL_PRVREG
-  ILL_COPROC,			/* Coprocessor error.  */
-# define ILL_COPROC	ILL_COPROC
-  ILL_BADSTK			/* Internal stack error.  */
-# define ILL_BADSTK	ILL_BADSTK
-};
-
-/* `si_code' values for SIGFPE signal.  */
-enum
-{
-  FPE_INTDIV = 1,		/* Integer divide by zero.  */
-# define FPE_INTDIV	FPE_INTDIV
-  FPE_INTOVF,			/* Integer overflow.  */
-# define FPE_INTOVF	FPE_INTOVF
-  FPE_FLTDIV,			/* Floating point divide by zero.  */
-# define FPE_FLTDIV	FPE_FLTDIV
-  FPE_FLTOVF,			/* Floating point overflow.  */
-# define FPE_FLTOVF	FPE_FLTOVF
-  FPE_FLTUND,			/* Floating point underflow.  */
-# define FPE_FLTUND	FPE_FLTUND
-  FPE_FLTRES,			/* Floating point inexact result.  */
-# define FPE_FLTRES	FPE_FLTRES
-  FPE_FLTINV,			/* Floating point invalid operation.  */
-# define FPE_FLTINV	FPE_FLTINV
-  FPE_FLTSUB			/* Subscript out of range.  */
-# define FPE_FLTSUB	FPE_FLTSUB
-};
-
-/* `si_code' values for SIGSEGV signal.  */
-enum
-{
-  SEGV_MAPERR = 1,		/* Address not mapped to object.  */
-# define SEGV_MAPERR	SEGV_MAPERR
-  SEGV_ACCERR			/* Invalid permissions for mapped object.  */
-# define SEGV_ACCERR	SEGV_ACCERR
-};
-
-/* `si_code' values for SIGBUS signal.  */
-enum
-{
-  BUS_ADRALN = 1,		/* Invalid address alignment.  */
-# define BUS_ADRALN	BUS_ADRALN
-  BUS_ADRERR,			/* Non-existant physical address.  */
-# define BUS_ADRERR	BUS_ADRERR
-  BUS_OBJERR			/* Object specific hardware error.  */
-# define BUS_OBJERR	BUS_OBJERR
-};
-
-/* `si_code' values for SIGTRAP signal.  */
-enum
-{
-  TRAP_BRKPT = 1,		/* Process breakpoint.  */
-# define TRAP_BRKPT	TRAP_BRKPT
-  TRAP_TRACE			/* Process trace trap.  */
-# define TRAP_TRACE	TRAP_TRACE
-};
-
-/* `si_code' values for SIGCHLD signal.  */
-enum
-{
-  CLD_EXITED = 1,		/* Child has exited.  */
-# define CLD_EXITED	CLD_EXITED
-  CLD_KILLED,			/* Child was killed.  */
-# define CLD_KILLED	CLD_KILLED
-  CLD_DUMPED,			/* Child terminated abnormally.  */
-# define CLD_DUMPED	CLD_DUMPED
-  CLD_TRAPPED,			/* Traced child has trapped.  */
-# define CLD_TRAPPED	CLD_TRAPPED
-  CLD_STOPPED,			/* Child has stopped.  */
-# define CLD_STOPPED	CLD_STOPPED
-  CLD_CONTINUED			/* Stopped child has continued.  */
-# define CLD_CONTINUED	CLD_CONTINUED
-};
-
-/* `si_code' values for SIGPOLL signal.  */
-enum
-{
-  POLL_IN = 1,			/* Data input available.  */
-# define POLL_IN	POLL_IN
-  POLL_OUT,			/* Output buffers available.  */
-# define POLL_OUT	POLL_OUT
-  POLL_MSG,			/* Input message available.   */
-# define POLL_MSG	POLL_MSG
-  POLL_ERR,			/* I/O error.  */
-# define POLL_ERR	POLL_ERR
-  POLL_PRI,			/* High priority input available.  */
-# define POLL_PRI	POLL_PRI
-  POLL_HUP			/* Device disconnected.  */
-# define POLL_HUP	POLL_HUP
-};
-
-# undef __need_siginfo_t
-#endif	/* !have siginfo_t && (have _SIGNAL_H || need siginfo_t).  */
-
-
-#if (defined _SIGNAL_H || defined __need_sigevent_t) \
-    && !defined __have_sigevent_t
-# define __have_sigevent_t	1
-
-/* Structure to transport application-defined values with signals.  */
-# define __SIGEV_MAX_SIZE	64
-# if __WORDSIZE == 64
-#  define __SIGEV_PAD_SIZE	((__SIGEV_MAX_SIZE / sizeof (int)) - 4)
-# else
-#  define __SIGEV_PAD_SIZE	((__SIGEV_MAX_SIZE / sizeof (int)) - 3)
-# endif
-
-typedef struct sigevent
-  {
-    sigval_t sigev_value;
-    int sigev_signo;
-    int sigev_notify;
-
-    union
-      {
-	int _pad[__SIGEV_PAD_SIZE];
-
-	/* When SIGEV_SIGNAL and SIGEV_THREAD_ID set, LWP ID of the
-	   thread to receive the signal.  */
-	__pid_t _tid;
-
-	struct
-	  {
-	    void (*_function) (sigval_t);	/* Function to start.  */
-	    void *_attribute;			/* Really pthread_attr_t.  */
-	  } _sigev_thread;
-      } _sigev_un;
-  } sigevent_t;
-
-/* POSIX names to access some of the members.  */
-# define sigev_notify_function   _sigev_un._sigev_thread._function
-# define sigev_notify_attributes _sigev_un._sigev_thread._attribute
-
-/* `sigev_notify' values.  */
-enum
-{
-  SIGEV_SIGNAL = 0,		/* Notify via signal.  */
-# define SIGEV_SIGNAL	SIGEV_SIGNAL
-  SIGEV_NONE,			/* Other notification: meaningless.  */
-# define SIGEV_NONE	SIGEV_NONE
-  SIGEV_THREAD,			/* Deliver via thread creation.  */
-# define SIGEV_THREAD	SIGEV_THREAD
-
-  SIGEV_THREAD_ID = 4		/* Send signal to specific thread.  */
-#define SIGEV_THREAD_ID	SIGEV_THREAD_ID
-};
-
-#endif	/* have _SIGNAL_H.  */
-- 
1.6.2.4


[-- Attachment #4: 0005--Update-ColdFire-sigcontext-ABI.patch --]
[-- Type: text/plain, Size: 5613 bytes --]

From 73b783bb7d989e4e347322a666c422c72c5ac9fa Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Tue, 9 Mar 2010 02:34:24 -0800
Subject: [PATCH 5/5] 	Update ColdFire sigcontext ABI.
 	* sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h: Remove, use kernel's
 	header.
 	* sysdeps/unix/sysv/linux/m68k/register-dump.h: Update.


Signed-off-by: Maxim Kuvyrkov <maxim@codesourcery.com>
---
 sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h |   62 ------------------------
 sysdeps/unix/sysv/linux/m68k/register-dump.h   |   32 +++----------
 2 files changed, 7 insertions(+), 87 deletions(-)
 delete mode 100644 sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h

diff --git a/sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h b/sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h
deleted file mode 100644
index 8ad0c96..0000000
--- a/sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (C) 2006 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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#if !defined _SIGNAL_H && !defined _SYS_UCONTEXT_H
-# error "Never use <bits/sigcontext.h> directly; include <signal.h> instead."
-#endif
-
-#ifndef _BITS_SIGCONTEXT_H
-#define _BITS_SIGCONTEXT_H 1
-
-struct sigcontext {
-  unsigned long sc_mask;
-  unsigned long sc_usp;
-  unsigned long sc_d0;
-  unsigned long sc_d1;
-#ifdef __mcoldfire__
-  unsigned long sc_d2;
-  unsigned long sc_d3;
-  unsigned long sc_d4;
-  unsigned long sc_d5;
-  unsigned long sc_d6;
-  unsigned long sc_d7;
-#endif
-  unsigned long sc_a0;
-  unsigned long sc_a1;
-#ifdef __mcoldfire__
-  unsigned long sc_a2;
-  unsigned long sc_a3;
-  unsigned long sc_a4;
-  unsigned long sc_a5;
-  unsigned long sc_a6;
-#endif
-  unsigned short sc_sr;
-  unsigned long sc_pc;
-  unsigned short sc_formatvec;
-#ifdef __mcoldfire__
-  unsigned long sc_fpregs[8][2];
-  unsigned long sc_fpcntl[3];
-  unsigned char sc_fpstate[16];
-#else
-  unsigned long sc_fpregs[2*3];
-  unsigned long sc_fpcntl[3];
-  unsigned char sc_fpstate[216];
-#endif
-};
-
-#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/register-dump.h b/sysdeps/unix/sysv/linux/m68k/register-dump.h
index 391902f..78709d9 100644
--- a/sysdeps/unix/sysv/linux/m68k/register-dump.h
+++ b/sysdeps/unix/sysv/linux/m68k/register-dump.h
@@ -40,7 +40,6 @@
 
 */
 
-#ifndef __mcoldfire__
 /* Linux saves only the call-clobbered registers in the sigcontext.  We
    need to use a trampoline that saves the rest so that the C code can
    access them.  We use the sc_fpstate field, since the handler is not
@@ -59,14 +58,17 @@ catch_segfault:\n\
 	/* Clear the first 4 bytes to make it a null fp state, just\n\
 	   in case the handler does return.  */\n\
 	clr.l (%%a0)+\n\
-	movem.l %%d2-%%d7/%%a2-%%a6,(%%a0)\n\
-	fmovem.x %%fp2-%%fp7,11*4(%%a0)\n\
-	jra real_catch_segfault"
+	movem.l %%d2-%%d7/%%a2-%%a6,(%%a0)\n"
+#ifndef __mcoldfire__
+       "fmovem.x %%fp2-%%fp7,11*4(%%a0)\n"
+#elif defined __mcffpu__
+       "fmovem.d %%fp2-%%fp7,11*4(%%a0)\n"
+#endif
+       "jra real_catch_segfault"
        : : "n" (offsetof (struct sigcontext, sc_fpstate)));
 }
 #define catch_segfault(a,b) \
   __attribute_used__ real_catch_segfault(a,b)
-#endif
 
 static void
 hexvalue (unsigned long int value, char *buf, size_t len)
@@ -104,36 +106,19 @@ register_dump (int fd, struct sigcontext *ctx)
   /* Generate strings of register contents.  */
   hexvalue (ctx->sc_d0, regs[0], 8);
   hexvalue (ctx->sc_d1, regs[1], 8);
-#ifdef __mcoldfire__
-  hexvalue (ctx->sc_d2, regs[2], 8);
-  hexvalue (ctx->sc_d3, regs[3], 8);
-  hexvalue (ctx->sc_d4, regs[4], 8);
-  hexvalue (ctx->sc_d5, regs[5], 8);
-  hexvalue (ctx->sc_d6, regs[6], 8);
-  hexvalue (ctx->sc_d7, regs[7], 8);
-#else
   hexvalue (*p++, regs[2], 8);
   hexvalue (*p++, regs[3], 8);
   hexvalue (*p++, regs[4], 8);
   hexvalue (*p++, regs[5], 8);
   hexvalue (*p++, regs[6], 8);
   hexvalue (*p++, regs[7], 8);
-#endif
   hexvalue (ctx->sc_a0, regs[8], 8);
   hexvalue (ctx->sc_a1, regs[9], 8);
-#ifdef __mcoldfire__
-  hexvalue (ctx->sc_a2, regs[10], 8);
-  hexvalue (ctx->sc_a3, regs[11], 8);
-  hexvalue (ctx->sc_a4, regs[12], 8);
-  hexvalue (ctx->sc_a5, regs[13], 8);
-  hexvalue (ctx->sc_a6, regs[14], 8);
-#else
   hexvalue (*p++, regs[10], 8);
   hexvalue (*p++, regs[11], 8);
   hexvalue (*p++, regs[12], 8);
   hexvalue (*p++, regs[13], 8);
   hexvalue (*p++, regs[14], 8);
-#endif
   hexvalue (ctx->sc_usp, regs[15], 8);
   hexvalue (ctx->sc_pc, regs[16], 8);
   hexvalue (ctx->sc_sr, regs[17], 4);
@@ -142,9 +127,6 @@ register_dump (int fd, struct sigcontext *ctx)
   for (i = 0; i < 2; i++)
     for (j = 0; j < fpreg_size; j += 8)
       hexvalue (*pfp++, fpregs[i] + j, 8);
-#ifdef __mcoldfire__
-  p = pfp;
-#endif
   for (i = 2; i < 8; i++)
     for (j = 0; j < fpreg_size; j += 8)
       hexvalue (*p++, fpregs[i] + j, 8);
-- 
1.6.2.4


[-- Attachment #5: m68k-nptl-full.patch --]
[-- Type: text/plain, Size: 93687 bytes --]

diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
index 08a4396..9bc35e7 100644
--- a/sysdeps/m68k/dl-machine.h
+++ b/sysdeps/m68k/dl-machine.h
@@ -1,5 +1,6 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  m68k version.
-   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2010
+   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
@@ -24,6 +25,7 @@
 
 #include <sys/param.h>
 #include <sysdep.h>
+#include <dl-tls.h>
 
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int
@@ -121,6 +123,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 	.globl _start\n\
 	.type _start,@function\n\
 _start:\n\
+	sub.l %fp, %fp\n\
 	move.l %sp, -(%sp)\n\
 	jbsr _dl_start\n\
 	addq.l #4, %sp\n\
@@ -159,12 +162,16 @@ _dl_start_user:\n\
 	.size _dl_start_user, . - _dl_start_user\n\
 	.previous");
 
-/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
-   PLT entries should not be allowed to define the value.
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
+   TLS variable, so undefined references should not be allowed to
+   define the value.
    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
    of the main executable's symbols, as for a COPY reloc.  */
 #define elf_machine_type_class(type) \
-  ((((type) == R_68K_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
+  ((((type) == R_68K_JMP_SLOT	     \
+     || (type) == R_68K_TLS_DTPMOD32 \
+     || (type) == R_68K_TLS_DTPREL32 \
+     || (type) == R_68K_TLS_TPREL32) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_68K_COPY) * ELF_RTYPE_CLASS_COPY))
 
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
@@ -262,6 +269,25 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 	case R_68K_PC32:
 	  *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
 	  break;
+#if defined USE_TLS && !defined RTLD_BOOTSTRAP
+	case R_68K_TLS_DTPMOD32:
+	  /* Get the information from the link map returned by the
+	     resolv function.  */
+	  if (sym_map != NULL)
+	    *reloc_addr = sym_map->l_tls_modid;
+	  break;
+	case R_68K_TLS_DTPREL32:
+	  if (sym != NULL)
+	    *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
+	  break;
+	case R_68K_TLS_TPREL32:
+	  if (sym != NULL)
+	    {
+	      CHECK_STATIC_TLS (map, sym_map);
+	      *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
+	    }
+	  break;
+#endif /* defined USE_TLS && !defined RTLD_BOOTSTRAP */
 	case R_68K_NONE:		/* Alright, Wilbur.  */
 	  break;
 	default:
diff --git a/sysdeps/m68k/dl-tls.h b/sysdeps/m68k/dl-tls.h
new file mode 100644
index 0000000..f2ce998
--- /dev/null
+++ b/sysdeps/m68k/dl-tls.h
@@ -0,0 +1,48 @@
+/* Thread-local storage handling in the ELF dynamic linker.  M68K version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* The thread pointer points 0x7000 past the first static TLS block.  */
+#define TLS_TP_OFFSET		0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET		0x8000
+
+/* Compute the value for a TPREL reloc.  */
+#define TLS_TPREL_VALUE(sym_map, sym, reloc)				\
+  ((sym_map)->l_tls_offset + (sym)->st_value + (reloc)->r_addend	\
+   - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc.  */
+#define TLS_DTPREL_VALUE(sym, reloc)				\
+  ((sym)->st_value + (reloc)->r_addend - TLS_DTV_OFFSET)
+
+extern void *__tls_get_addr (tls_index *ti);
+
+#define GET_ADDR_OFFSET	        (ti->ti_offset + TLS_DTV_OFFSET)
+#define __TLS_GET_ADDR(__ti)	(__tls_get_addr (__ti) - TLS_DTV_OFFSET)
diff --git a/sysdeps/m68k/jmpbuf-unwind.h b/sysdeps/m68k/jmpbuf-unwind.h
index 3490c79..d001039 100644
--- a/sysdeps/m68k/jmpbuf-unwind.h
+++ b/sysdeps/m68k/jmpbuf-unwind.h
@@ -1,5 +1,5 @@
 /* Examine __jmp_buf for unwinding frames.  m68k version.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 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
@@ -18,8 +18,29 @@
    02111-1307 USA.  */
 
 #include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
 
 /* Test if longjmp to JMPBUF would unwind the frame
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address, demangle)		\
   ((void *) (address) < (void *) demangle ((jmpbuf)->__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)
+{
+  uintptr_t sp = regs[0].__sp;
+#ifdef PTR_DEMANGLE
+  PTR_DEMANGLE (sp);
+#endif
+  return sp;
+}
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj))
+
+/* We use the normal longjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
diff --git a/sysdeps/m68k/libc-tls.c b/sysdeps/m68k/libc-tls.c
new file mode 100644
index 0000000..e865fac
--- /dev/null
+++ b/sysdeps/m68k/libc-tls.c
@@ -0,0 +1,38 @@
+/* Thread-local storage handling in the ELF dynamic linker.  m68k version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <csu/libc-tls.c>
+#include <dl-tls.h>
+
+#if USE_TLS
+
+/* On M68K, linker optimizations are not required, so __tls_get_addr
+   can be called even in statically linked binaries.  In this case module
+   must be always 1 and PT_TLS segment exist in the binary, otherwise it
+   would not link.  */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET;
+}
+
+#endif
diff --git a/sysdeps/m68k/nptl/Makefile b/sysdeps/m68k/nptl/Makefile
new file mode 100644
index 0000000..f36fc8f
--- /dev/null
+++ b/sysdeps/m68k/nptl/Makefile
@@ -0,0 +1,22 @@
+# Copyright (C) 2010 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+#
+# 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, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/sysdeps/m68k/nptl/pthread_spin_lock.c b/sysdeps/m68k/nptl/pthread_spin_lock.c
new file mode 100644
index 0000000..1cc16c8
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthread_spin_lock.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  while (atomic_compare_and_exchange_val_acq(lock, 1, 0) != 0)
+   while (*lock != 0)
+    ;
+
+  return 0;
+}
diff --git a/sysdeps/m68k/nptl/pthread_spin_trylock.c b/sysdeps/m68k/nptl/pthread_spin_trylock.c
new file mode 100644
index 0000000..831bffb
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthread_spin_trylock.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  return atomic_compare_and_exchange_val_acq(lock, 1, 0) ? EBUSY : 0;
+}
diff --git a/sysdeps/m68k/nptl/pthreaddef.h b/sysdeps/m68k/nptl/pthreaddef.h
new file mode 100644
index 0000000..0a54907
--- /dev/null
+++ b/sysdeps/m68k/nptl/pthreaddef.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* 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/sysdeps/m68k/nptl/tcb-offsets.sym b/sysdeps/m68k/nptl/tcb-offsets.sym
new file mode 100644
index 0000000..b1bba65
--- /dev/null
+++ b/sysdeps/m68k/nptl/tcb-offsets.sym
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Derive offsets relative to the thread register.
+#define thread_offsetof(mem)	(long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads)
+PID_OFFSET			thread_offsetof (pid)
+TID_OFFSET			thread_offsetof (tid)
diff --git a/sysdeps/m68k/nptl/tls.h b/sysdeps/m68k/nptl/tls.h
new file mode 100644
index 0000000..c29824c
--- /dev/null
+++ b/sysdeps/m68k/nptl/tls.h
@@ -0,0 +1,171 @@
+/* Definition for thread-local data handling.  NPTL/m68k version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H	1
+
+#include <dl-sysdep.h>
+
+#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__ */
+
+/* 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 <nptl/descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_INIT_TCB_SIZE	0
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN	__alignof__ (struct pthread)
+
+/* This is the size of the TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_TCB_SIZE		0
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN		__alignof__ (struct pthread)
+
+/* This is the size we need before TCB - actually, it includes the TCB.  */
+# define TLS_PRE_TCB_SIZE						\
+  (sizeof (struct pthread)						\
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* The thread pointer (TP) points to the end of the
+   TCB + 0x7000, as for PowerPC and MIPS.  This implies that TCB address is
+   TP - 0x7000.  As we define TLS_DTV_AT_TP we can
+   assume that the pthread struct is allocated immediately ahead of the
+   TCB.  This implies that the pthread_descr address is
+   TP - (TLS_PRE_TCB_SIZE + 0x7000).  */
+# define TLS_TCB_OFFSET	0x7000
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV () = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall)					\
+  ({									\
+    INTERNAL_SYSCALL_DECL (err);					\
+    int _sys_result;							\
+									\
+    _sys_result = INTERNAL_SYSCALL (set_thread_area, err, 1,		\
+				    ((void *) (tcbp)) + TLS_TCB_OFFSET); \
+    INTERNAL_SYSCALL_ERROR_P (_sys_result, err) ? "unknown error" : NULL; })
+
+extern void * __m68k_read_tp (void);
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) (__m68k_read_tp () - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+  ((struct pthread *) (__m68k_read_tp () - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Access to data in the thread descriptor is easy.  */
+# define THREAD_GETMEM(descr, member) \
+  descr->member
+# define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+# define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* l_tls_offset == 0 is perfectly valid on M68K, so we have to use some
+   different value to mean unset l_tls_offset.  */
+# define NO_TLS_OFFSET		-1
+
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG()					\
+  do									\
+    { int __res								\
+	= atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,	\
+			       THREAD_GSCOPE_FLAG_UNUSED);		\
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)				\
+	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+    }									\
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG()					\
+  do									\
+    {									\
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;	\
+      atomic_write_barrier ();						\
+    }									\
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif	/* tls.h */
diff --git a/sysdeps/m68k/tls-macros.h b/sysdeps/m68k/tls-macros.h
new file mode 100644
index 0000000..d03d7b9
--- /dev/null
+++ b/sysdeps/m68k/tls-macros.h
@@ -0,0 +1,70 @@
+/* Macros for accessing thread-local storage.  m68k version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define TLS_GD(x)							\
+  ({									\
+    void *__result;							\
+    extern void *__tls_get_addr (void *);				\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "lea " #x "@TLSGD(%0), %0"					\
+	 : "=&a" (__result));						\
+    (int *) __tls_get_addr (__result); })
+
+#define TLS_LD(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void *__tls_get_addr (void *);				\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "lea " #x "@TLSLDM(%0), %0"					\
+	 : "=&a" (__tp));						\
+    __tp = (char *) __tls_get_addr (__tp);				\
+    asm ("movel #" #x "@TLSLDO, %0"					\
+	 : "=a" (__offset));						\
+    (int *) (__tp + __offset); })
+
+#define TLS_IE(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void * __m68k_read_tp (void);				\
+									\
+    __tp = (char *) __m68k_read_tp ();					\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"			\
+	 "lea (-6, %%pc, %0), %0\n\t"					\
+	 "movel " #x "@TLSIE(%0), %0"					\
+	 : "=&a" (__offset));						\
+    (int *) (__tp + __offset); })
+
+#define TLS_LE(x)							\
+  ({									\
+    char *__tp;								\
+    int __offset;							\
+    extern void * __m68k_read_tp (void);				\
+									\
+    __tp = (char *) __m68k_read_tp ();					\
+    asm ("movel #" #x "@TLSLE, %0"					\
+	 : "=a" (__offset));						\
+    (int *) (__tp + __offset); })
+
diff --git a/sysdeps/unix/sysv/linux/m68k/Makefile b/sysdeps/unix/sysv/linux/m68k/Makefile
index 6bb4f6b..97d9584 100644
--- a/sysdeps/unix/sysv/linux/m68k/Makefile
+++ b/sysdeps/unix/sysv/linux/m68k/Makefile
@@ -2,12 +2,18 @@
 
 m68k-syntax-flag = -DMOTOROLA_SYNTAX
 
+ifeq ($(subdir),csu)
+sysdep_routines += m68k-helpers
+endif
+
 ifeq ($(subdir),misc)
 sysdep_routines += mremap
 sysdep_headers += sys/reg.h
 endif
 
 ifeq ($(subdir),elf)
+sysdep_routines += dl-vdso libc-m68k-vdso
+sysdep-rtld-routines += m68k-vdso
 sysdep-others += lddlibc4
 install-bin += lddlibc4
 endif
diff --git a/sysdeps/unix/sysv/linux/m68k/Versions b/sysdeps/unix/sysv/linux/m68k/Versions
index 5650f7f..8a941f8 100644
--- a/sysdeps/unix/sysv/linux/m68k/Versions
+++ b/sysdeps/unix/sysv/linux/m68k/Versions
@@ -32,4 +32,18 @@ libc {
   GLIBC_2.11 {
     fallocate64;
   }
+  GLIBC_2.12 {
+    __m68k_read_tp;
+  }
+  GLIBC_PRIVATE {
+    __vdso_atomic_cmpxchg_32; __vdso_atomic_barrier;
+  }
+}
+
+ld {
+  GLIBC_PRIVATE {
+    __rtld___vdso_read_tp;
+    __rtld___vdso_atomic_cmpxchg_32;
+    __rtld___vdso_atomic_barrier;
+  }
 }
diff --git a/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
new file mode 100644
index 0000000..c361060
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
@@ -0,0 +1,61 @@
+/* Resolve function pointers to VDSO functions.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+#ifndef _M68K_VDSO_H
+#define _M68K_VDSO_H
+
+#ifdef SHARED
+
+# ifdef IS_IN_rtld
+# define M68K_VDSO_SYMBOL(name) __rtld_##name
+# define STR_M68K_VDSO_SYMBOL(name) "__rtld_" #name
+# else
+# define M68K_VDSO_SYMBOL(name) name
+# define STR_M68K_VDSO_SYMBOL(name) #name
+# endif
+
+# ifndef __ASSEMBLER__
+
+/* We define __rtld_* copies for rtld.
+   We need them visible in libc to initialize.  */
+#  if defined IS_IN_rtld || !defined NOT_IN_libc
+extern void *__rtld___vdso_read_tp;
+extern void *__rtld___vdso_atomic_cmpxchg_32;
+extern void *__rtld___vdso_atomic_barrier;
+
+/* These stubs are meant to be invoked only from the assembly.  */
+extern void __vdso_read_tp_stub (void);
+extern void __vdso_atomic_cmpxchg_32_stub (void);
+extern void __vdso_atomic_barrier_stub (void);
+#  endif /* IS_IN_rtld || !NOT_IN_libc */
+
+/* RTLD should only use its own copies.  */
+#  ifndef IS_IN_rtld
+extern void *__vdso_read_tp;
+extern void *__vdso_atomic_cmpxchg_32;
+extern void *__vdso_atomic_barrier;
+#  endif /* !IS_IN_rtld */
+
+# endif /* !__ASSEMBLER__ */
+
+#endif /* SHARED */
+
+#endif /* _M68K_VDSO_H */
diff --git a/sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h b/sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h
deleted file mode 100644
index 8ad0c96..0000000
--- a/sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (C) 2006 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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#if !defined _SIGNAL_H && !defined _SYS_UCONTEXT_H
-# error "Never use <bits/sigcontext.h> directly; include <signal.h> instead."
-#endif
-
-#ifndef _BITS_SIGCONTEXT_H
-#define _BITS_SIGCONTEXT_H 1
-
-struct sigcontext {
-  unsigned long sc_mask;
-  unsigned long sc_usp;
-  unsigned long sc_d0;
-  unsigned long sc_d1;
-#ifdef __mcoldfire__
-  unsigned long sc_d2;
-  unsigned long sc_d3;
-  unsigned long sc_d4;
-  unsigned long sc_d5;
-  unsigned long sc_d6;
-  unsigned long sc_d7;
-#endif
-  unsigned long sc_a0;
-  unsigned long sc_a1;
-#ifdef __mcoldfire__
-  unsigned long sc_a2;
-  unsigned long sc_a3;
-  unsigned long sc_a4;
-  unsigned long sc_a5;
-  unsigned long sc_a6;
-#endif
-  unsigned short sc_sr;
-  unsigned long sc_pc;
-  unsigned short sc_formatvec;
-#ifdef __mcoldfire__
-  unsigned long sc_fpregs[8][2];
-  unsigned long sc_fpcntl[3];
-  unsigned char sc_fpstate[16];
-#else
-  unsigned long sc_fpregs[2*3];
-  unsigned long sc_fpcntl[3];
-  unsigned char sc_fpstate[216];
-#endif
-};
-
-#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/bits/siginfo.h b/sysdeps/unix/sysv/linux/m68k/bits/siginfo.h
deleted file mode 100644
index 1ded1c2..0000000
--- a/sysdeps/unix/sysv/linux/m68k/bits/siginfo.h
+++ /dev/null
@@ -1,316 +0,0 @@
-/* siginfo_t, sigevent and constants.  m68k linux version.
-   Copyright (C) 1997-2002, 2003 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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#if !defined _SIGNAL_H && !defined __need_siginfo_t \
-    && !defined __need_sigevent_t
-# error "Never include this file directly.  Use <signal.h> instead"
-#endif
-
-#include <bits/wordsize.h>
-
-#if (!defined __have_sigval_t \
-     && (defined _SIGNAL_H || defined __need_siginfo_t \
-	 || defined __need_sigevent_t))
-# define __have_sigval_t	1
-
-/* Type for data associated with a signal.  */
-typedef union sigval
-  {
-    int sival_int;
-    void *sival_ptr;
-  } sigval_t;
-#endif
-
-#if (!defined __have_siginfo_t \
-     && (defined _SIGNAL_H || defined __need_siginfo_t))
-# define __have_siginfo_t	1
-
-# define __SI_MAX_SIZE     128
-# if __WORDSIZE == 64
-#  define __SI_PAD_SIZE     ((__SI_MAX_SIZE / sizeof (int)) - 4)
-# else
-#  define __SI_PAD_SIZE     ((__SI_MAX_SIZE / sizeof (int)) - 3)
-# endif
-
-typedef struct siginfo
-  {
-    int si_signo;		/* Signal number.  */
-    int si_errno;		/* If non-zero, an errno value associated with
-				   this signal, as defined in <errno.h>.  */
-    int si_code;		/* Signal code.  */
-
-    union
-      {
-	int _pad[__SI_PAD_SIZE];
-
-	 /* kill().  */
-	struct
-	  {
-	    __pid_t si_pid;	/* Sending process ID.  */
-	    unsigned short __pad; /* 16-bit version of si_uid.  */
-	    __uid_t si_uid;	/* Real user ID of sending process.  */
-	  } _kill;
-
-	/* POSIX.1b timers.  */
-	struct
-	  {
-	    int si_tid;		/* Timer ID.  */
-	    int si_overrun;	/* Overrun count.  */
-	    sigval_t si_sigval;	/* Signal value.  */
-	  } _timer;
-
-	/* POSIX.1b signals.  */
-	struct
-	  {
-	    __pid_t si_pid;	/* Sending process ID.  */
-	    unsigned short __pad; /* 16-bit version of si_uid.  */
-	    sigval_t si_sigval;	/* Signal value.  */
-	    __uid_t si_uid;	/* Real user ID of sending process.  */
-	  } _rt;
-
-	/* SIGCHLD.  */
-	struct
-	  {
-	    __pid_t si_pid;	/* Which child.  */
-	    unsigned short __pad; /* 16-bit version of si_uid.  */
-	    int si_status;	/* Exit value or signal.  */
-	    __clock_t si_utime;
-	    __clock_t si_stime;
-	    __uid_t si_uid;	/* Real user ID of sending process.  */
-	  } _sigchld;
-
-	/* SIGILL, SIGFPE, SIGSEGV, SIGBUS.  */
-	struct
-	  {
-	    void *si_addr;	/* Faulting insn/memory ref.  */
-	  } _sigfault;
-
-	/* SIGPOLL.  */
-	struct
-	  {
-	    long int si_band;	/* Band event for SIGPOLL.  */
-	    int si_fd;
-	  } _sigpoll;
-      } _sifields;
-  } siginfo_t;
-
-
-/* X/Open requires some more fields with fixed names.  */
-# define si_pid		_sifields._kill.si_pid
-# define si_uid		_sifields._kill.si_uid
-# define si_timerid	_sifields._timer.si_tid
-# define si_overrun	_sifields._timer.si_overrun
-# define si_status	_sifields._sigchld.si_status
-# define si_utime	_sifields._sigchld.si_utime
-# define si_stime	_sifields._sigchld.si_stime
-# define si_value	_sifields._rt.si_sigval
-# define si_int		_sifields._rt.si_sigval.sival_int
-# define si_ptr		_sifields._rt.si_sigval.sival_ptr
-# define si_addr	_sifields._sigfault.si_addr
-# define si_band	_sifields._sigpoll.si_band
-# define si_fd		_sifields._sigpoll.si_fd
-
-
-/* Values for `si_code'.  Positive values are reserved for kernel-generated
-   signals.  */
-enum
-{
-  SI_ASYNCNL = -60,		/* Sent by asynch name lookup completion.  */
-# define SI_ASYNCNL	SI_ASYNCNL
-  SI_TKILL = -6,		/* Sent by tkill.  */
-# define SI_TKILL	SI_TKILL
-  SI_SIGIO,			/* Sent by queued SIGIO. */
-# define SI_SIGIO	SI_SIGIO
-  SI_ASYNCIO,			/* Sent by AIO completion.  */
-# define SI_ASYNCIO	SI_ASYNCIO
-  SI_MESGQ,			/* Sent by real time mesq state change.  */
-# define SI_MESGQ	SI_MESGQ
-  SI_TIMER,			/* Sent by timer expiration.  */
-# define SI_TIMER	SI_TIMER
-  SI_QUEUE,			/* Sent by sigqueue.  */
-# define SI_QUEUE	SI_QUEUE
-  SI_USER,			/* Sent by kill, sigsend, raise.  */
-# define SI_USER	SI_USER
-  SI_KERNEL = 0x80		/* Send by kernel.  */
-#define SI_KERNEL	SI_KERNEL
-};
-
-
-/* `si_code' values for SIGILL signal.  */
-enum
-{
-  ILL_ILLOPC = 1,		/* Illegal opcode.  */
-# define ILL_ILLOPC	ILL_ILLOPC
-  ILL_ILLOPN,			/* Illegal operand.  */
-# define ILL_ILLOPN	ILL_ILLOPN
-  ILL_ILLADR,			/* Illegal addressing mode.  */
-# define ILL_ILLADR	ILL_ILLADR
-  ILL_ILLTRP,			/* Illegal trap. */
-# define ILL_ILLTRP	ILL_ILLTRP
-  ILL_PRVOPC,			/* Privileged opcode.  */
-# define ILL_PRVOPC	ILL_PRVOPC
-  ILL_PRVREG,			/* Privileged register.  */
-# define ILL_PRVREG	ILL_PRVREG
-  ILL_COPROC,			/* Coprocessor error.  */
-# define ILL_COPROC	ILL_COPROC
-  ILL_BADSTK			/* Internal stack error.  */
-# define ILL_BADSTK	ILL_BADSTK
-};
-
-/* `si_code' values for SIGFPE signal.  */
-enum
-{
-  FPE_INTDIV = 1,		/* Integer divide by zero.  */
-# define FPE_INTDIV	FPE_INTDIV
-  FPE_INTOVF,			/* Integer overflow.  */
-# define FPE_INTOVF	FPE_INTOVF
-  FPE_FLTDIV,			/* Floating point divide by zero.  */
-# define FPE_FLTDIV	FPE_FLTDIV
-  FPE_FLTOVF,			/* Floating point overflow.  */
-# define FPE_FLTOVF	FPE_FLTOVF
-  FPE_FLTUND,			/* Floating point underflow.  */
-# define FPE_FLTUND	FPE_FLTUND
-  FPE_FLTRES,			/* Floating point inexact result.  */
-# define FPE_FLTRES	FPE_FLTRES
-  FPE_FLTINV,			/* Floating point invalid operation.  */
-# define FPE_FLTINV	FPE_FLTINV
-  FPE_FLTSUB			/* Subscript out of range.  */
-# define FPE_FLTSUB	FPE_FLTSUB
-};
-
-/* `si_code' values for SIGSEGV signal.  */
-enum
-{
-  SEGV_MAPERR = 1,		/* Address not mapped to object.  */
-# define SEGV_MAPERR	SEGV_MAPERR
-  SEGV_ACCERR			/* Invalid permissions for mapped object.  */
-# define SEGV_ACCERR	SEGV_ACCERR
-};
-
-/* `si_code' values for SIGBUS signal.  */
-enum
-{
-  BUS_ADRALN = 1,		/* Invalid address alignment.  */
-# define BUS_ADRALN	BUS_ADRALN
-  BUS_ADRERR,			/* Non-existant physical address.  */
-# define BUS_ADRERR	BUS_ADRERR
-  BUS_OBJERR			/* Object specific hardware error.  */
-# define BUS_OBJERR	BUS_OBJERR
-};
-
-/* `si_code' values for SIGTRAP signal.  */
-enum
-{
-  TRAP_BRKPT = 1,		/* Process breakpoint.  */
-# define TRAP_BRKPT	TRAP_BRKPT
-  TRAP_TRACE			/* Process trace trap.  */
-# define TRAP_TRACE	TRAP_TRACE
-};
-
-/* `si_code' values for SIGCHLD signal.  */
-enum
-{
-  CLD_EXITED = 1,		/* Child has exited.  */
-# define CLD_EXITED	CLD_EXITED
-  CLD_KILLED,			/* Child was killed.  */
-# define CLD_KILLED	CLD_KILLED
-  CLD_DUMPED,			/* Child terminated abnormally.  */
-# define CLD_DUMPED	CLD_DUMPED
-  CLD_TRAPPED,			/* Traced child has trapped.  */
-# define CLD_TRAPPED	CLD_TRAPPED
-  CLD_STOPPED,			/* Child has stopped.  */
-# define CLD_STOPPED	CLD_STOPPED
-  CLD_CONTINUED			/* Stopped child has continued.  */
-# define CLD_CONTINUED	CLD_CONTINUED
-};
-
-/* `si_code' values for SIGPOLL signal.  */
-enum
-{
-  POLL_IN = 1,			/* Data input available.  */
-# define POLL_IN	POLL_IN
-  POLL_OUT,			/* Output buffers available.  */
-# define POLL_OUT	POLL_OUT
-  POLL_MSG,			/* Input message available.   */
-# define POLL_MSG	POLL_MSG
-  POLL_ERR,			/* I/O error.  */
-# define POLL_ERR	POLL_ERR
-  POLL_PRI,			/* High priority input available.  */
-# define POLL_PRI	POLL_PRI
-  POLL_HUP			/* Device disconnected.  */
-# define POLL_HUP	POLL_HUP
-};
-
-# undef __need_siginfo_t
-#endif	/* !have siginfo_t && (have _SIGNAL_H || need siginfo_t).  */
-
-
-#if (defined _SIGNAL_H || defined __need_sigevent_t) \
-    && !defined __have_sigevent_t
-# define __have_sigevent_t	1
-
-/* Structure to transport application-defined values with signals.  */
-# define __SIGEV_MAX_SIZE	64
-# if __WORDSIZE == 64
-#  define __SIGEV_PAD_SIZE	((__SIGEV_MAX_SIZE / sizeof (int)) - 4)
-# else
-#  define __SIGEV_PAD_SIZE	((__SIGEV_MAX_SIZE / sizeof (int)) - 3)
-# endif
-
-typedef struct sigevent
-  {
-    sigval_t sigev_value;
-    int sigev_signo;
-    int sigev_notify;
-
-    union
-      {
-	int _pad[__SIGEV_PAD_SIZE];
-
-	/* When SIGEV_SIGNAL and SIGEV_THREAD_ID set, LWP ID of the
-	   thread to receive the signal.  */
-	__pid_t _tid;
-
-	struct
-	  {
-	    void (*_function) (sigval_t);	/* Function to start.  */
-	    void *_attribute;			/* Really pthread_attr_t.  */
-	  } _sigev_thread;
-      } _sigev_un;
-  } sigevent_t;
-
-/* POSIX names to access some of the members.  */
-# define sigev_notify_function   _sigev_un._sigev_thread._function
-# define sigev_notify_attributes _sigev_un._sigev_thread._attribute
-
-/* `sigev_notify' values.  */
-enum
-{
-  SIGEV_SIGNAL = 0,		/* Notify via signal.  */
-# define SIGEV_SIGNAL	SIGEV_SIGNAL
-  SIGEV_NONE,			/* Other notification: meaningless.  */
-# define SIGEV_NONE	SIGEV_NONE
-  SIGEV_THREAD,			/* Deliver via thread creation.  */
-# define SIGEV_THREAD	SIGEV_THREAD
-
-  SIGEV_THREAD_ID = 4		/* Send signal to specific thread.  */
-#define SIGEV_THREAD_ID	SIGEV_THREAD_ID
-};
-
-#endif	/* have _SIGNAL_H.  */
diff --git a/sysdeps/unix/sysv/linux/m68k/clone.S b/sysdeps/unix/sysv/linux/m68k/clone.S
index a179f8e..401e2ef 100644
--- a/sysdeps/unix/sysv/linux/m68k/clone.S
+++ b/sysdeps/unix/sysv/linux/m68k/clone.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996,97,98,2002,2010 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
 
@@ -17,14 +17,21 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-/* clone is even more special than fork as it mucks with stacks
+/* clone() is even more special than fork() as it mucks with stacks
    and invokes a function in the right context after its all over.  */
 
 #include <sysdep.h>
 #define _ERRNO_H	1
 #include <bits/errno.h>
+#ifdef RESET_PID
+#include <tls.h>
+#endif
+
+#define CLONE_VM      0x00000100
+#define CLONE_THREAD  0x00010000
 
-/* 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,
+	     void *parent_tidptr, void *tls, void *child_tidptr) */
 
         .text
 ENTRY (__clone)
@@ -42,7 +49,17 @@ ENTRY (__clone)
 	movel	16(%sp), -(%a1)
 
 	/* Do the system call */
-	movel	12(%sp), %d1		/* get flags */
+	movel	12+0(%sp), %d1		/* get flags */
+	movel	%d3, -(%a1)             /* save %d3 and get parent_tidptr */
+	movel	%d3, -(%sp)
+	movel	20+4(%sp), %d3
+	movel	%d4, -(%a1)		/* save %d4 and get child_tidptr */
+	movel	%d4, -(%sp)
+	movel	28+8(%sp), %d4
+	movel	%d5, -(%a1)             /* save %d5 and get tls */
+	movel	%d5, -(%sp)
+	movel	24+12(%sp), %d5
+	/* save %d2 and get stack pointer */
 #ifdef __mcoldfire__
 	movel	%d2, -(%a1)
 	movel	%d2, -(%sp)
@@ -57,6 +74,9 @@ ENTRY (__clone)
 #else
 	exg	%d2, %a1		/* restore %d2 */
 #endif
+	movel	(%sp)+, %d5             /* restore %d5, %d4 and %d3 */
+	movel	(%sp)+, %d4
+	movel	(%sp)+, %d3
 
 	tstl	%d0
 	jmi	SYSCALL_ERROR_LABEL
@@ -65,11 +85,35 @@ ENTRY (__clone)
 	rts
 
 thread_start:
+	cfi_startproc
+	cfi_undefined (pc)	/* Mark end of stack */
 	subl	%fp, %fp	/* terminate the stack frame */
+#ifdef RESET_PID
+	/* Check and see if we need to reset the PID.  */
+	movel	%d1, %a1
+	andl	#CLONE_THREAD, %d1
+	jne	donepid
+	movel	%a1, %d1
+	movel	#-1, %d0
+	andl	#CLONE_VM, %d1
+	jne	gotpid
+	movel	#SYS_ify (getpid), %d0
+	trap	#0
+gotpid:
+	movel	%a0, -(%sp)
+	movel	%d0, -(%sp)
+	bsrl	__m68k_read_tp@PLTPC
+	movel	(%sp)+, %d0
+	movel	%d0, PID_OFFSET(%a0)
+	movel	%d0, TID_OFFSET(%a0)
+	movel	(%sp)+, %a0
+donepid:
+#endif
 	jsr	(%a0)
 	movel	%d0, %d1
 	movel	#SYS_ify (exit), %d0
 	trap	#0
+	cfi_endproc
 
 PSEUDO_END (__clone)
 
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
new file mode 100644
index 0000000..1198bb9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
@@ -0,0 +1,105 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H	1
+
+#include <stdint.h>
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+/* Coldfire has no atomic compare-and-exchange operation, but the
+   kernel provides userspace atomicity operations.  Use them.  */
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+/* The only basic operation needed is compare and exchange.  */
+/* For ColdFire we'll have to trap into the kernel mode anyway,
+   so trap from the library rather then from the kernel wrapper.  */
+#ifdef SHARED
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  ({									\
+    /* Use temporary variables to workaround call-clobberness of */	\
+    /* the registers.  */						\
+    __typeof (mem) _mem = mem;						\
+    __typeof (oldval) _oldval = oldval;					\
+    __typeof (newval) _newval = newval;					\
+    register __typeof (mem) _a0 asm ("a0") = _mem;			\
+    register __typeof (oldval) _d0 asm ("d0") = _oldval;		\
+    register __typeof (newval) _d1 asm ("d1") = _newval;		\
+    void *tmp;								\
+									\
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %2\n\t"			\
+	 "lea (-6, %%pc, %2), %2\n\t"					\
+	 "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)	\
+	 "@GOT(%2), %2\n\t"						\
+	 "movel (%2), %2\n\t"						\
+	 "jsr (%2)\n\t"							\
+	 : "+d" (_d0), "+m" (*_a0), "=&a" (tmp)				\
+	 : "a" (_a0), "d" (_d1));					\
+    _d0;								\
+  })
+#else
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  ({									\
+    /* Use temporary variables to workaround call-clobberness of */	\
+    /* the registers.  */						\
+    __typeof (mem) _mem = mem;						\
+    __typeof (oldval) _oldval = oldval;					\
+    __typeof (newval) _newval = newval;					\
+    register __typeof (oldval) _d0 asm ("d0")				\
+      = SYS_ify (atomic_cmpxchg_32);					\
+    register __typeof (mem) _a0 asm ("a0") = _mem;			\
+    register __typeof (oldval) _d2 asm ("d2") = _oldval;		\
+    register __typeof (newval) _d1 asm ("d1") = _newval;		\
+									\
+    asm ("trap #0"							\
+	 : "+d" (_d0), "+m" (*_a0)					\
+	 : "a" (_a0), "d" (_d2), "d" (_d1));				\
+    _d0;								\
+  })
+#endif
+
+#ifdef SHARED
+# define atomic_full_barrier()					 \
+  ({								 \
+    void *tmp;							 \
+								 \
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"		 \
+	 "lea (-6, %pc, %0), %0\n\t"				 \
+	 "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_barrier)	 \
+	 "@GOT(%0), %0\n\t"					 \
+	 "movel (%0), %0\n\t"					 \
+	 "jsr (%0)\n\t"						 \
+	 : "=&a" (tmp));					 \
+  })
+#else
+# define atomic_full_barrier()				\
+  (INTERNAL_SYSCALL (atomic_barrier, , 0), (void) 0)
+#endif
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/init-first.c b/sysdeps/unix/sysv/linux/m68k/init-first.c
new file mode 100644
index 0000000..f8168d1
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/init-first.c
@@ -0,0 +1,74 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Note: linking in vDSO to a static binary requires changes to
+   the main GLIBC proper.  Not yet implemented.  */
+#ifdef SHARED
+
+#include <dl-vdso.h>
+#include <bits/m68k-vdso.h>
+
+static inline void
+_libc_vdso_platform_setup (void)
+{
+  void *p;
+
+  PREPARE_VERSION (linux26, "LINUX_2.6", 61765110);
+
+  /* It may happen that rtld didn't initialize the vDSO, so fallback
+     to the syscall implementations if _dl_vdso_vsym returns NULL.
+     This may happen when a static executable dlopen's a dynamic library.
+     This really is nothing more than a workaround for rtld/csu
+     deficiency.  Ideally, init code would setup the vDSO for static
+     binaries too.  */
+
+  p = _dl_vdso_vsym ("__kernel_read_tp", &linux26);
+  if (p != NULL)
+    {
+      __vdso_read_tp = p;
+      __rtld___vdso_read_tp = p;
+    }
+  else
+    assert (__vdso_read_tp == (void *) __vdso_read_tp_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_cmpxchg_32", &linux26);
+  if (p != NULL)
+    {
+      __vdso_atomic_cmpxchg_32 = p;
+      __rtld___vdso_atomic_cmpxchg_32 = p;
+    }
+  else
+    assert (__vdso_atomic_cmpxchg_32
+	    == (void *) __vdso_atomic_cmpxchg_32_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_barrier", &linux26);
+  if (p != NULL)
+    {
+      __vdso_atomic_barrier = p;
+      __rtld___vdso_atomic_barrier = p;
+    }
+  else
+    assert (__vdso_atomic_barrier == (void *) __vdso_atomic_barrier_stub);
+}
+
+#define VDSO_SETUP _libc_vdso_platform_setup
+
+#endif /* SHARED */
+
+#include <sysdeps/unix/sysv/linux/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
new file mode 100644
index 0000000..45982e9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
@@ -0,0 +1 @@
+#include "m68k-vdso.c"
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
new file mode 100644
index 0000000..00db4bb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
@@ -0,0 +1,105 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+	.text
+
+	.hidden __vdso_read_tp_stub
+ENTRY (__vdso_read_tp_stub)
+	cfi_startproc
+	move.l	#__NR_get_thread_area, %d0
+	trap	#0
+	move.l	%d0, %a0
+	rts
+	cfi_endproc
+END (__vdso_read_tp_stub)
+
+# ifdef SHARED
+/* GCC will emit calls to this routine.  Linux has an
+   equivalent helper function (which clobbers fewer registers than
+   a normal function call) in a vdso; tail call to the
+   helper.  */
+# ifdef IS_IN_rtld
+/* rtld gets a hidden copy of __m68k_read_tp.  */
+	.hidden __m68k_read_tp
+# endif
+ENTRY (__m68k_read_tp)
+	cfi_startproc
+	move.l	#_GLOBAL_OFFSET_TABLE_@GOTPC, %a0
+	lea	(-6, %pc, %a0), %a0
+	move.l	M68K_VDSO_SYMBOL (__vdso_read_tp)@GOT(%a0), %a0
+	move.l	(%a0), %a0
+	jmp	(%a0)
+	cfi_endproc
+END (__m68k_read_tp)
+
+/* The following two stubs are for macros in atomic.h, they can't
+   clobber anything.  */
+
+	.hidden __vdso_atomic_cmpxchg_32_stub
+ENTRY (__vdso_atomic_cmpxchg_32_stub)
+	cfi_startproc
+	move.l	%d2, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
+	move.l	%d0, %d2
+	move.l	#SYS_ify (atomic_cmpxchg_32), %d0
+	trap	#0
+	move.l	(%sp)+, %d2
+	cfi_adjust_cfa_offset (-4)
+	cfi_restore (%d2)
+	rts
+	cfi_endproc
+END (__vdso_atomic_cmpxchg_32_stub)
+	
+	.hidden __vdso_atomic_barrier_stub
+ENTRY (__vdso_atomic_barrier_stub)
+	cfi_startproc
+	move.l	%d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	move.l	#SYS_ify (atomic_barrier), %d0
+	trap	#0
+	move.l	(%sp)+, %d0
+	cfi_adjust_cfa_offset (-4)
+	rts
+	cfi_endproc
+END (__vdso_atomic_barrier_stub)
+# else /* !SHARED */
+/* If the vDSO is not available, use a syscall to get TP.  */
+	strong_alias (__vdso_read_tp_stub, __m68k_read_tp)
+# endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
new file mode 100644
index 0000000..73b2570
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifdef SHARED
+
+#include <bits/m68k-vdso.h>
+
+/* Because these pointers are used from other libraries than libc,
+   they are exported at GLIBC_PRIVATE version.
+   We initialize them to syscall implementation so that they will be ready
+   to use from the very beginning.  */
+void * M68K_VDSO_SYMBOL (__vdso_read_tp)
+= (void *) __vdso_read_tp_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)
+= (void *) __vdso_atomic_cmpxchg_32_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_barrier)
+= (void *) __vdso_atomic_barrier_stub;
+
+#endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
new file mode 100644
index 0000000..0140810
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
@@ -0,0 +1,172 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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_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
+   deliberately not exposed.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+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 deliberately not exposed.  */
+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;
+
+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 deliberately not exposed.  */
+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 deliberately not exposed.  */
+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;
+    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;
+    int __writer;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+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/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
new file mode 100644
index 0000000..2950cc9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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/sysdeps/unix/sysv/linux/m68k/nptl/clone.S b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
new file mode 100644
index 0000000..e7388fe
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include "../clone.S"
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
new file mode 100644
index 0000000..be11444
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE ((void *) (pd) \
+		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation.	 */
+#include <nptl/sysdeps/pthread/createthread.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/fork.c b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
new file mode 100644
index 0000000..dc1584e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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, &THREAD_SELF->tid, NULL)
+
+#include <sysdeps/unix/sysv/linux/fork.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
new file mode 100644
index 0000000..926077d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
@@ -0,0 +1,281 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Borrowed from ARM's version.  */
+
+#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 <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 __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAIT, private),	      \
+			      (val), (timespec));			      \
+    __ret;								      \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \
+			      __lll_private_flag (FUTEX_WAKE, private),	      \
+			      (nr), 0);					      \
+    __ret;								      \
+  })
+
+#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 __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),		      \
+			      __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+			      (nr_wake), (nr_move), (mutex), (val));	      \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __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 __ret;							      \
+    __ret = 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 (__ret, __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(lock, id)			\
+  atomic_compare_and_exchange_val_acq (&(lock), id, 0)
+
+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 (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex,       \
+								1, 0), 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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+								0), 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 (__builtin_expect (atomic_exchange_acq (__futex, 2), 0))		      \
+      __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 (__builtin_expect (atomic_exchange_acq (__futex, 1), 0))	      \
+       __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 (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+								0), 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 (__builtin_expect (__oldval > 1, 0))			\
+	 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 (__builtin_expect (__oldval & FUTEX_WAITERS, 0))	\
+	 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/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
new file mode 100644
index 0000000..36c9270
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
@@ -0,0 +1,36 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+	bsrl	__m68k_read_tp@PLTPC	; /* Get the thread pointer.  */ \
+	movel	%a0, %a1		; /* Save TP for RESTORE_PID.  */ \
+	movel	PID_OFFSET(%a1), %d0	; /* Get the PID.  */ \
+	movel	%d0, %d1		; /* Save PID for RESTORE_PID.  */ \
+	negl	%d0			; /* Negate the PID.  */ \
+	movel	%d0, PID_OFFSET(%a1)	; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+	tstl	%d0			; \
+	beq	1f			; /* If we are the parent... */ \
+	movel	%d1, PID_OFFSET(%a1)	; /* Restore the PID.  */ \
+1:	
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
new file mode 100644
index 0000000..415045f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
@@ -0,0 +1,91 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
new file mode 100644
index 0000000..87e2d55
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
@@ -0,0 +1,141 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				      \
+  .text;								      \
+  ENTRY (name)								      \
+    SINGLE_THREAD_P;							      \
+    jne .Lpseudo_cancel;						      \
+  .type __##syscall_name##_nocancel,@function;			              \
+  .globl __##syscall_name##_nocancel;				 	      \
+  __##syscall_name##_nocancel:					              \
+    DO_CALL (syscall_name, args);					      \
+    cmp.l &-4095, %d0;							      \
+    jcc SYSCALL_ERROR_LABEL;						      \
+    rts;								      \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \
+  .Lpseudo_cancel:							      \
+    cfi_startproc;							      \
+    CENABLE;								      \
+    DOCARGS_##args							      \
+    move.l %d0, -(%sp); /* Save result of CENABLE.  */  		      \
+    cfi_adjust_cfa_offset (4); \
+    move.l &SYS_ify (syscall_name), %d0;				      \
+    trap &0;								      \
+    move.l %d0, %d2;							      \
+    CDISABLE;								      \
+    addq.l &4, %sp; /* Remove result of CENABLE from the stack.  */           \
+    cfi_adjust_cfa_offset (-4); \
+    move.l %d2, %d0;							      \
+    UNDOCARGS_##args							      \
+    cmp.l &-4095, %d0;							      \
+    jcc SYSCALL_ERROR_LABEL;		                                      \
+    cfi_endproc
+
+/* Note: we use D2 to save syscall's return value as D0 will be clobbered in
+   CDISABLE.  */
+# define DOCARGS_0	move.l %d2, -(%sp);		\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d2, 0);
+# define UNDOCARGS_0	move.l (%sp)+, %d2;	\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d2);
+
+# define DOCARGS_1	_DOCARGS_1 (4); DOCARGS_0
+# define _DOCARGS_1(n)	move.l n(%sp), %d1;
+# define UNDOCARGS_1	UNDOCARGS_0
+
+# define DOCARGS_2	_DOCARGS_2 (8)
+# define _DOCARGS_2(n)	DOCARGS_0 move.l n+4(%sp), %d2; _DOCARGS_1 (n)
+# define UNDOCARGS_2	UNDOCARGS_0
+
+/* TODO: We can optimize DOCARGS_{3, 4} by saving registers to a0 and a1
+   instead of pushing them on stack.  */
+# define DOCARGS_3	_DOCARGS_3 (12)
+# define _DOCARGS_3(n)	move.l %d3, -(%sp);				\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d3, 0);			\
+  move.l n+4(%sp), %d3; _DOCARGS_2 (n)
+# define UNDOCARGS_3	UNDOCARGS_2 move.l (%sp)+, %d3;		\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d3);
+
+# define DOCARGS_4	_DOCARGS_4 (16)
+# define _DOCARGS_4(n)	move.l %d4, -(%sp);			\
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d4, 0);		\
+  move.l n+4(%sp), %d4; _DOCARGS_3 (n)
+# define UNDOCARGS_4	UNDOCARGS_3 move.l (%sp)+, %d4;	\
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d4);
+
+# define DOCARGS_5	_DOCARGS_5 (20)
+# define _DOCARGS_5(n)	move.l %d5, %a1; cfi_register (%d5, a1); \
+  move.l n(%sp), %d5; _DOCARGS_4 (n-4)
+# define UNDOCARGS_5	UNDOCARGS_4 move.l %a1, %d5; cfi_restore (%d5);
+
+# define DOCARGS_6	_DOCARGS_6 (24)
+# define _DOCARGS_6(n)	move.l n(%sp), %a0; _DOCARGS_5 (n-4)
+# define UNDOCARGS_6	UNDOCARGS_5
+
+# ifdef PIC
+#  define PSEUDO_JMP(sym) jbsr sym ## @PLTPC
+# else
+#  define PSEUDO_JMP(sym) jbsr sym
+# endif
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	PSEUDO_JMP (__pthread_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__pthread_disable_asynccancel)
+# elif !defined NOT_IN_libc
+#  define CENABLE	PSEUDO_JMP (__libc_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__libc_disable_asynccancel)
+# elif defined IS_IN_librt
+#  define CENABLE	PSEUDO_JMP (__librt_enable_asynccancel)
+#  define CDISABLE	PSEUDO_JMP (__librt_disable_asynccancel)
+# else
+#  error Unsupported library
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P						\
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\
+				   header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P			\
+  PSEUDO_JMP (__m68k_read_tp);		        \
+  tst.l MULTIPLE_THREADS_OFFSET(%a0)
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION (1)
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P					  \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,			  \
+				   header.multiple_threads) == 0, \
+		    1)
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
new file mode 100644
index 0000000..8599c3d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
@@ -0,0 +1,38 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tcb-offsets.h>
+
+#define SAVE_PID \
+	bsrl	__m68k_read_tp@PLTPC	; /* Get the thread pointer.  */ \
+	movel	%a0, %a1		; /* Save TP for RESTORE_PID.  */ \
+	movel	PID_OFFSET(%a1), %d0	; /* Get the PID.  */ \
+	movel	%d0, %d1		; /* Save PID for RESTORE_PID.  */ \
+	negl	%d0			; /* Negate the PID.  */ \
+	bne	1f			; /* If it was zero... */ \
+	movel	#0x80000000, %d0	; /* use 0x80000000 instead.  */ \
+1:	movel	%d0, PID_OFFSET(%a1)	; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+	tstl	%d0			; \
+	beq	1f			; /* If we are the parent... */ \
+	movel	%d1, PID_OFFSET(%a1)	; /* Restore the PID.  */ \
+1:	
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/register-dump.h b/sysdeps/unix/sysv/linux/m68k/register-dump.h
index 391902f..78709d9 100644
--- a/sysdeps/unix/sysv/linux/m68k/register-dump.h
+++ b/sysdeps/unix/sysv/linux/m68k/register-dump.h
@@ -40,7 +40,6 @@
 
 */
 
-#ifndef __mcoldfire__
 /* Linux saves only the call-clobbered registers in the sigcontext.  We
    need to use a trampoline that saves the rest so that the C code can
    access them.  We use the sc_fpstate field, since the handler is not
@@ -59,14 +58,17 @@ catch_segfault:\n\
 	/* Clear the first 4 bytes to make it a null fp state, just\n\
 	   in case the handler does return.  */\n\
 	clr.l (%%a0)+\n\
-	movem.l %%d2-%%d7/%%a2-%%a6,(%%a0)\n\
-	fmovem.x %%fp2-%%fp7,11*4(%%a0)\n\
-	jra real_catch_segfault"
+	movem.l %%d2-%%d7/%%a2-%%a6,(%%a0)\n"
+#ifndef __mcoldfire__
+       "fmovem.x %%fp2-%%fp7,11*4(%%a0)\n"
+#elif defined __mcffpu__
+       "fmovem.d %%fp2-%%fp7,11*4(%%a0)\n"
+#endif
+       "jra real_catch_segfault"
        : : "n" (offsetof (struct sigcontext, sc_fpstate)));
 }
 #define catch_segfault(a,b) \
   __attribute_used__ real_catch_segfault(a,b)
-#endif
 
 static void
 hexvalue (unsigned long int value, char *buf, size_t len)
@@ -104,36 +106,19 @@ register_dump (int fd, struct sigcontext *ctx)
   /* Generate strings of register contents.  */
   hexvalue (ctx->sc_d0, regs[0], 8);
   hexvalue (ctx->sc_d1, regs[1], 8);
-#ifdef __mcoldfire__
-  hexvalue (ctx->sc_d2, regs[2], 8);
-  hexvalue (ctx->sc_d3, regs[3], 8);
-  hexvalue (ctx->sc_d4, regs[4], 8);
-  hexvalue (ctx->sc_d5, regs[5], 8);
-  hexvalue (ctx->sc_d6, regs[6], 8);
-  hexvalue (ctx->sc_d7, regs[7], 8);
-#else
   hexvalue (*p++, regs[2], 8);
   hexvalue (*p++, regs[3], 8);
   hexvalue (*p++, regs[4], 8);
   hexvalue (*p++, regs[5], 8);
   hexvalue (*p++, regs[6], 8);
   hexvalue (*p++, regs[7], 8);
-#endif
   hexvalue (ctx->sc_a0, regs[8], 8);
   hexvalue (ctx->sc_a1, regs[9], 8);
-#ifdef __mcoldfire__
-  hexvalue (ctx->sc_a2, regs[10], 8);
-  hexvalue (ctx->sc_a3, regs[11], 8);
-  hexvalue (ctx->sc_a4, regs[12], 8);
-  hexvalue (ctx->sc_a5, regs[13], 8);
-  hexvalue (ctx->sc_a6, regs[14], 8);
-#else
   hexvalue (*p++, regs[10], 8);
   hexvalue (*p++, regs[11], 8);
   hexvalue (*p++, regs[12], 8);
   hexvalue (*p++, regs[13], 8);
   hexvalue (*p++, regs[14], 8);
-#endif
   hexvalue (ctx->sc_usp, regs[15], 8);
   hexvalue (ctx->sc_pc, regs[16], 8);
   hexvalue (ctx->sc_sr, regs[17], 4);
@@ -142,9 +127,6 @@ register_dump (int fd, struct sigcontext *ctx)
   for (i = 0; i < 2; i++)
     for (j = 0; j < fpreg_size; j += 8)
       hexvalue (*pfp++, fpregs[i] + j, 8);
-#ifdef __mcoldfire__
-  p = pfp;
-#endif
   for (i = 2; i < 8; i++)
     for (j = 0; j < fpreg_size; j += 8)
       hexvalue (*p++, fpregs[i] + j, 8);
diff --git a/sysdeps/unix/sysv/linux/m68k/socket.S b/sysdeps/unix/sysv/linux/m68k/socket.S
index 2690f18..147a3b2 100644
--- a/sysdeps/unix/sysv/linux/m68k/socket.S
+++ b/sysdeps/unix/sysv/linux/m68k/socket.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2010 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
@@ -41,8 +41,11 @@
 
 .globl __socket
 ENTRY (__socket)
-#if defined NEED_CANCELLATION && defined CENABLE
-	SINGLE_THREAD_P (%a0)
+#ifdef NEED_CANCELLATION
+# if !defined CENABLE || !defined CDISABLE
+#  error CENABLE and/or CDISABLE is not defined
+# endif
+	SINGLE_THREAD_P
 	jne 1f
 #endif
 
@@ -69,21 +72,26 @@ ENTRY (__socket)
 	/* Successful; return the syscall's value.  */
 	rts
 
-#if defined NEED_CANCELLATION && defined CENABLE
-1:	/* Enable asynchronous cancellation.  */
+#ifdef NEED_CANCELLATION
+1:	cfi_startproc
+	/* Enable asynchronous cancellation.  */
 	CENABLE
 
-	/* Save registers.  */
+	/* Save D2.  */
 	move.l %d2, -(%sp)
-	move.l %d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
 
-	move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
+	/* Save the result of CENABLE.  */
+	move.l %d0, -(%sp)
+	cfi_adjust_cfa_offset (4)
 
 	/* Use ## so `socket' is a separate token that might be #define'd.  */
 	move.l #P (SOCKOP_,socket), %d1	/* Subcode is first arg to syscall.  */
 	lea 4+8(%sp), %a1		/* Address of args is 2nd arg.  */
 	move.l %a1, %d2
 
+	move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
 	/* Do the system call trap.  */
 	trap #0
 
@@ -91,14 +99,18 @@ ENTRY (__socket)
 	move.l %d0, %d2
 	CDISABLE
 	addq.l #4, %sp
+	cfi_adjust_cfa_offset (-4)
 	move.l %d2, %d0
 
 	/* Restore registers.  */
 	move.l (%sp)+, %d2
+	cfi_adjust_cfa_offset (-4)
+	cfi_restore (%d2)
 
 	/* %d0 is < 0 if there was an error.  */
 	tst.l %d0
 	jmi SYSCALL_ERROR_LABEL
+	cfi_endproc
 
 	/* Successful; return the syscall's value.  */
 	rts
diff --git a/sysdeps/unix/sysv/linux/m68k/sysdep.h b/sysdeps/unix/sysv/linux/m68k/sysdep.h
index 12687d8..e3aed15 100644
--- a/sysdeps/unix/sysv/linux/m68k/sysdep.h
+++ b/sysdeps/unix/sysv/linux/m68k/sysdep.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2006, 2010
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>,
    December 1995.
@@ -23,6 +24,7 @@
 
 #include <sysdeps/unix/sysdep.h>
 #include <sysdeps/m68k/sysdep.h>
+#include <tls.h>
 
 /* Defines RTLD_PRIVATE_ERRNO.  */
 #include <dl-sysdep.h>
@@ -148,9 +150,11 @@ SYSCALL_ERROR_LABEL:							      \
 	arg 3		%d3	     call-saved
 	arg 4		%d4	     call-saved
 	arg 5		%d5	     call-saved
+	arg 6		%a0	     call-clobbered
 
    The stack layout upon entering the function is:
 
+	24(%sp)		Arg# 6
 	20(%sp)		Arg# 5
 	16(%sp)		Arg# 4
 	12(%sp)		Arg# 3
@@ -229,7 +233,7 @@ SYSCALL_ERROR_LABEL:							      \
    normally.  It will never touch errno.  This returns just what the kernel
    gave back.  */
 #undef INTERNAL_SYSCALL
-#define INTERNAL_SYSCALL(name, err, nr, args...)	\
+#define INTERNAL_SYSCALL_NCS(name, err, nr, args...)	\
   ({ unsigned int _sys_result;				\
      {							\
        /* Load argument values in temporary variables
@@ -237,7 +241,7 @@ SYSCALL_ERROR_LABEL:							      \
 	  before the call used registers are set.  */	\
        LOAD_ARGS_##nr (args)				\
        LOAD_REGS_##nr					\
-       register int _d0 asm ("%d0") = __NR_##name;	\
+       register int _d0 asm ("%d0") = name;		\
        asm volatile ("trap #0"				\
 		     : "=d" (_d0)			\
 		     : "0" (_d0) ASM_ARGS_##nr		\
@@ -245,6 +249,8 @@ SYSCALL_ERROR_LABEL:							      \
        _sys_result = _d0;				\
      }							\
      (int) _sys_result; })
+#define INTERNAL_SYSCALL(name, err, nr, args...)	\
+  INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)
 
 #undef INTERNAL_SYSCALL_ERROR_P
 #define INTERNAL_SYSCALL_ERROR_P(val, err)		\
@@ -300,4 +306,15 @@ SYSCALL_ERROR_LABEL:							      \
 #define ASM_ARGS_6	ASM_ARGS_5, "a" (_a0)
 
 #endif /* not __ASSEMBLER__ */
+
+/* Pointer mangling is not yet supported for M68K.  */
+#define PTR_MANGLE(var) (void) (var)
+#define PTR_DEMANGLE(var) (void) (var)
+
+#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
+/* M68K needs system-supplied DSO to access TLS helpers
+   even when statically linked.  */
+# define NEED_STATIC_SYSINFO_DSO 1
+#endif
+
 #endif
diff --git a/sysdeps/unix/sysv/linux/m68k/vfork.S b/sysdeps/unix/sysv/linux/m68k/vfork.S
index 8027b2f..61bbf2f 100644
--- a/sysdeps/unix/sysv/linux/m68k/vfork.S
+++ b/sysdeps/unix/sysv/linux/m68k/vfork.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2002, 2003, 2010 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab <schwab@gnu.org>.
 
@@ -22,6 +22,14 @@
 #include <bits/errno.h>
 #include <kernel-features.h>
 
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
 /* 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,
@@ -31,12 +39,20 @@ ENTRY (__vfork)
 
 #ifdef __NR_vfork
 
+	/* SAVE_PID clobbers call-clobbered registers and
+	   saves data in D1 and A1.  */
+
+	SAVE_PID
+	
 	/* Pop the return PC value into A0.  */
 	movel	%sp@+, %a0
 
 	/* Stuff the syscall number in D0 and trap into the kernel.  */
 	movel	#SYS_ify (vfork), %d0
 	trap	#0
+
+	RESTORE_PID
+
 	tstl	%d0
 	jmi	.Lerror		/* Branch forward if it failed.  */
 

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2010-03-09 10:52 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-25 12:27 [M68K/ColdFire] NPTL support and other updates Maxim Kuvyrkov
2009-08-25 12:36 ` [M68K/ColdFire patch 1/n] Update sysdep.h Maxim Kuvyrkov
2009-08-25 12:39 ` [M68K/ColdFire patch 2/n] Add CFI information to dl-trampoline.S Maxim Kuvyrkov
2009-08-25 12:52 ` [M68K/ColdFire patch 3/n] Update jmpbuf-unwind.h Maxim Kuvyrkov
2009-08-25 12:58 ` [M68K/ColdFire patch 4/n] Remove kernel headers Maxim Kuvyrkov
2009-08-25 13:21   ` Andreas Schwab
2009-08-25 14:25     ` Maxim Kuvyrkov
2009-08-25 14:41       ` Andreas Schwab
2009-08-25 15:28         ` Maxim Kuvyrkov
2009-08-25 15:44           ` Andreas Schwab
2009-08-25 16:52             ` Maxim Kuvyrkov
2009-08-25 18:16               ` Andreas Schwab
2009-08-30 17:46                 ` Maxim Kuvyrkov
2009-10-02 10:51                   ` Maxim Kuvyrkov
2009-08-25 13:04 ` [M68K/ColdFire patch 5/n] Main NPTL patch Maxim Kuvyrkov
2009-08-30 18:03   ` Maxim Kuvyrkov
2009-10-02 10:46     ` Maxim Kuvyrkov
2009-10-23  9:39       ` Maxim Kuvyrkov
2009-10-29 16:16         ` Joseph S. Myers
2009-08-25 13:39 ` [M68K/ColdFire patch 6/n] Add TLS relocations to elf/elf.h Maxim Kuvyrkov
2010-02-09 17:28   ` [m68k] " Maxim Kuvyrkov
2009-08-25 13:43 ` [M68K/ColdFire patch 7/n] Handle libgcc_s.so.2 Maxim Kuvyrkov
2009-09-07 20:36 ` [M68K/ColdFire] NPTL support and other updates Andreas Schwab
2009-09-08  5:52   ` Maxim Kuvyrkov
2009-09-13 17:07     ` Andreas Schwab
2010-02-09 19:01 ` Maxim Kuvyrkov
2010-03-01 12:17   ` Joseph S. Myers
2010-03-07 19:49   ` Andreas Schwab
2010-03-08  7:33     ` Maxim Kuvyrkov
2010-03-08 18:41       ` Andreas Schwab
2010-03-09 10:52         ` Maxim Kuvyrkov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).