From 23bb649090ff588e8642f0c581cfe7ce2d29c757 Mon Sep 17 00:00:00 2001
From: Waldemar Brodkorb <wbx@uclibc-ng.org>
Date: Sat, 16 Dec 2017 21:01:39 +0100
Subject: m68k: add NPTL/TLS support

Port over NPTL/TLS support from GNU C Library.
In the first step only the slower syscall is used for TLS
access. The uClibc-ng testsuite shows 79 errors, so their
is room for bugfixes and improvements.
---
 libc/sysdeps/linux/common/libgcc_s.h    |   4 ++
 libc/sysdeps/linux/m68k/Makefile.arch   |   3 +-
 libc/sysdeps/linux/m68k/clone.S         | 108 +++++++++++++++++++++++---------
 libc/sysdeps/linux/m68k/jmpbuf-unwind.h |  39 ++++++++++--
 libc/sysdeps/linux/m68k/m68k_read_tp.S  |   1 +
 libc/sysdeps/linux/m68k/sys/reg.h       | 101 +++++++++++++++++++++++++++++
 libc/sysdeps/linux/m68k/sysdep.h        |  26 ++++++++
 libc/sysdeps/linux/m68k/vfork.S         |  30 ++++-----
 8 files changed, 258 insertions(+), 54 deletions(-)
 create mode 100644 libc/sysdeps/linux/m68k/m68k_read_tp.S
 create mode 100644 libc/sysdeps/linux/m68k/sys/reg.h
 create mode 100644 libc/sysdeps/linux/m68k/sysdep.h

(limited to 'libc')

diff --git a/libc/sysdeps/linux/common/libgcc_s.h b/libc/sysdeps/linux/common/libgcc_s.h
index e74a1034c..bf43d78a7 100644
--- a/libc/sysdeps/linux/common/libgcc_s.h
+++ b/libc/sysdeps/linux/common/libgcc_s.h
@@ -1,2 +1,6 @@
 /* Name of libgcc_s library provided by gcc.  */
+#if defined(__m68k__)
+#define LIBGCC_S_SO "libgcc_s.so.2"
+#else
 #define LIBGCC_S_SO "libgcc_s.so.1"
+#endif
diff --git a/libc/sysdeps/linux/m68k/Makefile.arch b/libc/sysdeps/linux/m68k/Makefile.arch
index 88caa116f..191791aef 100644
--- a/libc/sysdeps/linux/m68k/Makefile.arch
+++ b/libc/sysdeps/linux/m68k/Makefile.arch
@@ -7,4 +7,5 @@
 
 CSRC-y := brk.c __syscall_error.c
 
-SSRC-y := __longjmp.S bsd-_setjmp.S bsd-setjmp.S clone.S setjmp.S vfork.S
+SSRC-y := __longjmp.S bsd-_setjmp.S bsd-setjmp.S clone.S setjmp.S vfork.S \
+	  m68k_read_tp.S
diff --git a/libc/sysdeps/linux/m68k/clone.S b/libc/sysdeps/linux/m68k/clone.S
index 7eddff10c..24071235b 100644
--- a/libc/sysdeps/linux/m68k/clone.S
+++ b/libc/sysdeps/linux/m68k/clone.S
@@ -1,54 +1,94 @@
-/* Adapted from glibc */
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. */
+/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
+   Contributed by Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
 
 /* clone is even more special than fork as it mucks with stacks
    and invokes a function in the right context after its all over.  */
 
 #define _ERRNO_H
+#include <sysdep.h>
 #include <features.h>
 #include <bits/errno.h>
 #include <sys/syscall.h>
 #include "m68k_pic.S"
 
-/* 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
-.align 4
-.type	clone,@function
-.globl	clone;
-clone:
+	.text
+	.align 4
+	.globl	__clone
+	.type	__clone,@function
+
+__clone:
 	/* Sanity check arguments.  */
-	movel   #-EINVAL, %d0
-	movel   4(%sp), %d1             /* no NULL function pointers */
-	movel	%d1, %a0
-	tstl    %d1
+	movel	#-EINVAL, %d0
+	movel	4(%sp), %a0		/* no NULL function pointers */
+	tstl	%a0
 	beq.w	__syscall_error_trampoline
-	movel   8(%sp), %d1             /* no NULL stack pointers */
-	movel	%d1, %a1
-	tstl    %d1
+	movel	8(%sp), %a1		/* no NULL stack pointers */
+	tstl	%a1
 	beq.w   __syscall_error_trampoline
 
 	/* Allocate space and copy the argument onto the new stack.  */
 	movel   16(%sp), -(%a1)
 
 	/* Do the system call */
-#if 1 /* defined (CONFIG_COLDFIRE) */
-	movel   %d2, %d1                /* save %d2 and get stack pointer */
-	movel   %a1, %d2
-	movel   %d1, %a1
+	movel   12(%sp), %d1            /* get flags */
+	movel	%d3, -(%a1)             /* save %d3 and get parent_tidptr */
+	movel	%d3, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d3, 0)
+	movel	20+4(%sp), %d3
+	movel	%d4, -(%a1)		/* save %d4 and get child_tidptr */
+	movel	%d4, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d4, 0)
+	movel	28+8(%sp), %d4
+	movel	%d5, -(%a1)             /* save %d5 and get tls */
+	movel	%d5, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d5, 0)
+	movel	24+12(%sp), %d5
+	/* save %d2 and get stack pointer */
+#ifdef __mcoldfire__
+	movel	%d2, -(%a1)
+	movel	%d2, -(%sp)
+	cfi_adjust_cfa_offset (4)
+	cfi_rel_offset (%d2, 0)
+	movel	%a1, %d2
 #else
-	exg     %d2, %a1                /* save %d2 and get stack pointer */
+	exg	%d2, %a1		/* save %d2 and get stack pointer */
+	cfi_register (%d2, %a1)
 #endif
-	movel   12(%sp), %d1            /* get flags */
 	movel   #__NR_clone, %d0
+
+	/* End FDE now, because in the child the unwind info will be
+	   wrong.  */
+	cfi_endproc
+
 	trap    #0
-#if 1 /* defined (CONFIG_COLDFIRE) */
-	movel   %d2, %d1                /* restore %d2 */
-	movel   %a1, %d2
-	movel   %d1, %a1
+#ifdef __mcoldfire__
+	movel	(%sp)+, %d2
 #else
-	exg     %d2, %a1                /* restore %d2 */
+	exg	%d2, %a1		/* restore %d2 */
 #endif
+	movel	(%sp)+, %d5             /* restore %d5, %d4 and %d3 */
+	movel	(%sp)+, %d4
+	movel	(%sp)+, %d3
 
 	tstl    %d0
 	bmi.w   __syscall_error_trampoline
@@ -57,13 +97,21 @@ clone:
 	rts
 
 thread_start:
-	/*subl    %fp, %fp*/        /* terminate the stack frame */
-	jsr     (%a0)
-	movel   %d0, -(%sp)
+	cfi_startproc
+	cfi_undefined (pc)	/* Mark end of stack */
+	subl	%fp, %fp	/* terminate the stack frame */
+	jsr	(%a0)
+	movel	%d0, %d1
 	movel	#__NR_exit, %d0
 	trap	#0
-	/*jsr    exit*/
+	cfi_endproc
+
+	cfi_startproc
 
 __syscall_error_trampoline:
 	JUMP	__syscall_error,%a0
 
+.size __clone,.-__clone
+
+weak_alias(__clone,clone)
+libc_hidden_def(clone)
diff --git a/libc/sysdeps/linux/m68k/jmpbuf-unwind.h b/libc/sysdeps/linux/m68k/jmpbuf-unwind.h
index c5a8886e2..8744ec7e8 100644
--- a/libc/sysdeps/linux/m68k/jmpbuf-unwind.h
+++ b/libc/sysdeps/linux/m68k/jmpbuf-unwind.h
@@ -1,8 +1,19 @@
-/*
- * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
- *
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
+/* Examine __jmp_buf for unwinding frames.  m68k version.
+   Copyright (C) 2006-2017 Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #include <setjmp.h>
 
@@ -10,3 +21,21 @@
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address) \
   ((void *) (address) < (void *) (jmpbuf)->__aregs[5])
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <stdint.h>
+#include <unwind.h>
+
+#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 = (uintptr_t) regs[0].__sp;
+  return sp;
+}
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj))
+#endif
diff --git a/libc/sysdeps/linux/m68k/m68k_read_tp.S b/libc/sysdeps/linux/m68k/m68k_read_tp.S
new file mode 100644
index 000000000..523e1b38a
--- /dev/null
+++ b/libc/sysdeps/linux/m68k/m68k_read_tp.S
@@ -0,0 +1 @@
+#include <ldso/ldso/m68k/m68k_read_tp.S>
diff --git a/libc/sysdeps/linux/m68k/sys/reg.h b/libc/sysdeps/linux/m68k/sys/reg.h
new file mode 100644
index 000000000..133c862b4
--- /dev/null
+++ b/libc/sysdeps/linux/m68k/sys/reg.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 1998-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _SYS_REG_H
+#define _SYS_REG_H	1
+
+/* Index into an array of 4 byte integers returned from ptrace for
+   location of the users' stored general purpose registers. */
+
+enum
+{
+  PT_D1 = 0,
+#define PT_D1 PT_D1
+  PT_D2 = 1,
+#define PT_D2 PT_D2
+  PT_D3 = 2,
+#define PT_D3 PT_D3
+  PT_D4 = 3,
+#define PT_D4 PT_D4
+  PT_D5 = 4,
+#define PT_D5 PT_D5
+  PT_D6 = 5,
+#define PT_D6 PT_D6
+  PT_D7 = 6,
+#define PT_D7 PT_D7
+  PT_A0 = 7,
+#define PT_A0 PT_A0
+  PT_A1 = 8,
+#define PT_A1 PT_A1
+  PT_A2 = 9,
+#define PT_A2 PT_A2
+  PT_A3 = 10,
+#define PT_A3 PT_A3
+  PT_A4 = 11,
+#define PT_A4 PT_A4
+  PT_A5 = 12,
+#define PT_A5 PT_A5
+  PT_A6 = 13,
+#define PT_A6 PT_A6
+  PT_D0 = 14,
+#define PT_D0 PT_D0
+  PT_USP = 15,
+#define PT_USP PT_USP
+  PT_ORIG_D0 = 16,
+#define PT_ORIG_D0 PT_ORIG_D0
+  PT_SR = 17,
+#define PT_SR PT_SR
+  PT_PC = 18,
+#define PT_PC PT_PC
+
+#ifdef __mcoldfire__
+  PT_FP0 = 21,
+  PT_FP1 = 23,
+  PT_FP2 = 25,
+  PT_FP3 = 27,
+  PT_FP4 = 29,
+  PT_FP5 = 31,
+  PT_FP6 = 33,
+  PT_FP7 = 35,
+#else
+  PT_FP0 = 21,
+  PT_FP1 = 24,
+  PT_FP2 = 27,
+  PT_FP3 = 30,
+  PT_FP4 = 33,
+  PT_FP5 = 36,
+  PT_FP6 = 39,
+  PT_FP7 = 42,
+#endif
+#define PT_FP0 PT_FP0
+#define PT_FP1 PT_FP1
+#define PT_FP2 PT_FP2
+#define PT_FP3 PT_FP3
+#define PT_FP4 PT_FP4
+#define PT_FP5 PT_FP5
+#define PT_FP6 PT_FP6
+#define PT_FP7 PT_FP7
+
+  PT_FPCR = 45,
+#define PT_FPCR PT_FPCR
+  PT_FPSR = 46,
+#define PT_FPSR PT_FPSR
+  PT_FPIAR = 47
+#define PT_FPIAR PT_FPIAR
+};
+
+#endif	/* _SYS_REG_H */
diff --git a/libc/sysdeps/linux/m68k/sysdep.h b/libc/sysdeps/linux/m68k/sysdep.h
new file mode 100644
index 000000000..9c18aae97
--- /dev/null
+++ b/libc/sysdeps/linux/m68k/sysdep.h
@@ -0,0 +1,26 @@
+#include <common/sysdep.h>
+
+#ifdef __ASSEMBLER__
+
+/* Define an entry point visible from C.
+
+   There is currently a bug in gdb which prevents us from specifying
+   incomplete stabs information.  Fake some entries here which specify
+   the current source file.  */
+# define ENTRY(name)							      \
+  .globl C_SYMBOL_NAME(name);						      \
+  .type C_SYMBOL_NAME(name),@function;					      \
+  .p2align 2;								      \
+  C_LABEL(name)								      \
+  cfi_startproc;							      \
+
+# undef END
+# define END(name)							      \
+  cfi_endproc;								      \
+  .size name,.-name
+
+/* Load the address of the GOT into register R.  */
+# define LOAD_GOT(R) \
+  lea _GLOBAL_OFFSET_TABLE_@GOTPC (%pc), R
+
+#endif
diff --git a/libc/sysdeps/linux/m68k/vfork.S b/libc/sysdeps/linux/m68k/vfork.S
index bde9d5a3a..eb1639e37 100644
--- a/libc/sysdeps/linux/m68k/vfork.S
+++ b/libc/sysdeps/linux/m68k/vfork.S
@@ -10,8 +10,6 @@
 #define __NR_vfork __NR_fork /* uClinux-2.0 only has fork which is vfork */
 #endif
 
-#define IMM #
-
 	.text
 	.align 2
 	.globl	__vfork
@@ -19,26 +17,22 @@
 	.type	__vfork,@function
 
 __vfork:
-	movl	%sp@+, %a1               /* save the return address for later */
-	movl	IMM __NR_vfork,%d0
+	/* 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
-	movl	%a1, -(%sp)
 
-	cmpil	#-4096,%d0
-	blss	1f
+	tstl	%d0
+	jmi	.Lerror		/* Branch forward if it failed.  */
 
-	neg.l	%d0
-#ifndef __PIC__					/* needs handling as the other archs */
-	movl	errno, %a0
-#else
-	movl	errno@GOT(%a5), %a0
-#endif
-	movl	%d0, %a0@
-	move.l	#-1, %d0
+	/* Jump to the return PC.  */
+	jmp	%a0@
 
-1:
-	move.l	%d0, %a0
-	rts
+.Lerror:
+	/* Push back the return PC.  */
+	movel	%a0,%sp@-
 
 .size __vfork,.-__vfork
 weak_alias(__vfork,vfork)
-- 
cgit v1.2.3