]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
RISC-V: Linux Syscall Interface
authorPalmer Dabbelt <palmer@dabbelt.com>
Mon, 29 Jan 2018 18:27:52 +0000 (10:27 -0800)
committerPalmer Dabbelt <palmer@dabbelt.com>
Mon, 29 Jan 2018 18:27:52 +0000 (10:27 -0800)
Contains the Linux system call interface, as well as the definitions of
a handful of system calls.

2018-01-29  Palmer Dabbelt  <palmer@sifive.com>

        * sysdeps/riscv/nptl/nptl-sysdep.S: New file.
        * sysdeps/unix/sysv/linux/riscv/arch-fork.h: Likewise.
        * sysdeps/unix/sysv/linux/riscv/clone.S: Likewise.
        * sysdeps/unix/sysv/linux/riscv/profil-counter.h: Likewise.
        * sysdeps/unix/sysv/linux/riscv/pt-vfork.S: Likewise.
        * sysdeps/unix/sysv/linux/riscv/syscall.c: Likewise.
        * sysdeps/unix/sysv/linux/riscv/sysdep.S: Likewise.
        * sysdeps/unix/sysv/linux/riscv/sysdep.h: Likewise.
        * sysdeps/unix/sysv/linux/riscv/vfork.S: Likewise.

ChangeLog
sysdeps/riscv/nptl/nptl-sysdep.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/riscv/arch-fork.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/riscv/clone.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/riscv/profil-counter.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/riscv/pt-vfork.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/riscv/syscall.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/riscv/sysdep.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/riscv/sysdep.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/riscv/vfork.S [new file with mode: 0644]

index 6df255ba3aaeeda29a97a4178844cfb2f316b8c5..7264430fad08837be0ae5a7b75b3027a62a08e5c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
        * sysdeps/riscv/nptl/bits/semaphore.h: Likewise.
        * sysdeps/riscv/nptl/libc-lowlevellock.c: Likewise.
        * sysdeps/unix/sysv/linux/riscv/atomic-machine.h: Likewise.
+       * sysdeps/riscv/nptl/nptl-sysdep.S: New file.
+       * sysdeps/unix/sysv/linux/riscv/arch-fork.h: Likewise.
+       * sysdeps/unix/sysv/linux/riscv/clone.S: Likewise.
+       * sysdeps/unix/sysv/linux/riscv/profil-counter.h: Likewise.
+       * sysdeps/unix/sysv/linux/riscv/pt-vfork.S: Likewise.
+       * sysdeps/unix/sysv/linux/riscv/syscall.c: Likewise.
+       * sysdeps/unix/sysv/linux/riscv/sysdep.S: Likewise.
+       * sysdeps/unix/sysv/linux/riscv/sysdep.h: Likewise.
+       * sysdeps/unix/sysv/linux/riscv/vfork.S: Likewise.
 
 2018-01-29  Florian Weimer  <fweimer@redhat.com>
 
diff --git a/sysdeps/riscv/nptl/nptl-sysdep.S b/sysdeps/riscv/nptl/nptl-sysdep.S
new file mode 100644 (file)
index 0000000..3f5c2a3
--- /dev/null
@@ -0,0 +1,2 @@
+/* Pull in __syscall_error.  */
+#include <sysdep.S>
diff --git a/sysdeps/unix/sysv/linux/riscv/arch-fork.h b/sysdeps/unix/sysv/linux/riscv/arch-fork.h
new file mode 100644 (file)
index 0000000..f6f5d73
--- /dev/null
@@ -0,0 +1,26 @@
+/* Internal definitions for thread-friendly fork implementation.  Linux/RISC-V.
+   Copyright (C) 2002-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sched.h>
+#include <sysdep.h>
+#include <tls.h>
+
+#define ARCH_FORK() \
+  INLINE_SYSCALL (clone, 5,                                                  \
+                 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \
+                 NULL, NULL, &THREAD_SELF->tid)
diff --git a/sysdeps/unix/sysv/linux/riscv/clone.S b/sysdeps/unix/sysv/linux/riscv/clone.S
new file mode 100644 (file)
index 0000000..392af72
--- /dev/null
@@ -0,0 +1,86 @@
+/* Wrapper around clone system call.  RISC-V version.
+   Copyright (C) 1996-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* 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 <sys/asm.h>
+#include <sysdep.h>
+#define _ERRNO_H       1
+#include <bits/errno.h>
+#include <tls.h>
+#include "tcb-offsets.h"
+
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+            void *parent_tidptr, void *tls, void *child_tidptr) */
+
+       .text
+LEAF (__clone)
+
+       /* Sanity check arguments.  */
+       beqz            a0,L (invalid)  /* No NULL function pointers.  */
+       beqz            a1,L (invalid)  /* No NULL stack pointers.  */
+
+       addi            a1,a1,-16       /* Reserve argument save space.  */
+       REG_S           a0,0(a1)        /* Save function pointer.  */
+       REG_S           a3,SZREG(a1)    /* Save argument pointer.  */
+
+       /* The syscall expects the args to be in different slots.  */
+       mv              a0,a2
+       mv              a2,a4
+       mv              a3,a5
+       mv              a4,a6
+
+       /* Do the system call.  */
+       li              a7,__NR_clone
+       scall
+
+       bltz            a0,L (error)
+       beqz            a0,L (thread_start)
+
+       /* Successful return from the parent.  */
+       ret
+
+L (invalid):
+       li              a0, -EINVAL
+       /* Something bad happened -- no child created.  */
+L (error):
+       j               __syscall_error
+       END (__clone)
+
+/* Load up the arguments to the function.  Put this block of code in
+   its own function so that we can terminate the stack trace with our
+   debug info.  */
+
+ENTRY (__thread_start)
+L (thread_start):
+       /* Restore the arg for user's function.  */
+       REG_L           a1,0(sp)        /* Function pointer.  */
+       REG_L           a0,SZREG(sp)    /* Argument pointer.  */
+
+       /* Call the user's function.  */
+       jalr            a1
+
+       /* Call exit with the function's return value.  */
+       li              a7, __NR_exit
+       scall
+
+       END (__thread_start)
+
+libc_hidden_def (__clone)
+weak_alias (__clone, clone)
diff --git a/sysdeps/unix/sysv/linux/riscv/profil-counter.h b/sysdeps/unix/sysv/linux/riscv/profil-counter.h
new file mode 100644 (file)
index 0000000..748019e
--- /dev/null
@@ -0,0 +1,31 @@
+/* Low-level statistical profiling support function.  Linux/RISC-V version.
+   Copyright (C) 1996-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <signal.h>
+#include <sigcontextinfo.h>
+
+static void
+__profil_counter (int signo, const SIGCONTEXT scp)
+{
+  profil_count ((void *) GET_PC (scp));
+
+  /* This is a hack to prevent the compiler from implementing the
+     above function call as a sibcall.  The sibcall would overwrite
+     the signal context.  */
+  asm volatile ("");
+}
diff --git a/sysdeps/unix/sysv/linux/riscv/pt-vfork.S b/sysdeps/unix/sysv/linux/riscv/pt-vfork.S
new file mode 100644 (file)
index 0000000..1cc8931
--- /dev/null
@@ -0,0 +1 @@
+/* Not needed.  */
diff --git a/sysdeps/unix/sysv/linux/riscv/syscall.c b/sysdeps/unix/sysv/linux/riscv/syscall.c
new file mode 100644 (file)
index 0000000..6589dde
--- /dev/null
@@ -0,0 +1,35 @@
+/* system call interface.  Linux/RISC-V version.
+   Copyright (C) 2001-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+long int
+syscall (long int syscall_number, long int arg1, long int arg2, long int arg3,
+        long int arg4, long int arg5, long int arg6, long int arg7)
+{
+  long int ret;
+  INTERNAL_SYSCALL_DECL (err);
+
+  ret = INTERNAL_SYSCALL_NCS (syscall_number, err, 7, arg1, arg2, arg3, arg4,
+                             arg5, arg6, arg7);
+
+  if (INTERNAL_SYSCALL_ERROR_P (ret, err))
+    return __syscall_error (ret);
+
+  return ret;
+}
diff --git a/sysdeps/unix/sysv/linux/riscv/sysdep.S b/sysdeps/unix/sysv/linux/riscv/sysdep.S
new file mode 100644 (file)
index 0000000..0d9c0b5
--- /dev/null
@@ -0,0 +1,51 @@
+/* syscall error handlers
+   Copyright (C) 2011-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+#if IS_IN (libc)
+# define errno __libc_errno
+#endif
+
+ENTRY (__syscall_error)
+       mv t0, ra
+       /* Fall through to __syscall_set_errno.  */
+END (__syscall_error)
+
+/* Non-standard calling convention: argument in a0, return address in t0,
+   and clobber only t1.  */
+ENTRY (__syscall_set_errno)
+       /* We got here because a0 < 0, but only codes in the range [-4095, -1]
+         represent errors.  Otherwise, just return the result normally.  */
+       li t1, -4096
+       bleu a0, t1, 1f
+       neg a0, a0
+#if RTLD_PRIVATE_ERRNO
+       sw a0, rtld_errno, t1
+#elif defined(__PIC__)
+       la.tls.ie t1, errno
+       add t1, t1, tp
+       sw a0, 0(t1)
+#else
+       lui t1, %tprel_hi(errno)
+       add t1, t1, tp, %tprel_add(errno)
+       sw a0, %tprel_lo(errno)(t1)
+#endif
+       li a0, -1
+1:     jr t0
+END (__syscall_set_errno)
diff --git a/sysdeps/unix/sysv/linux/riscv/sysdep.h b/sysdeps/unix/sysv/linux/riscv/sysdep.h
new file mode 100644 (file)
index 0000000..5470ea3
--- /dev/null
@@ -0,0 +1,325 @@
+/* Assembly macros for RISC-V.
+   Copyright (C) 2011-2018
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LINUX_RISCV_SYSDEP_H
+#define _LINUX_RISCV_SYSDEP_H 1
+
+#include <sysdeps/unix/sysv/linux/generic/sysdep.h>
+#include <tls.h>
+
+#ifdef __ASSEMBLER__
+
+# include <sys/asm.h>
+
+# define ENTRY(name) LEAF(name)
+
+# define L(label) .L ## label
+
+/* Performs a system call, handling errors by setting errno.  Linux indicates
+   errors by setting a0 to a value between -1 and -4095.  */
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                      \
+  .text;                                                       \
+  .align 2;                                                    \
+  ENTRY (name);                                                        \
+  li a7, SYS_ify (syscall_name);                               \
+  scall;                                                       \
+  li a7, -4096;                                                        \
+  bgtu a0, a7, .Lsyscall_error ## name;
+
+# undef PSEUDO_END
+# define PSEUDO_END(sym)                                       \
+  SYSCALL_ERROR_HANDLER (sym)                                  \
+  ret;                                                         \
+  END (sym)
+
+# if !IS_IN (libc)
+#  if RTLD_PRIVATE_ERRNO
+#   define SYSCALL_ERROR_HANDLER(name)                         \
+.Lsyscall_error ## name:                                       \
+       li t1, -4096;                                           \
+       neg a0, a0;                                             \
+        sw a0, rtld_errno, t1;                                 \
+        li a0, -1;
+#  elif defined (__PIC__)
+#   define SYSCALL_ERROR_HANDLER(name)                         \
+.Lsyscall_error ## name:                                       \
+        la.tls.ie t1, errno;                                   \
+       add t1, t1, tp;                                         \
+       neg a0, a0;                                             \
+       sw a0, 0(t1);                                           \
+        li a0, -1;
+#  else
+#   define SYSCALL_ERROR_HANDLER(name)                         \
+.Lsyscall_error ## name:                                       \
+        lui t1, %tprel_hi(errno);                              \
+        add t1, t1, tp, %tprel_add(errno);                     \
+       neg a0, a0;                                             \
+        sw a0, %tprel_lo(errno)(t1);                           \
+        li a0, -1;
+#  endif
+# else
+#  define SYSCALL_ERROR_HANDLER(name)                          \
+.Lsyscall_error ## name:                                       \
+        j       __syscall_error;
+# endif
+
+/* Performs a system call, not setting errno.  */
+# undef PSEUDO_NEORRNO
+# define PSEUDO_NOERRNO(name, syscall_name, args)      \
+  .align 2;                                            \
+  ENTRY (name);                                                \
+  li a7, SYS_ify (syscall_name);                       \
+  scall;
+
+# undef PSEUDO_END_NOERRNO
+# define PSEUDO_END_NOERRNO(name)                      \
+  END (name)
+
+# undef ret_NOERRNO
+# define ret_NOERRNO ret
+
+/* Perfroms a system call, returning the error code.  */
+# undef PSEUDO_ERRVAL
+# define PSEUDO_ERRVAL(name, syscall_name, args)       \
+  PSEUDO_NOERRNO (name, syscall_name, args)            \
+  neg a0, a0;
+
+# undef PSEUDO_END_ERRVAL
+# define PSEUDO_END_ERRVAL(name)                       \
+  END (name)
+
+# undef ret_ERRVAL
+# define ret_ERRVAL ret
+
+#endif /* __ASSEMBLER__ */
+
+/* In order to get __set_errno() definition in INLINE_SYSCALL.  */
+#ifndef __ASSEMBLER__
+# include <errno.h>
+#endif
+
+#include <sysdeps/unix/sysdep.h>
+
+#undef SYS_ify
+#define SYS_ify(syscall_name)  __NR_##syscall_name
+
+#ifndef __ASSEMBLER__
+
+/* List of system calls which are supported as vsyscalls.  */
+# define HAVE_CLOCK_GETRES_VSYSCALL    1
+# define HAVE_CLOCK_GETTIME_VSYSCALL   1
+# define HAVE_GETTIMEOFDAY_VSYSCALL    1
+# define HAVE_GETCPU_VSYSCALL          1
+
+/* Define a macro which expands into the inline wrapper code for a system
+   call.  */
+# undef INLINE_SYSCALL
+# define INLINE_SYSCALL(name, nr, args...)                             \
+  ({ INTERNAL_SYSCALL_DECL (err);                                      \
+     long int __sys_result = INTERNAL_SYSCALL (name, err, nr, args);   \
+     if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (__sys_result, )))  \
+       {                                                               \
+         __set_errno (INTERNAL_SYSCALL_ERRNO (__sys_result, ));                \
+        __sys_result = (unsigned long) -1;                             \
+       }                                                               \
+     __sys_result; })
+
+# define INTERNAL_SYSCALL_DECL(err) do { } while (0)
+
+# define INTERNAL_SYSCALL_ERROR_P(val, err) \
+        ((unsigned long int) (val) > -4096UL)
+
+# define INTERNAL_SYSCALL_ERRNO(val, err)     (-val)
+
+# define INTERNAL_SYSCALL(name, err, nr, args...) \
+       internal_syscall##nr (SYS_ify (name), err, args)
+
+# define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
+       internal_syscall##nr (number, err, args)
+
+# define internal_syscall0(number, err, dummy...)                      \
+({                                                                     \
+       long int _sys_result;                                           \
+                                                                       \
+       {                                                               \
+       register long int __a7 asm ("a7") = number;                     \
+       register long int __a0 asm ("a0");                              \
+       __asm__ volatile (                                              \
+       "scall\n\t"                                                     \
+       : "=r" (__a0)                                                   \
+       : "r" (__a7)                                                    \
+       : __SYSCALL_CLOBBERS);                                          \
+       _sys_result = __a0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+# define internal_syscall1(number, err, arg0)                          \
+({                                                                     \
+       long int _sys_result;                                           \
+                                                                       \
+       {                                                               \
+       register long int __a7 asm ("a7") = number;                     \
+       register long int __a0 asm ("a0") = (long int) (arg0);          \
+       __asm__ volatile (                                              \
+       "scall\n\t"                                                     \
+       : "+r" (__a0)                                                   \
+       : "r" (__a7)                                                    \
+       : __SYSCALL_CLOBBERS);                                          \
+       _sys_result = __a0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+# define internal_syscall2(number, err, arg0, arg1)                    \
+({                                                                     \
+       long int _sys_result;                                           \
+                                                                       \
+       {                                                               \
+       register long int __a7 asm ("a7") = number;                     \
+       register long int __a0 asm ("a0") = (long int) (arg0);          \
+       register long int __a1 asm ("a1") = (long int) (arg1);          \
+       __asm__ volatile (                                              \
+       "scall\n\t"                                                     \
+       : "+r" (__a0)                                                   \
+       : "r" (__a7), "r" (__a1)                                        \
+       : __SYSCALL_CLOBBERS);                                          \
+       _sys_result = __a0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+# define internal_syscall3(number, err, arg0, arg1, arg2)                      \
+({                                                                     \
+       long int _sys_result;                                           \
+                                                                       \
+       {                                                               \
+       register long int __a7 asm ("a7") = number;                     \
+       register long int __a0 asm ("a0") = (long int) (arg0);          \
+       register long int __a1 asm ("a1") = (long int) (arg1);          \
+       register long int __a2 asm ("a2") = (long int) (arg2);          \
+       __asm__ volatile (                                              \
+       "scall\n\t"                                                     \
+       : "+r" (__a0)                                                   \
+       : "r" (__a7), "r" (__a1), "r" (__a2)                            \
+       : __SYSCALL_CLOBBERS);                                          \
+       _sys_result = __a0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+# define internal_syscall4(number, err, arg0, arg1, arg2, arg3)          \
+({                                                                     \
+       long int _sys_result;                                           \
+                                                                       \
+       {                                                               \
+       register long int __a7 asm ("a7") = number;                     \
+       register long int __a0 asm ("a0") = (long int) (arg0);          \
+       register long int __a1 asm ("a1") = (long int) (arg1);          \
+       register long int __a2 asm ("a2") = (long int) (arg2);          \
+       register long int __a3 asm ("a3") = (long int) (arg3);          \
+       __asm__ volatile (                                              \
+       "scall\n\t"                                                     \
+       : "+r" (__a0)                                                   \
+       : "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3)                \
+       : __SYSCALL_CLOBBERS);                                          \
+       _sys_result = __a0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+# define internal_syscall5(number, err, arg0, arg1, arg2, arg3, arg4)   \
+({                                                                     \
+       long int _sys_result;                                           \
+                                                                       \
+       {                                                               \
+       register long int __a7 asm ("a7") = number;                     \
+       register long int __a0 asm ("a0") = (long int) (arg0);          \
+       register long int __a1 asm ("a1") = (long int) (arg1);          \
+       register long int __a2 asm ("a2") = (long int) (arg2);          \
+       register long int __a3 asm ("a3") = (long int) (arg3);          \
+       register long int __a4 asm ("a4") = (long int) (arg4);          \
+       __asm__ volatile (                                              \
+       "scall\n\t"                                                     \
+       : "+r" (__a0)                                                   \
+       : "r" (__a7), "r"(__a1), "r"(__a2), "r"(__a3), "r" (__a4)       \
+       : __SYSCALL_CLOBBERS);                                          \
+       _sys_result = __a0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+# define internal_syscall6(number, err, arg0, arg1, arg2, arg3, arg4, arg5) \
+({                                                                     \
+       long int _sys_result;                                           \
+                                                                       \
+       {                                                               \
+       register long int __a7 asm ("a7") = number;                     \
+       register long int __a0 asm ("a0") = (long int) (arg0);          \
+       register long int __a1 asm ("a1") = (long int) (arg1);          \
+       register long int __a2 asm ("a2") = (long int) (arg2);          \
+       register long int __a3 asm ("a3") = (long int) (arg3);          \
+       register long int __a4 asm ("a4") = (long int) (arg4);          \
+       register long int __a5 asm ("a5") = (long int) (arg5);          \
+       __asm__ volatile (                                              \
+       "scall\n\t"                                                     \
+       : "+r" (__a0)                                                   \
+       : "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3),               \
+         "r" (__a4), "r" (__a5)                                        \
+       : __SYSCALL_CLOBBERS);                                          \
+       _sys_result = __a0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+# define internal_syscall7(number, err, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \
+({                                                                     \
+       long int _sys_result;                                           \
+                                                                       \
+       {                                                               \
+       register long int __a7 asm ("a7") = number;                     \
+       register long int __a0 asm ("a0") = (long int) (arg0);          \
+       register long int __a1 asm ("a1") = (long int) (arg1);          \
+       register long int __a2 asm ("a2") = (long int) (arg2);          \
+       register long int __a3 asm ("a3") = (long int) (arg3);          \
+       register long int __a4 asm ("a4") = (long int) (arg4);          \
+       register long int __a5 asm ("a5") = (long int) (arg5);          \
+       register long int __a6 asm ("a6") = (long int) (arg6);          \
+       __asm__ volatile (                                              \
+       "scall\n\t"                                                     \
+       : "+r" (__a0)                                                   \
+       : "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3),               \
+         "r" (__a4), "r" (__a5), "r" (__a6)                            \
+       : __SYSCALL_CLOBBERS);                                          \
+       _sys_result = __a0;                                             \
+       }                                                               \
+       _sys_result;                                                    \
+})
+
+# define __SYSCALL_CLOBBERS "memory"
+
+extern long int __syscall_error (long int neg_errno);
+
+#endif /* ! __ASSEMBLER__ */
+
+/* Pointer mangling is not supported.  */
+#define PTR_MANGLE(var) (void) (var)
+#define PTR_DEMANGLE(var) (void) (var)
+
+#endif /* linux/riscv/sysdep.h */
diff --git a/sysdeps/unix/sysv/linux/riscv/vfork.S b/sysdeps/unix/sysv/linux/riscv/vfork.S
new file mode 100644 (file)
index 0000000..6c53e93
--- /dev/null
@@ -0,0 +1,44 @@
+/* vfork for Linux, RISC-V version.
+   Copyright (C) 2005-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* vfork() is just a special case of clone().  */
+
+#include <sys/asm.h>
+#include <sysdep.h>
+#define __ASSEMBLY__
+#include <linux/sched.h>
+#include <asm/signal.h>
+
+       .text
+LEAF (__libc_vfork)
+
+       li      a0, (CLONE_VFORK | CLONE_VM | SIGCHLD)
+       mv      a1, sp
+
+       li      a7, __NR_clone
+       scall
+
+       bltz    a0, 1f
+       ret
+
+1:     j               __syscall_error
+END (__libc_vfork)
+
+weak_alias (__libc_vfork, vfork)
+strong_alias (__libc_vfork, __vfork)
+libc_hidden_def (__vfork)