Browse Source

riscv32: sync with riscv64

Waldemar Brodkorb 1 month ago
parent
commit
6bb2d37af6

+ 2 - 2
ldso/ldso/riscv32/elfinterp.c

@@ -214,11 +214,11 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 			*reloc_addr = tls_tpnt->l_tls_modid;
 			break;
 		case R_RISCV_TLS_DTPREL32:
-			*reloc_addr = symbol_addr + rpnt->r_addend;
+			*reloc_addr = symbol_addr -TLS_DTV_OFFSET + rpnt->r_addend;
 			break;
 		case R_RISCV_TLS_TPREL32:
 			CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
-			*reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend - TLS_TCB_SIZE;
+			*reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend;
 			break;
 #endif
 		default:

+ 170 - 0
libc/sysdeps/linux/riscv32/bits/atomic.h

@@ -0,0 +1,170 @@
+/* Copyright (C) 2003-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/>.  */
+
+#ifndef _RISCV32_ATOMIC_MACHINE_H
+#define _RISCV32_ATOMIC_MACHINE_H	1
+
+#define typeof __typeof__
+
+#include <stdint.h>
+#include <sysdep.h>
+
+typedef int8_t  atomic8_t;
+typedef int16_t atomic16_t;
+typedef int32_t atomic32_t;
+typedef int64_t atomic64_t;
+
+typedef uint8_t  uatomic8_t;
+typedef uint16_t uatomic16_t;
+typedef uint32_t uatomic32_t;
+typedef uint64_t uatomic64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+#define __HAVE_64B_ATOMICS 1
+#define USE_ATOMIC_COMPILER_BUILTINS 1
+
+/* Compare and exchange.
+   For all "bool" routines, we return FALSE if exchange succesful.  */
+
+# define __arch_compare_and_exchange_bool_8_int(mem, newval, oldval, model) \
+  ({									\
+    typeof (*mem) __oldval = (oldval);					\
+    !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
+				  model, __ATOMIC_RELAXED);		\
+  })
+
+# define __arch_compare_and_exchange_bool_16_int(mem, newval, oldval, model) \
+  ({									\
+    typeof (*mem) __oldval = (oldval);					\
+    !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
+				  model, __ATOMIC_RELAXED);		\
+  })
+
+# define __arch_compare_and_exchange_bool_32_int(mem, newval, oldval, model) \
+  ({									\
+    typeof (*mem) __oldval = (oldval);					\
+    !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
+				  model, __ATOMIC_RELAXED);		\
+  })
+
+#  define __arch_compare_and_exchange_bool_64_int(mem, newval, oldval, model) \
+  ({									\
+    typeof (*mem) __oldval = (oldval);					\
+    !__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
+				  model, __ATOMIC_RELAXED);		\
+  })
+
+# define __arch_compare_and_exchange_val_8_int(mem, newval, oldval, model) \
+  ({									\
+    typeof (*mem) __oldval = (oldval);					\
+    __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
+				 model, __ATOMIC_RELAXED);		\
+    __oldval;								\
+  })
+
+# define __arch_compare_and_exchange_val_16_int(mem, newval, oldval, model) \
+  ({									\
+    typeof (*mem) __oldval = (oldval);					\
+    __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
+				 model, __ATOMIC_RELAXED);		\
+    __oldval;								\
+  })
+
+# define __arch_compare_and_exchange_val_32_int(mem, newval, oldval, model) \
+  ({									\
+    typeof (*mem) __oldval = (oldval);					\
+    __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
+				 model, __ATOMIC_RELAXED);		\
+    __oldval;								\
+  })
+
+#  define __arch_compare_and_exchange_val_64_int(mem, newval, oldval, model) \
+  ({									\
+    typeof (*mem) __oldval = (oldval);					\
+    __atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0,	\
+				 model, __ATOMIC_RELAXED);		\
+    __oldval;								\
+  })
+
+
+/* Compare and exchange with "acquire" semantics, ie barrier after.  */
+
+# define atomic_compare_and_exchange_bool_acq(mem, new, old)	\
+  __atomic_bool_bysize (__arch_compare_and_exchange_bool, int,	\
+			mem, new, old, __ATOMIC_ACQUIRE)
+
+# define atomic_compare_and_exchange_val_acq(mem, new, old)	\
+  __atomic_val_bysize (__arch_compare_and_exchange_val, int,	\
+		       mem, new, old, __ATOMIC_ACQUIRE)
+
+/* Compare and exchange with "release" semantics, ie barrier before.  */
+
+# define atomic_compare_and_exchange_val_rel(mem, new, old)	 \
+  __atomic_val_bysize (__arch_compare_and_exchange_val, int,    \
+                       mem, new, old, __ATOMIC_RELEASE)
+
+
+/* Atomic exchange (without compare).  */
+
+# define __arch_exchange_8_int(mem, newval, model)	\
+  __atomic_exchange_n (mem, newval, model)
+
+# define __arch_exchange_16_int(mem, newval, model)	\
+  __atomic_exchange_n (mem, newval, model)
+
+# define __arch_exchange_32_int(mem, newval, model)	\
+  __atomic_exchange_n (mem, newval, model)
+
+#  define __arch_exchange_64_int(mem, newval, model)	\
+  __atomic_exchange_n (mem, newval, model)
+
+# define atomic_exchange_acq(mem, value)				\
+  __atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_ACQUIRE)
+
+# define atomic_exchange_rel(mem, value)				\
+  __atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_RELEASE)
+
+
+/* Atomically add value and return the previous (unincremented) value.  */
+
+# define __arch_exchange_and_add_8_int(mem, value, model)	\
+  __atomic_fetch_add (mem, value, model)
+
+# define __arch_exchange_and_add_16_int(mem, value, model)	\
+  __atomic_fetch_add (mem, value, model)
+
+# define __arch_exchange_and_add_32_int(mem, value, model)	\
+  __atomic_fetch_add (mem, value, model)
+
+#  define __arch_exchange_and_add_64_int(mem, value, model)	\
+  __atomic_fetch_add (mem, value, model)
+
+# define atomic_exchange_and_add_acq(mem, value)			\
+  __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,	\
+		       __ATOMIC_ACQUIRE)
+
+# define atomic_exchange_and_add_rel(mem, value)			\
+  __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,	\
+		       __ATOMIC_RELEASE)
+
+/* Barrier macro. */
+#define atomic_full_barrier() __sync_synchronize()
+
+#endif

+ 1 - 1
libc/sysdeps/linux/riscv32/bits/uClibc_page.h

@@ -21,7 +21,7 @@
 #define _UCLIBC_PAGE_H
 
 /* PAGE_SHIFT determines the page size -- in this case 4096 */
-#define PAGE_SHIFT	13
+#define PAGE_SHIFT	12
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 

+ 7 - 1
libc/sysdeps/linux/riscv32/clone.S

@@ -29,6 +29,9 @@
 	.text
 LEAF (clone)
 
+	/* Align stack to a 128-bit boundary as per RISC-V ABI.  */
+	andi            a1,a1,ALMASK
+
 	/* Sanity check arguments.  */
 	beqz		a0,L (invalid)	/* No NULL function pointers.  */
 	beqz		a1,L (invalid)	/* No NULL stack pointers.  */
@@ -57,7 +60,7 @@ L (invalid):
 	li		a0, -EINVAL
 	/* Something bad happened -- no child created.  */
 L (error):
-	j		__syscall_error
+	tail		__syscall_error
 	END (clone)
 
 /* Load up the arguments to the function.  Put this block of code in
@@ -66,6 +69,9 @@ L (error):
 
 ENTRY (__thread_start)
 L (thread_start):
+	.cfi_label .Ldummy
+	cfi_undefined (ra)
+
 	/* Restore the arg for user's function.  */
 	REG_L		a1,0(sp)	/* Function pointer.  */
 	REG_L		a0,SZREG(sp)	/* Argument pointer.  */

+ 10 - 0
libpthread/nptl/sysdeps/riscv32/dl-tls.h

@@ -21,4 +21,14 @@ typedef struct
   unsigned long int ti_offset;
 } tls_index;
 
+/* The thread pointer points to the first static TLS block.  */
+#define TLS_TP_OFFSET           0
+
+/* Dynamic thread vector pointers point 0x800 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET          0x800
+
 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)

+ 4 - 3
libpthread/nptl/sysdeps/riscv32/tcb-offsets.sym

@@ -1,6 +1,7 @@
 #include <sysdep.h>
 #include <tls.h>
 
-MULTIPLE_THREADS_OFFSET         offsetof (struct pthread, header.multiple_threads)
-TID_OFFSET                      offsetof (struct pthread, tid)
-TP_TO_PTHREAD_OFFSET            -(sizeof (struct pthread) + sizeof (tcbhead_t))
+#define thread_offsetof(mem)   (long)(offsetof (struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET                thread_offsetof (header.multiple_threads)
+

+ 43 - 74
libpthread/nptl/sysdeps/riscv32/tls.h

@@ -1,6 +1,5 @@
 /* Definition for thread-local data handling.  NPTL/RISCV32 version.
    Copyright (C) 2005, 2007, 2011 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
@@ -35,15 +34,6 @@ typedef union dtv
   } pointer;
 } dtv_t;
 
-typedef struct
-{
-  dtv_t *dtv;
-} tcbhead_t;
-
-register tcbhead_t *__thread_self __asm__("tp");
-
-# define TLS_MULTIPLE_THREADS_IN_TCB 1
-
 #else /* __ASSEMBLER__ */
 # include <tcb-offsets.h>
 #endif /* __ASSEMBLER__ */
@@ -58,71 +48,56 @@ register tcbhead_t *__thread_self __asm__("tp");
 
 #ifndef __ASSEMBLER__
 
+register void *__thread_self __asm__("tp");
+# define READ_THREAD_POINTER() ({ __thread_self; })
+
 /* Get system call information.  */
 # include <sysdep.h>
 
-/* The TP points to the start of the TLS block.
- * As I understand it, this isn't strictly that "TP points to DTV" - it's
- * more where to place the TCB in the TLS block. This will place it in 
- * the beginning.
- *
- * Layout:
- *  ------------------------------------
- *  | PRE | TCB | TLS MEMORY ..        |
- *  ------------------------------------
- *              ^ x4 / TP
- *
- * PRE is the struct pthread described below
- * TCB is tcbhead_t
- * TLS memory is where the TLS program sections are loaded
- *
- * See _dl_allocate_tls_storage and __libc_setup_tls for more information.
- */
+/* The TP points to the start of the TLS block.  */
 # define TLS_DTV_AT_TP  1
 
 /* Get the thread descriptor definition.  */
 # include <../../descr.h>
 
-/* Requirements for the TCB.  */
-# define TLS_INIT_TCB_SIZE    sizeof (tcbhead_t)
-# define TLS_INIT_TCB_ALIGN   __alignof__ (tcbhead_t)
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
 
-# define TLS_TCB_SIZE         sizeof (tcbhead_t)
-# define TLS_TCB_ALIGN        __alignof__ (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
+# define TLS_INIT_TCB_ALIGN   __alignof__ (struct pthread)
 
-/* This is the size of the TCB.  */
+/* 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
+# define TLS_TCB_ALIGN        __alignof__ (struct pthread)
 
-/* This is the size we need before TCB.
- * To support THREAD_GETMEM with friends we want to have a
- * struct pthread available.
- * Yank it in infront of everything, I'm sure nobody will mind.
- *
- * This memory is really allocated PRE the TLS block, so it's possible
- * to do ((char*)tlsblock) - TLS_PRE_TCB_SIZE to access it.
- * This is done for THREAD_SELF. */
-# define TLS_PRE_TCB_SIZE sizeof (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) + __alignof (struct pthread) - 1)                   \
+      & ~(__alignof (struct pthread) - 1)))
 
+/* The thread pointer tp points to the end of the TCB.
+   The pthread_descr structure is immediately in front of the TCB.  */
+# define TLS_TCB_OFFSET 0
 
-/* Install the dtv pointer.
- * When called, dtvp is a pointer not the DTV per say (which should start
- * with the generation counter) but to the length of the DTV.
- * We can always index with -1, so we store dtvp[1]
- */
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
 # define INSTALL_DTV(tcbp, dtvp) \
-  (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1)
+  (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1)
 
-/* Install new dtv for current thread
- * In a logicial world dtv here would also point to the length of the DTV.
- * However it does not, this time it points to the generation counter,
- * so just store it.
- *
- * Note: -1 is still valid and contains the length. */
+/* Install new dtv for current thread  */
 # define INSTALL_NEW_DTV(dtv) \
   (THREAD_DTV() = (dtv))
 
 /* Return dtv of given thread descriptor.  */
 # define GET_DTV(tcbp) \
-  (((tcbhead_t *) (tcbp))->dtv)
+  (((tcbhead_t *) (tcbp))[-1].dtv)
 
 /* Code to initially initialize the thread pointer.
  *
@@ -136,31 +111,21 @@ register tcbhead_t *__thread_self __asm__("tp");
  * It's hard to fail this, so return NULL always.
  */
 # define TLS_INIT_TP(tcbp, secondcall) \
-  ({__thread_self = ((tcbhead_t *)tcbp + 1); NULL;})
+  ({ __thread_self = (char*)tcbp + TLS_TCB_OFFSET; NULL; })
 
-/* Return the address of the dtv for the current thread.
- *
- * Dereference TP, offset to dtv - really straightforward.
- * Remember that we made TP point to after tcb, so we need to reverse that.
- */
+/* Return the address of the dtv for the current thread.  */
 #  define THREAD_DTV() \
-  ((((tcbhead_t *)__thread_self)-1)->dtv)
+  (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv)
 
-/* Return the thread descriptor for the current thread. 
- *
- * Return a pointer to the TLS_PRE area where we allocated space for
- * a struct pthread. Again, TP points to after tcbhead_t, compensate with
- * TLS_INIT_TCB_SIZE.
- *
- * I regard this is a seperate system from the "normal" TLS.
- */
+/* Return the thread descriptor for the current thread.  */
 # define THREAD_SELF \
-  ((struct pthread *) ((char *) __thread_self - TLS_INIT_TCB_SIZE \
-    - TLS_PRE_TCB_SIZE))
+  ((struct pthread *) (READ_THREAD_POINTER ()                         \
+                       - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
 
-/* Magic for libthread_db to know how to do THREAD_SELF.  */
+/* Informs libthread_db that the thread pointer is register 4, which is used
+ * to know how to do THREAD_SELF.  */
 # define DB_THREAD_SELF \
-  CONST_THREAD_AREA (64, sizeof (struct pthread))
+  REGISTER (64, 64, 4 * 8, - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
 
 /* Access to data in the thread descriptor is easy.  */
 #define THREAD_GETMEM(descr, member) \
@@ -172,6 +137,10 @@ register tcbhead_t *__thread_self __asm__("tp");
 #define THREAD_SETMEM_NC(descr, member, idx, value) \
   descr->member[idx] = (value)
 
+/* l_tls_offset == 0 is perfectly valid, 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

+ 7 - 6
libpthread/nptl/sysdeps/unix/sysv/linux/riscv32/createthread.c

@@ -1,4 +1,5 @@
-/* Copyright (C) 2012 Free Software Foundation, Inc.
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -7,16 +8,16 @@
 
    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
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If
-   not, see <http://www.gnu.org/licenses/>.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 /* Value passed to 'clone' for initialization of the thread register.  */
 #define TLS_VALUE ((void *) (pd) \
-		   + TLS_PRE_TCB_SIZE + TLS_INIT_TCB_SIZE)
+		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
 
-/* Get the real implementation.  */
+/* Get the real implementation.	 */
 #include <sysdeps/pthread/createthread.c>

+ 1 - 17
libpthread/nptl/sysdeps/unix/sysv/linux/riscv32/fork.c

@@ -1,19 +1,3 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
-   Contributed by Phil Blundell <pb@nexus.co.uk>, 2005
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
 #include <sched.h>
 #include <signal.h>
 #include <sysdep.h>
@@ -22,6 +6,6 @@
 #define ARCH_FORK() \
   INLINE_SYSCALL (clone, 5,                                                  \
                  CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \
-                 NULL, &THREAD_SELF->tid, NULL)
+                 NULL, NULL, &THREAD_SELF->tid)
 
 #include "../fork.c"