From 6bb2d37af6772cada51b0871d3184f7783779364 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 20 Mar 2024 09:44:40 +0100 Subject: riscv32: sync with riscv64 --- ldso/ldso/riscv32/elfinterp.c | 4 +- libc/sysdeps/linux/riscv32/bits/atomic.h | 170 +++++++++++++++++++++ libc/sysdeps/linux/riscv32/bits/uClibc_page.h | 2 +- libc/sysdeps/linux/riscv32/clone.S | 8 +- libpthread/nptl/sysdeps/riscv32/dl-tls.h | 10 ++ libpthread/nptl/sysdeps/riscv32/tcb-offsets.sym | 7 +- libpthread/nptl/sysdeps/riscv32/tls.h | 117 ++++++-------- .../sysdeps/unix/sysv/linux/riscv32/createthread.c | 13 +- .../nptl/sysdeps/unix/sysv/linux/riscv32/fork.c | 18 +-- 9 files changed, 245 insertions(+), 104 deletions(-) create mode 100644 libc/sysdeps/linux/riscv32/bits/atomic.h diff --git a/ldso/ldso/riscv32/elfinterp.c b/ldso/ldso/riscv32/elfinterp.c index dc1ac994d..1a0d5d445 100644 --- a/ldso/ldso/riscv32/elfinterp.c +++ b/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: diff --git a/libc/sysdeps/linux/riscv32/bits/atomic.h b/libc/sysdeps/linux/riscv32/bits/atomic.h new file mode 100644 index 000000000..555a73dec --- /dev/null +++ b/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 + . */ + +#ifndef _RISCV32_ATOMIC_MACHINE_H +#define _RISCV32_ATOMIC_MACHINE_H 1 + +#define typeof __typeof__ + +#include +#include + +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 diff --git a/libc/sysdeps/linux/riscv32/bits/uClibc_page.h b/libc/sysdeps/linux/riscv32/bits/uClibc_page.h index 669d122c8..d1f9262fd 100644 --- a/libc/sysdeps/linux/riscv32/bits/uClibc_page.h +++ b/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)) diff --git a/libc/sysdeps/linux/riscv32/clone.S b/libc/sysdeps/linux/riscv32/clone.S index f7684c88d..315de2ac8 100644 --- a/libc/sysdeps/linux/riscv32/clone.S +++ b/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. */ diff --git a/libpthread/nptl/sysdeps/riscv32/dl-tls.h b/libpthread/nptl/sysdeps/riscv32/dl-tls.h index 01663edf3..31991be0d 100644 --- a/libpthread/nptl/sysdeps/riscv32/dl-tls.h +++ b/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) diff --git a/libpthread/nptl/sysdeps/riscv32/tcb-offsets.sym b/libpthread/nptl/sysdeps/riscv32/tcb-offsets.sym index 86025a402..fe6856c5d 100644 --- a/libpthread/nptl/sysdeps/riscv32/tcb-offsets.sym +++ b/libpthread/nptl/sysdeps/riscv32/tcb-offsets.sym @@ -1,6 +1,7 @@ #include #include -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) + diff --git a/libpthread/nptl/sysdeps/riscv32/tls.h b/libpthread/nptl/sysdeps/riscv32/tls.h index ed6df8186..8ef9f3511 100644 --- a/libpthread/nptl/sysdeps/riscv32/tls.h +++ b/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 #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 -/* 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 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/riscv32/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/riscv32/createthread.c index 10bb1bbfe..3079007c7 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/riscv32/createthread.c +++ b/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 .  */ + License along with the GNU C Library; if not, see + . */ /* 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 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/riscv32/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/riscv32/fork.c index e55d05d41..c5d963aad 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/riscv32/fork.c +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/riscv32/fork.c @@ -1,19 +1,3 @@ -/* Copyright (C) 2005 Free Software Foundation, Inc. - Contributed by Phil Blundell , 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 - . */ #include #include #include @@ -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" -- cgit v1.2.3