From 6af3332a4cbd1ffbc81f74759ef7c5e1a87d2e10 Mon Sep 17 00:00:00 2001 From: Vincent Ren-Wei Chen Date: Tue, 17 Jan 2017 07:31:24 +0100 Subject: nds32: add NPTL/TLS, *context function, libm changes and code cleanup This commit includes following features. 1. Support NPTL/TLS 2. Add libm function which is used to handle FP rounding and excpetions (ex: fclrexcpt,fedisblxcpti,feenablxcpt... ) 3. Add *context function for operating user context (ex: setcontext,getcontext,makecontext... ) 4. Change the return flow from signal handler 5. Cleanup of old code The testsuite only has 2 errors, tst-cpuclock1 and tst-cputimer1, which are related to timing accuracy. (math and locale tests are disabled) Signed-off-by: Vincent Ren-Wei Chen --- extra/Configs/Config.in | 1 - extra/Configs/Config.nds32 | 1 + extra/Configs/defconfigs/nds32/defconfig | 167 ++++++++++ include/elf.h | 3 + ldso/ldso/nds32/dl-startup.h | 94 +----- ldso/ldso/nds32/dl-sysdep.h | 5 +- ldso/ldso/nds32/dl-tlsdesc.S | 100 ++++++ ldso/ldso/nds32/elfinterp.c | 94 ++++-- ldso/ldso/nds32/resolve.S | 24 -- ldso/libdl/Makefile.in | 1 - libc/string/nds32/memcpy.S | 22 +- libc/string/nds32/memset.S | 2 +- libc/sysdeps/linux/common/posix_fadvise.c | 2 +- libc/sysdeps/linux/common/posix_fadvise64.c | 2 +- libc/sysdeps/linux/common/sync_file_range.c | 2 +- libc/sysdeps/linux/nds32/Makefile | 6 +- libc/sysdeps/linux/nds32/Makefile.arch | 6 +- libc/sysdeps/linux/nds32/__longjmp.S | 2 +- libc/sysdeps/linux/nds32/bits/atomic.h | 110 +++++++ libc/sysdeps/linux/nds32/bits/fcntl.h | 6 +- libc/sysdeps/linux/nds32/bits/fenv.h | 79 +++++ libc/sysdeps/linux/nds32/bits/mman.h | 1 + libc/sysdeps/linux/nds32/bits/setjmp.h | 18 +- libc/sysdeps/linux/nds32/bits/sigcontext.h | 59 ---- libc/sysdeps/linux/nds32/bits/sigcontextinfo.h | 35 ++ libc/sysdeps/linux/nds32/bits/syscalls.h | 354 ++++++++++++++++----- .../linux/nds32/bits/uClibc_arch_features.h | 2 +- libc/sysdeps/linux/nds32/bsd-_setjmp.S | 5 +- libc/sysdeps/linux/nds32/bsd-setjmp.S | 4 +- libc/sysdeps/linux/nds32/clone.S | 200 ++++++++---- libc/sysdeps/linux/nds32/crt1.S | 7 - libc/sysdeps/linux/nds32/crti.S | 24 -- libc/sysdeps/linux/nds32/fpu_control.h | 77 +++++ libc/sysdeps/linux/nds32/getcontext.S | 106 ++++++ libc/sysdeps/linux/nds32/jmpbuf-unwind.h | 18 +- libc/sysdeps/linux/nds32/makecontext.c | 77 +++++ libc/sysdeps/linux/nds32/mmap.S | 101 ------ libc/sysdeps/linux/nds32/mremap.c | 28 ++ libc/sysdeps/linux/nds32/prctl.c | 23 ++ libc/sysdeps/linux/nds32/setcontext.S | 85 +++++ libc/sysdeps/linux/nds32/setjmp.S | 2 +- libc/sysdeps/linux/nds32/sigaction.c | 40 --- libc/sysdeps/linux/nds32/sigrestorer.S | 42 --- libc/sysdeps/linux/nds32/swapcontext.c | 38 +++ libc/sysdeps/linux/nds32/sys/ucontext.h | 117 ++----- libc/sysdeps/linux/nds32/syscall.S | 60 ---- libc/sysdeps/linux/nds32/syscall.c | 28 ++ libc/sysdeps/linux/nds32/sysdep.S | 39 ++- libc/sysdeps/linux/nds32/sysdep.h | 321 +++++++------------ libc/sysdeps/linux/nds32/ucontext_i.sym | 27 ++ libc/sysdeps/linux/nds32/vfork.S | 114 +++++-- libm/nds32/Makefile.arch | 16 + libm/nds32/e_sqrt.c | 34 ++ libm/nds32/fclrexcpt.c | 52 +++ libm/nds32/fedisblxcpt.c | 49 +++ libm/nds32/feenablxcpt.c | 50 +++ libm/nds32/fegetenv.c | 40 +++ libm/nds32/fegetexcept.c | 41 +++ libm/nds32/fegetround.c | 40 +++ libm/nds32/feholdexcpt.c | 51 +++ libm/nds32/fenv_libc.h | 33 ++ libm/nds32/fesetenv.c | 51 +++ libm/nds32/fesetround.c | 42 +++ libm/nds32/feupdateenv.c | 48 +++ libm/nds32/fgetexcptflg.c | 44 +++ libm/nds32/fraiseexcpt.c | 104 ++++++ libm/nds32/fsetexcptflg.c | 48 +++ libm/nds32/ftestexcept.c | 40 +++ libpthread/linuxthreads/sysdeps/nds32/pspinlock.c | 2 +- libpthread/linuxthreads/sysdeps/nds32/pt-machine.h | 2 +- libpthread/nptl/sysdeps/nds32/Makefile.arch | 16 + libpthread/nptl/sysdeps/nds32/dl-tls.h | 59 ++++ libpthread/nptl/sysdeps/nds32/libc-dl-tlsdesc.S | 1 + libpthread/nptl/sysdeps/nds32/pthread_spin_lock.c | 65 ++++ .../nptl/sysdeps/nds32/pthread_spin_trylock.c | 26 ++ libpthread/nptl/sysdeps/nds32/pthreaddef.h | 39 +++ libpthread/nptl/sysdeps/nds32/tcb-offsets.sym | 12 + libpthread/nptl/sysdeps/nds32/tls.h | 178 +++++++++++ libpthread/nptl/sysdeps/nds32/tlsdesc.sym | 17 + .../nptl/sysdeps/unix/sysv/linux/nds32/Makefile | 9 + .../sysdeps/unix/sysv/linux/nds32/Makefile.arch | 12 + .../unix/sysv/linux/nds32/bits/pthreadtypes.h | 177 +++++++++++ .../sysdeps/unix/sysv/linux/nds32/bits/semaphore.h | 38 +++ .../nptl/sysdeps/unix/sysv/linux/nds32/clone.S | 4 + .../sysdeps/unix/sysv/linux/nds32/createthread.c | 22 ++ .../nptl/sysdeps/unix/sysv/linux/nds32/fork.c | 27 ++ .../sysdeps/unix/sysv/linux/nds32/lowlevellock.h | 323 +++++++++++++++++++ .../nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c | 18 ++ .../sysdeps/unix/sysv/linux/nds32/pthread_once.c | 92 ++++++ .../sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h | 273 ++++++++++++++++ .../nptl/sysdeps/unix/sysv/linux/nds32/vfork.S | 43 +++ 91 files changed, 4023 insertions(+), 996 deletions(-) create mode 100644 extra/Configs/defconfigs/nds32/defconfig create mode 100644 ldso/ldso/nds32/dl-tlsdesc.S create mode 100644 libc/sysdeps/linux/nds32/bits/atomic.h create mode 100644 libc/sysdeps/linux/nds32/bits/fenv.h delete mode 100644 libc/sysdeps/linux/nds32/bits/sigcontext.h create mode 100644 libc/sysdeps/linux/nds32/bits/sigcontextinfo.h create mode 100644 libc/sysdeps/linux/nds32/fpu_control.h create mode 100644 libc/sysdeps/linux/nds32/getcontext.S create mode 100644 libc/sysdeps/linux/nds32/makecontext.c delete mode 100644 libc/sysdeps/linux/nds32/mmap.S create mode 100644 libc/sysdeps/linux/nds32/mremap.c create mode 100644 libc/sysdeps/linux/nds32/prctl.c create mode 100644 libc/sysdeps/linux/nds32/setcontext.S delete mode 100644 libc/sysdeps/linux/nds32/sigaction.c delete mode 100644 libc/sysdeps/linux/nds32/sigrestorer.S create mode 100644 libc/sysdeps/linux/nds32/swapcontext.c delete mode 100644 libc/sysdeps/linux/nds32/syscall.S create mode 100644 libc/sysdeps/linux/nds32/syscall.c create mode 100644 libc/sysdeps/linux/nds32/ucontext_i.sym create mode 100644 libm/nds32/Makefile.arch create mode 100644 libm/nds32/e_sqrt.c create mode 100644 libm/nds32/fclrexcpt.c create mode 100644 libm/nds32/fedisblxcpt.c create mode 100644 libm/nds32/feenablxcpt.c create mode 100644 libm/nds32/fegetenv.c create mode 100644 libm/nds32/fegetexcept.c create mode 100644 libm/nds32/fegetround.c create mode 100644 libm/nds32/feholdexcpt.c create mode 100644 libm/nds32/fenv_libc.h create mode 100644 libm/nds32/fesetenv.c create mode 100644 libm/nds32/fesetround.c create mode 100644 libm/nds32/feupdateenv.c create mode 100644 libm/nds32/fgetexcptflg.c create mode 100644 libm/nds32/fraiseexcpt.c create mode 100644 libm/nds32/fsetexcptflg.c create mode 100644 libm/nds32/ftestexcept.c create mode 100644 libpthread/nptl/sysdeps/nds32/Makefile.arch create mode 100644 libpthread/nptl/sysdeps/nds32/dl-tls.h create mode 100644 libpthread/nptl/sysdeps/nds32/libc-dl-tlsdesc.S create mode 100644 libpthread/nptl/sysdeps/nds32/pthread_spin_lock.c create mode 100644 libpthread/nptl/sysdeps/nds32/pthread_spin_trylock.c create mode 100644 libpthread/nptl/sysdeps/nds32/pthreaddef.h create mode 100644 libpthread/nptl/sysdeps/nds32/tcb-offsets.sym create mode 100644 libpthread/nptl/sysdeps/nds32/tls.h create mode 100644 libpthread/nptl/sysdeps/nds32/tlsdesc.sym create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/lowlevellock.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in index f312e7a13..a9d62f50f 100644 --- a/extra/Configs/Config.in +++ b/extra/Configs/Config.in @@ -521,7 +521,6 @@ config UCLIBC_HAS_THREADS_NATIVE !TARGET_hppa && \ !TARGET_ia64 && \ !TARGET_m68k && \ - !TARGET_nds32 && \ !TARGET_or1k && \ ARCH_USE_MMU help diff --git a/extra/Configs/Config.nds32 b/extra/Configs/Config.nds32 index a74249947..2ed6a32b7 100644 --- a/extra/Configs/Config.nds32 +++ b/extra/Configs/Config.nds32 @@ -13,6 +13,7 @@ config FORCE_OPTIONS_FOR_ARCH select ARCH_ANY_ENDIAN select ARCH_HAS_DEPRECATED_SYSCALLS select ARCH_HAS_MMU + select ARCH_HAS_UCONTEXT choice prompt "MMU Page Size" diff --git a/extra/Configs/defconfigs/nds32/defconfig b/extra/Configs/defconfigs/nds32/defconfig new file mode 100644 index 000000000..d870ad747 --- /dev/null +++ b/extra/Configs/defconfigs/nds32/defconfig @@ -0,0 +1,167 @@ +TARGET_nds32=y +# +# Using ELF file format +# +ARCH_HAS_DEPRECATED_SYSCALLS=y +ARCH_ANY_ENDIAN=y +ARCH_LITTLE_ENDIAN=y +# ARCH_WANTS_BIG_ENDIAN is not set +ARCH_WANTS_LITTLE_ENDIAN=y +ARCH_HAS_MMU=y +ARCH_USE_MMU=y +UCLIBC_HAS_FLOATS=y +UCLIBC_HAS_FPU=y +DO_C99_MATH=y +DO_XSI_MATH=y +UCLIBC_HAS_FENV=y +KERNEL_HEADERS="" +HAVE_DOT_CONFIG=y + +# +# General Library Settings +# +DOPIC=y +ARCH_HAS_UCONTEXT=y +HAVE_SHARED=y +# FORCE_SHAREABLE_TEXT_SEGMENTS is not set +LDSO_LDD_SUPPORT=y +LDSO_CACHE_SUPPORT=y +# LDSO_PRELOAD_ENV_SUPPORT is not set +# LDSO_PRELOAD_FILE_SUPPORT is not set +LDSO_BASE_FILENAME="ld.so" +# LDSO_STANDALONE_SUPPORT is not set +# LDSO_PRELINK_SUPPORT is not set +UCLIBC_STATIC_LDCONFIG=y +LDSO_RUNPATH=y +LDSO_RUNPATH_OF_EXECUTABLE=y +LDSO_SAFE_RUNPATH=y +LDSO_SEARCH_INTERP_PATH=y +LDSO_LD_LIBRARY_PATH=y +LDSO_NO_CLEANUP=y +UCLIBC_CTOR_DTOR=y +LDSO_GNU_HASH_SUPPORT=y +# HAS_NO_THREADS is not set +# UCLIBC_HAS_LINUXTHREADS is not set +UCLIBC_HAS_THREADS_NATIVE=y +UCLIBC_HAS_THREADS=y +UCLIBC_HAS_TLS=y +PTHREADS_DEBUG_SUPPORT=y +UCLIBC_HAS_SYSLOG=y +UCLIBC_HAS_LFS=y +# MALLOC is not set +# MALLOC_SIMPLE is not set +MALLOC_STANDARD=y +MALLOC_GLIBC_COMPAT=y +# UCLIBC_HAS_OBSTACK is not set +UCLIBC_DYNAMIC_ATEXIT=y +COMPAT_ATEXIT=y +UCLIBC_HAS_UTMPX=y +UCLIBC_HAS_UTMP=y +UCLIBC_SUSV2_LEGACY=y +UCLIBC_SUSV3_LEGACY=y +UCLIBC_HAS_CONTEXT_FUNCS=y +UCLIBC_SUSV3_LEGACY_MACROS=y +UCLIBC_SUSV4_LEGACY=y +# UCLIBC_STRICT_HEADERS is not set +# UCLIBC_HAS_STUBS is not set +UCLIBC_HAS_SHADOW=y +UCLIBC_HAS_PROGRAM_INVOCATION_NAME=y +UCLIBC_HAS___PROGNAME=y +UCLIBC_HAS_PTY=y +ASSUME_DEVPTS=y +UNIX98PTY_ONLY=y +UCLIBC_HAS_GETPT=y +UCLIBC_HAS_LIBUTIL=y +UCLIBC_HAS_TM_EXTENSIONS=y +UCLIBC_HAS_TZ_CACHING=y +UCLIBC_HAS_TZ_FILE=y +UCLIBC_HAS_TZ_FILE_READ_MANY=y +UCLIBC_TZ_FILE_PATH="/etc/TZ" +UCLIBC_FALLBACK_TO_ETC_LOCALTIME=y + +# +# Advanced Library Settings +# +UCLIBC_PWD_BUFFER_SIZE=256 +UCLIBC_GRP_BUFFER_SIZE=256 + +# +# Support various families of functions +# +UCLIBC_LINUX_MODULE_26=y +# UCLIBC_LINUX_MODULE_24 is not set +UCLIBC_LINUX_SPECIFIC=y +UCLIBC_HAS_GNU_ERROR=y +UCLIBC_BSD_SPECIFIC=y +UCLIBC_HAS_BSD_ERR=y +UCLIBC_HAS_OBSOLETE_BSD_SIGNAL=y +# UCLIBC_HAS_OBSOLETE_SYSV_SIGNAL is not set +# UCLIBC_NTP_LEGACY is not set +UCLIBC_SV4_DEPRECATED=y +UCLIBC_HAS_REALTIME=y +UCLIBC_HAS_ADVANCED_REALTIME=y +UCLIBC_HAS_EPOLL=y +UCLIBC_HAS_XATTR=y +UCLIBC_HAS_PROFILING=y +UCLIBC_HAS_CRYPT_IMPL=y +UCLIBC_HAS_SHA256_CRYPT_IMPL=y +# UCLIBC_HAS_SHA512_CRYPT_IMPL is not set +UCLIBC_HAS_CRYPT=y +UCLIBC_HAS_NETWORK_SUPPORT=y +UCLIBC_HAS_SOCKET=y +UCLIBC_HAS_IPV4=y +UCLIBC_HAS_IPV6=y +UCLIBC_HAS_RPC=y +UCLIBC_HAS_FULL_RPC=y +# UCLIBC_HAS_REENTRANT_RPC is not set +UCLIBC_USE_NETLINK=y +UCLIBC_SUPPORT_AI_ADDRCONFIG=y +UCLIBC_HAS_BSD_RES_CLOSE=y +UCLIBC_HAS_COMPAT_RES_STATE=y +# UCLIBC_HAS_EXTRA_COMPAT_RES_STATE is not set +UCLIBC_HAS_RESOLVER_SUPPORT=y +UCLIBC_HAS_LIBRESOLV_STUB=y +UCLIBC_HAS_LIBNSL_STUB=y + +UCLIBC_HAS_STRING_GENERIC_OPT=y +UCLIBC_HAS_STRING_ARCH_OPT=y +UCLIBC_HAS_STDIO_FUTEXES=y +UCLIBC_HAS_CTYPE_TABLES=y +UCLIBC_HAS_CTYPE_SIGNED=y +# UCLIBC_HAS_CTYPE_UNSAFE is not set +UCLIBC_HAS_CTYPE_CHECKED=y +# UCLIBC_HAS_CTYPE_ENFORCED is not set +UCLIBC_HAS_WCHAR=y +# UCLIBC_HAS_LOCALE is not set +UCLIBC_HAS_HEXADECIMAL_FLOATS=y +UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y +UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=9 +UCLIBC_HAS_STDIO_BUFSIZ_4096=y +UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE=y +UCLIBC_HAS_STDIO_GETC_MACRO=y +UCLIBC_HAS_STDIO_PUTC_MACRO=y +UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION=y +UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE=y +UCLIBC_HAS_GLIBC_CUSTOM_STREAMS=y +UCLIBC_HAS_PRINTF_M_SPEC=y +UCLIBC_HAS_ERRNO_MESSAGES=y +UCLIBC_HAS_SIGNUM_MESSAGES=y +UCLIBC_HAS_GNU_GETOPT=y +UCLIBC_HAS_GETOPT_LONG=y +UCLIBC_HAS_GNU_GETSUBOPT=y +UCLIBC_HAS_ARGP=y + +UCLIBC_HAS_REGEX=y +# UCLIBC_HAS_REGEX_OLD is not set +UCLIBC_HAS_FNMATCH=y +# UCLIBC_HAS_FNMATCH_OLD is not set +UCLIBC_HAS_WORDEXP=y +UCLIBC_HAS_NFTW=y +UCLIBC_HAS_FTW=y +UCLIBC_HAS_FTS=y +UCLIBC_HAS_GLOB=y +UCLIBC_HAS_GNU_GLOB=y + +CROSS_COMPILER_PREFIX="" +UCLIBC_EXTRA_CFLAGS="" +# DOSTRIP is not set diff --git a/include/elf.h b/include/elf.h index e0937b732..0f188e792 100644 --- a/include/elf.h +++ b/include/elf.h @@ -2985,6 +2985,9 @@ typedef Elf32_Addr Elf32_Conflict; #define R_NDS32_PLTREL_LO12 65 #define R_NDS32_PLT_GOTREL_HI20 66 #define R_NDS32_PLT_GOTREL_LO12 67 +#define R_NDS32_TLS_TPOFF 102 +#define R_NDS32_TLS_DESC 119 + /* Processor specific section indices. These sections do not actually exist. Symbols with a st_shndx field corresponding to one of these diff --git a/ldso/ldso/nds32/dl-startup.h b/ldso/ldso/nds32/dl-startup.h index f700531ca..56892a2ba 100644 --- a/ldso/ldso/nds32/dl-startup.h +++ b/ldso/ldso/nds32/dl-startup.h @@ -6,68 +6,7 @@ /* Need bootstrap relocations */ #define ARCH_NEEDS_BOOTSTRAP_RELOCS -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) -# define STACK_PUSH -# define STACK_POP -#else -# define STACK_PUSH "addi $sp, $sp, -24" -# define STACK_POP "addi $sp, $sp, 24" -#endif - -#ifdef __NDS32_N1213_43U1H__ -__asm__("\ - .text\n\ - .globl _start\n\ - .globl _dl_start\n\ - .globl _dl_start_user\n\ - .type _start,#function\n\ - .type _dl_start,#function\n\ - .type _dl_start_user,#function\n\ - .align 4\n\ - .pic\n\ -1:\n\ - ret\n\ -_start:\n\ - ! we are PIC code, so get global offset table\n\ - jal 1b\n\ - sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_)\n\ - ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_+4)\n\ - add $gp, $lp, $gp\n\ -\n\ - ! at start time, all the args are on the stack\n\ - addi $r0, $sp, 0\n\ - ! adjust stack\n\ - !addi $sp, $sp, -24\n\ - "STACK_PUSH"\n\ - bal _dl_start@PLT\n\ - ! save user entry point in r6\n\ - addi $r6, $r0, 0\n\ - ! adjust sp and reload registers\n\ - !addi $sp, $sp, 24\n\ - "STACK_POP"\n\ -\n\ -_dl_start_user:\n\ -\n\ - ! See if we were run as a command with the executable file\n\ - ! name as an extra leading argument.\n\ - ! skip these arguments\n\ - l.w $r2, _dl_skip_args@GOTOFF ! args to skip\n\ - lwi $r0, [$sp+0] ! original argc\n\ - slli $r1, $r2, 2 ! offset for new sp\n\ - add $sp, $sp, $r1 ! adjust sp to skip args\n\ - sub $r0, $r0, $r2 ! set new argc\n\ - swi $r0, [$sp+0] ! save new argc\n\ -\n\ - ! load address of _dl_fini finalizer function\n\ - la $r5, _dl_fini@GOTOFF\n\ - ! jump to the user_s entry point\n\ - addi $r15, $r6, 0\n\ - jr $r15\n\ - .size _dl_start_user, . - _dl_start_user\n\ - .previous\n\ -"); -#else __asm__("\ .text\n\ .globl _start\n\ @@ -89,13 +28,11 @@ _start:\n\ addi $r0, $sp, 0\n\ ! adjust stack\n\ !addi $sp, $sp, -24\n\ - "STACK_PUSH"\n\ bal _dl_start@PLT\n\ ! save user entry point in r6\n\ addi $r6, $r0, 0\n\ ! adjust sp and reload registers\n\ !addi $sp, $sp, 24\n\ - "STACK_POP"\n\ \n\ _dl_start_user:\n\ ! See if we were run as a command with the executable file\n\ @@ -115,31 +52,12 @@ _dl_start_user:\n\ .size _dl_start_user, . - _dl_start_user\n\ .previous\n\ "); -#endif -#define COPY_UNALIGNED_WORD(swp, twp, align) \ - { \ - void *__s = (swp), *__t = (twp); \ - unsigned char *__s1 = __s, *__t1 = __t; \ - unsigned short *__s2 = __s, *__t2 = __t; \ - unsigned long *__s4 = __s, *__t4 = __t; \ - switch ((align)) \ - { \ - case 0: \ - *__t4 = *__s4; \ - break; \ - case 2: \ - *__t2++ = *__s2++; \ - *__t2 = *__s2; \ - break; \ - default: \ - *__t1++ = *__s1++; \ - *__t1++ = *__s1++; \ - *__t1++ = *__s1++; \ - *__t1 = *__s1; \ - break; \ - } \ - } +#define COPY_UNALIGNED_WORD(swp, twp) \ +{ \ + __typeof (swp) __tmp = __builtin_nds32_unaligned_load_w ((unsigned int*)&swp); \ + __builtin_nds32_unaligned_store_w ((unsigned int *)twp, __tmp); \ +} /* Get a pointer to the argv array. On many platforms this can be just * the address if the first argument, on other platforms we need to @@ -162,7 +80,7 @@ void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr, break; case R_NDS32_32_RELA: value = symbol_addr + rpnt->r_addend; - COPY_UNALIGNED_WORD (&value, reloc_addr, (int) reloc_addr & 3); + COPY_UNALIGNED_WORD (value, reloc_addr); break; #undef COPY_UNALIGNED_WORD case R_NDS32_RELATIVE: diff --git a/ldso/ldso/nds32/dl-sysdep.h b/ldso/ldso/nds32/dl-sysdep.h index c4a32ca71..5ff2aa9ae 100644 --- a/ldso/ldso/nds32/dl-sysdep.h +++ b/ldso/ldso/nds32/dl-sysdep.h @@ -57,7 +57,8 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); 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_NDS32_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \ + ((((type) == R_NDS32_JMP_SLOT || (type) == R_NDS32_TLS_TPOFF \ + || (type) == R_NDS32_TLS_DESC) * ELF_RTYPE_CLASS_PLT) \ | (((type) == R_NDS32_COPY) * ELF_RTYPE_CLASS_COPY)) /* Return the link-time address of _DYNAMIC. Conveniently, this is the @@ -81,7 +82,7 @@ elf_machine_load_address (void) via the GOT to make sure the compiler initialized %ebx in time. */ Elf32_Addr addr; - __asm__ ("la %0, _dl_start@GOTOFF\n" : "=r" (addr) ); + __asm__ ("la %0, _DYNAMIC@GOTOFF\n" : "=r" (addr) ); return addr - elf_machine_dynamic(); } diff --git a/ldso/ldso/nds32/dl-tlsdesc.S b/ldso/ldso/nds32/dl-tlsdesc.S new file mode 100644 index 000000000..a7ea1f2d1 --- /dev/null +++ b/ldso/ldso/nds32/dl-tlsdesc.S @@ -0,0 +1,100 @@ +/* Thread-local storage handling in the ELF dynamic linker. NDS32 version. + Copyright (C) 2006-2013 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 + . */ + +#include +#if defined __UCLIBC_HAS_TLS__ +#include +#include "tlsdesc.h" + + .text + .hidden _dl_tlsdesc_return + .global _dl_tlsdesc_return + .type _dl_tlsdesc_return,#function + cfi_startproc + .align 2 +_dl_tlsdesc_return: + lwi $r0, [$r0 + 4] + add $r0, $r0, $r25 + ret + cfi_endproc + .size _dl_tlsdesc_return, .-_dl_tlsdesc_return + +#ifdef SHARED + .hidden _dl_tlsdesc_dynamic + .global _dl_tlsdesc_dynamic + .type _dl_tlsdesc_dynamic,#function + cfi_startproc + .pic +/* + The assembly code that follows is a rendition of the following + C code, hand-optimized a little bit. + +ptrdiff_t +_dl_tlsdesc_dynamic(struct tlsdesc *tdp) +{ + struct tlsdesc_dynamic_arg *td = tdp->argument.pointer; + dtv_t *dtv = (dtv_t *)THREAD_DTV(); + if (__builtin_expect (td->gen_count <= dtv[0].counter + && dtv[td->tlsinfo.ti_module].pointer.val + != TLS_DTV_UNALLOCATED, + 1)) + return dtv[td->tlsinfo.ti_module].pointer.val + + td->tlsinfo.ti_offset - __builtin_thread_pointer(); + + return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer(); +} +*/ + .align 2 + +_dl_tlsdesc_dynamic: + lwi $r0, [$r0 + 4] + lwi $r1, [$r0 + #TLSDESC_GEN_COUNT] /* $r0=td $r1=td->gen_count*/ + lwi $r2, [$r25 + #DTV_OFFSET] /* $r2=&dtv[0]*/ + lwi $r3, [$r2] + sub $r1, $r1, $r3 + bgtz $r1, 2f + lwi $r3, [$r0 + #TLSDESC_MODID] /* r3=module id */ + slli $r3, $r3, #3 /* r3=module offset=module id*8(byte) */ + lw $r3, [$r2 + $r3] /* r3=&dtc[module ID]=&dtv[0]+ module offset*/ + movi $r1, #-1 + beq $r3, $r1, 2f + lwi $r1, [$r0 + #TLSDESC_MODOFF] + add $r0, $r3, $r1 +1: + ret +2: + smw.adm $sp,[$sp],$sp,#0x6 + cfi_adjust_cfa_offset(8) + cfi_rel_offset(gp, 0) + cfi_rel_offset(lp, 4) + mfusr $r15, $PC; + sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_ + 4); + ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_ + 8); + add $gp, $r15, $gp; + sethi $r15, hi20(__tls_get_addr@PLT); + ori $r15, $r15, lo12(__tls_get_addr@PLT); + add $r15, $r15, $gp + jral $r15 + lmw.bim $sp,[$sp],$sp,#0x6 + cfi_adjust_cfa_offset(-8) + cfi_restore(gp) + cfi_restore(lp) + j 1b + cfi_endproc + .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic +#endif +#endif // __UCLIBC_HAS_TLS__ diff --git a/ldso/ldso/nds32/elfinterp.c b/ldso/ldso/nds32/elfinterp.c index 6a091f80a..9f671419c 100644 --- a/ldso/ldso/nds32/elfinterp.c +++ b/ldso/ldso/nds32/elfinterp.c @@ -44,6 +44,11 @@ #include "ldso.h" +#if defined(USE_TLS) && USE_TLS +#include "dl-tls.h" +#include "tlsdeschtab.h" +#endif + extern int _dl_linux_resolve(void); unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) @@ -95,7 +100,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) { _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname); if (_dl_debug_detail) _dl_dprintf(_dl_debug_file, - "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr); + "\tpatch %x ==> %x @ %x", (unsigned int)*got_addr, (unsigned int)new_addr, (unsigned int)got_addr); } } if (!_dl_debug_nofixups) { @@ -168,6 +173,9 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, int reloc_type; int symtab_index; char *symname = NULL; +#if defined USE_TLS && USE_TLS + struct elf_resolve *tls_tpnt = NULL; +#endif unsigned long *reloc_addr; unsigned long symbol_addr; int goof = 0; @@ -190,40 +198,40 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, * have been intentional. We should not be linking local symbols * here, so all bases should be covered. */ - if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) { + if (!symbol_addr + && (ELF32_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS) + && (ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) { _dl_dprintf (2, "%s: can't resolve symbol '%s'\n", - _dl_progname, strtab + symtab[symtab_index].st_name); + _dl_progname, symname); _dl_exit (1); } + if (_dl_trace_prelink) { + _dl_debug_lookup(symname, tpnt, &symtab[symtab_index], + &sym_ref, elf_machine_type_class(reloc_type)); + } +#if defined USE_TLS && USE_TLS + tls_tpnt = sym_ref.tpnt; +#endif } -#define COPY_UNALIGNED_WORD(swp, twp, align) \ - { \ - void *__s = (swp), *__t = (twp); \ - unsigned char *__s1 = __s, *__t1 = __t; \ - unsigned short *__s2 = __s, *__t2 = __t; \ - unsigned long *__s4 = __s, *__t4 = __t; \ - switch ((align)) \ - { \ - case 0: \ - *__t4 = *__s4; \ - break; \ - case 2: \ - *__t2++ = *__s2++; \ - *__t2 = *__s2; \ - break; \ - default: \ - *__t1++ = *__s1++; \ - *__t1++ = *__s1++; \ - *__t1++ = *__s1++; \ - *__t1 = *__s1; \ - break; \ - } \ - } +#if defined USE_TLS && USE_TLS + /* In case of a TLS reloc, tls_tpnt NULL means we have an 'anonymous' + symbol. This is the case for a static tls variable, so the lookup + module is just that one is referencing the tls variable. */ + if (!tls_tpnt) + tls_tpnt = tpnt; +#endif +#define COPY_UNALIGNED_WORD(swp, twp) \ +{ \ + __typeof (swp) __tmp = __builtin_nds32_unaligned_load_w ((unsigned int*)&swp); \ + __builtin_nds32_unaligned_store_w ((unsigned int *)twp, __tmp); \ +} #if defined (__SUPPORT_LD_DEBUG__) { - unsigned long old_val = *reloc_addr; + unsigned long old_val = 0; + if(reloc_type != R_NDS32_NONE) + old_val = *reloc_addr; #endif symbol_addr += rpnt->r_addend ; switch (reloc_type) { @@ -235,7 +243,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, *reloc_addr = symbol_addr; break; case R_NDS32_32_RELA: - COPY_UNALIGNED_WORD (&symbol_addr, reloc_addr,(int) reloc_addr & 3); + COPY_UNALIGNED_WORD (symbol_addr, reloc_addr); break; #undef COPY_UNALIGNED_WORD case R_NDS32_RELATIVE: @@ -245,12 +253,38 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, _dl_memcpy((void *) reloc_addr, (void *) symbol_addr, symtab[symtab_index].st_size); break; +#if defined USE_TLS && USE_TLS + case R_NDS32_TLS_TPOFF: + CHECK_STATIC_TLS ((struct link_map *) tls_tpnt); + *reloc_addr = (symbol_addr + tls_tpnt->l_tls_offset); + break; + case R_NDS32_TLS_DESC: + { + struct tlsdesc volatile *td = + (struct tlsdesc volatile *)reloc_addr; +#ifndef SHARED + CHECK_STATIC_TLS((struct link_map *) tls_tpnt); +#else + if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt)) + { + td->argument.pointer = _dl_make_tlsdesc_dynamic((struct link_map *) tls_tpnt, symbol_addr); + td->entry = _dl_tlsdesc_dynamic; + } + else +#endif + { + td->argument.value = symbol_addr + tls_tpnt->l_tls_offset; + td->entry = _dl_tlsdesc_return; + } + } + break; +#endif default: return -1; /*call _dl_exit(1) */ } #if defined (__SUPPORT_LD_DEBUG__) if (_dl_debug_reloc && _dl_debug_detail) - _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr); + _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", (unsigned int)old_val, (unsigned int)*reloc_addr, (unsigned int)reloc_addr); } #endif @@ -283,7 +317,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, } #if defined (__SUPPORT_LD_DEBUG__) if (_dl_debug_reloc && _dl_debug_detail) - _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr); + _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", (unsigned int)old_val, (unsigned int)*reloc_addr, (unsigned int)reloc_addr); } #endif diff --git a/ldso/ldso/nds32/resolve.S b/ldso/ldso/nds32/resolve.S index 8c53850d7..e88d9ad60 100644 --- a/ldso/ldso/nds32/resolve.S +++ b/ldso/ldso/nds32/resolve.S @@ -3,14 +3,6 @@ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) -# define STACK_PUSH -# define STACK_POP -#else -# define STACK_PUSH addi $sp, $sp, -24 -# define STACK_POP addi $sp, $sp, 24 -#endif - .text .align 4 ! 16 byte boundary .globl _dl_linux_resolve @@ -28,22 +20,11 @@ _dl_linux_resolve: smw.adm $r0, [$sp], $r5, 6 ! init gp -#ifdef __NDS32_N1213_43U1H__ - sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_+4) - ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_+8) - add $gp, $ta, $gp -#else mfusr $ta, $PC sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_+4) ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_+8) add $gp, $ta, $gp -#endif - ! #ifdef __NDS32_ABI_1__ - ! adjust stack - !addi $sp, $sp, -24 - STACK_PUSH - ! #endif ! set arguments addi $r0, $r17, 0 @@ -61,11 +42,6 @@ _dl_linux_resolve: ! save the return addi $ta, $r0, 0 - ! #ifdef __NDS32_ABI_1__ - ! adjust sp - !addi $sp, $sp, 24 - STACK_POP - ! #endif ! reload registers lmw.bim $r0, [$sp], $r5, 6 diff --git a/ldso/libdl/Makefile.in b/ldso/libdl/Makefile.in index 24e00faf0..3fd8a6cd1 100644 --- a/ldso/libdl/Makefile.in +++ b/ldso/libdl/Makefile.in @@ -33,7 +33,6 @@ libdl_SRC := $(libdl_DIR)/libdl.c libdl_OBJ := $(patsubst $(libdl_DIR)/%.c,$(libdl_OUT)/%.o,$(libdl_SRC)) resolve := $(top_builddir)ldso/ldso/$(TARGET_ARCH)/resolve.o - libdl-a-y := $(libdl_OBJ) $(resolve) ifeq ($(DOPIC),y) libdl-a-y := $(libdl-a-y:.o=.os) diff --git a/libc/string/nds32/memcpy.S b/libc/string/nds32/memcpy.S index 4f285b5ee..4da2c83ea 100644 --- a/libc/string/nds32/memcpy.S +++ b/libc/string/nds32/memcpy.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Andes Technology, Inc. + * Copyright (C) 2016-2017 Andes Technology, Inc. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ @@ -54,12 +54,32 @@ ENTRY(memcpy) srli $r3, $r2, #5 beqz $r3, .Lword_copy_entry pushm $r6, $r13 + cfi_adjust_cfa_offset(32) + cfi_rel_offset(r6, 0) + cfi_rel_offset(r7, 4) + cfi_rel_offset(r8, 8) + cfi_rel_offset(r9, 12) + cfi_rel_offset(r10, 16) + cfi_rel_offset(r11, 20) + cfi_rel_offset(r12, 24) + cfi_rel_offset(r13, 28) + .L3: lmw.bim $r6, [$r1], $r13 addi $r3, $r3, #-1 smw.bim $r6, [$r0], $r13 bnez $r3, .L3 popm $r6, $r13 + cfi_adjust_cfa_offset(-32) + cfi_restore(r6) + cfi_restore(r7) + cfi_restore(r8) + cfi_restore(r9) + cfi_restore(r10) + cfi_restore(r11) + cfi_restore(r12) + cfi_restore(r13) + .Lword_copy_entry: andi $r2, $r2, #31 diff --git a/libc/string/nds32/memset.S b/libc/string/nds32/memset.S index edd15a410..ba208f6cf 100644 --- a/libc/string/nds32/memset.S +++ b/libc/string/nds32/memset.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Andes Technology, Inc. + * Copyright (C) 2016-2017 Andes Technology, Inc. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ diff --git a/libc/sysdeps/linux/common/posix_fadvise.c b/libc/sysdeps/linux/common/posix_fadvise.c index c4ebeaa31..82a25d031 100644 --- a/libc/sysdeps/linux/common/posix_fadvise.c +++ b/libc/sysdeps/linux/common/posix_fadvise.c @@ -41,7 +41,7 @@ int posix_fadvise(int fd, off_t offset, off_t len, int advice) # if __WORDSIZE == 64 ret = INTERNAL_SYSCALL(fadvise64_64, err, 4, fd, offset, len, advice); # else -# if defined (__arm__) || \ +# if defined (__arm__) || defined (__nds32__) || \ (defined(__UCLIBC_SYSCALL_ALIGN_64BIT__) && (defined(__powerpc__) || defined(__xtensa__))) /* arch with 64-bit data in even reg alignment #1: [powerpc/xtensa] * custom syscall handler (rearranges @advice to avoid register hole punch) */ diff --git a/libc/sysdeps/linux/common/posix_fadvise64.c b/libc/sysdeps/linux/common/posix_fadvise64.c index eb722ec20..b9a9d93ab 100644 --- a/libc/sysdeps/linux/common/posix_fadvise64.c +++ b/libc/sysdeps/linux/common/posix_fadvise64.c @@ -25,7 +25,7 @@ int posix_fadvise64(int fd, off64_t offset, off64_t len, int advice) int ret; INTERNAL_SYSCALL_DECL (err); /* ARM has always been funky. */ -#if defined (__arm__) || \ +#if defined (__arm__) || defined (__nds32__) || \ (defined(__UCLIBC_SYSCALL_ALIGN_64BIT__) && (defined(__powerpc__) || defined(__xtensa__))) /* arch with 64-bit data in even reg alignment #1: [powerpc/xtensa] * custom syscall handler (rearranges @advice to avoid register hole punch) */ diff --git a/libc/sysdeps/linux/common/sync_file_range.c b/libc/sysdeps/linux/common/sync_file_range.c index ed03d2f85..faeae3c61 100644 --- a/libc/sysdeps/linux/common/sync_file_range.c +++ b/libc/sysdeps/linux/common/sync_file_range.c @@ -28,7 +28,7 @@ static int __NC(sync_file_range)(int fd, off64_t offset, off64_t nbytes, unsigne return INLINE_SYSCALL(sync_file_range, 6, fd, OFF64_HI_LO(offset), OFF64_HI_LO(nbytes), flags); # elif (defined __mips__ && _MIPS_SIM == _ABIO32) || \ - (defined(__UCLIBC_SYSCALL_ALIGN_64BIT__) && !(defined(__powerpc__) || defined(__xtensa__))) + (defined(__UCLIBC_SYSCALL_ALIGN_64BIT__) && !(defined(__powerpc__) || defined(__xtensa__) || defined(__nds32__))) /* arch with 64-bit data in even reg alignment #2: [arcv2/others-in-future] * stock syscall handler in kernel (reg hole punched) * see libc/sysdeps/linux/common/posix_fadvise.c for more details */ diff --git a/libc/sysdeps/linux/nds32/Makefile b/libc/sysdeps/linux/nds32/Makefile index 633c91f3e..86a32a613 100644 --- a/libc/sysdeps/linux/nds32/Makefile +++ b/libc/sysdeps/linux/nds32/Makefile @@ -1,9 +1,5 @@ -# Makefile for uClibc -# -# Copyright (C) 2000-2005 Erik Andersen -# +# Makefile for uClibc-ng # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. -# top_srcdir=../../../../ top_builddir=../../../../ diff --git a/libc/sysdeps/linux/nds32/Makefile.arch b/libc/sysdeps/linux/nds32/Makefile.arch index 8691875ee..d5cdddbfa 100644 --- a/libc/sysdeps/linux/nds32/Makefile.arch +++ b/libc/sysdeps/linux/nds32/Makefile.arch @@ -1,5 +1,7 @@ # Copyright (C) 2016 Andes Technology, Inc. # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. -CSRC-y := brk.c sigaction.c -SSRC-y := setjmp.S __longjmp.S bsd-setjmp.S bsd-_setjmp.S clone.S mmap.S sigrestorer.S vfork.S sysdep.S syscall.S +CSRC-y := brk.c prctl.c mremap.c syscall.c +SSRC-y := setjmp.S __longjmp.S bsd-setjmp.S bsd-_setjmp.S clone.S vfork.S sysdep.S syscall.S +CSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += makecontext.c swapcontext.c +SSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += getcontext.S setcontext.S diff --git a/libc/sysdeps/linux/nds32/__longjmp.S b/libc/sysdeps/linux/nds32/__longjmp.S index fbea6f6f4..16c4dad38 100644 --- a/libc/sysdeps/linux/nds32/__longjmp.S +++ b/libc/sysdeps/linux/nds32/__longjmp.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Andes Technology, Inc. + * Copyright (C) 2016-2017 Andes Technology, Inc. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ diff --git a/libc/sysdeps/linux/nds32/bits/atomic.h b/libc/sysdeps/linux/nds32/bits/atomic.h new file mode 100644 index 000000000..f93fa7a43 --- /dev/null +++ b/libc/sysdeps/linux/nds32/bits/atomic.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#ifndef _NDS32_BITS_ATOMIC_H +#define _NDS32_BITS_ATOMIC_H + +#include + +typedef int8_t atomic8_t; +typedef uint8_t uatomic8_t; +typedef int_fast8_t atomic_fast8_t; +typedef uint_fast8_t uatomic_fast8_t; + +typedef int16_t atomic16_t; +typedef uint16_t uatomic16_t; +typedef int_fast16_t atomic_fast16_t; +typedef uint_fast16_t uatomic_fast16_t; + +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 int64_t atomic64_t; +typedef uint64_t uatomic64_t; +typedef int_fast64_t atomic_fast64_t; +typedef uint_fast64_t uatomic_fast64_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + + +#ifndef atomic_full_barrier +# define atomic_full_barrier() __asm__ ("dsb" ::: "memory") +#endif + +#ifndef atomic_read_barrier +# define atomic_read_barrier() atomic_full_barrier () +#endif + +#ifndef atomic_write_barrier +# define atomic_write_barrier() atomic_full_barrier () +#endif + +#define atomic_exchange_acq(mem, newval) \ + ({ unsigned long val, offset, temp; \ + \ + __asm__ volatile ( \ + "move %2, %4\n\t" \ + "move %1, #0x0\n\t" \ + "1:\n\t" \ + "llw %0, [%3 + %1 << 0]\n\t" \ + "move %2, %4\n\t" \ + "scw %2, [%3 + %1 << 0]\n\t" \ + "beqz %2, 1b\n\t" \ + : "=&r" (val), "=&r" (offset), "=&r" (temp) \ + : "r" (mem), "r" (newval) \ + : "memory" ); \ + val; }) + +#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ + ({ unsigned long val, offset, temp; \ + \ + __asm__ volatile ( \ + "move %1, #0x0\n\t" \ + "move %2, %4\n\t" \ + "1:\n\t" \ + "llw %0, [%3 + %1 << 0]\n\t" \ + "bne %0, %5, 2f\n\t" \ + "move %2, %4\n\t" \ + "scw %2, [%3 + %1 << 0]\n\t" \ + "beqz %2, 1b\n\t" \ + "j 3f\n\t" \ + "2:\n\t" \ + "move %2, %0\n\t" \ + "scw %2, [%3 + %1 << 0]\n\t" \ + "3:\n\t" \ + : "=&r" (val), "=&r" (offset), "=&r" (temp) \ + : "r" (mem), "r" (newval), "r" (oldval) \ + : "memory" ); \ + val; }) + +#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ + ({ unsigned long val, offset, temp; \ + \ + __asm__ volatile ( \ + "move %1, #0x0\n\t" \ + "move %2, %4\n\t" \ + "1:\n\t" \ + "llw %0, [%3 + %1 << 0]\n\t" \ + "bne %5, %0, 2f\n\t" \ + "move %2, %4\n\t" \ + "scw %2, [%3 + %1 << 0]\n\t" \ + "beqz %2, 1b\n\t" \ + "addi %0, %1, #0\n\t" \ + "j 3f\n\t" \ + "2:\n\t" \ + "scw %0, [%3 + %1 << 0]\n\t" \ + "addi %0, %1, #0x1\n\t" \ + "3:\n\t" \ + : "=&r" (val), "=&r" (offset), "=&r" (temp) \ + : "r" (mem), "r" (newval), "r" (oldval) \ + : "memory" ); \ + val; }) + +#endif diff --git a/libc/sysdeps/linux/nds32/bits/fcntl.h b/libc/sysdeps/linux/nds32/bits/fcntl.h index d21c4e03c..a936023aa 100644 --- a/libc/sysdeps/linux/nds32/bits/fcntl.h +++ b/libc/sysdeps/linux/nds32/bits/fcntl.h @@ -1,7 +1,11 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + /* O_*, F_*, FD_* bit values for Linux. Copyright (C) 1995, 1996, 1997, 1998, 2000, 2004, 2007 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 diff --git a/libc/sysdeps/linux/nds32/bits/fenv.h b/libc/sysdeps/linux/nds32/bits/fenv.h new file mode 100644 index 000000000..010d870f5 --- /dev/null +++ b/libc/sysdeps/linux/nds32/bits/fenv.h @@ -0,0 +1,79 @@ +/* Copyright (C) 2004-2012 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 _FENV_H +# error "Never use directly; include instead." +#endif + +/* Define bits representing exceptions in the FPCSR status word. */ +enum + { + FE_INVALID = +#define FE_INVALID 0x4 + FE_INVALID, + FE_DIVBYZERO = +#define FE_DIVBYZERO 0x8 + FE_DIVBYZERO, + FE_OVERFLOW = +#define FE_OVERFLOW 0x10 + FE_OVERFLOW, + FE_UNDERFLOW = +#define FE_UNDERFLOW 0x20 + FE_UNDERFLOW, + FE_INEXACT = +#define FE_INEXACT 0x40 + FE_INEXACT, + }; + + +/* All supported exceptions. */ +#define FE_ALL_EXCEPT \ + (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) + +/* Define bits representing rounding modes in the FPCSR RM field. */ +enum + { + FE_TONEAREST = +#define FE_TONEAREST 0x0 + FE_TONEAREST, + FE_UPWARD = +#define FE_UPWARD 0x1 + FE_UPWARD, + FE_DOWNWARD = +#define FE_DOWNWARD 0x2 + FE_DOWNWARD, + FE_TOWARDZERO = +#define FE_TOWARDZERO 0x3 + FE_TOWARDZERO + }; + +/* Type representing exception flags. */ +typedef unsigned int fexcept_t; + +/* Type representing floating-point environment. */ +typedef struct + { + unsigned int __fpcsr; + } +fenv_t; + +/* If the default argument is used we use this value. */ +#define FE_DFL_ENV ((const fenv_t *) -1l) + +#ifdef __USE_GNU +/* Floating-point environment where none of the exceptions are masked. */ +# define FE_NOMASK_ENV ((const fenv_t *) -2) +#endif diff --git a/libc/sysdeps/linux/nds32/bits/mman.h b/libc/sysdeps/linux/nds32/bits/mman.h index 13f3e60b3..ac242e065 100644 --- a/libc/sysdeps/linux/nds32/bits/mman.h +++ b/libc/sysdeps/linux/nds32/bits/mman.h @@ -103,4 +103,5 @@ /* Flags for `mremap'. */ #ifdef __USE_GNU # define MREMAP_MAYMOVE 1 +# define MREMAP_FIXED 2 #endif diff --git a/libc/sysdeps/linux/nds32/bits/setjmp.h b/libc/sysdeps/linux/nds32/bits/setjmp.h index 92d89003a..e287c2481 100644 --- a/libc/sysdeps/linux/nds32/bits/setjmp.h +++ b/libc/sysdeps/linux/nds32/bits/setjmp.h @@ -24,19 +24,25 @@ #ifndef _BITS_SETJMP_H #define _BITS_SETJMP_H 1 -#ifndef _SETJMP_H +#if !defined _SETJMP_H && !defined _PTHREAD_H # error "Never include directly; use instead." #endif #ifndef _ASM typedef struct { - /* Callee-saved registers r6 - r14, r16 - r19 and r28 - r31. */ - int __regs[31]; + /* Callee-saved registers: r6 - r14, + * * fp, gp, lp, sp: r28 - r31. */ + int __regs[13]; + + /* Floating-Point Configuration Register. */ + int __fpcfg; + + /* Callee-saved fp registers pointer. */ + int __fpregs[32]; + + } __jmp_buf[1] __attribute__((__aligned__ (8))); - /* Program counter. */ - void * __pc; - } __jmp_buf[1]; #endif #endif /* bits/setjmp.h */ diff --git a/libc/sysdeps/linux/nds32/bits/sigcontext.h b/libc/sysdeps/linux/nds32/bits/sigcontext.h deleted file mode 100644 index e91f6a9b0..000000000 --- a/libc/sysdeps/linux/nds32/bits/sigcontext.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2016 Andes Technology, Inc. - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. - */ - -#ifndef _BITS_SIGCONTEXT_H -#define _BITS_SIGCONTEXT_H 1 - -#ifndef sigcontext_struct -#define sigcontext_struct sigcontext - -struct sigcontext{ - unsigned long trap_no; - unsigned long error_code; - unsigned long oldmask; - unsigned long nds32_r0; - unsigned long nds32_r1; - unsigned long nds32_r2; - unsigned long nds32_r3; - unsigned long nds32_r4; - unsigned long nds32_r5; - unsigned long nds32_r6; - unsigned long nds32_r7; - unsigned long nds32_r8; - unsigned long nds32_r9; - unsigned long nds32_r10; - unsigned long nds32_r11; - unsigned long nds32_r12; - unsigned long nds32_r13; - unsigned long nds32_r14; - unsigned long nds32_r15; - unsigned long nds32_r16; - unsigned long nds32_r17; - unsigned long nds32_r18; - unsigned long nds32_r19; - unsigned long nds32_r20; - unsigned long nds32_r21; - unsigned long nds32_r22; - unsigned long nds32_r23; - unsigned long nds32_r24; - unsigned long nds32_r25; - unsigned long nds32_fp; //r28 - unsigned long nds32_gp; //r29 - unsigned long nds32_lp; //r30 - unsigned long nds32_sp; //r31 - unsigned long nds32_d1lo; - unsigned long nds32_d1hi; - unsigned long nds32_d0lo; - unsigned long nds32_d0hi; - unsigned long nds32_ipsw; - unsigned long nds32_ipc; - unsigned long fault_address; -}; - -#define sc_pc nds32_ipc /* For sysdeps/generic/profil-counter.h. */ - -#endif /* sigcontext_struct */ - -#endif /* _BITS_SIGCONTEXT_H */ diff --git a/libc/sysdeps/linux/nds32/bits/sigcontextinfo.h b/libc/sysdeps/linux/nds32/bits/sigcontextinfo.h new file mode 100644 index 000000000..f3237bd57 --- /dev/null +++ b/libc/sysdeps/linux/nds32/bits/sigcontextinfo.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 1999-2013 Free Software Foundation, Inc. + Contributed by Philip Blundell , 1999. + + 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 + +#define SIGCONTEXT siginfo_t *_si, struct ucontext * +#define SIGCONTEXT_EXTRA_ARGS _si, + +#define GET_PC(ctx) ((void *) (ctx)->uc_mcontext.nds32_ipc) +#define GET_FRAME(ctx) ADVANCE_STACK_FRAME ((void *) ctx->uc_mcontext.nds32_fp) +#define GET_STACK(ctx) ((void *) (ctx)->uc_mcontext.nds32_sp) + + +#define CALL_SIGHANDLER(handler, signo, ctx) \ + (handler)((signo), SIGCONTEXT_EXTRA_ARGS (ctx)) + diff --git a/libc/sysdeps/linux/nds32/bits/syscalls.h b/libc/sysdeps/linux/nds32/bits/syscalls.h index f69ad4c41..215ce3467 100644 --- a/libc/sysdeps/linux/nds32/bits/syscalls.h +++ b/libc/sysdeps/linux/nds32/bits/syscalls.h @@ -3,6 +3,26 @@ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ +/* + * For nds32 ISA, the syscall number(SWID) shall be determined at compile time. + * (ex: asm("syscall SWID"); ) + * If the value of syscall number is determined at run time, we shall issue + * this syscall through sys_syscall. + * (ex: + * asm("move $r0, SYSCALL_number" + * "syscall 0x5071"); + * where 0x5071 is syscall number for sys_syscall + * ) + * + * The following two macros are implemented according that syscall number + * is determined in compiler time or run time, + * + * 1. INTERNAL_SYSCALL_NCS: the syscall number is determined at run time + * 2. INTERNAL_SYSCALL: the syscall number is determined at compile time + * + */ + + #ifndef _BITS_SYSCALLS_H #define _BITS_SYSCALLS_H #ifndef _SYSCALL_H @@ -11,6 +31,14 @@ #ifndef __ASSEMBLER__ #include +#include + +#define X(x) #x +#define Y(x) X(x) +#define LIB_SYSCALL __NR_syscall + +#define __issue_syscall(syscall_name) \ +" syscall " Y(syscall_name) "; \n" #undef INTERNAL_SYSCALL_ERROR_P #define INTERNAL_SYSCALL_ERROR_P(val, err) ((unsigned int) (val) >= 0xfffff001u) @@ -18,86 +46,258 @@ #undef INTERNAL_SYSCALL_ERRNO #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) -#define X(x) #x -#define Y(x) X(x) +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) \ + ({ \ + INTERNAL_SYSCALL_DECL (err); \ + long result_var = INTERNAL_SYSCALL (name, err, nr, args); \ + if (INTERNAL_SYSCALL_ERROR_P (result_var, err)) \ + { \ + __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, err)); \ + result_var = -1 ; \ + } \ + result_var; \ + }) + + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) do { } while (0) + -#define __issue_syscall(syscall_name) \ -" syscall " Y(syscall_name) "; \n" - -#define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ -(__extension__ \ -({ \ - register long __result __asm__("$r0"); \ - register long _sys_num __asm__("$r8"); \ - \ - LOAD_ARGS_##nr (name, args) \ - _sys_num = (name); \ - \ - __asm__ volatile ( \ - __issue_syscall (name) \ - : "=r" (__result) \ - : "r"(_sys_num) ASM_ARGS_##nr \ - : "$lp", "memory"); \ - __result; \ -}) \ -) - -/* Macros for setting up inline __asm__ input regs */ -#define ASM_ARGS_0 -#define ASM_ARGS_1 ASM_ARGS_0, "r" (__result) -#define ASM_ARGS_2 ASM_ARGS_1, "r" (_arg2) -#define ASM_ARGS_3 ASM_ARGS_2, "r" (_arg3) -#define ASM_ARGS_4 ASM_ARGS_3, "r" (_arg4) -#define ASM_ARGS_5 ASM_ARGS_4, "r" (_arg5) -#define ASM_ARGS_6 ASM_ARGS_5, "r" (_arg6) -#define ASM_ARGS_7 ASM_ARGS_6, "r" (_arg7) - -/* Macros for converting sys-call wrapper args into sys call args */ -#define LOAD_ARGS_0(name, arg) \ - _sys_num = (long) (name); \ - -#define LOAD_ARGS_1(name, arg1) \ - __result = (long) (arg1); \ - LOAD_ARGS_0 (name, arg1) +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...) internal_syscall##nr(__NR_##name, err, args) /* - * Note that the use of _tmpX might look superflous, however it is needed - * to ensure that register variables are not clobbered if arg happens to be - * a function call itself. e.g. sched_setaffinity() calling getpid() for arg2 - * - * Also this specific order of recursive calling is important to segregate - * the tmp args evaluation (function call case described above) and assigment - * of register variables - */ -#define LOAD_ARGS_2(name, arg1, arg2) \ - long _tmp2 = (long) (arg2); \ - LOAD_ARGS_1 (name, arg1) \ - register long _arg2 __asm__ ("$r1") = _tmp2; - -#define LOAD_ARGS_3(name, arg1, arg2, arg3) \ - long _tmp3 = (long) (arg3); \ - LOAD_ARGS_2 (name, arg1, arg2) \ - register long _arg3 __asm__ ("$r2") = _tmp3; - -#define LOAD_ARGS_4(name, arg1, arg2, arg3, arg4) \ - long _tmp4 = (long) (arg4); \ - LOAD_ARGS_3 (name, arg1, arg2, arg3) \ - register long _arg4 __asm__ ("$r3") = _tmp4; - -#define LOAD_ARGS_5(name, arg1, arg2, arg3, arg4, arg5) \ - long _tmp5 = (long) (arg5); \ - LOAD_ARGS_4 (name, arg1, arg2, arg3, arg4) \ - register long _arg5 __asm__ ("$r4") = _tmp5; - -#define LOAD_ARGS_6(name, arg1, arg2, arg3, arg4, arg5, arg6) \ - long _tmp6 = (long) (arg6); \ - LOAD_ARGS_5 (name, arg1, arg2, arg3, arg4, arg5) \ - register long _arg6 __asm__ ("$r5") = _tmp6; - -#define LOAD_ARGS_7(name, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ - long _tmp7 = (long) (arg7); \ - LOAD_ARGS_6 (name, arg1, arg2, arg3, arg4, arg5, arg6) \ - register long _arg7 __asm__ ("$r6") = _tmp7; + The _NCS variant allows non-constant syscall numbers but it is not + possible to use more than four parameters. +*/ +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(name, err, nr, args...) internal_syscall_ncs##nr(name, err, args) + + +#define internal_syscall0(name, err, dummy...) \ + ({ \ + register long ___res __asm__("$r0"); \ + __asm__ volatile ( \ + __issue_syscall (name) \ + : "=r" (___res) /* output operands */ \ + : \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + ___res; \ + }) + +#define internal_syscall1(name, err, arg1) \ + ({ \ + register long ___res __asm__("$r0"); \ + register long __arg1 __asm__("$r0") = (long) (arg1); \ + __asm__ volatile ( \ + __issue_syscall (name) \ + : "=r" (___res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + ___res; \ + }) + +#define internal_syscall2(name, err, arg1, arg2) \ + ({ \ + register long ___res __asm__("$r0"); \ + register long __arg1 __asm__("$r0") = (long) (arg1); \ + register long __arg2 __asm__("$r1") = (long) (arg2); \ + __asm__ volatile ( \ + __issue_syscall (name) \ + : "=r" (___res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + , "r" (__arg2) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + ___res; \ + }) + +#define internal_syscall3(name, err, arg1, arg2, arg3) \ + ({ \ + register long ___res __asm__("$r0"); \ + register long __arg1 __asm__("$r0") = (long) (arg1); \ + register long __arg2 __asm__("$r1") = (long) (arg2); \ + register long __arg3 __asm__("$r2") = (long) (arg3); \ + __asm__ volatile ( \ + __issue_syscall (name) \ + : "=r" (___res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + , "r" (__arg2) /* input operands */ \ + , "r" (__arg3) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + ___res; \ + }) + +#define internal_syscall4(name, err, arg1, arg2, arg3, arg4) \ + ({ \ + register long ___res __asm__("$r0"); \ + register long __arg1 __asm__("$r0") = (long) (arg1); \ + register long __arg2 __asm__("$r1") = (long) (arg2); \ + register long __arg3 __asm__("$r2") = (long) (arg3); \ + register long __arg4 __asm__("$r3") = (long) (arg4); \ + __asm__ volatile ( \ + __issue_syscall (name) \ + : "=r" (___res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + , "r" (__arg2) /* input operands */ \ + , "r" (__arg3) /* input operands */ \ + , "r" (__arg4) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + ___res; \ + }) + +#define internal_syscall5(name, err, arg1, arg2, arg3, arg4, arg5) \ + ({ \ + register long ___res __asm__("$r0"); \ + register long __arg1 __asm__("$r0") = (long) (arg1); \ + register long __arg2 __asm__("$r1") = (long) (arg2); \ + register long __arg3 __asm__("$r2") = (long) (arg3); \ + register long __arg4 __asm__("$r3") = (long) (arg4); \ + register long __arg5 __asm__("$r4") = (long) (arg5); \ + __asm__ volatile ( \ + __issue_syscall (name) \ + : "=r" (___res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + , "r" (__arg2) /* input operands */ \ + , "r" (__arg3) /* input operands */ \ + , "r" (__arg4) /* input operands */ \ + , "r" (__arg5) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + ___res; \ + }) + +#define internal_syscall6(name, err, arg1, arg2, arg3, arg4, arg5, arg6) \ + ({ \ + register long ___res __asm__("$r0"); \ + register long __arg1 __asm__("$r0") = (long) (arg1); \ + register long __arg2 __asm__("$r1") = (long) (arg2); \ + register long __arg3 __asm__("$r2") = (long) (arg3); \ + register long __arg4 __asm__("$r3") = (long) (arg4); \ + register long __arg5 __asm__("$r4") = (long) (arg5); \ + register long __arg6 __asm__("$r5") = (long) (arg6); \ + __asm__ volatile ( \ + __issue_syscall (name) \ + : "=r" (___res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + , "r" (__arg2) /* input operands */ \ + , "r" (__arg3) /* input operands */ \ + , "r" (__arg4) /* input operands */ \ + , "r" (__arg5) /* input operands */ \ + , "r" (__arg6) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + ___res; \ + }) +#define internal_syscall7(name, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + ({ \ + register long ___res __asm__("$r0"); \ + register long __arg1 __asm__("$r0") = (long) (arg1); \ + register long __arg2 __asm__("$r1") = (long) (arg2); \ + register long __arg3 __asm__("$r2") = (long) (arg3); \ + register long __arg4 __asm__("$r3") = (long) (arg4); \ + register long __arg5 __asm__("$r4") = (long) (arg5); \ + register long __arg6 __asm__("$r5") = (long) (arg6); \ + __asm__ volatile ( \ + "addi10.sp\t #-4\n\t" \ + CFI_ADJUST_CFA_OFFSET(4)"\n\t" \ + "push\t %7\n\t" \ + CFI_ADJUST_CFA_OFFSET(4)"\n\t" \ + __issue_syscall (name) \ + "addi10.sp\t #4\n\t" \ + CFI_ADJUST_CFA_OFFSET(-4)"\n\t" \ + "pop\t %7\n\t" \ + CFI_ADJUST_CFA_OFFSET(-4)"\n\t" \ + : "=r" (___res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + , "r" (__arg2) /* input operands */ \ + , "r" (__arg3) /* input operands */ \ + , "r" (__arg4) /* input operands */ \ + , "r" (__arg5) /* input operands */ \ + , "r" (__arg6) /* input operands */ \ + , "r" (arg7) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + ___res; \ + }) + +#define internal_syscall_ncs0(name, err, dummy...) \ + ({ \ + register long __res __asm__("$r0"); \ + register long __no __asm__("$r0") = (long) (name); \ + __asm__ volatile ( \ + __issue_syscall (LIB_SYSCALL) \ + : "=r" (__res) /* output operands */ \ + : "r" (__no) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + __res; \ + }) + +#define internal_syscall_ncs1(name, err, arg1) \ + ({ \ + register long __res __asm__("$r0"); \ + register long __no __asm__("$r0") = (long) (name); \ + register long __arg1 __asm__("$r1") = (long) (arg1); \ + __asm__ volatile ( \ + __issue_syscall (LIB_SYSCALL) \ + : "=r" (__res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + , "r" (__no) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + __res; \ + }) + +#define internal_syscall_ncs2(name, err, arg1, arg2) \ + ({ \ + register long __res __asm__("$r0"); \ + register long __no __asm__("$r0") = (long) (name); \ + register long __arg1 __asm__("$r1") = (long) (arg1); \ + register long __arg2 __asm__("$r2") = (long) (arg2); \ + __asm__ volatile ( \ + __issue_syscall (LIB_SYSCALL) \ + : "=r" (__res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + , "r" (__arg2) /* input operands */ \ + , "r" (__no) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + __res; \ + }) + +#define internal_syscall_ncs3(name, err, arg1, arg2, arg3) \ + ({ \ + register long __res __asm__("$r0"); \ + register long __no __asm__("$r0") = (long) (name); \ + register long __arg1 __asm__("$r1") = (long) (arg1); \ + register long __arg2 __asm__("$r2") = (long) (arg2); \ + register long __arg3 __asm__("$r3") = (long) (arg3); \ + __asm__ volatile ( \ + __issue_syscall (LIB_SYSCALL) \ + : "=r" (__res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + , "r" (__arg2) /* input operands */ \ + , "r" (__arg3) /* input operands */ \ + , "r" (__no) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + __res; \ + }) + +#define internal_syscall_ncs4(name, err, arg1, arg2, arg3, arg4) \ + ({ \ + register long __res __asm__("$r0"); \ + register long __no __asm__("$r0") = (long) (name); \ + register long __arg1 __asm__("$r1") = (long) (arg1); \ + register long __arg2 __asm__("$r2") = (long) (arg2); \ + register long __arg3 __asm__("$r3") = (long) (arg3); \ + register long __arg4 __asm__("$r4") = (long) (arg4); \ + __asm__ volatile ( \ + __issue_syscall (LIB_SYSCALL) \ + : "=r" (__res) /* output operands */ \ + : "r" (__arg1) /* input operands */ \ + , "r" (__arg2) /* input operands */ \ + , "r" (__arg3) /* input operands */ \ + , "r" (__arg4) /* input operands */ \ + , "r" (__no) /* input operands */ \ + : __SYSCALL_CLOBBERS); /* list of clobbered registers */ \ + __res; \ + }) +#define __SYSCALL_CLOBBERS "$lp", "memory" #endif /* ! __ASSEMBLER__ */ #endif /* _BITS_SYSCALLS_H */ diff --git a/libc/sysdeps/linux/nds32/bits/uClibc_arch_features.h b/libc/sysdeps/linux/nds32/bits/uClibc_arch_features.h index 12e4af9cd..5c4f634a0 100644 --- a/libc/sysdeps/linux/nds32/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/nds32/bits/uClibc_arch_features.h @@ -11,7 +11,7 @@ #define _BITS_UCLIBC_ARCH_FEATURES_H /* instruction used when calling abort() to kill yourself */ -#undef __UCLIBC_ABORT_INSTRUCTION__ +#define __UCLIBC_ABORT_INSTRUCTION__ "bal abort" /* does your target align 64bit values in register pairs ? (32bit arches only) */ #define __UCLIBC_SYSCALL_ALIGN_64BIT__ diff --git a/libc/sysdeps/linux/nds32/bsd-_setjmp.S b/libc/sysdeps/linux/nds32/bsd-_setjmp.S index a7ab1c731..745f109b4 100644 --- a/libc/sysdeps/linux/nds32/bsd-_setjmp.S +++ b/libc/sysdeps/linux/nds32/bsd-_setjmp.S @@ -21,8 +21,8 @@ ENTRY(_setjmp) add $r2, $r15, $r2 ! la $r3, __sigsetjmp@PLT - sethi $r3, hi20(__sigsetjmp@PLT) - ori $r3, $r3, lo12(__sigsetjmp@PLT) + sethi $r3, hi20(HIDDEN_JUMPTARGET(__sigsetjmp)@PLT) + ori $r3, $r3, lo12(HIDDEN_JUMPTARGET(__sigsetjmp)@PLT) add $r3, $r3, $r2 jr $r3 @@ -32,4 +32,3 @@ ENTRY(_setjmp) #endif END(_setjmp) -libc_hidden_def(_setjmp) diff --git a/libc/sysdeps/linux/nds32/bsd-setjmp.S b/libc/sysdeps/linux/nds32/bsd-setjmp.S index b00e62da8..e1f7c83fc 100644 --- a/libc/sysdeps/linux/nds32/bsd-setjmp.S +++ b/libc/sysdeps/linux/nds32/bsd-setjmp.S @@ -21,8 +21,8 @@ ENTRY(setjmp) add $r2, $r15, $r2 ! la $r3, __sigsetjmp@PLT - sethi $r3, hi20(__sigsetjmp@PLT) - ori $r3, $r3, lo12(__sigsetjmp@PLT) + sethi $r3, hi20(HIDDEN_JUMPTARGET(__sigsetjmp)@PLT) + ori $r3, $r3, lo12(HIDDEN_JUMPTARGET(__sigsetjmp)@PLT) add $r3, $r3, $r2 jr $r3 diff --git a/libc/sysdeps/linux/nds32/clone.S b/libc/sysdeps/linux/nds32/clone.S index 5dba17896..1ed77fb2e 100644 --- a/libc/sysdeps/linux/nds32/clone.S +++ b/libc/sysdeps/linux/nds32/clone.S @@ -1,92 +1,180 @@ /* - * Copyright (C) 2016 Andes Technology, Inc. + * Copyright (C) 2016-2017 Andes Technology, Inc. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ +/* Copyright (C) 2010-2014 Free Software Foundation, Inc. + Contributed by Pat Beirne + + 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. */ + /* 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 -#include #define _ERRNO_H 1 #include -/* - int clone(int (*fn)(void *), void *child_stack, int flags, void *arg); - _syscall2(int, clone, int, flags, void *, child_stack) -*/ +#ifdef RESET_PID +#include +#endif + +#define CLONE_VM 0x00000100 +#define CLONE_THREAD 0x00010000 + +/* int clone(int (*fn)(void *), void *child_stack, int flags, void *arg); + _syscall2(int, clone, int, flags, void *, child_stack) */ ENTRY(__clone) +#ifdef __NDS32_ABI_2FP_PLUS__ + lwi $r4, [$sp] + lwi $r5, [$sp+4] +#endif #ifdef PIC /* set GP register to parent only, cause child's $SP will be $r1. */ pushm $fp, $gp -#ifndef __NDS32_N1213_43U1H__ - mfusr $r15, $PC -#endif - sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4) - ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8) - add $gp, $gp, $r15 -#endif - /* sanity check arguments. */ - beqz $r0, 1f - bnez $r1, 2f + cfi_adjust_cfa_offset(8) + cfi_rel_offset(fp, 0) + cfi_rel_offset(gp, 4) + mfusr $r15, $pc + sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4) + ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8) + add $gp, $gp, $r15 +#endif /* PIC */ + + /* sanity check arguments. */ + beqz $r0, 1f + bnez $r1, 2f 1: - movi $r0, -EINVAL + movi $r0, -EINVAL + 5: #ifdef PIC - /* restore GP register, only in parent's stack */ - popm $fp, $gp - la $r15, C_SYMBOL_NAME(__syscall_error@PLT) - jr $r15 -#else - b C_SYMBOL_NAME(__syscall_error) -#endif + /* restore GP register, only in parent's stack */ + la $r15, C_SYMBOL_NAME(__syscall_error@PLT) + push $lp + cfi_adjust_cfa_offset(4) + cfi_rel_offset(lp, 0) + addi $sp, $sp, -4 + cfi_adjust_cfa_offset(4) + jral $r15 + addi $sp, $sp, 4 + cfi_adjust_cfa_offset(-4) + pop $lp + cfi_adjust_cfa_offset(-4) + cfi_restore(lp) + popm $fp, $gp + cfi_adjust_cfa_offset(-8) + cfi_restore(fp) + cfi_restore(gp) + ret +#else /* ! PIC */ + la $r15, C_SYMBOL_NAME(__syscall_error) + jr $r15 +#endif /* ! PIC */ 2: - /* Child's $SP will be $r1, push to child's stack only. */ + /* Child's $sp will be $r1, make $sp 8-byte alignment */ + bitci $r1, $r1, 7 + /* push to child's stack only. */ addi $r1, $r1, -4 - swi.p $r3, [$r1], -4 ! arg - swi $r0, [$r1] ! fn + swi.p $r3, [$r1], -4 ! arg + swi $r0, [$r1] ! fn + + /* do the system call */ + or $r0, $r2, $r2 ! move $r0, $r2 + + move $r3, $r5 + move $r5, $r2 ! Use $r5 to backup $r2 + ! The pt_regs is placed in $r5 in kerenl (sys_clone_wrapper) + move $r2, $r4 - /* do the system call */ - or $r0, $r2, $r2 ! move r0, r2 - __do_syscall(clone) - !syscall (__NR_clone) - beqz $r0, 4f - bltz $r0, 5b +#ifdef __NDS32_ABI_2FP_PLUS__ +# ifdef PIC + lwi $r4, [$sp+#0x10] +# else + lwi $r4, [$sp+#0x8] +# endif +#else +# ifdef PIC + lwi $r4, [$sp+#0x8] +# else + lwi $r4, [$sp] +# endif +#endif + + __do_syscall(clone) + beqz $r0, 4f + bltz $r0, 5b - ! parent + +10: #ifdef PIC - /* restore GP register, only in parent's stack */ + /* restore GP register, only in parent's stack */ popm $fp, $gp -#endif - ret + cfi_adjust_cfa_offset(-8) + cfi_restore(gp) + cfi_restore(fp) +#endif /* PIC */ + ret +#ifdef RESET_PID 4: - /* Only in child's stack. */ - pop $r1 ! fn - pop $r0 ! arg -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) + cfi_undefined(lp) + movi $r0, CLONE_THREAD ! Skip when CLONE_THREAD is set. + and $r0, $r5, $r0 + bnez $r0, 8f + movi $r0, CLONE_VM ! Value = -1 when CLONE_VM is set. + and $r0, $r5, $r0 + beqz $r0, 6f + movi $r0, -1 + j 7f +6: + __do_syscall(getpid) ! __do_syscall(gettid) ! __do_syscall(getpid) +7: + swi $r0, [$r25 + PID_OFFSET] + swi $r0, [$r25 + TID_OFFSET] +8: #else - addi $sp, $sp, -24 -#endif - ! use r15 in case _exit is PIC -#ifdef __NDS32_N1213_43U1H__ - or $r15, $r1, $r1 ! move r15, r2 +4: #endif - bral $r1 -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) -#else + /* Only in child's stack. */ + pop $r1 ! fn + pop $r0 ! arg + + +#if !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__) + addi $sp, $sp, -24 +#endif /* !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__) */ + + ! use $r15 in case _exit is PIC + bral $r1 + +#if !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__) addi $sp, $sp, 24 -#endif - ! use r15 in case _exit is PIC +#endif /* !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__) */ + + ! use $r15 in case _exit is PIC #ifdef PIC - la $r15, C_SYMBOL_NAME(_exit@PLT) - jr $r15 -#else - b C_SYMBOL_NAME(_exit) -#endif + la $r15, C_SYMBOL_NAME(_exit@PLT) +#else /* ! PIC */ + la $r15, C_SYMBOL_NAME(_exit) +#endif /* ! PIC */ + jr $r15 PSEUDO_END (__clone) diff --git a/libc/sysdeps/linux/nds32/crt1.S b/libc/sysdeps/linux/nds32/crt1.S index 54544010f..c30f4334d 100644 --- a/libc/sysdeps/linux/nds32/crt1.S +++ b/libc/sysdeps/linux/nds32/crt1.S @@ -45,17 +45,10 @@ _start: #ifdef SHARED /* set gp register */ -#ifdef __NDS32_N1213_43U1H__ - jal 1b - sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_) - ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_ + 4) - add $gp, $lp, $gp -#else mfusr $r15, $PC sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_+4) ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_ + 8) add $gp, $r15, $gp -#endif la $r3, _init@GOTOFF la $r4, _fini@GOTOFF diff --git a/libc/sysdeps/linux/nds32/crti.S b/libc/sysdeps/linux/nds32/crti.S index 92e5e7175..61d01b63a 100644 --- a/libc/sysdeps/linux/nds32/crti.S +++ b/libc/sysdeps/linux/nds32/crti.S @@ -11,8 +11,6 @@ .type _init, @function _init: .LFB28: - ! Generate instructions for ABI: 1 - ! pretend args size: 0, auto vars size: 0, pushed regs size: 12, outgoing args size: 24 ! Generate instructions for ABI: 2 ! pretend args size: 0, auto vars size: 0, pushed regs size: 12, outgoing args size: 0 ! frame pointer: $fp, needed: yes @@ -22,22 +20,12 @@ _init: smw.adm $sp,[$sp],$sp,#0x8 smw.adm $sp,[$sp],$sp,#0x6 .restore_16bit -#ifdef __NDS32_N1213_43U1H__ - sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+8) - ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+12) -#else sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_-8) ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4) mfusr $ta, $pc -#endif add $gp, $ta, $gp -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) addi $sp, $sp, -4 addi $fp, $sp, 8 -#else - addi $sp, $sp, -28 - addi $fp, $sp, 32 -#endif ! end of prologue #APP .align 2 @@ -48,8 +36,6 @@ _init: .type _fini, @function _fini: .LFB29: - ! Generate instructions for ABI: 1 - ! pretend args size: 0, auto vars size: 0, pushed regs size: 12, outgoing args size: 24 ! Generate instructions for ABI: 2 ! pretend args size: 0, auto vars size: 0, pushed regs size: 12, outgoing args size: 0 ! frame pointer: $fp, needed: yes @@ -59,22 +45,12 @@ _fini: smw.adm $sp,[$sp],$sp,#0x8 smw.adm $sp,[$sp],$sp,#0x6 .restore_16bit -#ifdef __NDS32_N1213_43U1H__ - sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+8) - ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+12) -#else sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_-8) ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4) mfusr $ta, $pc -#endif add $gp, $ta, $gp -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) addi $sp, $sp, -4 addi $fp, $sp, 8 -#else - addi $sp, $sp, -28 - addi $fp, $sp, 32 -#endif ! end of prologue #APP .align 2 diff --git a/libc/sysdeps/linux/nds32/fpu_control.h b/libc/sysdeps/linux/nds32/fpu_control.h new file mode 100644 index 000000000..8ad43f623 --- /dev/null +++ b/libc/sysdeps/linux/nds32/fpu_control.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#ifndef _FPU_CONTROL_H + +#ifdef __NDS32_ABI_2FP_PLUS__ +/* + * Andes Floating-Point Control Status Register + * 31-20 -> Reserved + * 19 -> RIT (RO) + * 18 -> DNIT(RO) + * 17 -> IEXT(RO) + * 16 -> UDFT(RO) + * 15 -> OVFT(RO) + * 14 -> DBZT(RO) + * 13 -> IVOT(RO) + * 12 -> DNZ(RW),Denormalized flush-to-Zero mode. + * 11 -> IEXE(RW),IEEE Ineaxct (IEX) exception trapping enable. + * 10 -> UDFE(RW),IEEE Underflow (UDF) exception trapping enable. + * 9 -> OVFE(RW),IEEE Overflow (OVF) exception trapping enable. + * 8 -> DBZE(RW),IEEE Divide by Zero (DBZ) exception trapping enable. + * 7 -> IVOE(RW),IEEE Invalid Operation (IVO) exception trapping enable. + * 6 -> IEX(RW),IEEE Inexact (IEX) cumulative exception flag. + * 5 -> UDF(RW),IEEE Underflow (UDF) cumulative exception flag. + * 4 -> OVF(RW),IEEE Overflow (OVF) cumulative exception flag. + * 3 -> DBZ(RW),IEEE Divide by Zero (DBZ) cumulative exception flag. + * 2 -> IVO(RW),IEEE Invalid Operation (IVO) cumulative exception flag. + * 1-0 -> Rounding modes. + * + * Rounding modes. + * 00 - rounding to nearest (RN) + * 01 - rounding (up) toward plus infinity (RP) + * 10 - rounding (down)toward minus infinity (RM) + * 11 - rounding toward zero (RZ) + * + */ + + +/* masking of interrupts */ +#define _FPU_MASK_IEX 0x0800 /* Invalid operation */ +#define _FPU_MASK_UDF 0x0400 /* Underflow */ +#define _FPU_MASK_OVF 0x0200 /* Overflow */ +#define _FPU_MASK_DBZ 0x0100 /* Division by zero */ +#define _FPU_MASK_IVO 0x0080 /* Invalid operation */ + +/*Reserved and read-only bits*/ +#define _FPU_RESERVED 0xffffe000 +#define _FPU_DEFAULT 0x00000000 + +/* Default + exceptions enabled. */ +#define _FPU_IEEE (_FPU_DEFAULT | 0x00000f80) + +/* Type of the control word. */ +typedef unsigned int fpu_control_t; + +/* Macros for accessing the hardware control word. */ +/* This is fmrx %0, fpscr. */ +#define _FPU_GETCW(cw) \ + __asm__ __volatile__ ("fmfcsr\t %0\n\t" : "=r" (cw)) +/* This is fmxr fpscr, %0. */ +#define _FPU_SETCW(cw) \ + __asm__ __volatile__ ("fmtcsr\t %0\n\t": : "r" (cw)) + +/* Default control word set at startup. */ +extern fpu_control_t __fpu_control; +#else +#define _FPU_GETCW(cw) (cw) = 0 +#define _FPU_SETCW(cw) (void) (cw) +#define _FPU_RESERVED 0xffffffff +#define _FPU_DEFAULT 0x00000000 +typedef unsigned int fpu_control_t; +extern fpu_control_t __fpu_control; + +#endif //__NDS32_ABI_2FP_PLUS__ +#endif //_FPU_CONTROL_H diff --git a/libc/sysdeps/linux/nds32/getcontext.S b/libc/sysdeps/linux/nds32/getcontext.S new file mode 100644 index 000000000..7bc1ca292 --- /dev/null +++ b/libc/sysdeps/linux/nds32/getcontext.S @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 20[B01-2013 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + + 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 "ucontext_i.h" + +/* __getcontext (const ucontext_t *ucp) + + Saves the machine context in UCP such that when it is activated, + it appears as if __getcontext() returned again. + + This implementation is intended to be used for *synchronous* context + switches only. Therefore, it does not have to save anything + other than the PRESERVED state. */ + +ENTRY(__getcontext) + swi $lp, [$r0 + UCONTEXT_PC] + addi $r15, $r0, UCONTEXT_GREGS + xor $r1, $r1, $r1 + smw.bim $r1, [$r15], $r1 + smw.bim $r1, [$r15], $r14 + addi $r15, $r15, 4 + smw.bim $r16, [$r15], $r25, #0xf + move $r4, $r0 + + /* sigprocmask (SIG_BLOCK, NULL, &sc->sc_mask). */ + move $r0, SIG_BLOCK + move $r1, 0 + addi $r2, $r4, UCONTEXT_SIGMASK + move $r3, _NSIG8 + syscall SYS_ify(rt_sigprocmask) + bnez $r0, 1f + + +#ifdef __NDS32_ABI_2FP_PLUS__ + addi $r2, $r4, UCONTEXT_FDREGS +/* Process for FPU registers. */ + fmfcfg $r20 /* Keep $fpcfg in $r20. */ + slli $r20, $r20, #28 + srli $r20, $r20, #30 /* Set $r20 as $fpcfg.freg. */ + + /* Case switch for $r20 as $fpcfg.freg. */ + beqz $r20, .LCFG0 /* Branch if $fpcfg.freg = 0b00. */ + xori $r15, $r20, #0b10 + beqz $r15, .LCFG2 /* Branch if $fpcfg.freg = 0b10. */ + srli $r20, $r20, #0b01 + beqz $r20, .LCFG1 /* Branch if $fpcfg.freg = 0b01. */ + /* Fall-through if $fpcfg.freg = 0b11. */ +.LCFG3: + fsdi $fd31, [$r2 + 248] + fsdi $fd30, [$r2 + 240] + fsdi $fd29, [$r2 + 232] + fsdi $fd28, [$r2 + 224] + fsdi $fd27, [$r2 + 216] + fsdi $fd26, [$r2 + 208] + fsdi $fd25, [$r2 + 200] + fsdi $fd24, [$r2 + 192] +.LCFG2: + fsdi $fd10, [$r2 + 80] + fsdi $fd9, [$r2 + 72] + fsdi $fd8, [$r2 + 64] +.LCFG1: + fsdi $fd7, [$r2 + 56] + fsdi $fd6, [$r2 + 48] + fsdi $fd5, [$r2 + 40] + fsdi $fd4, [$r2 + 32] +.LCFG0: + fsdi $fd3, [$r2 + 24] + /*save fpcsr*/ + fmfcsr $r1 + swi $r1, [$r2 + 0x100] +#endif /* __NDS32_ABI_2FP_PLUS__ */ + + /* Set __getcontext return value to 0. */ + xor $r0, $r0, $r0 + /* Return first_return: 1 */ + addi $r1, $r0, 1 + ret + +1: + move $r0, -1 + ret +END(__getcontext) + +weak_alias (__getcontext, getcontext) + diff --git a/libc/sysdeps/linux/nds32/jmpbuf-unwind.h b/libc/sysdeps/linux/nds32/jmpbuf-unwind.h index 14a302969..8499e99b4 100644 --- a/libc/sysdeps/linux/nds32/jmpbuf-unwind.h +++ b/libc/sysdeps/linux/nds32/jmpbuf-unwind.h @@ -5,8 +5,24 @@ #include #include +#include +#include +#include /* Test if longjmp to JMPBUF would unwind the frame containing a local variable at ADDRESS. */ #define _JMPBUF_UNWINDS(jmpbuf, address) \ - ((void *) (address) < (void *) &(jmpbuf)[0].__regs[__JMP_BUF_SP]) + ((void *) (address) < &(jmpbuf)[0].__regs[__JMP_BUF_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].__regs[__JMP_BUF_SP]; + return sp; +} + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj)) diff --git a/libc/sysdeps/linux/nds32/makecontext.c b/libc/sysdeps/linux/nds32/makecontext.c new file mode 100644 index 000000000..d8f38aa15 --- /dev/null +++ b/libc/sysdeps/linux/nds32/makecontext.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 2011-2013 Free Software Foundation, Inc. + Contributed by Chris Metcalf , 2011. + + 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 +#include +#include + +/* makecontext sets up a stack and the registers for the + user context. The stack looks like this: + + +-----------------------+ + | padding as required | + +-----------------------+ + sp -> | parameter 7-n | + +-----------------------+ + + The registers are set up like this: + $r0 .. $r5: parameter 1 to 6 + $r6 : uc_link + $sp : stack pointer. +*/ +void +__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) +{ + extern void __startcontext (void); + unsigned long int *sp; + unsigned long *regptr; + va_list ap; + int i; + + sp = (unsigned long int *) + ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); + + /* Allocate stack arguments. */ + sp -= argc < 6 ? 0 : argc - 6; + + /* Keep the stack aligned. */ + sp = (unsigned long int *) (((uintptr_t) sp) & -8L); + + ucp->uc_mcontext.nds32_r6 = (uintptr_t) ucp->uc_link; + ucp->uc_mcontext.nds32_sp = (uintptr_t) sp; + ucp->uc_mcontext.nds32_ipc = (uintptr_t) func; + ucp->uc_mcontext.nds32_lp = (uintptr_t) &__startcontext; + + va_start (ap, argc); + regptr = &ucp->uc_mcontext.nds32_r0; + for (i = 0; i < argc; ++i) + if (i < 6) + *regptr++ = va_arg (ap, unsigned long int); + else + sp[i - 6] = va_arg (ap, unsigned long int); + + va_end (ap); + +} +weak_alias (__makecontext, makecontext) diff --git a/libc/sysdeps/linux/nds32/mmap.S b/libc/sysdeps/linux/nds32/mmap.S deleted file mode 100644 index 351d1c502..000000000 --- a/libc/sysdeps/linux/nds32/mmap.S +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2016 Andes Technology, Inc. - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. - */ - -/* Copyright (C) 1998, 2000, 2003 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, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include -#include - .text - -.globl __mmap -ENTRY (__mmap) - -#ifdef PIC -.pic -#endif - - // reserve space for r0, r1 -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) -#else - addi $sp, $sp, -8 -#endif - // change to units of the system page size - srli $r5, $r5, 0xc - - syscall SYS_ify(mmap2) -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) -#else - addi $sp, $sp, 8 -#endif - - /* r0 is < -4096 if there was an error. */ - bgez $r0, 1f - sltsi $r1,$r0,-4096 - beqz $r1,2f - -1: - ret -2: -#ifdef PIC -#ifdef __NDS32_N1213_43U1H__ - ! save lp - addi $r2, $lp, 0 - - ! set r1 as gp - jal 1b - sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_) - ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+4) - add $r1, $lp, $r1 - - ! restore lp - addi $lp, $r2, 0 - - ! r15=SYSCALL_ERROR@PLT - sethi $r15, hi20(SYSCALL_ERROR@PLT) - ori $r15, $r15, lo12(SYSCALL_ERROR@PLT) - add $r15, $r15, $r1 - - ! jump to SYSCALL_ERROR - jr $r15 -#else - ! set r1 as gp - mfusr $r15, $PC - sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_+4) - ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+8) - add $r1, $r1, $r15 - - ! r15=SYSCALL_ERROR@PLT - sethi $r15, hi20(SYSCALL_ERROR@PLT) - ori $r15, $r15, lo12(SYSCALL_ERROR@PLT) - add $r15, $r15, $r1 - - ! jump to SYSCALL_ERROR - jr $r15 -#endif -#else - j SYSCALL_ERROR -#endif - -ret - -PSEUDO_END (__mmap) - -weak_alias (__mmap, mmap) -libc_hidden_def(mmap) diff --git a/libc/sysdeps/linux/nds32/mremap.c b/libc/sysdeps/linux/nds32/mremap.c new file mode 100644 index 000000000..9b2d83544 --- /dev/null +++ b/libc/sysdeps/linux/nds32/mremap.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include +#include +#include + +#include +#include + +#ifdef __NR_mremap +void *mremap (void *__addr, size_t __old_len, size_t __new_len, + int __flags, ...); +libc_hidden_proto(mremap) + +void *mremap (void *__addr, size_t __old_len, size_t __new_len, int __flags, ...) +{ + unsigned long arg1; + va_list arg; + va_start (arg, __flags); + arg1 = va_arg (arg, int); + va_end (arg); + return (void *)INLINE_SYSCALL(mremap,5,__addr,__old_len,__new_len,__flags,arg1); +} +libc_hidden_def (mremap) +#endif diff --git a/libc/sysdeps/linux/nds32/prctl.c b/libc/sysdeps/linux/nds32/prctl.c new file mode 100644 index 000000000..b20f4ca79 --- /dev/null +++ b/libc/sysdeps/linux/nds32/prctl.c @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include +#include +#include +#include +#include + +int prctl (int __option, ...) +{ + unsigned long arg1,arg2,arg3,arg4; + va_list arg; + va_start (arg, __option); + arg1 = va_arg (arg, unsigned long); + arg2 = va_arg (arg, unsigned long); + arg3 = va_arg (arg, unsigned long); + arg4 = va_arg (arg, unsigned long); + va_end (arg); + return INLINE_SYSCALL(prctl,5,__option,arg1,arg2,arg3,arg4); +} diff --git a/libc/sysdeps/linux/nds32/setcontext.S b/libc/sysdeps/linux/nds32/setcontext.S new file mode 100644 index 000000000..f9265328f --- /dev/null +++ b/libc/sysdeps/linux/nds32/setcontext.S @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include + +#include "ucontext_i.h" + +ENTRY(__setcontext) + move $r4, $r0 + +#ifdef __NDS32_ABI_2FP_PLUS__ + addi $r0, $r4, UCONTEXT_FDREGS + + /* Case switch for $r20 as $fpcfg.freg. */ + beqz $r20, .LCFG0 /* Branch if $fpcfg.freg = 0b00. */ + xori $r15, $r20, #0b10 + beqz $r15, .LCFG2 /* Branch if $fpcfg.freg = 0b10. */ + srli $r20, $r20, #0b01 + beqz $r20, .LCFG1 /* Branch if $fpcfg.freg = 0b01. */ + /* Fall-through if $fpcfg.freg = 0b11. */ +.LCFG3: + fldi $fd31, [$r0 + 248] + fldi $fd30, [$r0 + 240] + fldi $fd29, [$r0 + 232] + fldi $fd28, [$r0 + 224] + fldi $fd27, [$r0 + 216] + fldi $fd26, [$r0 + 208] + fldi $fd25, [$r0 + 200] + fldi $fd24, [$r0 + 192] +.LCFG2: + fldi $fd10, [$r0 + 80] + fldi $fd9, [$r0 + 72] + fldi $fd8, [$r0 + 64] +.LCFG1: + fldi $fd7, [$r0 + 56] + fldi $fd6, [$r0 + 48] + fldi $fd5, [$r0 + 40] + fldi $fd4, [$r0 + 32] +.LCFG0: + fldi $fd3, [$r0 + 24] + /*save fpcsr*/ + lwi $r1, [$r0 + 0x100] + fmtcsr $r1 +#endif /* __NDS32_ABI_2FP_PLUS__ */ + + /* sigprocmask (SIG_BLOCK, &sc->sc_mask, NULL). */ + move $r0, SIG_SETMASK + addi $r1, $r4, UCONTEXT_SIGMASK + move $r2, 0 + move $r3, _NSIG8 + syscall SYS_ify(rt_sigprocmask) + bnez $r0, 1f + + move $r0, $r4 + addi $r15, $r4, UCONTEXT_GREGS + 4 + lmw.bim $r1, [$r15], $r14 + addi $r15, $r15, 4 + lmw.bim $r16, [$r15], $r25, #0xf + lwi $r15, [$r0 + UCONTEXT_PC] + push $r1 + cfi_adjust_cfa_offset (4) + move $r1, $r0 + lwi $r0, [$r1 + UCONTEXT_GREGS] + pop $r1 + cfi_adjust_cfa_offset (-4) + jr $r15 +1: + move $r0, -1 + ret +END(__setcontext) + +weak_alias (__setcontext, setcontext) +libc_hidden_def(__setcontext) + +ENTRY (__startcontext) + move $r0, $r6 + beqz $r0, 1f + jal HIDDEN_JUMPTARGET(__setcontext) +1: + move $r0, 0 + j HIDDEN_JUMPTARGET(exit) +END (__startcontext) + diff --git a/libc/sysdeps/linux/nds32/setjmp.S b/libc/sysdeps/linux/nds32/setjmp.S index 8cb9adbeb..262d74925 100644 --- a/libc/sysdeps/linux/nds32/setjmp.S +++ b/libc/sysdeps/linux/nds32/setjmp.S @@ -106,4 +106,4 @@ ENTRY(__sigsetjmp) #endif END(__sigsetjmp) -hidden_def(__sigsetjmp) +libc_hidden_def(__sigsetjmp) diff --git a/libc/sysdeps/linux/nds32/sigaction.c b/libc/sysdeps/linux/nds32/sigaction.c deleted file mode 100644 index 1a24c49b4..000000000 --- a/libc/sysdeps/linux/nds32/sigaction.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2016 Andes Technology, Inc. - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. - */ - -#include -#include -#include -#include -#include - -#define SA_RESTORER 0x04000000 - -extern void __default_sa_restorer(void); - -int __libc_sigaction(int sig, const struct sigaction *act, - struct sigaction *oact) -{ - struct sigaction kact; - - if (act && !(act->sa_flags & SA_RESTORER)) { - memcpy(&kact, act, sizeof(kact)); - kact.sa_restorer = __default_sa_restorer; - kact.sa_flags |= SA_RESTORER; - act = &kact; - } - /* NB: kernel (as of 2.6.25) will return EINVAL - * if sizeof(act->sa_mask) does not match kernel's sizeof(sigset_t) */ - return __syscall_rt_sigaction(sig, act, oact, sizeof(act->sa_mask)); -} - -#ifndef LIBC_SIGACTION -# ifndef __UCLIBC_HAS_THREADS__ -strong_alias(__libc_sigaction,sigaction) -libc_hidden_def(sigaction) -# else -weak_alias(__libc_sigaction,sigaction) -libc_hidden_weak(sigaction) -# endif -#endif diff --git a/libc/sysdeps/linux/nds32/sigrestorer.S b/libc/sysdeps/linux/nds32/sigrestorer.S deleted file mode 100644 index bf6188656..000000000 --- a/libc/sysdeps/linux/nds32/sigrestorer.S +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2016 Andes Technology, Inc. - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. - */ - -/* Copyright (C) 1999 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, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include -#include - -/* If no SA_RESTORER function was specified by the application we use - one of these. This avoids the need for the kernel to synthesise a return - instruction on the stack, which would involve expensive cache flushes. */ - -ENTRY(__default_sa_restorer) - /* DO NOT SAVE r7 INTO STACK, THIS SYSCALL NEVER RETURN */ - syscall SYS_ify(sigreturn) -END(__default_sa_restorer) - -#ifdef __NR_rt_sigreturn - -ENTRY(__default_rt_sa_restorer) - /* DO NOT SAVE r7 INTO STACK, THIS SYSCALL NEVER RETURN */ - syscall SYS_ify(rt_sigreturn) -END(__default_rt_sa_restorer) - -#endif diff --git a/libc/sysdeps/linux/nds32/swapcontext.c b/libc/sysdeps/linux/nds32/swapcontext.c new file mode 100644 index 000000000..310923f0d --- /dev/null +++ b/libc/sysdeps/linux/nds32/swapcontext.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2001-2013 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang . + + 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 + +struct rv + { + long retval; + long first_return; + }; + +extern struct rv __getcontext (ucontext_t *__ucp); +extern int __setcontext (const ucontext_t *__ucp); + +int +__swapcontext (ucontext_t *oucp, const ucontext_t *ucp) +{ + struct rv rv = __getcontext (oucp); + if (rv.first_return) + __setcontext (ucp); + return 0; +} + +weak_alias (__swapcontext, swapcontext) diff --git a/libc/sysdeps/linux/nds32/sys/ucontext.h b/libc/sysdeps/linux/nds32/sys/ucontext.h index 4dca27fd5..0d7422aab 100644 --- a/libc/sysdeps/linux/nds32/sys/ucontext.h +++ b/libc/sysdeps/linux/nds32/sys/ucontext.h @@ -1,7 +1,20 @@ -/* - * Copyright (C) 2016 Andes Technology, Inc. - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. - */ +/* Copyright (C) 1998, 1999, 2001, 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, see + . */ + #ifndef _SYS_UCONTEXT_H #define _SYS_UCONTEXT_H 1 @@ -10,103 +23,25 @@ #include #include -typedef int greg_t; - -/* Number of general registers. */ -#define NGREG 32 - -/* Container for all general registers. */ -typedef elf_gregset_t gregset_t; +/* We need the signal context definitions even if they are not used + * included in . */ +#include -/* Number of each register is the `gregset_t' array. */ -enum -{ - R0 = 0, -#define R0 R0 - R1 = 1, -#define R1 R1 - R2 = 2, -#define R2 R2 - R3 = 3, -#define R3 R3 - R4 = 4, -#define R4 R4 - R5 = 5, -#define R5 R5 - R6 = 6, -#define R6 R6 - R7 = 7, -#define R7 R7 - R8 = 8, -#define R8 R8 - R9 = 9, -#define R9 R9 - R10 = 10, -#define R10 R10 - R11 = 11, -#define R11 R11 - R12 = 12, -#define R12 R12 - R13 = 13, -#define R13 R13 - R14 = 14, -#define R14 R14 - R15 = 15, -#define R15 R15 - R16 = 16, -#define R16 R16 - R17 = 17, -#define R17 R17 - R18 = 18, -#define R18 R18 - R19 = 19, -#define R19 R19 - R20 = 20, -#define R20 R20 - R21 = 21, -#define R21 R21 - R22 = 22, -#define R22 R22 - R23 = 23, -#define R23 R23 - R24 = 24, -#define R24 R24 - R25 = 25, -#define R25 R25 - R26 = 26, -#define R26 R26 - R27 = 27, -#define R27 R27 - R28 = 28, -#define R28 R28 - R29 = 29, -#define R29 R29 - R30 = 30, -#define R30 R30 - R31 = 31 -#define R31 R31 -}; +/* Context to describe whole processor state. This only describes + the core registers; coprocessor registers get saved elsewhere + (e.g. in uc_regspace, or somewhere unspecified on the stack + during non-RT signal handlers). */ +typedef struct sigcontext mcontext_t; -/* Structure to describe FPU registers. */ -typedef elf_fpregset_t fpregset_t; - -/* Context to describe whole processor state. */ -typedef struct - { - gregset_t gregs; - fpregset_t fpregs; - } mcontext_t; /* Userlevel context. */ typedef struct ucontext { unsigned long int uc_flags; struct ucontext *uc_link; - __sigset_t uc_sigmask; stack_t uc_stack; mcontext_t uc_mcontext; - long int uc_filler[5]; + __sigset_t uc_sigmask; } ucontext_t; - #endif /* sys/ucontext.h */ diff --git a/libc/sysdeps/linux/nds32/syscall.S b/libc/sysdeps/linux/nds32/syscall.S deleted file mode 100644 index 032c643fd..000000000 --- a/libc/sysdeps/linux/nds32/syscall.S +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2016 Andes Technology, Inc. - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. - */ - -#include -#include - - .text -#ifdef PIC - .pic -#endif - .align 2 - - -#ifdef PIC -#ifdef __NDS32_N1213_43U1H__ -1: - ret -99: - addi $r2, $lp, 0 - jal 1b - sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_) - ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+4) - add $r1, $lp, $r1 - addi $lp, $r2, 0 -#else /* !__NDS32_N1213_43U1H__ */ -99: - mfusr $r15, $PC - sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_ + 4) - ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_ + 8) - add $r1, $r15, $r1 -#endif /* end of __NDS32_N1213_43U1H__ */ - sethi $r15, hi20(__syscall_error@PLT) - ori $r15, $r15, lo12(__syscall_error@PLT) - add $r15, $r15, $r1 - jr $r15 -#else /* !PIC */ -99: - j __syscall_error -#endif /* end of PIC */ - -#ifdef PIC - .pic -#endif - - .align 2 - .globl syscall - .func syscall - .type syscall, @function - -syscall: - syscall __NR_syscall - bgez $r0, 2f - sltsi $r1, $r0, -4096; - beqz $r1, 99b; -2: - ret - .endfunc - .size syscall, .-syscall diff --git a/libc/sysdeps/linux/nds32/syscall.c b/libc/sysdeps/linux/nds32/syscall.c new file mode 100644 index 000000000..2c949ef3a --- /dev/null +++ b/libc/sysdeps/linux/nds32/syscall.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include +#include +#include +#include +#include +long int syscall (long int __sysno, ...) +{ + + int result; + unsigned long arg1,arg2,arg3,arg4,arg5,arg6; + va_list arg; + va_start (arg, __sysno); + arg1 = va_arg (arg, unsigned long); + arg2 = va_arg (arg, unsigned long); + arg3 = va_arg (arg, unsigned long); + arg4 = va_arg (arg, unsigned long); + arg5 = va_arg (arg, unsigned long); + arg6 = va_arg (arg, unsigned long); + va_end (arg); + __asm__ volatile ( "" ::: "memory" ); + result = INLINE_SYSCALL(syscall,7,__sysno,arg1,arg2,arg3,arg4,arg5,arg6); + return result; +} diff --git a/libc/sysdeps/linux/nds32/sysdep.S b/libc/sysdeps/linux/nds32/sysdep.S index 4e86a26e0..0ab325f26 100644 --- a/libc/sysdeps/linux/nds32/sysdep.S +++ b/libc/sysdeps/linux/nds32/sysdep.S @@ -26,15 +26,10 @@ .text -.globl C_SYMBOL_NAME(errno) .globl __syscall_error ENTRY (__syscall_error) -#ifdef OLD_ABI - subri $r5, $r5, #0 -#else subri $r0, $r0, #0 -#endif #define __syscall_error __syscall_error_1 @@ -48,56 +43,57 @@ syscall_error: #ifdef PIC /* set GP register */ pushm $gp, $lp -#ifdef __NDS32_N1213_43U1H__ - jal 2f - sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_) - ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+4) - add $gp, $gp, $lp -#else + cfi_adjust_cfa_offset(8) + cfi_rel_offset(gp, 0) + cfi_rel_offset(lp, 4) mfusr $r15, $PC sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4) ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8) add $gp, $gp, $r15 #endif -#endif #if defined (EWOULDBLOCK_sys) && EWOULDBLOCK_sys != EAGAIN /* We translate the system's EWOULDBLOCK error into EAGAIN. The GNU C library always defines EWOULDBLOCK==EAGAIN. EWOULDBLOCK_sys is the original number. */ push $t0 + cfi_adjust_cfa_offset(4) li $t0, EWOULDBLOCK_sys bne $r0, $t0, 1f pop $t0 + cfi_adjust_cfa_offset(-4) li $r0, EAGAIN 1: #endif #ifdef _LIBC_REENTRANT push $lp + cfi_adjust_cfa_offset(4) + cfi_rel_offset(lp, 0) push $r0 -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) -#else - addi $sp, $sp, -24 -#endif + cfi_adjust_cfa_offset(4) + cfi_rel_offset(r0, 0) #ifdef PIC bal C_SYMBOL_NAME(__errno_location@PLT) #else bal C_SYMBOL_NAME(__errno_location) -#endif -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) -#else - addi $sp, $sp, 24 #endif pop $r1 + cfi_adjust_cfa_offset(-4) + cfi_restore(r1) swi $r1, [$r0] li $r0, -1 pop $lp + cfi_adjust_cfa_offset(-4) + cfi_restore(lp) #ifdef PIC /* restore GP register */ popm $gp, $lp + cfi_adjust_cfa_offset(-8) + cfi_restore(lp) + cfi_restore(gp) #endif 2: ret @@ -115,6 +111,9 @@ syscall_error: /* restore GP register */ popm $gp, $lp + cfi_adjust_cfa_offset(-8) + cfi_restore(lp) + cfi_restore(gp) 2: ret diff --git a/libc/sysdeps/linux/nds32/sysdep.h b/libc/sysdeps/linux/nds32/sysdep.h index 7472a99d4..340797858 100644 --- a/libc/sysdeps/linux/nds32/sysdep.h +++ b/libc/sysdeps/linux/nds32/sysdep.h @@ -1,148 +1,96 @@ -//#include +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#ifndef _LINUX_NDS32_SYSDEP_H +#define _LINUX_NDS32_SYSDEP_H 1 + +#include + #ifdef __ASSEMBLER__ /* Define an entry point visible from C. */ -#ifdef PIC -#define ENTRY(name) \ +# ifdef PIC +# define ENTRY(name) \ .pic \ .align 2; \ .globl C_SYMBOL_NAME(name); \ .func C_SYMBOL_NAME(name); \ .type C_SYMBOL_NAME(name), @function; \ -C_SYMBOL_NAME(name): -#else -#define ENTRY(name) \ +C_SYMBOL_NAME(name): \ + cfi_startproc; + +# else +# define ENTRY(name) \ .align 2; \ .globl C_SYMBOL_NAME(name); \ .func C_SYMBOL_NAME(name); \ .type C_SYMBOL_NAME(name), @function; \ -C_SYMBOL_NAME(name): -#endif +C_SYMBOL_NAME(name): \ + cfi_startproc; +# endif #undef END #define END(name) \ + cfi_endproc; \ .endfunc; \ .size C_SYMBOL_NAME(name), .-C_SYMBOL_NAME(name) /* If compiled for profiling, call `mcount' at the start of each function. */ -#ifdef HAVE_ELF +# ifdef HAVE_ELF #undef NO_UNDERSCORES #define NO_UNDERSCORES -#endif +# endif -#ifdef NO_UNDERSCORES +# ifdef NO_UNDERSCORES #define syscall_error __syscall_error -#endif +# endif #define SYS_ify(syscall_name) (__NR_##syscall_name) #define __do_syscall(syscall_name) \ syscall SYS_ify(syscall_name); -#define SYSCALL_ERROR_HANDLER -#define SYSCALL_ERROR __syscall_error - - -#ifdef PIC -#ifdef __NDS32_N1213_43U1H__ -#ifdef NDS_ABI_V0 -#define PSEUDO(name, syscall_name, args) \ - .pic; \ - .align 2; \ - 1: ret; \ - 99: addi $r0, $lp, 0; \ - jal 1b; \ - sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_); \ - ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+4); \ - add $r1, $lp, $r1; \ - addi $lp, $r0, 0; \ - sethi $r15, hi20(SYSCALL_ERROR@PLT); \ - ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \ - add $r15, $r15, $r1; \ - jr $r15; \ - nop; \ - ENTRY(name); \ - __do_syscall(syscall_name); \ - bgez $r5, 2f; \ - sltsi $r0, $r5, -4096; \ - beqz $r0, 99b; \ - 2: -#else -#define PSEUDO(name, syscall_name, args) \ - .pic; \ - .align 2; \ - 1: ret; \ - 99: addi $r2, $lp, 0; \ - jal 1b; \ - sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_); \ - ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+4); \ - add $r1, $lp, $r1; \ - addi $lp, $r2, 0; \ - sethi $r15, hi20(SYSCALL_ERROR@PLT); \ - ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \ - add $r15, $r15, $r1; \ - jr $r15; \ - nop; \ - ENTRY(name); \ - __do_syscall(syscall_name); \ - bgez $r0, 2f; \ - sltsi $r1, $r0, -4096; \ - beqz $r1, 99b; \ - 2: -#endif -#else -#define PSEUDO(name, syscall_name, args) \ - .pic; \ - .align 2; \ - 99: mfusr $r15, $PC; \ - sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \ +# ifdef PIC +# define PSEUDO(name, syscall_name, args) \ + .pic; \ + .align 2; \ + 99: mfusr $r15, $PC; \ + sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \ ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \ - add $r1, $r15, $r1; \ - sethi $r15, hi20(SYSCALL_ERROR@PLT); \ - ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \ - add $r15, $r15, $r1; \ - jr $r15; \ - nop; \ - ENTRY(name); \ - __do_syscall(syscall_name); \ - bgez $r0, 2f; \ - sltsi $r1, $r0, -4096; \ - beqz $r1, 99b; \ + add $r1, $r15, $r1; \ + sethi $r15, hi20(SYSCALL_ERROR@PLT); \ + ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \ + add $r15, $r15, $r1; \ + jr $r15; \ + nop; \ + ENTRY(name); \ + __do_syscall(syscall_name); \ + bgez $r0, 2f; \ + sltsi $r1, $r0, -4096; \ + beqz $r1, 99b; \ 2: -#endif -#else -#ifdef OLD2_ABI -#define PSEUDO(name, syscall_name, args) \ - .align 2; \ - 99: j SYSCALL_ERROR; \ - nop; \ - ENTRY(name); \ - __do_syscall(syscall_name); \ - bgez $r5, 2f; \ - sltsi $r0, $r5, -4096; \ - beqz $r0, 99b; \ +# else +# define PSEUDO(name, syscall_name, args) \ + .align 2; \ + 99: j SYSCALL_ERROR; \ + nop; \ + ENTRY(name); \ + __do_syscall(syscall_name); \ + bgez $r0, 2f; \ + sltsi $r1, $r0, -4096; \ + beqz $r1, 99b; \ 2: -#else -#define PSEUDO(name, syscall_name, args) \ - .align 2; \ - 99: j SYSCALL_ERROR; \ - nop; \ - ENTRY(name); \ - __do_syscall(syscall_name); \ - bgez $r0, 2f; \ - sltsi $r1, $r0, -4096; \ - beqz $r1, 99b; \ - 2: -#endif -#endif +# endif -#define PSEUDO_NOERRNO(name, syscall_name, args) \ - ENTRY(name); \ +#define PSEUDO_NOERRNO(name, syscall_name, args) \ + ENTRY(name); \ __do_syscall(syscall_name); #undef PSEUDO_END -#define PSEUDO_END(sym) \ - SYSCALL_ERROR_HANDLER \ +#define PSEUDO_END(sym) \ + SYSCALL_ERROR_HANDLER \ END(sym) #undef PSEUDO_END_ERRVAL @@ -152,120 +100,65 @@ C_SYMBOL_NAME(name): #define ret_ERRVAL ret -#define ret_NOERRNO ret +#define ret_NOERRNO ret #if defined NOT_IN_libc #define SYSCALL_ERROR __local_syscall_error #ifdef PIC - #ifdef __NDS32_N1213_43U1H__ - #ifdef NDS_ABI_V0 - #define SYSCALL_ERROR_HANDLER \ - __local_syscall_error: pushm $gp, $lp, $sp; \ - jal 1f; \ - sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_); \ - ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+4); \ - add $gp, $gp, $lp; \ - neg $r5, $r5; \ - push $r5; \ - addi $sp, $sp, -28; \ - bal C_SYMBOL_NAME(__errno_location@PLT); \ - addi $sp, $sp, 28; \ - pop $r1; \ - swi $r1, [$r5]; \ - li $r5, -1; \ - popm $gp, $lp, $sp; \ - 1: ret; - #else - #define SYSCALL_ERROR_HANDLER \ - __local_syscall_error: pushm $gp, $lp, $sp; \ - jal 1f; \ - sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_); \ - ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+4); \ - add $gp, $gp, $lp; \ - neg $r0, $r0; \ - push $r0; \ - #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \ - addi $sp, $sp, -4; \ - #else \ - addi $sp, $sp, -28; \ - #endif \ - bal C_SYMBOL_NAME(__errno_location@PLT); \ - #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \ - addi $sp, $sp, 4; \ - #else \ - addi $sp, $sp, 28; \ - #endif \ - pop $r1; \ - swi $r1, [$r0]; \ - li $r0, -1; \ - popm $gp, $lp, $sp; \ - 1: ret; - #endif - #else - #define SYSCALL_ERROR_HANDLER \ - __local_syscall_error: pushm $gp, $lp, $sp; \ - mfusr $r15, $PC; \ - sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4); \ - ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8); \ - add $gp, $gp, $r15; \ - neg $r0, $r0; \ - push $r0; \ - #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \ - addi $sp, $sp, -4; \ - #else \ - addi $sp, $sp, -28; \ - #endif \ - bal C_SYMBOL_NAME(__errno_location@PLT); \ - #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \ - addi $sp, $sp, 4; \ - #else \ - addi $sp, $sp, 28; \ - #endif \ - pop $r1; \ - swi $r1, [$r0]; \ - li $r0, -1; \ - popm $gp, $lp, $sp; \ - 1: ret; - #endif + #define SYSCALL_ERROR_HANDLER \ + __local_syscall_error: \ + pushm $gp, $lp; \ + cfi_adjust_cfa_offset(8) \ + cfi_rel_offset(gp, 0) \ + cfi_rel_offset(lp, 4) \ + mfusr $r15, $PC; \ + sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4); \ + ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8); \ + add $gp, $gp, $r15; \ + neg $r0, $r0; \ + push $r0; \ + cfi_adjust_cfa_offset(4) \ + cfi_rel_offset(r0, 0) \ + addi $sp, $sp, -4; \ + bal C_SYMBOL_NAME(__errno_location@PLT); \ + addi $sp, $sp, 4; \ + pop $r1; \ + cfi_adjust_cfa_offset(-4); \ + cfi_restore(r1); \ + swi $r1, [$r0]; \ + li $r0, -1; \ + popm $gp, $lp; \ + cfi_adjust_cfa_offset(-8); \ + cfi_restore(lp); \ + cfi_restore(gp); \ + 1: ret; #else - #ifdef NDS_ABI_V0 - #define SYSCALL_ERROR_HANDLER \ - __local_syscall_error: push $lp; \ - neg $r5, $r5; \ - push $r5; \ - addi $sp, $sp, -28; \ - bal C_SYMBOL_NAME(__errno_location); \ - addi $sp, $sp, 28; \ - pop $r1; \ - swi $r1, [$r5]; \ - li $r5, -1; \ - pop $lp; \ + #define SYSCALL_ERROR_HANDLER \ + __local_syscall_error: \ + push $lp; \ + cfi_adjust_cfa_offset(4) \ + cfi_rel_offset(lp, 0) \ + neg $r0, $r0; \ + push $r0; \ + cfi_adjust_cfa_offset(4) \ + cfi_rel_offset(r0, 0) \ + addi $sp, $sp, -4; \ + bal C_SYMBOL_NAME(__errno_location); \ + addi $sp, $sp, 4; \ + pop $r1; \ + cfi_adjust_cfa_offset(-4); \ + cfi_restore(r1); \ + swi $r1, [$r0]; \ + li $r0, -1; \ + pop $lp; \ + cfi_adjust_cfa_offset(-4); \ + cfi_restore(lp); \ ret; - #else - #define SYSCALL_ERROR_HANDLER \ - __local_syscall_error: push $lp; \ - neg $r0, $r0; \ - push $r0; \ - #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \ - addi $sp, $sp, -4; \ - #else \ - addi $sp, $sp, -28; \ - #endif \ - bal C_SYMBOL_NAME(__errno_location); \ - #if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) \ - addi $sp, $sp, 4; \ - #else \ - addi $sp, $sp, 28; \ - #endif \ - pop $r1; \ - swi $r1, [$r0]; \ - li $r0, -1; \ - pop $lp; \ - ret; - #endif #endif #else #define SYSCALL_ERROR_HANDLER #define SYSCALL_ERROR __syscall_error #endif + #endif /* __ASSEMBLER__ */ +#endif //_LINUX_NDS32_SYSDEP_H diff --git a/libc/sysdeps/linux/nds32/ucontext_i.sym b/libc/sysdeps/linux/nds32/ucontext_i.sym new file mode 100644 index 000000000..1a5f2e5f3 --- /dev/null +++ b/libc/sysdeps/linux/nds32/ucontext_i.sym @@ -0,0 +1,27 @@ +#include +#include +#include + +-- + +SIG_BLOCK +SIG_SETMASK +_NSIG8 (_NSIG / 8) + +#define ucontext(member) offsetof (ucontext_t, member) +#define mcontext(member) ucontext (uc_mcontext.member) +#define mreg(reg) mcontext (nds32_##reg) + + +UCONTEXT_GREGS mcontext (nds32_r0) +#ifdef __NDS32_ABI_2FP_PLUS__ +UCONTEXT_FDREGS mcontext (fpu.fd_regs) +#endif +UCONTEXT_PC mcontext (nds32_ipc) + + +UCONTEXT_FLAGS ucontext (uc_flags) +UCONTEXT_LINK ucontext (uc_link) +UCONTEXT_STACK ucontext (uc_stack) +UCONTEXT_MCONTEXT ucontext (uc_mcontext) +UCONTEXT_SIGMASK ucontext (uc_sigmask) diff --git a/libc/sysdeps/linux/nds32/vfork.S b/libc/sysdeps/linux/nds32/vfork.S index c955359fb..ac3fa30fd 100644 --- a/libc/sysdeps/linux/nds32/vfork.S +++ b/libc/sysdeps/linux/nds32/vfork.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Andes Technology, Inc. + * Copyright (C) 2016-2017 Andes Technology, Inc. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ @@ -21,24 +21,36 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include #include - #define _ERRNO_H 1 +#include + +#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, and the process ID of the new process to the old process. */ + ENTRY (__vfork) #ifdef PIC .pic #endif #ifdef __NR_vfork - +# ifdef SAVE_PID + SAVE_PID +# endif syscall __NR_vfork +# ifdef RESTORE_PID + RESTORE_PID +# endif bltz $r0, 2f 1: ret @@ -46,42 +58,86 @@ ENTRY (__vfork) sltsi $r1, $r0, -4096 bnez $r1, 1b; +# ifdef __ASSUME_VFORK_SYSCALL # ifdef PIC - #ifdef __NDS32_N1213_43U1H__ - ! save lp - addi $r2, $lp, 0 - - ! set r1 as gp - jal 1b - sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_) - ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+4) - add $r1, $lp, $r1 - - ! restore lp - addi $lp, $r2, 0 - #else - ! set r1 as gp - mfusr $r15, $PC - sethi $r1, hi20(_GLOBAL_OFFSET_TABLE_+4) - ori $r1, $r1, lo12(_GLOBAL_OFFSET_TABLE_+8) - add $r1, $r1, $r15 - #endif + pushm $gp, $lp + cfi_adjust_cfa_offset(8) + cfi_rel_offset(gp, 0) + cfi_rel_offset(lp, 4) + mfusr $r15, $PC + sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4) + ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8) + add $gp, $gp, $r15 ! r15=C_SYMBOL_NAME(__syscall_error)@PLT - sethi $r15, hi20(C_SYMBOL_NAME(__syscall_error)@PLT) + sethi $r15, hi20(C_SYMBOL_NAME(__syscall_error)@PLT) ori $r15, $r15, lo12(C_SYMBOL_NAME(__syscall_error)@PLT) - add $r15, $r15, $r1 + add $r15, $r15, $gp ! jump to SYSCALL_ERROR - jr $r15 + jral $r15 + popm $gp, $lp + cfi_adjust_cfa_offset(-8) + cfi_restore(lp) + cfi_restore(gp) + ret # else j C_SYMBOL_NAME(__syscall_error) # endif +# else + /* Check if vfork syscall is known at all. */ + li $r1, -ENOSYS + beq $r0, $r1, 1f + +# ifdef PIC +3: + pushm $gp, $lp + cfi_adjust_cfa_offset(8) + cfi_rel_offset(gp, 0) + cfi_rel_offset(lp, 4) + mfusr $r15, $PC + sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4) + ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8) + add $gp, $gp, $r15 + + ! r15=C_SYMBOL_NAME(__syscall_error)@PLT + sethi $r15, hi20(C_SYMBOL_NAME(__syscall_error)@PLT) + ori $r15, $r15, lo12(C_SYMBOL_NAME(__syscall_error)@PLT) + add $r15, $r15, $gp + + ! jump to SYSCALL_ERROR + jral $r15 + popm $gp, $lp + cfi_adjust_cfa_offset(-8) + cfi_restore(lp) + cfi_restore(gp) + ret +# else + j C_SYMBOL_NAME(__syscall_error) +# endif +1: +# endif +#endif + +#ifndef __ASSUME_VFORK_SYSCALL + /* If we don't have vfork, fork is close enough. */ + syscall __NR_fork + bgez $r0, 1f + sltsi $r1, $r0, -4096 + bnez $r1, 1f + +# ifdef PIC + b 3b +# else + j C_SYMBOL_NAME(__syscall_error) +# endif +1: + ret -#else -# error "__NR_vfork not available" +#elif !defined __NR_vfork +# error "__NR_vfork not available and __ASSUME_VFORK_SYSCALL defined" #endif PSEUDO_END (__vfork) weak_alias (__vfork, vfork) -libc_hidden_def(vfork) +libc_hidden_def (vfork) diff --git a/libm/nds32/Makefile.arch b/libm/nds32/Makefile.arch new file mode 100644 index 000000000..bd38690be --- /dev/null +++ b/libm/nds32/Makefile.arch @@ -0,0 +1,16 @@ +# Makefile for uClibc-ng +# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + +ifeq ($(UCLIBC_HAS_FENV),y) +libm_ARCH_SRC:=$(wildcard $(libm_ARCH_DIR)/*.c) +libm_ARCH_OBJ:=$(patsubst $(libm_ARCH_DIR)/%.c,$(libm_ARCH_OUT)/%.o,$(libm_ARCH_SRC)) +endif + +libm_ARCH_OBJS:=$(libm_ARCH_OBJ) + +ifeq ($(DOPIC),y) +libm-a-y+=$(libm_ARCH_OBJS:.o=.os) +else +libm-a-y+=$(libm_ARCH_OBJS) +endif +libm-so-y+=$(libm_ARCH_OBJS:.o=.os) diff --git a/libm/nds32/e_sqrt.c b/libm/nds32/e_sqrt.c new file mode 100644 index 000000000..c737e10c6 --- /dev/null +++ b/libm/nds32/e_sqrt.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 2002-2013 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 + . */ + +#if defined(__NDS32_ABI_2FP_PLUS__) && defined(__NDS32_EXT_FPU_DP__) + +double __ieee754_sqrt (double x) +{ + double z; + __asm__ ("fsqrtd %0,%1" : "=f" (z) : "f" (x)); + return z; +} +strong_alias(__ieee754_sqrt, sqrt) +libm_hidden_def(sqrt) +#else +#include +#endif diff --git a/libm/nds32/fclrexcpt.c b/libm/nds32/fclrexcpt.c new file mode 100644 index 000000000..938f15a25 --- /dev/null +++ b/libm/nds32/fclrexcpt.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Clear given exceptions in current floating-point environment. + Copyright (C) 1997-2013 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 + . */ + +#include +#include "fenv_libc.h" +#include + + +int +feclearexcept (int excepts) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + unsigned long int temp; + + /* Mask out unsupported bits/exceptions. */ + excepts &= FE_ALL_EXCEPT; + + /* Get the current floating point status. */ + _FPU_GETCW (temp); + + /* Clear the relevant bits. */ + temp &= ~excepts; + + /* Put the new data in effect. */ + _FPU_SETCW (temp); + + /* Success. */ + return 0; +#else + /* Unsupported, so fail unless nothing needs to be done. */ + return (excepts != 0); +#endif +} diff --git a/libm/nds32/fedisblxcpt.c b/libm/nds32/fedisblxcpt.c new file mode 100644 index 000000000..bbb6d54e4 --- /dev/null +++ b/libm/nds32/fedisblxcpt.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Disable floating-point exceptions. + Copyright (C) 2001-2013 Free Software Foundation, Inc. + Contributed by Philip Blundell , 2001. + + 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 "fenv_libc.h" +#include + +int +fedisableexcept (int excepts) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + unsigned long int new_exc, old_exc; + + _FPU_GETCW(new_exc); + + old_exc = (new_exc & ENABLE_MASK) >> ENABLE_SHIFT; + + excepts &= FE_ALL_EXCEPT; + + new_exc &= ~(excepts << ENABLE_SHIFT); + new_exc &= ~_FPU_RESERVED; + _FPU_SETCW (new_exc); + + return old_exc; +#else + /* Unsupported, so return -1 for failure. */ + return -1; +#endif +} diff --git a/libm/nds32/feenablxcpt.c b/libm/nds32/feenablxcpt.c new file mode 100644 index 000000000..14aef9850 --- /dev/null +++ b/libm/nds32/feenablxcpt.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Enable floating-point exceptions. + Copyright (C) 2001-2013 Free Software Foundation, Inc. + Contributed by Philip Blundell , 2001. + + 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 "fenv_libc.h" +#include + +int +feenableexcept (int excepts) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + unsigned long int new_exc, old_exc; + + _FPU_GETCW(new_exc); + + old_exc = (new_exc & ENABLE_MASK) >> ENABLE_SHIFT; + + excepts &= FE_ALL_EXCEPT; + + new_exc |= (excepts << ENABLE_SHIFT); + new_exc &= ~_FPU_RESERVED; + + _FPU_SETCW(new_exc); + + return old_exc; +#else + /* Unsupported, so return -1 for failure. */ + return -1; +#endif +} diff --git a/libm/nds32/fegetenv.c b/libm/nds32/fegetenv.c new file mode 100644 index 000000000..782cf793e --- /dev/null +++ b/libm/nds32/fegetenv.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Store current floating-point environment. + Copyright (C) 1997-2013 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 + . */ + +#include +#include + +int +fegetenv (fenv_t *envp) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + unsigned long int temp; + _FPU_GETCW (temp); + envp->__fpcsr = temp; + + /* Success. */ + return 0; +#else + /* Unsupported, so fail. */ + return 1; +#endif +} diff --git a/libm/nds32/fegetexcept.c b/libm/nds32/fegetexcept.c new file mode 100644 index 000000000..1ffe361cc --- /dev/null +++ b/libm/nds32/fegetexcept.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Get floating-point exceptions. + Copyright (C) 2001-2013 Free Software Foundation, Inc. + Contributed by Philip Blundell , 2001 + + 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 "fenv_libc.h" +#include + +int +fegetexcept (void) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + unsigned long temp; + + _FPU_GETCW (temp); + + return (temp & ENABLE_MASK) >> ENABLE_SHIFT; +#else + /* Unsupported. Return all exceptions disabled. */ + return 0; +#endif +} diff --git a/libm/nds32/fegetround.c b/libm/nds32/fegetround.c new file mode 100644 index 000000000..e4e70eaad --- /dev/null +++ b/libm/nds32/fegetround.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Return current rounding direction. + Copyright (C) 2004-2013 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 + . */ + +#include +#include + +int +fegetround (void) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + unsigned int temp; + + /* Get the current environment. */ + _FPU_GETCW (temp); + + return temp & 0x3; +#else + /* The current soft-float implementation only handles TONEAREST. */ + return FE_TONEAREST; +#endif +} diff --git a/libm/nds32/feholdexcpt.c b/libm/nds32/feholdexcpt.c new file mode 100644 index 000000000..4ea3679f5 --- /dev/null +++ b/libm/nds32/feholdexcpt.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Store current floating-point environment and clear exceptions. + Copyright (C) 1997-2013 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 + . */ + +#include +#include +#include "fenv_libc.h" + +int +feholdexcept (fenv_t *envp) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + unsigned long int temp; + + /* Store the environment. */ + _FPU_GETCW(temp); + envp->__fpcsr = temp; + + /* Now set all exceptions to non-stop. */ + temp &= ~(FE_ALL_EXCEPT << ENABLE_SHIFT); + + /* And clear all exception flags. */ + temp &= ~FE_ALL_EXCEPT; + + _FPU_SETCW(temp); + + return 0; +#else + /* Unsupported, so fail. */ + return 1; +#endif +} + diff --git a/libm/nds32/fenv_libc.h b/libm/nds32/fenv_libc.h new file mode 100644 index 000000000..a76f131e4 --- /dev/null +++ b/libm/nds32/fenv_libc.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 2000-2013 Free Software Foundation, Inc. + Contributed by Alexandre Oliva + based on the corresponding file in the mips port. + + 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 _FENV_LIBC_H +#define _FENV_LIBC_H + +/* Mask for enabling exceptions and for the CAUSE bits. */ +#define ENABLE_MASK 0x00F80U + +/* Shift for FE_* flags to get up to the ENABLE bits. */ +#define ENABLE_SHIFT 5 + +#endif /* _FENV_LIBC_H */ diff --git a/libm/nds32/fesetenv.c b/libm/nds32/fesetenv.c new file mode 100644 index 000000000..4682d3c8e --- /dev/null +++ b/libm/nds32/fesetenv.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Install given floating-point environment. + Copyright (C) 2004-2013 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 + . */ + +#include +#include + +int +fesetenv (const fenv_t *envp) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + unsigned int temp; + + _FPU_GETCW (temp); + temp &= _FPU_RESERVED; + + if (envp == FE_DFL_ENV) + temp |= _FPU_DEFAULT; + else if (envp == FE_NOMASK_ENV) + temp |= _FPU_IEEE; + else + temp |= envp->__fpcsr & ~_FPU_RESERVED; + + _FPU_SETCW (temp); + + /* Success. */ + return 0; +#else + + /* Unsupported, so fail. */ + return 1; +#endif +} diff --git a/libm/nds32/fesetround.c b/libm/nds32/fesetround.c new file mode 100644 index 000000000..012a5bfff --- /dev/null +++ b/libm/nds32/fesetround.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Set current rounding direction. + Copyright (C) 2004-2013 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 + . */ + +#include +#include + +int +fesetround (int round) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + fpu_control_t temp; + if ((round & ~0x3) != 0) + /* ROUND is no valid rounding mode. */ + return 1; + + _FPU_GETCW (temp); + temp = (temp & ~0x3) | round; + _FPU_SETCW (temp); + return 0; +#else + return (round != FE_TONEAREST); +#endif +} diff --git a/libm/nds32/feupdateenv.c b/libm/nds32/feupdateenv.c new file mode 100644 index 000000000..d58c9004b --- /dev/null +++ b/libm/nds32/feupdateenv.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Install given floating-point environment and raise exceptions. + Copyright (C) 1997-2013 Free Software Foundation, Inc. + Contributed by Ulrich Drepper , 1997. + + 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 + +int +feupdateenv (const fenv_t *envp) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + unsigned int temp; + + /* Get the current exception state. */ + _FPU_GETCW (temp); + + /* Install new environment. */ + fesetenv (envp); + + /* Raise the saved exceptions. */ + feraiseexcept (temp & FE_ALL_EXCEPT); + + /* Success. */ + return 0; +#else + /* Unsupported, so fail. */ + return 1; +#endif +} diff --git a/libm/nds32/fgetexcptflg.c b/libm/nds32/fgetexcptflg.c new file mode 100644 index 000000000..e446c429c --- /dev/null +++ b/libm/nds32/fgetexcptflg.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Store current representation for exceptions. + Copyright (C) 1997-2013 Free Software Foundation, Inc. + Contributed by Ulrich Drepper , 1997. + + 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 + +int +fegetexceptflag (fexcept_t *flagp, int excepts) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + fpu_control_t temp; + + /* Get the current exceptions. */ + _FPU_GETCW (temp); + + *flagp = temp & excepts & FE_ALL_EXCEPT; + + /* Success. */ + return 0; +#else + /* Unsupported, so fail. */ + return 1; +#endif +} diff --git a/libm/nds32/fraiseexcpt.c b/libm/nds32/fraiseexcpt.c new file mode 100644 index 000000000..d1942110c --- /dev/null +++ b/libm/nds32/fraiseexcpt.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Raise given exceptions. + Copyright (C) 2004-2013 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 + . */ + +#include +#include +#include +#include "fenv_libc.h" + +int +feraiseexcept (int excepts) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + float temp1 = 0.0, temp2 = 1.0; + if (FE_INVALID & excepts) + { + __asm__ volatile( + "fmtsr\t %0, $fs0\n\t" + "fdivs\t $fs0, $fs0, $fs0\n\t" + : + :"r"(temp1) + :"$fs0" + ); + } + if (FE_DIVBYZERO & excepts) + { + __asm__ volatile( + "fmtsr\t %0, $fs0\n\t" + "fmtsr\t %1, $fs1\n\t" + "fdivs\t $fs0, $fs1, $fs0\n\t" + : + :"r"(temp1),"r"(temp2) + :"$fs0" + ); + } + if (FE_OVERFLOW & excepts) + { + /* There's no way to raise overflow without also raising inexact. + */ + unsigned int fpcsr; + temp1 = FLT_MAX; + __asm__ volatile( + "fmfcsr\t %0\n\t" + "fmtsr\t %1, $fs0\n\t" + "fadds\t $fs0, $fs0, $fs0\n\t" + "ori\t %0,%0,0x10\n\t" + "fmtcsr\t %0\n\t" + :"=&r"(fpcsr) + :"r"(temp1) + :"$fs0" + ); + } + if (FE_UNDERFLOW & excepts) + { + /* There's no way to raise overflow without also raising inexact. + */ + temp1 = FLT_MIN; + temp2 = 2.0; + __asm__ volatile( + "fmtsr\t %0, $fs0\n\t" + "fmtsr\t %1, $fs1\n\t" + "fdivs\t $fs1, $fs0, $fs1\n\t" + : + :"r"(temp1),"r"(temp2) + :"$fs0","$fs1" + ); + } + if (FE_INEXACT & excepts) + { + temp1 = 3.0; + __asm__ volatile( + "fmtsr\t %0, $fs1\n\t" + "fmtsr\t %1, $fs0\n\t" + "fdivs\t $fs1, $fs0, $fs1\n\t" + : + :"r"(temp1),"r"(temp2) + :"$fs0","$fs1" + ); + } + + return 0; + +#endif + /* Unsupported, so fail unless nothing needs to be done. */ + return (excepts != 0); +} diff --git a/libm/nds32/fsetexcptflg.c b/libm/nds32/fsetexcptflg.c new file mode 100644 index 000000000..7da943b9d --- /dev/null +++ b/libm/nds32/fsetexcptflg.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Set floating-point environment exception handling. + Copyright (C) 1997-2013 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 + . */ + +#include +#include + +int +fesetexceptflag (const fexcept_t *flagp, int excepts) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + fexcept_t temp; + + /* Get the current environment. */ + _FPU_GETCW (temp); + + /* Set the desired exception mask. */ + temp &= ~(excepts & FE_ALL_EXCEPT); + temp |= (*flagp & excepts & FE_ALL_EXCEPT); + + /* Save state back to the FPU. */ + _FPU_SETCW (temp); + + /* Success. */ + return 0; +#else + /* Unsupported, so fail unless nothing needs to be done. */ + return (excepts != 0); +#endif +} diff --git a/libm/nds32/ftestexcept.c b/libm/nds32/ftestexcept.c new file mode 100644 index 000000000..8257b6f45 --- /dev/null +++ b/libm/nds32/ftestexcept.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Test exception in current environment. + Copyright (C) 1997-2013 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 + . */ + +#include +#include + +int +fetestexcept (int excepts) +{ +#ifdef __NDS32_ABI_2FP_PLUS__ + fexcept_t temp; + + /* Get current exceptions. */ + _FPU_GETCW(temp); + + return temp & excepts & FE_ALL_EXCEPT; +#else + /* Unsupported, return 0. */ + return 0; +#endif +} diff --git a/libpthread/linuxthreads/sysdeps/nds32/pspinlock.c b/libpthread/linuxthreads/sysdeps/nds32/pspinlock.c index f8adf07be..770a55ab3 100644 --- a/libpthread/linuxthreads/sysdeps/nds32/pspinlock.c +++ b/libpthread/linuxthreads/sysdeps/nds32/pspinlock.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Andes Technology, Inc. + * Copyright (C) 2016-2017 Andes Technology, Inc. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ diff --git a/libpthread/linuxthreads/sysdeps/nds32/pt-machine.h b/libpthread/linuxthreads/sysdeps/nds32/pt-machine.h index 5bbb9e850..631c28491 100644 --- a/libpthread/linuxthreads/sysdeps/nds32/pt-machine.h +++ b/libpthread/linuxthreads/sysdeps/nds32/pt-machine.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Andes Technology, Inc. + * Copyright (C) 2016-2017 Andes Technology, Inc. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ diff --git a/libpthread/nptl/sysdeps/nds32/Makefile.arch b/libpthread/nptl/sysdeps/nds32/Makefile.arch new file mode 100644 index 000000000..7eb852af1 --- /dev/null +++ b/libpthread/nptl/sysdeps/nds32/Makefile.arch @@ -0,0 +1,16 @@ +# Makefile for uClibc-ng NPTL +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +ASFLAGS-dl-tlsdesc.S = -DNOT_IN_libc=1 +libc_arch_a_SSRC = libc-dl-tlsdesc.S + +CFLAGS-gen_tlsdesc.c = -S +$(libpthread_arch_OUT)/gen_tlsdesc.c: $(libpthread_arch_DIR)/tlsdesc.sym | $(libpthread_arch_OUT) + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ +$(libpthread_arch_OUT)/gen_tlsdesc.s: $(libpthread_arch_OUT)/gen_tlsdesc.c | headers + $(compile.c) +libpthread-generated-y += $(libpthread_arch_OUT)/gen_tlsdesc.s +$(libpthread_arch_OUT)/tlsdesc.h: $(libpthread_arch_OUT)/gen_tlsdesc.s + $(do_sed) $(PTHREAD_GENERATE_MANGLE) $< > $@ + @if test ! -s $@ ; then rm -f $@ ; false ; fi +pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(libpthread_arch_OUT)/tlsdesc.h diff --git a/libpthread/nptl/sysdeps/nds32/dl-tls.h b/libpthread/nptl/sysdeps/nds32/dl-tls.h new file mode 100644 index 000000000..3b11e7f42 --- /dev/null +++ b/libpthread/nptl/sysdeps/nds32/dl-tls.h @@ -0,0 +1,59 @@ +/* Thread-local storage handling in the ELF dynamic linker. NDS32 version. + Copyright (C) 2013 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 _NDS32_DL_TLS_H +#define _NDS32_DL_TLS_H 1 + + +/* Type used to represent a TLS descriptor. */ +struct tlsdesc +{ + ptrdiff_t (*entry)(struct tlsdesc *); + union + { + void *pointer; + long value; + } argument; +}; + +/* 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; + + +/* Type used as the argument in a TLS descriptor for a symbol that + * needs dynamic TLS offsets. */ +struct tlsdesc_dynamic_arg +{ + tls_index tlsinfo; + size_t gen_count; +}; + + +extern void *__tls_get_addr (tls_index *ti); + +extern ptrdiff_t attribute_hidden + _dl_tlsdesc_return(struct tlsdesc_dynamic_arg *); + +extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset); +extern ptrdiff_t attribute_hidden + _dl_tlsdesc_dynamic(struct tlsdesc *); + +#endif //_NDS32_DL_TLS_H diff --git a/libpthread/nptl/sysdeps/nds32/libc-dl-tlsdesc.S b/libpthread/nptl/sysdeps/nds32/libc-dl-tlsdesc.S new file mode 100644 index 000000000..5892a8b28 --- /dev/null +++ b/libpthread/nptl/sysdeps/nds32/libc-dl-tlsdesc.S @@ -0,0 +1 @@ +#include diff --git a/libpthread/nptl/sysdeps/nds32/pthread_spin_lock.c b/libpthread/nptl/sysdeps/nds32/pthread_spin_lock.c new file mode 100644 index 000000000..cec3acbc6 --- /dev/null +++ b/libpthread/nptl/sysdeps/nds32/pthread_spin_lock.c @@ -0,0 +1,65 @@ +/* pthread_spin_lock -- lock a spin lock. Generic version. + Copyright (C) 2012-2016 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 + . */ + +#include +#include "pthreadP.h" + +/* A machine-specific version can define SPIN_LOCK_READS_BETWEEN_CMPXCHG + to the number of plain reads that it's optimal to spin on between uses + of atomic_compare_and_exchange_val_acq. If spinning forever is optimal + then use -1. If no plain reads here would ever be optimal, use 0. */ +#define SPIN_LOCK_READS_BETWEEN_CMPXCHG 1000 + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ + /* atomic_exchange usually takes less instructions than + atomic_compare_and_exchange. On the other hand, + atomic_compare_and_exchange potentially generates less bus traffic + when the lock is locked. + We assume that the first try mostly will be successful, and we use + atomic_exchange. For the subsequent tries we use + atomic_compare_and_exchange. */ + if (atomic_exchange_acq (lock, 1) == 0) + return 0; + + do + { + /* The lock is contended and we need to wait. Going straight back + to cmpxchg is not a good idea on many targets as that will force + expensive memory synchronizations among processors and penalize other + running threads. + On the other hand, we do want to update memory state on the local core + once in a while to avoid spinning indefinitely until some event that + will happen to update local memory as a side-effect. */ + if (SPIN_LOCK_READS_BETWEEN_CMPXCHG >= 0) + { + int wait = SPIN_LOCK_READS_BETWEEN_CMPXCHG; + + while (*lock != 0 && wait > 0) + --wait; + } + else + { + while (*lock != 0) + ; + } + } + while (atomic_compare_and_exchange_val_acq (lock, 1, 0) != 0); + + return 0; +} diff --git a/libpthread/nptl/sysdeps/nds32/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/nds32/pthread_spin_trylock.c new file mode 100644 index 000000000..4e9aa64d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/nds32/pthread_spin_trylock.c @@ -0,0 +1,26 @@ +/* pthread_spin_trylock -- trylock a spin lock. Generic version. + Copyright (C) 2012-2016 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 + . */ + +#include +#include +#include "pthreadP.h" + +int +pthread_spin_trylock (pthread_spinlock_t *lock) +{ + return atomic_exchange_acq (lock, 1) ? EBUSY : 0; +} diff --git a/libpthread/nptl/sysdeps/nds32/pthreaddef.h b/libpthread/nptl/sysdeps/nds32/pthreaddef.h new file mode 100644 index 000000000..c9d3f7781 --- /dev/null +++ b/libpthread/nptl/sysdeps/nds32/pthreaddef.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002, 2003 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 + . */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. SSE requires 16 + bytes. */ +#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/libpthread/nptl/sysdeps/nds32/tcb-offsets.sym b/libpthread/nptl/sysdeps/nds32/tcb-offsets.sym new file mode 100644 index 000000000..3b9e10186 --- /dev/null +++ b/libpthread/nptl/sysdeps/nds32/tcb-offsets.sym @@ -0,0 +1,12 @@ +#include +#include + +-- + +-- 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/libpthread/nptl/sysdeps/nds32/tls.h b/libpthread/nptl/sysdeps/nds32/tls.h new file mode 100644 index 000000000..e2a38626d --- /dev/null +++ b/libpthread/nptl/sysdeps/nds32/tls.h @@ -0,0 +1,178 @@ +/* Definition for thread-local data handling. NPTL/NDS32 version. + Copyright (C) 2005, 2007 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 _TLS_H +#define _TLS_H 1 + + +#ifndef __ASSEMBLER__ +# include +# include +# include + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 +#define HAVE___THREAD 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include + +/* The TP points to the start of the thread blocks. */ +# define TLS_DTV_AT_TP 1 + +/* We use the multiple_threads field in the pthread struct */ +#define TLS_MULTIPLE_THREADS_IN_TCB 1 + +/* Get the thread descriptor definition. */ +# include <../../descr.h> + +/* The stack_guard is accessed directly by GCC -fstack-protector code, + so it is a part of public ABI. The dtv and pointer_guard fields + are private. */ +typedef struct +{ + dtv_t *dtv; + void *private; +} tcbhead_t; + +/* This is the size of the initial TCB. */ +# 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. */ +# 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))) + +/* Return the thread descriptor (tp) for the current thread. */ +register void *__thread_pointer __asm__ ("$r25"); + + +/* The thread pointer (in hardware register tp) points to the end of + the TCB. The pthread_descr structure is immediately in front of the TCB. */ +#ifndef TLS_TCB_OFFSET +# define TLS_TCB_OFFSET 0 +#endif + +/* 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 (tp). */ +# define TLS_INIT_TP(tcbp, secondcall) \ + (__thread_pointer = (char *)(tcbp) + TLS_TCB_OFFSET, NULL) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *) (__thread_pointer - TLS_TCB_OFFSET))[-1].dtv) + +/* Return the thread descriptor for the current thread. */ +# define THREAD_SELF \ + ((struct pthread *) (__thread_pointer \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + REGISTER (32, 32, 152, - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(descr, member) (descr->member) + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member, idx) \ + (descr->member[idx]) + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM(descr, member, value) \ + (descr->member = (value)) + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + (descr->member[idx] = (value)) + + +/* l_tls_offset == 0 is perfectly valid on Tile, 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/libpthread/nptl/sysdeps/nds32/tlsdesc.sym b/libpthread/nptl/sysdeps/nds32/tlsdesc.sym new file mode 100644 index 000000000..4fa3adacf --- /dev/null +++ b/libpthread/nptl/sysdeps/nds32/tlsdesc.sym @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +#define dtv_offsetof(dtv) (long)(offsetof(tcbhead_t, dtv) - sizeof (tcbhead_t)) +DTV_OFFSET dtv_offsetof(dtv) + +TLSDESC_ARG offsetof(struct tlsdesc, argument.pointer) + +TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count) +TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module) +TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile new file mode 100644 index 000000000..2caba11b7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile @@ -0,0 +1,9 @@ +# Makefile for uClibc-ng NPTL +# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch new file mode 100644 index 000000000..3b8935ce5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch @@ -0,0 +1,12 @@ +# Makefile for uClibc-ng NPTL +# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + +libpthread_linux_arch_SSRC = +libpthread_linux_arch_CSRC = pthread_once.c + +libc_linux_arch_CSRC = fork.c +libc_linux_arch_SSRC = clone.S vfork.S +libc_linux_arch_SSRC-OMIT = waitpid.S + +CFLAGS += $(SSP_ALL_CFLAGS) + diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h new file mode 100644 index 000000000..695a61fdd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h @@ -0,0 +1,177 @@ +/* Copyright (C) 2002,2003,2004,2005,2006,2007 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, 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 + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + +union pthread_attr_t +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +}; +#ifndef __have_pthread_attr_t +typedef union pthread_attr_t pthread_attr_t; +# define __have_pthread_attr_t 1 +#endif + + +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned char __flags; + unsigned char __shared; + unsigned char __pad1; + unsigned char __pad2; + 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 +/* Extra attributes for the cleanup functions. */ +/* + FIXME, check this after gcc uprgrade. + #define __cleanup_fct_attribute __attribute__ ((__regparm__ (1))) + warning: '__regparm__' attribute directive ignored +*/ + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h new file mode 100644 index 000000000..8ee77429a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Ulrich Drepper , 2002. + + 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 directly; include instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S new file mode 100644 index 000000000..94b39fcf9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S @@ -0,0 +1,4 @@ +/* We want an #include_next, but we are the main source file. + So, #include ourselves and in that incarnation we can use #include_next. */ +# define RESET_PID +# include diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c new file mode 100644 index 000000000..486bc24f5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c @@ -0,0 +1,22 @@ +/* Copyright (C) 2005-2013 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 + . */ + +/* 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 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c new file mode 100644 index 000000000..beb6cb0f7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c @@ -0,0 +1,27 @@ +/* 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 +#include + +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 5, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \ + NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/lowlevellock.h new file mode 100644 index 000000000..32b004486 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/lowlevellock.h @@ -0,0 +1,323 @@ +/* Copyright (C) 2005-2013 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 _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include +#include +#include +#include +#include +#include + + +#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_WAIT_REQUEUE_PI 11 +#define FUTEX_CMP_REQUEUE_PI 12 +#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_timed_wait_bitset(futexp, val, timespec, clockbit, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + int __op = FUTEX_WAIT_BITSET | clockbit; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + __lll_private_flag (__op, private), \ + (val), (timespec), NULL /* Unused. */, \ + FUTEX_BITSET_MATCH_ANY); \ + __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); \ + }) + +/* Priority Inheritance support. */ +#define lll_futex_wait_requeue_pi(futexp, val, mutex, private) \ + lll_futex_timed_wait_requeue_pi (futexp, val, NULL, 0, mutex, private) + +#define lll_futex_timed_wait_requeue_pi(futexp, val, timespec, clockbit, \ + mutex, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + int __op = FUTEX_WAIT_REQUEUE_PI | clockbit; \ + \ + INTERNAL_SYSCALL (futex, __err, 5, (futexp), \ + __lll_private_flag (__op, private), \ + (val), (timespec), mutex); \ + }) + +#define lll_futex_cmp_requeue_pi(futexp, nr_wake, nr_move, mutex, val, priv) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + __lll_private_flag (FUTEX_CMP_REQUEUE_PI, priv),\ + (nr_wake), (nr_move), (mutex), (val)); \ + 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(futex, id) \ + (atomic_compare_and_exchange_val_acq (futex, id, 0) != 0) +#define lll_robust_trylock(lock, id) \ + __lll_robust_trylock (&(lock), id) + +extern void __lll_lock_wait_private (int *futex) attribute_hidden; +extern void __lll_lock_wait (int *futex, int private) attribute_hidden; +extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden; + +#define __lll_lock(futex, private) \ + ((void) ({ \ + int *__futex = (futex); \ + if (__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); \ + 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); \ + 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_CHILD_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/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c new file mode 100644 index 000000000..6c0d4b5d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c @@ -0,0 +1,18 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + Contributed by Ulrich Drepper , 2002. + + 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 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c new file mode 100644 index 000000000..ce68ce68c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2003-2013 Free Software Foundation, Inc. + Contributed by Jakub Jelinek , 2003. + + 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 "pthreadP.h" +#include + + +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 (once_control, init_routine) + pthread_once_t *once_control; + void (*init_routine) (void); +{ + while (1) + { + int oldval, val, newval; + + val = *once_control; + do + { + /* Check if the initialized has already been done. */ + if ((val & 2) != 0) + return 0; + + oldval = val; + newval = (oldval & 3) | __fork_generation | 1; + val = atomic_compare_and_exchange_val_acq (once_control, newval, + oldval); + } + while (__builtin_expect (val != oldval, 0)); + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) != 0) + { + /* Check whether the initializer execution was interrupted + by a fork. */ + if (((oldval ^ newval) & -4) == 0) + { + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, newval, LLL_PRIVATE); + continue; + } + } + + /* 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); + + + /* Add one to *once_control. */ + atomic_increment (once_control); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); + break; + } + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h new file mode 100644 index 000000000..a0f4de5c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 2003-2013 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 + . */ + +#include +#include +#ifndef __ASSEMBLER__ +# include +#endif + + + +#define PUSHARGS_0 +#define PUSHARGS_1 smw.adm $r0, [$sp], $r0, #0; \ + cfi_adjust_cfa_offset(4); \ + cfi_rel_offset(r0,0); \ + addi $sp, $sp, -4; \ + cfi_adjust_cfa_offset(4); +#define PUSHARGS_2 smw.adm $r0, [$sp], $r1, #0; \ + cfi_adjust_cfa_offset(8); \ + cfi_rel_offset(r1, 4); \ + cfi_rel_offset(r0, 0); +#define PUSHARGS_3 smw.adm $r0, [$sp], $r2, #0; \ + cfi_adjust_cfa_offset(12); \ + cfi_rel_offset(r2, 8); \ + cfi_rel_offset(r1, 4); \ + cfi_rel_offset(r0, 0); \ + addi $sp, $sp, -4; \ + cfi_adjust_cfa_offset(4); +#define PUSHARGS_4 smw.adm $r0, [$sp], $r3, #0; \ + cfi_adjust_cfa_offset(16); \ + cfi_rel_offset(r3, 12); \ + cfi_rel_offset(r2, 8); \ + cfi_rel_offset(r1, 4); \ + cfi_rel_offset(r0, 0); +#define PUSHARGS_5 smw.adm $r0, [$sp], $r4, #0; \ + cfi_adjust_cfa_offset(20); \ + cfi_rel_offset(r4, 16); \ + cfi_rel_offset(r3, 12); \ + cfi_rel_offset(r2, 8); \ + cfi_rel_offset(r1, 4); \ + cfi_rel_offset(r0, 0); \ + addi $sp, $sp, -4; \ + cfi_adjust_cfa_offset(4); +#define PUSHARGS_6 smw.adm $r0, [$sp], $r5, #0; \ + cfi_adjust_cfa_offset(24); \ + cfi_rel_offset(r5, 20); \ + cfi_rel_offset(r4, 16); \ + cfi_rel_offset(r3, 12); \ + cfi_rel_offset(r2, 8); \ + cfi_rel_offset(r1, 4); \ + cfi_rel_offset(r0, 0); + +#define POPARGS2_0 +#define POPARGS2_1 addi $sp, $sp, 4; \ + cfi_adjust_cfa_offset(-4); \ + lmw.bim $r0, [$sp], $r0, #0; \ + cfi_adjust_cfa_offset(-4); \ + cfi_restore(r0); +#define POPARGS2_2 lmw.bim $r0, [$sp], $r1, #0; \ + cfi_adjust_cfa_offset(-8); \ + cfi_restore(r0); \ + cfi_restore(r1); +#define POPARGS2_3 addi $sp, $sp, 4; \ + cfi_adjust_cfa_offset(-4); \ + lmw.bim $r0, [$sp], $r2, #0; \ + cfi_adjust_cfa_offset(-12); \ + cfi_restore(r0); \ + cfi_restore(r1); \ + cfi_restore(r2); +#define POPARGS2_4 lmw.bim $r0, [$sp], $r3, #0; \ + cfi_adjust_cfa_offset(-16); \ + cfi_restore(r0); \ + cfi_restore(r1); \ + cfi_restore(r2); \ + cfi_restore(r3); +#define POPARGS2_5 addi $sp, $sp, 4; \ + cfi_adjust_cfa_offset(-4); \ + lmw.bim $r0, [$sp], $r4, #0; \ + cfi_adjust_cfa_offset(-20); \ + cfi_restore(r0); \ + cfi_restore(r1); \ + cfi_restore(r2); \ + cfi_restore(r3); \ + cfi_restore(r4); +#define POPARGS2_6 lmw.bim $r0, [$sp], $r5, #0; \ + cfi_adjust_cfa_offset(-24); \ + cfi_restore(r0); \ + cfi_restore(r1); \ + cfi_restore(r2); \ + cfi_restore(r3); \ + cfi_restore(r4); \ + cfi_restore(r5); + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +/* NOTE: We do mark syscalls with unwind annotations, for the benefit of + cancellation; but they're really only accurate at the point of the + syscall. The ARM unwind directives are not rich enough without adding + a custom personality function. */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .align 2; \ + ENTRY (__##syscall_name##_nocancel); \ + __do_syscall(syscall_name); \ + PSEUDO_RET; \ + ret; \ + END (__##syscall_name##_nocancel); \ + ENTRY (name); \ + smw.adm $r6,[$sp],$r6,0x2; \ + cfi_adjust_cfa_offset(8); \ + cfi_offset(r6,-8); \ + cfi_offset(lp,-4); \ + SINGLE_THREAD_P ($r15); \ + bgtz $r15, .Lpseudo_cancel; \ + __do_syscall(syscall_name); \ + j 50f; \ + .Lpseudo_cancel: \ + PUSHARGS_##args; /* save syscall args etc. around CENABLE. */ \ + CENABLE ($r5); \ + mov55 $r6, $r0; /* put mask in safe place. */ \ + POPARGS2_##args; \ + __do_syscall(syscall_name); /* do the call. */ \ + push $r0; \ + cfi_adjust_cfa_offset(4); \ + cfi_rel_offset(r0, 0); \ + addi $sp, $sp, -4; \ + cfi_adjust_cfa_offset(4); \ + mov55 $r0, $r6; /* save syscall return value. */\ + CDISABLE($r5); \ + addi $sp, $sp, 4; \ + cfi_adjust_cfa_offset(-4); \ + pop $r0; /* retrieve return value. */ \ + cfi_adjust_cfa_offset(-4); \ + cfi_restore(r0); \ +50: \ + lmw.bim $r6,[$sp],$r6, 0x2; \ + cfi_adjust_cfa_offset(-8); \ + cfi_restore(lp); \ + cfi_restore(r6); \ + PSEUDO_RET; +# ifndef __ASSEMBLER__ +//# if defined IS_IN_libpthread || !defined NOT_IN_libc +//extern int __local_multiple_threads attribute_hidden; +//# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +//# else +/* There is no __local_multiple_threads for librt */ +# define SINGLE_THREAD_P __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +//# endif +# else +# define SINGLE_THREAD_P(reg) \ + addi reg, $r25, MULTIPLE_THREADS_OFFSET; \ + lw reg, [reg]; +# define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P(x) +# endif + + +# ifdef IS_IN_libpthread +# define CENABLE(reg) jmp(reg, __pthread_enable_asynccancel) +# define CDISABLE(reg) jmp(reg, __pthread_disable_asynccancel) +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE(reg) jmp(reg, __libc_enable_asynccancel) +# define CDISABLE(reg) jmp(reg, __libc_disable_asynccancel) +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define CENABLE(reg) jmp(reg, __librt_enable_asynccancel) +# define CDISABLE(reg) jmp(reg, __librt_disable_asynccancel) +# else +# error Unsupported library +# endif + +#elif !defined __ASSEMBLER__ + +/* For rtld, et cetera. */ +# 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 + + + +#ifdef PIC +#define PSEUDO_RET \ + .pic \ + .align 2; \ + bgez $r0, 1f; \ + sltsi $r1, $r0, -4096; \ + bgtz $r1, 1f; \ + PIC_jmp_err \ + nop; \ + 1: +#else /* PIC*/ +#define PSEUDO_RET \ + .align 2; \ + bgez $r0, 1f; \ + sltsi $r1, $r0, -4096; \ + bgtz $r1, 1f; \ + j SYSCALL_ERROR; \ + 1: +#endif + +#ifdef PIC +#define jmp(reg, symble) PIC_jmpr(reg, symble) +/* reg: available register */ +#define PIC_jmp_err \ + smw.adm $sp,[$sp],$sp,#0x6; \ + mfusr $r15, $PC; \ + sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \ + ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \ + add $gp, $r15, $gp; \ + sethi $r15, hi20(SYSCALL_ERROR@PLT); \ + ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \ + add $r15, $r15, $gp; \ + jral $r15; \ + lmw.bim $sp,[$sp],$sp,#0x6; \ + ret; + +#define PIC_jmp(reg, symble) \ + mfusr $r15, $PC; \ + sethi reg, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \ + ori reg, reg, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \ + add reg, $r15, reg; \ + sethi $r15, hi20(symble@PLT); \ + ori $r15, $r15, lo12(symble@PLT); \ + add $r15, $r15, reg; \ + jr $r15; + + +#define PIC_jmpr(reg, symble) \ + mfusr $r15, $PC; \ + sethi reg, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \ + ori reg, reg, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \ + add reg, $r15, reg; \ + sethi $r15, hi20(symble@PLT); \ + ori $r15, $r15, lo12(symble@PLT); \ + add $r15, $r15, reg; \ + jral $r15; + +#else +#define jmp(reg, symble) jal symble +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S new file mode 100644 index 000000000..f11f76ae1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 2013 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 + . */ + +#include + +/* Save the PID value. */ +#define SAVE_PID \ + lwi $r1, [$r25 + PID_OFFSET];/* Get the thread pointer. */ \ + subri $r1, $r1, 0x0; /* Negate it. */ \ + bnez $r1, 1f; /* If it was zero... */ \ + sethi $r1, 0x80000; /* use 0x80000000 instead. */ \ +1: swi $r1, [$r25 + PID_OFFSET];/* Store the temporary PID. */ + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + beqz $r0, 1f; /* If we are the parent... */ \ + lwi $r1, [$r25 + PID_OFFSET];/* Get the thread pointer. */ \ + subri $r1, $r1, 0x0; /* Re-negate it. */ \ + sethi $r2, 0x80000; /* Load 0x80000000... */ \ + bne $r1, $r2, 2f; /* ... compare against it... */ \ + movi $r1, 0; /* ... use 0 instead. */ \ +2: swi $r1, [$r25 + PID_OFFSET];/* Restore the PID. */ \ +1: + +#include <../../../../../../../libc/sysdeps/linux/nds32/vfork.S> -- cgit v1.2.3