Pārlūkot izejas kodu

riscv: add support for ucontext functions

These functions (largely obsolescent) are from SUSv3 and allow
contex switching within userspace ("green threading").

Ported over from the patch where they were added to glibc
7f33b09c65e3fdb6 ("RISC-V: Linux ABI").
Only minimal change was __glibc_unlikely => unlikely

Signed-off-by: Charles Mirabile <cmirabil@redhat.com>
Charles Mirabile 4 mēneši atpakaļ
vecāks
revīzija
ef7f32713e

+ 1 - 0
extra/Configs/Config.riscv32

@@ -12,3 +12,4 @@ config FORCE_OPTIONS_FOR_ARCH
 	default y
 	select ARCH_LITTLE_ENDIAN
 	select ARCH_HAS_MMU
+	select ARCH_HAS_UCONTEXT

+ 1 - 0
extra/Configs/Config.riscv64

@@ -12,3 +12,4 @@ config FORCE_OPTIONS_FOR_ARCH
 	default y
 	select ARCH_LITTLE_ENDIAN
 	select ARCH_HAS_MMU
+	select ARCH_HAS_UCONTEXT

+ 2 - 0
libc/sysdeps/linux/riscv32/Makefile.arch

@@ -1,2 +1,4 @@
 CSRC-y := __syscall_error.c cache.c
 SSRC-y := __longjmp.S setjmp.S vfork.S clone.S
+CSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += makecontext.c
+SSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += getcontext.S setcontext.S swapcontext.S

+ 77 - 0
libc/sysdeps/linux/riscv32/getcontext.S

@@ -0,0 +1,77 @@
+/* Save current context.
+   Copyright (C) 2009-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 "ucontext-macros.h"
+
+/* int getcontext (ucontext_t *ucp) */
+
+	.text
+LEAF (__getcontext)
+	SAVE_INT_REG (ra,   0, a0)
+	SAVE_INT_REG (ra,   1, a0)
+	SAVE_INT_REG (sp,   2, a0)
+	SAVE_INT_REG (s0,   8, a0)
+	SAVE_INT_REG (s1,   9, a0)
+	SAVE_INT_REG (x0,  10, a0)	/* return 0 by overwriting a0.  */
+	SAVE_INT_REG (s2,  18, a0)
+	SAVE_INT_REG (s3,  19, a0)
+	SAVE_INT_REG (s4,  20, a0)
+	SAVE_INT_REG (s5,  21, a0)
+	SAVE_INT_REG (s6,  22, a0)
+	SAVE_INT_REG (s7,  23, a0)
+	SAVE_INT_REG (s8,  24, a0)
+	SAVE_INT_REG (s9,  25, a0)
+	SAVE_INT_REG (s10, 26, a0)
+	SAVE_INT_REG (s11, 27, a0)
+
+#ifndef __riscv_float_abi_soft
+	frsr	a1
+
+	SAVE_FP_REG (fs0,   8, a0)
+	SAVE_FP_REG (fs1,   9, a0)
+	SAVE_FP_REG (fs2,  18, a0)
+	SAVE_FP_REG (fs3,  19, a0)
+	SAVE_FP_REG (fs4,  20, a0)
+	SAVE_FP_REG (fs5,  21, a0)
+	SAVE_FP_REG (fs6,  22, a0)
+	SAVE_FP_REG (fs7,  23, a0)
+	SAVE_FP_REG (fs8,  24, a0)
+	SAVE_FP_REG (fs9,  25, a0)
+	SAVE_FP_REG (fs10, 26, a0)
+	SAVE_FP_REG (fs11, 27, a0)
+
+	sw	a1, MCONTEXT_FSR(a0)
+#endif /* __riscv_float_abi_soft */
+
+/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
+	li	a3, _NSIG8
+	add     a2, a0, UCONTEXT_SIGMASK
+	mv	a1, zero
+	li	a0, SIG_BLOCK
+
+	li	a7, SYS_ify (rt_sigprocmask)
+	scall
+	bltz	a0, 99f
+
+	ret
+
+99:	j	__syscall_error
+
+PSEUDO_END (__getcontext)
+
+weak_alias (__getcontext, getcontext)

+ 78 - 0
libc/sysdeps/linux/riscv32/makecontext.c

@@ -0,0 +1,78 @@
+/* Create new context.  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>
+#include <sys/asm.h>
+#include <sys/ucontext.h>
+#include <stdarg.h>
+#include <assert.h>
+
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc,
+	       long int a0, long int a1, long int a2, long int a3, long int a4,
+	       ...)
+{
+  extern void __start_context (void) attribute_hidden;
+  long int i, sp;
+
+  _Static_assert (REG_NARGS == 8, "__makecontext assumes 8 argument registers");
+
+  /* Set up the stack.  */
+  sp = ((long int) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size) & ALMASK;
+
+  /* Set up the register context.
+     ra = s0 = 0, terminating the stack for backtracing purposes.
+     s1 = the function we must call.
+     s2 = the subsequent context to run.  */
+  ucp->uc_mcontext.__gregs[REG_RA] = 0;
+  ucp->uc_mcontext.__gregs[REG_S0] = 0;
+  ucp->uc_mcontext.__gregs[REG_S1] = (long int) func;
+  ucp->uc_mcontext.__gregs[REG_S2] = (long int) ucp->uc_link;
+  ucp->uc_mcontext.__gregs[REG_SP] = sp;
+  ucp->uc_mcontext.__gregs[REG_PC] = (long int) &__start_context;
+
+  /* Put args in a0-a7, then put any remaining args on the stack.  */
+  ucp->uc_mcontext.__gregs[REG_A0 + 0] = a0;
+  ucp->uc_mcontext.__gregs[REG_A0 + 1] = a1;
+  ucp->uc_mcontext.__gregs[REG_A0 + 2] = a2;
+  ucp->uc_mcontext.__gregs[REG_A0 + 3] = a3;
+  ucp->uc_mcontext.__gregs[REG_A0 + 4] = a4;
+
+  if (unlikely(argc > 5))
+    {
+      va_list vl;
+      va_start (vl, a4);
+
+      long reg_args = argc < REG_NARGS ? argc : REG_NARGS;
+      for (i = 5; i < reg_args; i++)
+        ucp->uc_mcontext.__gregs[REG_A0 + i] = va_arg (vl, long);
+
+      long int stack_args = argc - reg_args;
+      if (stack_args > 0)
+	{
+	  sp = (sp - stack_args * sizeof (long int)) & ALMASK;
+	  ucp->uc_mcontext.__gregs[REG_SP] = sp;
+	  for (i = 0; i < stack_args; i++)
+	    ((long int *) sp)[i] = va_arg (vl, long int);
+	}
+
+      va_end (vl);
+    }
+}
+
+weak_alias (__makecontext, makecontext)

+ 114 - 0
libc/sysdeps/linux/riscv32/setcontext.S

@@ -0,0 +1,114 @@
+/* Set current context.
+   Copyright (C) 2009-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 "ucontext-macros.h"
+
+/*  int __setcontext (const ucontext_t *ucp)
+
+  Restores the machine context in UCP and thereby resumes execution
+  in that context.
+
+  This implementation is intended to be used for *synchronous* context
+  switches only.  Therefore, it does not have to restore anything
+  other than the PRESERVED state.  */
+
+	.text
+LEAF (__setcontext)
+
+	mv	t0, a0	/* Save ucp into t0.  */
+
+/* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, NULL, _NSIG8) */
+	li	a3, _NSIG8
+	mv	a2, zero
+	add     a1, a0, UCONTEXT_SIGMASK
+	li	a0, SIG_SETMASK
+
+	li	a7, SYS_ify (rt_sigprocmask)
+	scall
+
+	bltz	a0, 99f
+
+	cfi_def_cfa (t0, 0)
+
+#ifndef __riscv_float_abi_soft
+	lw	t1, MCONTEXT_FSR(t0)
+
+	RESTORE_FP_REG_CFI (fs0,   8, t0)
+	RESTORE_FP_REG_CFI (fs1,   9, t0)
+	RESTORE_FP_REG_CFI (fs2,  18, t0)
+	RESTORE_FP_REG_CFI (fs3,  19, t0)
+	RESTORE_FP_REG_CFI (fs4,  20, t0)
+	RESTORE_FP_REG_CFI (fs5,  21, t0)
+	RESTORE_FP_REG_CFI (fs6,  22, t0)
+	RESTORE_FP_REG_CFI (fs7,  23, t0)
+	RESTORE_FP_REG_CFI (fs8,  24, t0)
+	RESTORE_FP_REG_CFI (fs9,  25, t0)
+	RESTORE_FP_REG_CFI (fs10, 26, t0)
+	RESTORE_FP_REG_CFI (fs11, 27, t0)
+
+	fssr	t1
+#endif /* __riscv_float_abi_soft */
+
+	/* Note the contents of argument registers will be random
+	   unless makecontext() has been called.  */
+	RESTORE_INT_REG     (t1,   0, t0)
+	RESTORE_INT_REG_CFI (ra,   1, t0)
+	RESTORE_INT_REG     (sp,   2, t0)
+	RESTORE_INT_REG_CFI (s0,   8, t0)
+	RESTORE_INT_REG_CFI (s1,   9, t0)
+	RESTORE_INT_REG     (a0,  10, t0)
+	RESTORE_INT_REG     (a1,  11, t0)
+	RESTORE_INT_REG     (a2,  12, t0)
+	RESTORE_INT_REG     (a3,  13, t0)
+	RESTORE_INT_REG     (a4,  14, t0)
+	RESTORE_INT_REG     (a5,  15, t0)
+	RESTORE_INT_REG     (a6,  16, t0)
+	RESTORE_INT_REG     (a7,  17, t0)
+	RESTORE_INT_REG_CFI (s2,  18, t0)
+	RESTORE_INT_REG_CFI (s3,  19, t0)
+	RESTORE_INT_REG_CFI (s4,  20, t0)
+	RESTORE_INT_REG_CFI (s5,  21, t0)
+	RESTORE_INT_REG_CFI (s6,  22, t0)
+	RESTORE_INT_REG_CFI (s7,  23, t0)
+	RESTORE_INT_REG_CFI (s8,  24, t0)
+	RESTORE_INT_REG_CFI (s9,  25, t0)
+	RESTORE_INT_REG_CFI (s10, 26, t0)
+	RESTORE_INT_REG_CFI (s11, 27, t0)
+
+	jr	t1
+
+99:	j	__syscall_error
+
+PSEUDO_END (__setcontext)
+weak_alias (__setcontext, setcontext)
+
+LEAF (__start_context)
+
+	/* Terminate call stack by noting ra == 0.  Happily, s0 == 0 here.  */
+	cfi_register (ra, s0)
+
+	/* Call the function passed to makecontext.  */
+	jalr	s1
+
+	/* Invoke subsequent context if present, else exit(0).  */
+	mv	a0, s2
+	beqz	s2, 1f
+	jal	__setcontext
+1:	j	exit
+
+PSEUDO_END (__start_context)

+ 125 - 0
libc/sysdeps/linux/riscv32/swapcontext.S

@@ -0,0 +1,125 @@
+/* Save and set current context.
+   Copyright (C) 2009-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 "ucontext-macros.h"
+
+/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
+
+LEAF (__swapcontext)
+	mv	t0, a1			/* Save ucp into t0.  */
+
+	SAVE_INT_REG (ra,   0, a0)
+	SAVE_INT_REG (ra,   1, a0)
+	SAVE_INT_REG (sp,   2, a0)
+	SAVE_INT_REG (s0,   8, a0)
+	SAVE_INT_REG (s1,   9, a0)
+	SAVE_INT_REG (x0,  10, a0)	/* return 0 by overwriting a0.  */
+	SAVE_INT_REG (s2,  18, a0)
+	SAVE_INT_REG (s3,  19, a0)
+	SAVE_INT_REG (s4,  20, a0)
+	SAVE_INT_REG (s5,  21, a0)
+	SAVE_INT_REG (s6,  22, a0)
+	SAVE_INT_REG (s7,  23, a0)
+	SAVE_INT_REG (s8,  24, a0)
+	SAVE_INT_REG (s9,  25, a0)
+	SAVE_INT_REG (s10, 26, a0)
+	SAVE_INT_REG (s11, 27, a0)
+
+#ifndef __riscv_float_abi_soft
+	frsr a1
+
+	SAVE_FP_REG (fs0,   8, a0)
+	SAVE_FP_REG (fs1,   9, a0)
+	SAVE_FP_REG (fs2,  18, a0)
+	SAVE_FP_REG (fs3,  19, a0)
+	SAVE_FP_REG (fs4,  20, a0)
+	SAVE_FP_REG (fs5,  21, a0)
+	SAVE_FP_REG (fs6,  22, a0)
+	SAVE_FP_REG (fs7,  23, a0)
+	SAVE_FP_REG (fs8,  24, a0)
+	SAVE_FP_REG (fs9,  25, a0)
+	SAVE_FP_REG (fs10, 26, a0)
+	SAVE_FP_REG (fs11, 27, a0)
+
+	sw	a1, MCONTEXT_FSR(a0)
+#endif /* __riscv_float_abi_soft */
+
+/* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, _NSIG8) */
+	li	a3, _NSIG8
+	add	a2, a0, UCONTEXT_SIGMASK
+	add     a1, t0, UCONTEXT_SIGMASK
+	li	a0, SIG_SETMASK
+
+	li	a7, SYS_ify (rt_sigprocmask)
+	scall
+
+	bltz	a0, 99f
+
+#ifndef __riscv_float_abi_soft
+	lw	t1, MCONTEXT_FSR(t0)
+
+	RESTORE_FP_REG (fs0,   8, t0)
+	RESTORE_FP_REG (fs1,   9, t0)
+	RESTORE_FP_REG (fs2,  18, t0)
+	RESTORE_FP_REG (fs3,  19, t0)
+	RESTORE_FP_REG (fs4,  20, t0)
+	RESTORE_FP_REG (fs5,  21, t0)
+	RESTORE_FP_REG (fs6,  22, t0)
+	RESTORE_FP_REG (fs7,  23, t0)
+	RESTORE_FP_REG (fs8,  24, t0)
+	RESTORE_FP_REG (fs9,  25, t0)
+	RESTORE_FP_REG (fs10, 26, t0)
+	RESTORE_FP_REG (fs11, 27, t0)
+
+	fssr	t1
+#endif /* __riscv_float_abi_soft */
+
+	/* Note the contents of argument registers will be random
+	   unless makecontext() has been called.  */
+	RESTORE_INT_REG (t1,   0, t0)
+	RESTORE_INT_REG (ra,   1, t0)
+	RESTORE_INT_REG (sp,   2, t0)
+	RESTORE_INT_REG (s0,   8, t0)
+	RESTORE_INT_REG (s1,   9, t0)
+	RESTORE_INT_REG (a0,  10, t0)
+	RESTORE_INT_REG (a1,  11, t0)
+	RESTORE_INT_REG (a2,  12, t0)
+	RESTORE_INT_REG (a3,  13, t0)
+	RESTORE_INT_REG (a4,  14, t0)
+	RESTORE_INT_REG (a5,  15, t0)
+	RESTORE_INT_REG (a6,  16, t0)
+	RESTORE_INT_REG (a7,  17, t0)
+	RESTORE_INT_REG (s2,  18, t0)
+	RESTORE_INT_REG (s3,  19, t0)
+	RESTORE_INT_REG (s4,  20, t0)
+	RESTORE_INT_REG (s5,  21, t0)
+	RESTORE_INT_REG (s6,  22, t0)
+	RESTORE_INT_REG (s7,  23, t0)
+	RESTORE_INT_REG (s8,  24, t0)
+	RESTORE_INT_REG (s9,  25, t0)
+	RESTORE_INT_REG (s10, 26, t0)
+	RESTORE_INT_REG (s11, 27, t0)
+
+	jr	t1
+
+
+99:	j	__syscall_error
+
+PSEUDO_END (__swapcontext)
+
+weak_alias (__swapcontext, swapcontext)

+ 49 - 0
libc/sysdeps/linux/riscv32/ucontext-macros.h

@@ -0,0 +1,49 @@
+/* Macros for ucontext routines.
+   Copyright (C) 2017-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/>.  */
+
+#ifndef _LINUX_RISCV_UCONTEXT_MACROS_H
+#define _LINUX_RISCV_UCONTEXT_MACROS_H
+
+#include <sysdep.h>
+#include <sys/asm.h>
+
+#include "ucontext_i.h"
+
+#define MCONTEXT_FSR (32 * SZFREG + MCONTEXT_FPREGS)
+
+#define SAVE_FP_REG(name, num, base)			\
+  FREG_S name, ((num) * SZFREG + MCONTEXT_FPREGS)(base)
+
+#define RESTORE_FP_REG(name, num, base)			\
+  FREG_L name, ((num) * SZFREG + MCONTEXT_FPREGS)(base)
+
+#define RESTORE_FP_REG_CFI(name, num, base)		\
+  RESTORE_FP_REG (name, num, base);			\
+  cfi_offset (name, (num) * SZFREG + MCONTEXT_FPREGS)
+
+#define SAVE_INT_REG(name, num, base)			\
+  REG_S name, ((num) * SZREG + MCONTEXT_GREGS)(base)
+
+#define RESTORE_INT_REG(name, num, base)		\
+  REG_L name, ((num) * SZREG + MCONTEXT_GREGS)(base)
+
+#define RESTORE_INT_REG_CFI(name, num, base)		\
+  RESTORE_INT_REG (name, num, base);			\
+  cfi_offset (name, (num) * SZREG + MCONTEXT_GREGS)
+
+#endif /* _LINUX_RISCV_UCONTEXT_MACROS_H */

+ 31 - 0
libc/sysdeps/linux/riscv32/ucontext_i.sym

@@ -0,0 +1,31 @@
+#include <inttypes.h>
+#include <signal.h>
+#include <stddef.h>
+#include <sys/ucontext.h>
+
+-- Constants used by the rt_sigprocmask call.
+
+SIG_BLOCK
+SIG_SETMASK
+
+_NSIG8				(_NSIG / 8)
+
+-- Offsets of the fields in the ucontext_t structure.
+#define ucontext(member)	offsetof (ucontext_t, member)
+#define stack(member)		ucontext (uc_stack.member)
+#define mcontext(member)	ucontext (uc_mcontext.member)
+
+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)
+
+STACK_SP			stack (ss_sp)
+STACK_SIZE			stack (ss_size)
+STACK_FLAGS			stack (ss_flags)
+
+MCONTEXT_GREGS			mcontext (__gregs)
+MCONTEXT_FPREGS			mcontext (__fpregs)
+
+UCONTEXT_SIZE			sizeof (ucontext_t)

+ 2 - 0
libc/sysdeps/linux/riscv64/Makefile.arch

@@ -1,2 +1,4 @@
 CSRC-y := __syscall_error.c cache.c
 SSRC-y := __longjmp.S setjmp.S vfork.S clone.S
+CSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += makecontext.c
+SSRC-$(UCLIBC_HAS_CONTEXT_FUNCS) += getcontext.S setcontext.S swapcontext.S

+ 77 - 0
libc/sysdeps/linux/riscv64/getcontext.S

@@ -0,0 +1,77 @@
+/* Save current context.
+   Copyright (C) 2009-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 "ucontext-macros.h"
+
+/* int getcontext (ucontext_t *ucp) */
+
+	.text
+LEAF (__getcontext)
+	SAVE_INT_REG (ra,   0, a0)
+	SAVE_INT_REG (ra,   1, a0)
+	SAVE_INT_REG (sp,   2, a0)
+	SAVE_INT_REG (s0,   8, a0)
+	SAVE_INT_REG (s1,   9, a0)
+	SAVE_INT_REG (x0,  10, a0)	/* return 0 by overwriting a0.  */
+	SAVE_INT_REG (s2,  18, a0)
+	SAVE_INT_REG (s3,  19, a0)
+	SAVE_INT_REG (s4,  20, a0)
+	SAVE_INT_REG (s5,  21, a0)
+	SAVE_INT_REG (s6,  22, a0)
+	SAVE_INT_REG (s7,  23, a0)
+	SAVE_INT_REG (s8,  24, a0)
+	SAVE_INT_REG (s9,  25, a0)
+	SAVE_INT_REG (s10, 26, a0)
+	SAVE_INT_REG (s11, 27, a0)
+
+#ifndef __riscv_float_abi_soft
+	frsr	a1
+
+	SAVE_FP_REG (fs0,   8, a0)
+	SAVE_FP_REG (fs1,   9, a0)
+	SAVE_FP_REG (fs2,  18, a0)
+	SAVE_FP_REG (fs3,  19, a0)
+	SAVE_FP_REG (fs4,  20, a0)
+	SAVE_FP_REG (fs5,  21, a0)
+	SAVE_FP_REG (fs6,  22, a0)
+	SAVE_FP_REG (fs7,  23, a0)
+	SAVE_FP_REG (fs8,  24, a0)
+	SAVE_FP_REG (fs9,  25, a0)
+	SAVE_FP_REG (fs10, 26, a0)
+	SAVE_FP_REG (fs11, 27, a0)
+
+	sw	a1, MCONTEXT_FSR(a0)
+#endif /* __riscv_float_abi_soft */
+
+/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
+	li	a3, _NSIG8
+	add     a2, a0, UCONTEXT_SIGMASK
+	mv	a1, zero
+	li	a0, SIG_BLOCK
+
+	li	a7, SYS_ify (rt_sigprocmask)
+	scall
+	bltz	a0, 99f
+
+	ret
+
+99:	j	__syscall_error
+
+PSEUDO_END (__getcontext)
+
+weak_alias (__getcontext, getcontext)

+ 78 - 0
libc/sysdeps/linux/riscv64/makecontext.c

@@ -0,0 +1,78 @@
+/* Create new context.  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>
+#include <sys/asm.h>
+#include <sys/ucontext.h>
+#include <stdarg.h>
+#include <assert.h>
+
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc,
+	       long int a0, long int a1, long int a2, long int a3, long int a4,
+	       ...)
+{
+  extern void __start_context (void) attribute_hidden;
+  long int i, sp;
+
+  _Static_assert (REG_NARGS == 8, "__makecontext assumes 8 argument registers");
+
+  /* Set up the stack.  */
+  sp = ((long int) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size) & ALMASK;
+
+  /* Set up the register context.
+     ra = s0 = 0, terminating the stack for backtracing purposes.
+     s1 = the function we must call.
+     s2 = the subsequent context to run.  */
+  ucp->uc_mcontext.__gregs[REG_RA] = 0;
+  ucp->uc_mcontext.__gregs[REG_S0] = 0;
+  ucp->uc_mcontext.__gregs[REG_S1] = (long int) func;
+  ucp->uc_mcontext.__gregs[REG_S2] = (long int) ucp->uc_link;
+  ucp->uc_mcontext.__gregs[REG_SP] = sp;
+  ucp->uc_mcontext.__gregs[REG_PC] = (long int) &__start_context;
+
+  /* Put args in a0-a7, then put any remaining args on the stack.  */
+  ucp->uc_mcontext.__gregs[REG_A0 + 0] = a0;
+  ucp->uc_mcontext.__gregs[REG_A0 + 1] = a1;
+  ucp->uc_mcontext.__gregs[REG_A0 + 2] = a2;
+  ucp->uc_mcontext.__gregs[REG_A0 + 3] = a3;
+  ucp->uc_mcontext.__gregs[REG_A0 + 4] = a4;
+
+  if (unlikely(argc > 5))
+    {
+      va_list vl;
+      va_start (vl, a4);
+
+      long reg_args = argc < REG_NARGS ? argc : REG_NARGS;
+      for (i = 5; i < reg_args; i++)
+        ucp->uc_mcontext.__gregs[REG_A0 + i] = va_arg (vl, long);
+
+      long int stack_args = argc - reg_args;
+      if (stack_args > 0)
+	{
+	  sp = (sp - stack_args * sizeof (long int)) & ALMASK;
+	  ucp->uc_mcontext.__gregs[REG_SP] = sp;
+	  for (i = 0; i < stack_args; i++)
+	    ((long int *) sp)[i] = va_arg (vl, long int);
+	}
+
+      va_end (vl);
+    }
+}
+
+weak_alias (__makecontext, makecontext)

+ 114 - 0
libc/sysdeps/linux/riscv64/setcontext.S

@@ -0,0 +1,114 @@
+/* Set current context.
+   Copyright (C) 2009-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 "ucontext-macros.h"
+
+/*  int __setcontext (const ucontext_t *ucp)
+
+  Restores the machine context in UCP and thereby resumes execution
+  in that context.
+
+  This implementation is intended to be used for *synchronous* context
+  switches only.  Therefore, it does not have to restore anything
+  other than the PRESERVED state.  */
+
+	.text
+LEAF (__setcontext)
+
+	mv	t0, a0	/* Save ucp into t0.  */
+
+/* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, NULL, _NSIG8) */
+	li	a3, _NSIG8
+	mv	a2, zero
+	add     a1, a0, UCONTEXT_SIGMASK
+	li	a0, SIG_SETMASK
+
+	li	a7, SYS_ify (rt_sigprocmask)
+	scall
+
+	bltz	a0, 99f
+
+	cfi_def_cfa (t0, 0)
+
+#ifndef __riscv_float_abi_soft
+	lw	t1, MCONTEXT_FSR(t0)
+
+	RESTORE_FP_REG_CFI (fs0,   8, t0)
+	RESTORE_FP_REG_CFI (fs1,   9, t0)
+	RESTORE_FP_REG_CFI (fs2,  18, t0)
+	RESTORE_FP_REG_CFI (fs3,  19, t0)
+	RESTORE_FP_REG_CFI (fs4,  20, t0)
+	RESTORE_FP_REG_CFI (fs5,  21, t0)
+	RESTORE_FP_REG_CFI (fs6,  22, t0)
+	RESTORE_FP_REG_CFI (fs7,  23, t0)
+	RESTORE_FP_REG_CFI (fs8,  24, t0)
+	RESTORE_FP_REG_CFI (fs9,  25, t0)
+	RESTORE_FP_REG_CFI (fs10, 26, t0)
+	RESTORE_FP_REG_CFI (fs11, 27, t0)
+
+	fssr	t1
+#endif /* __riscv_float_abi_soft */
+
+	/* Note the contents of argument registers will be random
+	   unless makecontext() has been called.  */
+	RESTORE_INT_REG     (t1,   0, t0)
+	RESTORE_INT_REG_CFI (ra,   1, t0)
+	RESTORE_INT_REG     (sp,   2, t0)
+	RESTORE_INT_REG_CFI (s0,   8, t0)
+	RESTORE_INT_REG_CFI (s1,   9, t0)
+	RESTORE_INT_REG     (a0,  10, t0)
+	RESTORE_INT_REG     (a1,  11, t0)
+	RESTORE_INT_REG     (a2,  12, t0)
+	RESTORE_INT_REG     (a3,  13, t0)
+	RESTORE_INT_REG     (a4,  14, t0)
+	RESTORE_INT_REG     (a5,  15, t0)
+	RESTORE_INT_REG     (a6,  16, t0)
+	RESTORE_INT_REG     (a7,  17, t0)
+	RESTORE_INT_REG_CFI (s2,  18, t0)
+	RESTORE_INT_REG_CFI (s3,  19, t0)
+	RESTORE_INT_REG_CFI (s4,  20, t0)
+	RESTORE_INT_REG_CFI (s5,  21, t0)
+	RESTORE_INT_REG_CFI (s6,  22, t0)
+	RESTORE_INT_REG_CFI (s7,  23, t0)
+	RESTORE_INT_REG_CFI (s8,  24, t0)
+	RESTORE_INT_REG_CFI (s9,  25, t0)
+	RESTORE_INT_REG_CFI (s10, 26, t0)
+	RESTORE_INT_REG_CFI (s11, 27, t0)
+
+	jr	t1
+
+99:	j	__syscall_error
+
+PSEUDO_END (__setcontext)
+weak_alias (__setcontext, setcontext)
+
+LEAF (__start_context)
+
+	/* Terminate call stack by noting ra == 0.  Happily, s0 == 0 here.  */
+	cfi_register (ra, s0)
+
+	/* Call the function passed to makecontext.  */
+	jalr	s1
+
+	/* Invoke subsequent context if present, else exit(0).  */
+	mv	a0, s2
+	beqz	s2, 1f
+	jal	__setcontext
+1:	j	exit
+
+PSEUDO_END (__start_context)

+ 125 - 0
libc/sysdeps/linux/riscv64/swapcontext.S

@@ -0,0 +1,125 @@
+/* Save and set current context.
+   Copyright (C) 2009-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 "ucontext-macros.h"
+
+/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
+
+LEAF (__swapcontext)
+	mv	t0, a1			/* Save ucp into t0.  */
+
+	SAVE_INT_REG (ra,   0, a0)
+	SAVE_INT_REG (ra,   1, a0)
+	SAVE_INT_REG (sp,   2, a0)
+	SAVE_INT_REG (s0,   8, a0)
+	SAVE_INT_REG (s1,   9, a0)
+	SAVE_INT_REG (x0,  10, a0)	/* return 0 by overwriting a0.  */
+	SAVE_INT_REG (s2,  18, a0)
+	SAVE_INT_REG (s3,  19, a0)
+	SAVE_INT_REG (s4,  20, a0)
+	SAVE_INT_REG (s5,  21, a0)
+	SAVE_INT_REG (s6,  22, a0)
+	SAVE_INT_REG (s7,  23, a0)
+	SAVE_INT_REG (s8,  24, a0)
+	SAVE_INT_REG (s9,  25, a0)
+	SAVE_INT_REG (s10, 26, a0)
+	SAVE_INT_REG (s11, 27, a0)
+
+#ifndef __riscv_float_abi_soft
+	frsr a1
+
+	SAVE_FP_REG (fs0,   8, a0)
+	SAVE_FP_REG (fs1,   9, a0)
+	SAVE_FP_REG (fs2,  18, a0)
+	SAVE_FP_REG (fs3,  19, a0)
+	SAVE_FP_REG (fs4,  20, a0)
+	SAVE_FP_REG (fs5,  21, a0)
+	SAVE_FP_REG (fs6,  22, a0)
+	SAVE_FP_REG (fs7,  23, a0)
+	SAVE_FP_REG (fs8,  24, a0)
+	SAVE_FP_REG (fs9,  25, a0)
+	SAVE_FP_REG (fs10, 26, a0)
+	SAVE_FP_REG (fs11, 27, a0)
+
+	sw	a1, MCONTEXT_FSR(a0)
+#endif /* __riscv_float_abi_soft */
+
+/* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, _NSIG8) */
+	li	a3, _NSIG8
+	add	a2, a0, UCONTEXT_SIGMASK
+	add     a1, t0, UCONTEXT_SIGMASK
+	li	a0, SIG_SETMASK
+
+	li	a7, SYS_ify (rt_sigprocmask)
+	scall
+
+	bltz	a0, 99f
+
+#ifndef __riscv_float_abi_soft
+	lw	t1, MCONTEXT_FSR(t0)
+
+	RESTORE_FP_REG (fs0,   8, t0)
+	RESTORE_FP_REG (fs1,   9, t0)
+	RESTORE_FP_REG (fs2,  18, t0)
+	RESTORE_FP_REG (fs3,  19, t0)
+	RESTORE_FP_REG (fs4,  20, t0)
+	RESTORE_FP_REG (fs5,  21, t0)
+	RESTORE_FP_REG (fs6,  22, t0)
+	RESTORE_FP_REG (fs7,  23, t0)
+	RESTORE_FP_REG (fs8,  24, t0)
+	RESTORE_FP_REG (fs9,  25, t0)
+	RESTORE_FP_REG (fs10, 26, t0)
+	RESTORE_FP_REG (fs11, 27, t0)
+
+	fssr	t1
+#endif /* __riscv_float_abi_soft */
+
+	/* Note the contents of argument registers will be random
+	   unless makecontext() has been called.  */
+	RESTORE_INT_REG (t1,   0, t0)
+	RESTORE_INT_REG (ra,   1, t0)
+	RESTORE_INT_REG (sp,   2, t0)
+	RESTORE_INT_REG (s0,   8, t0)
+	RESTORE_INT_REG (s1,   9, t0)
+	RESTORE_INT_REG (a0,  10, t0)
+	RESTORE_INT_REG (a1,  11, t0)
+	RESTORE_INT_REG (a2,  12, t0)
+	RESTORE_INT_REG (a3,  13, t0)
+	RESTORE_INT_REG (a4,  14, t0)
+	RESTORE_INT_REG (a5,  15, t0)
+	RESTORE_INT_REG (a6,  16, t0)
+	RESTORE_INT_REG (a7,  17, t0)
+	RESTORE_INT_REG (s2,  18, t0)
+	RESTORE_INT_REG (s3,  19, t0)
+	RESTORE_INT_REG (s4,  20, t0)
+	RESTORE_INT_REG (s5,  21, t0)
+	RESTORE_INT_REG (s6,  22, t0)
+	RESTORE_INT_REG (s7,  23, t0)
+	RESTORE_INT_REG (s8,  24, t0)
+	RESTORE_INT_REG (s9,  25, t0)
+	RESTORE_INT_REG (s10, 26, t0)
+	RESTORE_INT_REG (s11, 27, t0)
+
+	jr	t1
+
+
+99:	j	__syscall_error
+
+PSEUDO_END (__swapcontext)
+
+weak_alias (__swapcontext, swapcontext)

+ 49 - 0
libc/sysdeps/linux/riscv64/ucontext-macros.h

@@ -0,0 +1,49 @@
+/* Macros for ucontext routines.
+   Copyright (C) 2017-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/>.  */
+
+#ifndef _LINUX_RISCV_UCONTEXT_MACROS_H
+#define _LINUX_RISCV_UCONTEXT_MACROS_H
+
+#include <sysdep.h>
+#include <sys/asm.h>
+
+#include "ucontext_i.h"
+
+#define MCONTEXT_FSR (32 * SZFREG + MCONTEXT_FPREGS)
+
+#define SAVE_FP_REG(name, num, base)			\
+  FREG_S name, ((num) * SZFREG + MCONTEXT_FPREGS)(base)
+
+#define RESTORE_FP_REG(name, num, base)			\
+  FREG_L name, ((num) * SZFREG + MCONTEXT_FPREGS)(base)
+
+#define RESTORE_FP_REG_CFI(name, num, base)		\
+  RESTORE_FP_REG (name, num, base);			\
+  cfi_offset (name, (num) * SZFREG + MCONTEXT_FPREGS)
+
+#define SAVE_INT_REG(name, num, base)			\
+  REG_S name, ((num) * SZREG + MCONTEXT_GREGS)(base)
+
+#define RESTORE_INT_REG(name, num, base)		\
+  REG_L name, ((num) * SZREG + MCONTEXT_GREGS)(base)
+
+#define RESTORE_INT_REG_CFI(name, num, base)		\
+  RESTORE_INT_REG (name, num, base);			\
+  cfi_offset (name, (num) * SZREG + MCONTEXT_GREGS)
+
+#endif /* _LINUX_RISCV_UCONTEXT_MACROS_H */

+ 31 - 0
libc/sysdeps/linux/riscv64/ucontext_i.sym

@@ -0,0 +1,31 @@
+#include <inttypes.h>
+#include <signal.h>
+#include <stddef.h>
+#include <sys/ucontext.h>
+
+-- Constants used by the rt_sigprocmask call.
+
+SIG_BLOCK
+SIG_SETMASK
+
+_NSIG8				(_NSIG / 8)
+
+-- Offsets of the fields in the ucontext_t structure.
+#define ucontext(member)	offsetof (ucontext_t, member)
+#define stack(member)		ucontext (uc_stack.member)
+#define mcontext(member)	ucontext (uc_mcontext.member)
+
+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)
+
+STACK_SP			stack (ss_sp)
+STACK_SIZE			stack (ss_size)
+STACK_FLAGS			stack (ss_flags)
+
+MCONTEXT_GREGS			mcontext (__gregs)
+MCONTEXT_FPREGS			mcontext (__fpregs)
+
+UCONTEXT_SIZE			sizeof (ucontext_t)